[erlang-questions] Complex state machines for complex telnet applications

Thom Cherryhomes <>
Tue Jan 24 18:24:07 CET 2017


Thanks so much for replying!

I've definitely got a ton of thinking ahead, but your comments have
verified what little I have been able to figure out, thus far.

The irony here is that I think the telnet part of the system will be the
most complex, as it has to convey a highly stateful and interactive
graph... a web frontend, or a json API for a thick client will be
infinitely easier to deal with when the time comes...heheh...

I'll try to do a pattern where each part of the BBS is its own application,
with a well defined protocol, that a proxy links to and requests a new
process for...

...as well as remove gen_statem from the client, and turn it into a
gen_server, leaving gen_statem for the "other" side...

To tell a bit more about what I'm writing:

This is a sort of 21st century equivalent to a BBS system, think a BBS that
has learned the lessons from today's social networks, and provides multiple
front-ends for computers vintage and new alike, where:

* frontends for telnet
  * ASCII, ANSI, PETSCII, ATASCII, etc..etc.
* web frontend
* JSON API for thick clients
* Users create their own boards, public, or private
* Ability to utilize distributed model to replicate boards to other BBSes
* Chat
* Games

Yeah, it may seem quaint, but i've wanted to write a board of my own for
about 25 years, but never found the time.

The combination of learning Erlang, and seeing what it could provide to
facilitate this idea, is what has spurred me into finally implementing it.

I do not intend to make any money off of it, and will release it GPL, but I
want to make an actual, real example of a _LARGE_ Erlang system, so people
can see how one would be put together.

-Thom

On Tue, Jan 24, 2017 at 5:48 AM Jesper Louis Andersen <
> wrote:

> Here are some thoughts off-hand. They are not too fleshed out.
>
> * I'd definitely run things via Ranch if possible. Some of the subtler
> things in and around reconnect accept pools and so on happens to be solved
> well by Loic in Ranch.
>
> * It may be possible to generalize buffer handling from the user. Consider
> a function handle(Data, BufferState) -> {Cmds, UpdatedBufferState}, where
> Cmds is a list of the commands the user entered.
>
> * Most modules in a BBS probably runs in a Request -> Reply fashion. You
> send a command to the module and it replies with a new display state you
> send to the BBS client. Since each module will keep its own state, you can
> stuff that into a process.
>
> * Modules may have their own state. They may also have BBS-global state
> which enables communication between clients. Say you have a forum module.
> It will have a forum_backend in which you store the actual posts in the
> forum. When a client requests forum access, you spawn a helper which runs
> the Request/Reply pattern proxying the data in the backend to the client.
>
> * gen_statem is probably most useful in modules, and not so much in the
> client itself, unless the interactions are complex and there are certain
> things which can only happen in some limited states, etc.
>
> * Be aggressive and link everything or use monitors. That way, you can
> easily handle errors in parts of the system without taking it all down.
> Also, you can probably handle a hangup by simply terminating the client
> process and then have modules handle a 'DOWN' message and clean up.
>
> * Old BBS'es did not really have it that much, but you could write a
> general command parser and then supply parsed terms to modules. This
> becomes yet another state machine, but it often kept inside the client
> process:
>
> -record(state, {
>     buffer_state :: buffer_state(),
>     parser_state :: parser_state(),
>     socket :: inet:socket(),
>     ...
> }).
>
> * A common beginners mistake is to want to process everything en masse.
> The rule of thumb is to create a process for each truly concurrent activity
> in the system. With that in mind, it may be that module state should not by
> in a proxy process, as above, but rather be embedded directly in the
> client. The forum_backend is truly concurrent however and warrants its own
> process.
>
> * The counterpoint to the last remark: don't be afraid to use a process to
> isolate parts of your system and keep complexity down. Juggling many states
> in one process at the same time means you have to handle every complex
> cross-interaction between them. If you push something to its own process,
> then chances are there are less cross-talk and thus a system which is
> easier to understand and handle.
>
> * Finally: rather than focusing on the "behaviour", focus on the
> interaction protocol. When you talk HTTP, you don't do that by inheriting a
> HTTP-class. You do that by speaking the protocol. This is powerful because
> you *don't* know the internal implementation of the HTTP server. REST was
> only possible in the first place because HTTP was a protocol. In a BBS,
> focus on the module interaction protocol. You don't care for the internal
> implementation, but rather how you talk to it. Once established, it may be
> that 80% of the modules can implemented via a generic callback framework,
> as is the case for the gen_server (where the protocol is OTP). But there
> are always 20% which are not fitting in, and you want that to be possible
> as well.
>
> Feel free to follow up :)
>
>
> On Tue, Jan 24, 2017 at 6:02 AM Thom Cherryhomes <
> > wrote:
>
> Would you, for example, build the ranch protocol as simple as possible,
> and link the other application servers, as needed, with a common protocol?
>
> -Thom
>
> On Sun, Jan 22, 2017 at 2:56 PM Thom Cherryhomes <
> > wrote:
>
> Hello, everyone. This is my first post to the list.
>
>
> I’m a long time swiss army knife of a software and hardware engineer who
> has started to pick up Erlang, because I believe it and languages like it
> to be the future of software development.
>
> With that said, I am working on a personal project of mine that I have
> wanted to complete, a 21st century version of a BBS system, and I believe
> Erlang and OTP are a good language and toolkit to write it in.
>
>
> Code is being dropped here: http://github.com/tschak909/nakbbs
>
>
> I am experimenting with both Ranch and just using gen_tcp with my own
> socket pools, but I do have some design questions.
>
>
> The telnet ports need to present a definite series of states, broken up
> into seperate pieces:
>
>
> I have definite common events that can be stretched across multiple use
> cases:
>
>
> * Display
>
> * Wait for line of input
>
> * Wait for character input
>
> * branch to another menu
>
> * hang up
>
>
> But there will also be definite sections of the system, which could be
> thought of as states:
>
>
> * Authentication
>
> * Message Browser
>
> * Message Editor
>
> * Various Games
>
>
> etc.
>
>
> and I’m trying to think of an appropriate architectural pattern that will
> avoid me basically having to cram every conceivable state as a sort of
> hierarchy of tuples into a single gen_statem module. How can I approach
> this in a nice abstract and extensible manner, that I could for example
> push into a Behaviour and subsequently utilize for different terminal
> types? It would be nice to split up the different parts of the system into
> applications that would essentially be called from well defined APIs…
>
>
> I’m just trying to figure this all out, and would love a semblence of
> direction so I can do the proper research and deeply understand what I need
> to learn.
>
>
> -Thom
>
>
> _______________________________________________
> erlang-questions mailing list
> 
> http://erlang.org/mailman/listinfo/erlang-questions
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://erlang.org/pipermail/erlang-questions/attachments/20170124/582f7000/attachment.html>


More information about the erlang-questions mailing list