#Messaging
Flok uses two endpoints named if_dispatch and int_dispatch to communicate between the flok server and client. When the flok server wants to message the client, the flok server
calls if_dispatch. When the client wants to message the flok server, the client calls int_disptach. These two receive virtually the same formats
with the difference being that if_dispatch receives a multi-array queue where each array has a number pre-pended to the front that indicates the
queue the message is supposed to be interpreted in. int_dispatch always run synchronously, so it does not have a multi-dimensional array, only one
array that has no integer in the front.
#Scheme Each message is composed of 3 parts.
[arg_length, function_name, *args]
- arg_length - How many argugments are in *args
- message_name - What message type (function) is this?
- *args - A list of arguments that are being sent to the function (any type, including hashes are supported)
Multiple messages can be coalesced by just appending them to the same (flat) array.
###Examples Here are some simple examples
//3+4
[2, "sum", 3, 4]
//sqrt(12)
[1, "sqrt", 12]
//3+4 and then sqrt(12)
[2, "sum", 3, 4, 1, "sqrt", 12]On the server, all messages come through int_dispatch. Messages are then turned into function calls by using the
message_name as the function name and parameters are passed via apply. All functions that are caled in this manner
live in ./app/kern/mod/ and have the convention of being called int_*.
On the client, the driver decides on how messages are handled. At a minimum, the client must support the if_dispatch function
call. The driver is given a queue suggestion based on the first number for each message queue in the if_dispatch call. See
Dispatching for more information.
Both the client and server are responsible for being able to reply to a few test messages.
#####For the client
- Given
[[0, 0, "ping_nothing"]], do nothing. Used fordispatch_spec - Given
[[0, 0, "ping"]]respond with[0, pong] - Given
[[0, 1, "ping1", arg]]respond with[1, pong1, arg] - Given
[[0, 2, "ping2", arg1, arg2]]respond with[1, "pong2", arg1]and[2, "pong2", arg1, arg2] - Given
[[0, 2, "ping2", arg1, arg2]]respond with[1, "pong2", arg1]and[2, "pong2", arg1, arg2] - Given
[[0, 0, "ping", 0, "ping"]]respond with[0, "pong"]and[0, "pong"] - Given
[[0, 1, "ping1", secret1, 1, "ping1", secret2]]respond with[1, "pong1", secret1]and[1, "pong1", secret2] - Given
[[0, 1, "ping1", secret1, 1, "ping1", secret2]]respond with[1, "pong1", secret1]and[1, "pong1", secret2] - Given
[[0, 2, "ping2", secret1, secret2, 2, "ping2", secret2, secret1]]respond with:[1, "pong2", secret1][2, "pong2", secret1, secret2][1, "pong2", secret2][2, "pong2", secret2, secret1]
#####For the server
- Given
[0, "ping"]respond with[[0, 0, pong]] - Given
[1, "ping1", arg]respond with[[0, 1, pong1, arg]] - Given
[2, "ping2", arg1, arg2]]respond with[[0, 1, "pong2", arg1, 2, "pong2", arg1, arg2]] - Given
[2, "ping2", arg1, arg2]]respond with[[0, 1, "pong2", arg1, 2, "pong2", arg1, arg2]] - Given
[0, "ping", 0, "ping"]respond with[[0, 0, "pong", 0, "pong"]] - Given
[1, "ping1", secret1, 1, "ping1", secret2]respond with[[0, 1, "pong1", secret1, 1, "pong1", secret2]] - Given
[1, "ping1", secret1, 1, "ping1", secret2]respond with[[0, 1, "pong1", secret1, 1, "pong1", secret2]] - Given
[2, "ping2", secret1, secret2, 2, "ping2", secret2, secret1]respond with:[[0, 1, "pong2", secret1, 2, "pong2", secret1, secret2, 1, "pong2", secret2, 2, "pong2", secret2, secret1]]
- Given
[1, "ping3", queue_name]respond with[[queue_index, 0, "pong3"]] - Given
[1, "ping3", queue_nameA, 1, "ping3", queue_nameA, 1, "ping3", queue_nameB]respond with[[queue_indexA, 0, "pong3", 0, "pong3"], [queue_indexB, 0, "pong3"]] - Given
[1, "ping3", queue_name]respond with[[queue_index, 0, "pong3"]]and then given[1, "ping3", queue_name]respond with[[queue_index, 0, "pong3"]] - Given
[1, "ping4", queue_index]x6respond with `[[queue_index, *[0, "pong4"]*5]]- Then given
[1, "ping4", queue_index]respond with[] - Given
[0, "ping4_int"]respond with[[queue_index, 0, "pong4"]]
- Then given
- If the queue_index is 0 (main), it should queue all 6
- Given `['i', *]` for a queue will force the client to request another queue after it is done processing.
Protocols are informal conventions used in Flok when sending certain messages.
[N+2, "if_*", ... , tp_base, tp_targets, ...]- Multiple targets[N+1, "if_*", ..., tp_base, ...]- One target (acts as same above but only one target)
This protocol supports virtual de-referencing. When an entity is initialized, the server notifies the client that it (the client) should be able to dereference that entity via the telepathic pointer (tele-pointer for short) the server just gave in the initialization.
For most clients, this would work via having a global hash table that can relate the telepathic pointers to native pointers. Here is an example de-reference table:
[tp native_addr]
0 0x30203023
1 0x12040212The client receives to arguments in the message,
tp_base- The base pointertp_targets- An array that contains the names of all the objects that need to be accessible via a tele-pointer.
An example of these arguments could be:
tp_base- 33tp_targets- ['main_view', 'content']
These arguments are saying that the first pointer will be given the address 33 and needs to refer to the main_view.
The second pointer will be given the address 34, you increment the pointer by 1 each new target. 34 will refer to the content
[tp native_addr]
33 0x10ab4022(&mainView)
34 0x10ab3012(&content)On the server side, the tp_base comes from calling tels(n) where n is the number of targets you will need.