-
Notifications
You must be signed in to change notification settings - Fork 22
State Machine
Here I try to document the finite state machine I've created for the bot.
The core of the bot is a gen_statem process that has two child processes. First of the children is a gen_event process that manages the Plugins. The other process is created when needed and handles the tcp connection. The state machine (ircbot_statem.erl) has 4 states: standby
, connecting
, registering
, ready
, and reconnect
.
The bot starts in the standby state and it only cares about one event, the connect
command. When it receives the connect command, it'll spawn a connection process and change to the connecting
state. It will also set a timeout (CONNECT_TIMEOUT), so that if no events happen in that time, a timeout event is sent.
In the connecting state we handle 3 events: timeout
, exit
and success
. success is sent from the connection process when the TCP connection is successfully established, the bot then sends the irc login commands and changes to the registering
state (again with a timeout set, REGISTER_TIMEOUT).
The exit
event is triggered when the fsm detects that the connection child process is dead (see also handle_info in the fsm source). timeout
is triggered if no other event is received for CONNECT_TIMEOUT time (this needs to be at least as long as a dns resolve could take). Both on exit and timeout the handler will send a reconnect event to itself and change back to the standby
state.
The registering state is very similar to the connecting
. It similarly handles a timeout
and exit
events and goes back to the standby
state.
The main purpose of this state is to wait for the 001 "welcome" response from the irc server. When it receives it, it'll notify the plugins that the system is online, and continue to the ready
state. Then it's the job of plugins, like for example the channels plugin will connect to all the configured channels, to initialize their state.
Here I should probably also handle a 433 "nickname is in use" response from the irc server.
The ready state is the main operational state of the ircbot. It handles a {send, Msg} and {received, Msg} events (commands). The {send, Msg} command is forwarded to the connection process. The {received, Msg} event is received from the connection process, and dispatched to the gen_event manager that handles the plugins. Everything else is handled by the plugins (including joining channels, responding to server PINGs and to CTCP requests).
The ready state doesn't have any timeouts, but the connection process will die if there's nohing happening for some time. In the ready state I handle the exit event, which as ever will change to standby and trigger a reconnect event.
…
There is a global synchronous handler for the disconnect
command. And also for plugin management, the commands add_plugin, delete_plugin and which_plugins are mapped on the ircbot_plugins/gen_event functions.
There are some catch-all event handlers in almost all the states that should probably be removed. It's a kind of defensive programing that's not idiomatic in the Erlang world. The Erlang way is "fail early, fail often… and use supervisors!".