Table of Contents
FluidAE is a system of Modules which communicate over a special messaging system that uses concepts similar to "remote procedure calls".
A module looks like this:
include kernel/modules.e as mod --the module needs this library to work with the kernel
atom ModID --each module gets an ID assigned by the kernel and uses it when calling certain routines.
constant --each module declares some basic information about itself
ModName = "example",
ModVerson = "1.0",
ModDate = "2008-08-01",
ModAuthor = "Ryan Johnson",
ModDescription = "Example module source code"
sequence sessions = {} --List of client sessions established
----------------------------------------------------------------
--Module's internal routines, variables, etc.
---------------------------------------------------------------
function start()
--This is called when the kernel starts the module.
return 1
end function
function stop()
--This is called when the kernel stops the module.
return 1
end function
procedure main()
--Each module has a main task which the kernel schedules after the start() function is called.
while 1 do
mod:nextmsg(ModID) --process next message from the kernel so that events can be processed.
--do internal module processing here
task_yield()
end while
end procedure
procedure event(atom sesid, sequence evname, object evdata)
--called by the kernel when an event is received from another module
end procedure
procedure open_session(atom sesid, atom remoteid, sequence remotemodulepath, object userid)
sessions &= sesid
--called by the kernel when another module has opened a session with this module.
--This is where the module may initialize data for the session.
end procedure
procedure close_session(atom sesid)
sessions = remove(sessions, find(sesid, sessions))
--called by the kernel when another module has closed a session with this module.
--This is where the module may clean up data from the session.
end procedure
--The module must register itself with the kernel and receive an ID.
--Later, the kernel can start up the module if configured to do so.
ModID = mod:register(
ModName,
ModVerson,
ModDate,
ModAuthor,
ModDescription,
routine_id("start"),
routine_id("stop"),
routine_id("main"),
routine_id("event"),
routine_id("open_session"),
routine_id("close_session")
)
--Module Commands-----------------------------------------------------------------------------
--This is where all of the module's commands are declared and registered with the module.
--Once another module has established a session with this module, it can call these commands.
procedure command_example1(atom sesid, object returnkey, atom exampleparam1, sequence exampleparam2, object exampleparam2)
--This command acts like a function by returning data to the caller:
returnval(ModID, sesid, returnkey, "command example return data")
end procedure
mod:command(ModID, "command_example1", routine_id("command_example1"), "This is a built-in description of the command.")
procedure command_example2(atom sesid, object returnkey, atom exampleparam1, sequence exampleparam2, object exampleparam2)
--This command acts like a procedure. It simply executes.
end procedure
mod:command(ModID, "command_example2", routine_id("command_example2"), "This is a built-in description of another command.")
A module opens Sessions with other modules. In this example, the local "gui" module is referred to. In a later document, I will explain how you can connect to modules on remote computers.
atom sesGui, winMain sesGui = mod:sesopen(ModID, "gui")
Once a session is established, it can call Commands and receive Events.
Some commands are like procedures - they are simply called.
mod:cmd(ModID, sesGui, "widget_show", {winMain})
Other commands are similar to functions - a module calls a command and waits for a Return-Data Message.
winMain = mod:waitfor(ModID, sesGui, "widget_create", {0, "window", {
{"title", "Test Window " & sprint(w)},
{"position", {100, 100}},
{"size", {640, 480}}
}})
The widget_create command in the GUI module looks like this:
procedure widget_create(atom sesid, object returnkey, atom wparent, sequence wclass, object wprops)
mod:returnval(ModID, sesid, returnkey, widget:widget_create(sesid, wparent, wclass, wprops))
end procedure
mod:command(ModID, "widget_create", routine_id("widget_create"), "Create widget")
As you can see in this example, when the command is called, it returns a value.
The "server" module (the module that you open the session with and call it's commands) cannot call commands in the "client" module (the module that requested to open a session). In other words, command calls are one-way. However, if the "server" module needs to send a data back to the client, it sends an Event.
mod:event(ModID, sessions[s], "TEST_EVENT", "eventdata")
An Event is similar to a Return Data message, but the difference is a Return Data is waited for after calling a command that is expected to return data (function-type command). An event can be received at any time while the session is established. Sometimes, an Event is randomly received, but sometimes a series of events might be received after calling a command. For example, lets say you call a "load_list" command. The server module will begin processing the request and send a series of events, each one containing an item of the list that has been requested. All this can be happening while both modules are doing other things. FluidAE is designed for multi-tasking. This may seem complicated, but consider this: There may be many modules running at the same time which need a way to communicate with each other and share the CPU. Also, they may communicate over a network, which always has the possibility of network delays and intermittent connection problems. So, the Module API may be more complicated than simple including a library and calling routines, but compared to setting up your own multi-tasking multi-user networked system from scratch, it's very simple! The Module API is designed to have many simultaneous sessions established between modules and can therefore make it very easy to set up server-client systems and even parallel processing!
The module API does not define how data is formatted or how events may be handled, it simply provides a framework to allow modules to easily call commands and receive events. It is up to the module programmer to define how the commands and events will work. In many cases, programming in FluidAE requires event-based programming, not sequential.