Skip to content

Latest commit

 

History

History
115 lines (93 loc) · 6.09 KB

messaging.md

File metadata and controls

115 lines (93 loc) · 6.09 KB

#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]

How messages are handled

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.

Ping

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 for dispatch_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. [1, "pong2", secret1]
    2. [2, "pong2", secret1, secret2]
    3. [1, "pong2", secret2]
    4. [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]x6 respond with `[[queue_index, *[0, "pong4"]*5]]
    • Then given [1, "ping4", queue_index] respond with []
    • Given [0, "ping4_int"] respond with [[queue_index, 0, "pong4"]]
  • If the queue_index is 0 (main), it should queue all 6

Dispatch Spec

- Given `['i', *]` for a queue will force the client to request another queue after it is done processing.

Protocols

Protocols are informal conventions used in Flok when sending certain messages.

@telepathy(2)
  1. [N+2, "if_*", ... , tp_base, tp_targets, ...] - Multiple targets
  2. [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     0x12040212

The client receives to arguments in the message,

  1. tp_base - The base pointer
  2. tp_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:

  1. tp_base - 33
  2. tp_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.