MRCI/docs/async.md
Maurice O'Neal c8f53d1e5c Slimmed down and simplified host administering
- I decided to remove the entire concept of a root user.
  Instead, the host initializes as a blank slate and it
  will be up to the host admin to create a rank 1 user via
  the new command line option "-add_admin" to do initial
  setup with.

- There is no longer such a concept as a protected user.
  Meaning even the last rank 1 user in the host database
  is allowed to delete or modify the rank of their own
  account. To prevent permanent "admin lock out" in this
  scenario the "-elevate" command line option was created.

- Host settings are no longer stored in the database.
  Instead, host settings are now stored in a conf.json file
  in /etc/mrci/conf.json if running on a linux based OS or
  in %Programdata%\mrci\conf.json if running on Windows.

- Email templates are no longer stored in the database.
  Instead, the templates can be any file formatted in UTF-8
  text stored in the host file system. The files they point
  to can be modified in the conf.json file.

- The conf file also replaced all use env variables so
  MRCI_DB_PATH, MRCI_WORK_DIR, MRCI_PRIV_KEY and
  MRCI_PUB_KEY are no longer in use. SSL/TLS cert paths can
  be modified in the conf file.

- Removed email template cmds set_email_template and
  preview_email.

- Also removed cmds close_host, host_config and
  restart_host. The actions these commands could do is best
  left to the host system command line.

- The database class will now explicitly check for write
  permissions to the database and throw an appropriate
  error message if the check fails. "DROP TABLE" SQL
  abilities were added to make this happen.

- Removed async cmds exit(3), maxses(5) and restart(11).
2020-11-10 14:47:00 -05:00

303 lines
21 KiB
Markdown

### 5.1 Async Commands ###
An async command is a virtual command that the host can use to send data to the client at any time while connected to the host. As the name implies, the occurance of a client receiving data from an async command is not always the result of running a regular command in the current session. This can occur for example when information in your account is changed by another client connected to the host; your client would not know about this change until an async command is sent notify it of the change. These commands can be called directly or indirectly by a module and are considered "virtual" commands because there is no defined objects attached to them. Instead, async commands are best identified by command id values 1-255.
Async commands are not only used to send data to the client but also used internally within the host to help objects operating in different processes to communicate with each other. Some async commands in fact are considered internal only because the client should never see any data come from them at anytime. There is also data flow contriants for async commands, meaning some gets blocked if sent from the module or has no effect if sent with the unexpected [IPC](type_ids.md) type id. The list below shows the various data flow contriants each of these async commands have.
Here is a describtion of what the keywords in the list mean:
```
client - this means the async command id will be used to forward
data of any type to client if needed.
internal - this means the async command used by internal host
objects only so it never gets forwarded to a client at
any time.
public - this means the aysnc command will be broadcasted to all
session objects currently connected to the host. which
sessions will resond to it depends on the data being
sent. some async's broadcasted this way will also feed
back to source session depending on the data.
private - this means the async command will only be sent to the
local session.
retricted - this means the async command will be used by the local
session object only. any modules/commands sending it
will be ignored or blocked.
```
```
enum AsyncCommands : quint16
{
ASYNC_RDY = 1, // client | retricted
ASYNC_SYS_MSG = 2, // client | retricted
ASYNC_CAST = 4, // client | public
ASYNC_LOGOUT = 6, // internal | private
ASYNC_USER_DELETED = 7, // client | public
ASYNC_DISP_RENAMED = 8, // internal | public
ASYNC_USER_RANK_CHANGED = 9, // internal | public
ASYNC_CMD_RANKS_CHANGED = 10, // internal | public
ASYNC_ENABLE_MOD = 12, // internal | public
ASYNC_DISABLE_MOD = 13, // internal | public
ASYNC_END_SESSION = 14, // internal | private
ASYNC_USER_LOGIN = 15, // internal | private
ASYNC_TO_PEER = 16, // client | retricted
ASYNC_LIMITED_CAST = 17, // client | public
ASYNC_RW_MY_INFO = 18, // internal | public
ASYNC_P2P = 19, // client | public
ASYNC_CLOSE_P2P = 20, // internal | public
ASYNC_NEW_CH_MEMBER = 21, // client | public
ASYNC_DEL_CH = 22, // client | public
ASYNC_RENAME_CH = 23, // client | public
ASYNC_CH_ACT_FLAG = 24, // internal | public
ASYNC_NEW_SUB_CH = 25, // client | public
ASYNC_RM_SUB_CH = 26, // client | public
ASYNC_RENAME_SUB_CH = 27, // client | public
ASYNC_INVITED_TO_CH = 28, // client | public
ASYNC_RM_CH_MEMBER = 29, // client | public
ASYNC_INVITE_ACCEPTED = 30, // client | public
ASYNC_MEM_LEVEL_CHANGED = 31, // client | public
ASYNC_SUB_CH_LEVEL_CHG = 32, // client | public
ASYNC_ADD_RDONLY = 33, // client | public
ASYNC_RM_RDONLY = 34, // client | public
ASYNC_ADD_CMD = 35, // client | retricted
ASYNC_RM_CMD = 36, // client | retricted
ASYNC_USER_RENAMED = 37, // internal | public
ASYNC_PING_PEERS = 38, // internal | private
ASYNC_OPEN_SUBCH = 39, // internal | private
ASYNC_CLOSE_SUBCH = 40, // internal | private
ASYNC_KEEP_ALIVE = 42, // internal | private
ASYNC_SET_DIR = 43, // internal | private
ASYNC_DEBUG_TEXT = 44, // internal | private
ASYNC_HOOK_INPUT = 45, // internal | private
ASYNC_UNHOOK = 46 // internal | private
};
```
### 5.2 Async Data ###
```ASYNC_RDY (1)```
This command signals to the client that your current session is now ready to start running commands. This is sent to the client after successfully setting up the tcp connection ([protocol](protocol.md)). It can carry [TEXT](type_ids.md) data that can be displayed directly to the user if needed.
```ASYNC_SYS_MSG (2)```
This command carry [TEXT](type_ids.md) or [ERR](type_ids.md) data that are system messages that can be directly displayed to the user of needed. It is also used to carry MY_INFO data when local user account information is changed.
```ASYNC_CAST (4)```
This is an internal only command that carries a 54byte open sub-channels list described in section 5.3 and an embedded frame that can then be sent to clients that have any of the matching open sub-channels. It drops that sub-channel list before arriving at the client so it will apppear like a regular [mrci frame](protocol.md) of any data type.
```
from_module: [54bytes(sub_channel_list)][1byte(type_id)][rest-of-bytes(pay_load)]
to_client: [type_id][cmd_id(4)][branch_id(0)][size_of_payload][payload]
```
```ASYNC_LOGOUT (6)```
This internal only async command doesn't carry any data. This can be used by modules to tell the session object to logout the current user.
```ASYNC_USER_DELETED (7)```
This command carries a 32byte user id hash of the user account that was delete from the host database. All sessions that are currently logged into this account will force logout.
```ASYNC_DISP_RENAMED (8)```
This command carries a combination of the 32byte user id hash and the 64byte new display name (UTF-8, padded with 0x00) of the user account that changed it's display name. This will trigger all sessions that are currently logged into this account to send an updated [MY_INFO](type_ids.md) frame via ASYNC_SYS_MSG to the clients.
```
from_module: [32bytes(user_id)][64bytes(new_disp_name)]
to_client: [type_id(9)][cmd_id(2)][branch_id(0)][size_of_payload][payload(MY_INFO)]
```
```ASYNC_USER_RANK_CHANGED (9)```
This command carries a combination of the 32byte user id hash and 4byte new rank (32bit uint_le) of the user account that changed it's host rank. This will trigger all sessions that are currently logged into this account to send an updated [MY_INFO](type_ids.md) frame via ASYNC_SYS_MSG to the clients.
```
from_module: [32bytes(userId)][4bytes(newRank)]
to_client: [type_id(9)][cmd_id(2)][branch_id(0)][size_of_payload][payload(MY_INFO)]
```
```ASYNC_CMD_RANKS_CHANGED (10)```
This internal only command doesn't carry any data, it just triggers all sessions to re-load runable commands.
```ASYNC_ENABLE_MOD (12)```
This internal only async commmand that carry a [TEXT](type_ids.md) path to a module executable. All session objects that receive this will then attempt to load the module.
```ASYNC_DISABLE_MOD (13)```
This is the other half to ASYNC_ENABLE_MOD. All session objects that receive this will remove and terminate all commands associated with this module.
```ASYNC_END_SESSION (14)```
This internal only async commmand doesn't carry any data. It is used by modules to logout the current user.
```ASYNC_USER_LOGIN (15)```
This command carries a 32byte user id hash. This can be used by modules to tell the session object to login as this user.
```ASYNC_TO_PEER (16)```
This is an async command that carry an embedded data frame directly to/from peer sessions without any restrictions. It is prepended with the 224bit hash of the target session id; however, it drops that session id before arriving at the client so it will apppear as a regular mrci frame of any data type. modules do not have direct access to this, the host internal objects will handle it.
```
from_module: [28bytes(sessionId)][1byte(typeId)][rest-of-bytes(payload)]
to_client: [type_id][cmd_id(16)][branch_id(0)][size_of_payload][payload]
```
```ASYNC_LIMITED_CAST (17)```
This operate exactly like ASYNC_CAST except only sessions with active update sub-channels open will respond to it.
```ASYNC_RW_MY_INFO (18)```
This command carries a 32byte user id hash of a user account who's data has been overwritten by another user. This will trigger all sessions that are currently logged into this account to send an updated [MY_INFO](type_ids.md) frame via ASYNC_SYS_MSG to the clients.
```
from_module: [32bytes(user_id)]
to_client: [type_id(9)][cmd_id(2)][branch_id(0)][size_of_payload][payload(MY_INFO)]
```
```ASYNC_P2P (19)```
This async command carry an embedded data frames directly to/from peer sessions following the p2p negotiation process as described in [Type_IDs](type_ids.md), section 3.2 at the P2P specific data types. It prepends the 28byte hash of the destination session id and source session id; however, it drops the destination id and source id for just the P2P specific data types before arriving at the client. For all other data types (if a p2p connection is estabished), the source id is prepend-moved to the payload of the mrci frame before arriving at the client.
```
from_module: [28bytes(dst_sessionId)][28bytes(src_sessionId)][1byte(typeId)][rest-of-bytes(payload)]
to_client (P2P): [type_id][cmd_id(19)][branch_id(0)][size_of_payload][payload(src_sessionId)]
to_client: [type_id][cmd_id(19)][branch_id(0)][size_of_payload + 28][src_sessionId + payload]
```
```ASYNC_CLOSE_P2P (20)```
This internal only async command carry the 28byte hash session id of a session that is about to close. All sessions that receive this will close the p2p connection with this session if such a connection exists. If such a connection did exist, the session will convert the frame into a P2P_CLOSE mrci frame and send it to the client via ASYNC_P2P.
```
from_module: [28bytes(src_sessionId)]
to_client: [type_id(12)][cmd_id(19)][branch_id(0)][size_of_payload][payload(src_sessionId)]
```
```ASYNC_NEW_CH_MEMBER (21)```
This async command carries a [CH_MEMBER_INFO](type_ids.md) frame containing public information about a user that has been added to a channel member list. All sessions that are logged in as a member of the channel will forward the frame (unchanged) to the clients.
```
to_client: [type_id(25)][cmd_id(21)][branch_id(0)][size_of_payload][payload(CH_MEMBER_INFO)]
```
```ASYNC_DEL_CH (22)```
This async command carries a [CH_ID](type_ids.md) frame of a channel that has been deleted. All sessions that receive will forward the frame to the client (unchanged) and close all sub-channels related to the channel.
```
to_client: [type_id(26)][cmd_id(22)][branch_id(0)][size_of_payload][payload(CH_ID)]
```
```ASYNC_RENAME_CH (23)```
This async command carries a combination of the channel id and a null terminated UTF-8 string containing the new name of the channel that has been renamed. This command desn't use any of the standard frame formats so it sends a [BYTES](type_ids.md) frame to the client.
```
to_client: [type_id(14)][cmd_id(28)][branch_id(0)][size_of_payload][payload(channel_id + new_channel_name)]
```
```ASYNC_CH_ACT_FLAG (24)```
This internal only async command carries a combination of the channel id and and sub-channel id to tell sessions that the sub-channel has changed it's active update flag. All sessions that have this sub-channel open will re-check this flag and determine if it should continue active updating.
```
format: [8bytes(64bit_ch_id)][1byte(8bit_sub_ch_id)]
```
```ASYNC_NEW_SUB_CH (25)```
This async command carries a comination of the channel id, sub-channel id, access level and a null terminated UTF-8 string containing the sub-channel name when a new sub-channel is created. All sessions that are logged in as a member of the channel forwards the data to the clients as a [BYTES](type_ids.md) frame.
```
to_client: [type_id(14)][cmd_id(25)][branch_id(0)][8bytes(64bit_ch_id)][1byte(8bit_sub_ch_id)]
[1byte(8bit_access_level)][16bit_null_term_sub-channel_name]
```
```ASYNC_RM_SUB_CH (26)```
This is the other half to ASYNC_NEW_SUB_CH. It carries just a combination of the channel id and and sub-channel id to tell all sessions that the sub-channel was deleted. All sessions that have the sub-channel open will close it.
```
to_client: [type_id(14)][cmd_id(26)][branch_id(0)][8bytes(64bit_ch_id)][1byte(8bit_sub_ch_id)]
```
```ASYNC_RENAME_SUB_CH (27)```
This async command carries a combination of the channel id, sub-channel id, access level and a null terminated UTF-8 string containing the new sub-channel name. All sessions that are logged in as a member of the channel forwards the data to the clients as a [BYTES](type_ids.md) frame.
```
to_client: [type_id(14)][cmd_id(27)][branch_id(0)][8bytes(64bit_ch_id)][1byte(8bit_sub_ch_id)]
[16bit_null_term_sub-channel_name]
```
```ASYNC_INVITED_TO_CH (28)```
This async command carries a [CH_MEMBER_INFO](type_ids.md) frame containing public information about a user that has been invited to a channel. All sessions that are logged in as a member of the channel will forward the frame (unchanged) to the clients.
```
to_client: [type_id(25)][cmd_id(28)][branch_id(0)][size_of_payload][payload(CH_MEMBER_INFO)]
```
```ASYNC_RM_CH_MEMBER (29)```
This async command carries a combination of the channel id and the 32byte user id of the channel member that has left or kicked from the channel member list. All sessions that are logged in as a member of the channel forwards the data to the clients as a [BYTES](type_ids.md) frame. This async aommand also sent when a user declines an invite to a channel.
```
from_module: [8bytes(chId)][32bytes(userId)]
to_client: [type_id(14)][cmd_id(29)][branch_id(0)][size_of_payload][payload(64bit_ch_id + 256bit_user_id)]
```
```ASYNC_INVITE_ACCEPTED (30)```
This async command carries a [CH_MEMBER_INFO](type_ids.md) frame containing public information about a user that has accepted an invite to a channel. All sessions that are logged in as a member of the channel will forward the frame (unchanged) to the clients.
```
to_client: [type_id(25)][cmd_id(30)][branch_id(0)][size_of_payload][payload(CH_MEMBER_INFO)]
```
```ASYNC_MEM_LEVEL_CHANGED (31)```
This async command carries a combination of the channel id, new level and the 32byte user id of the channel member that changed it's level of privilege in the channel. All sessions that are logged in as a member of the channel forwards the data to the clients as a [BYTES](type_ids.md) frame. All sessions that are currently logged in as this user also closes all sub-channels related to the channel.
```
from_module: [8bytes(chId)][32bytes(userId)][1byte(newLevel)]
to_client: [type_id(14)][cmd_id(31)][branch_id(0)][size_of_payload][payload(64bit_ch_id + 256bit_user_id + 8bit_new_level)]
```
```ASYNC_SUB_CH_LEVEL_CHG (32)```
This async command carries a combination of the channel id and sub-channel id of a sub-channel that has changed it's level of access. All sessions that have this sub-channel open will close the sub-channel and/or all sessions that are logged in as a member of the channel forwards the data to the clients as a [BYTES](type_ids.md) frame.
```
from_module: [8bytes(chId)][1byte(subId)]
to_client: [type_id(14)][cmd_id(32)][branch_id(0)][size_of_payload][payload(64bit_ch_id + 8bit_sub_id)]
```
```ASYNC_ADD_RDONLY (33)```
This async command carries exactly the same data as ASYNC_SUB_CH_LEVEL_CHG and has the same effect on the session sub-channels except it tells the clients that a read-only flag was added to the sub-channel.
```ASYNC_RM_RDONLY (34)```
This is the other half to ASYNC_ADD_RDONLY except if tells the clients that a read-only was removed from the sub-channel.
```ASYNC_ADD_CMD (35)```
This async command is used indirectly by modules to send [NEW_CMD](type_ids.md) frames to the session object. The session object will decide which frame gets forwarded to the client and which doesn't. Both this or ASYNC_RM_CMD sent directly to the session object does nothing. Instead, for modules called in listing mode [2.3](modules.md) (public_cmds, exempt_cmds or user_cmds); the session will detect the [NEW_CMD](type_ids.md) frames from the module and forward them to the client with this async command.
```
to_client: [type_id(16)][cmd_id(35)][branch_id(0)][size_of_payload][payload(NEW_CMD)]
```
```ASYNC_RM_CMD (36)```
This is the other half to ASYNC_ADD_CMD expect it is used to tell the client that the command was removed from the session and it carries a [CMD_ID](type_ids.md) frame instead.
```
to_client: [type_id(17)][cmd_id(36)][branch_id(0)][size_of_payload][payload(CMD_ID)]
```
```ASYNC_USER_RENAMED (37)```
This command carries a combination of the 32byte user id hash and the 48byte new user name (UTF-16LE, padded with 0x00) of the user account that changed it's user name. This will trigger all sessions that are currently logged into this account to send an updated [MY_INFO](type_ids.md) frame via ASYNC_SYS_MSG to the clients.
```
from_module: [32bytes(user_id)][48bytes(new_user_name)]
to_client: [type_id(9)][cmd_id(2)][branch_id(0)][size_of_payload][payload(MY_INFO)]
```
```ASYNC_PING_PEERS (38)```
This internal only async commmand doesn't carry any data. It can be used by modules to request all peer sessions that have matching active update sub-channels open to return [PEER_INFO](type_ids.md) frames via ASYNC_TO_PEER directly to the session that has sent it. The session that receives these frames will in turn forward them to the client via ASYNC_LIMITED_CAST.
```
to_client: [type_id(8)][cmd_id(17)][branch_id(0)][size_of_payload][payload(PEER_INFO)]
```
```ASYNC_OPEN_SUBCH (39)```
This internal only async command carries a combination of the channel id and sub-channel id. it can be used by modules to tell the session object open a sub-channel.
```
format: [8bytes(64bit_ch_id)][1byte(8bit_sub_ch_id)]
```
```ASYNC_CLOSE_SUBCH (40)```
This is the other half to ASYNC_OPEN_SUBCH that tells the session to close the requested sub-channel.
```ASYNC_KEEP_ALIVE (42)```
This internal only async command doesn't carry any data. The session object normally sends a [KILL_CMD](type_ids.md) to the module when it detects that the module process has not sent an IPC frame in 2 minutes to terminate the module process. If desired, the module can send this async command in regular intervals to reset this 2 minute idle timer to prevent auto termination.
```ASYNC_SET_DIR (43)```
This internal only async command carries a [TEXT](type_ids.md) path that sets the working directory for the local session. All module processes started by the session will use this directory as the working directory and it is not shared among peer sessions. nothing happens if the path is invalid or does not exists.
```ASYNC_DEBUG_TEXT (44)```
This internal only async command carries a [TEXT](type_ids.md) debug message to be logged into the host debug log from the module. Modules can use this to help with debugging issues if it doesn't have direct access to the host database.
```ASYNC_HOOK_INPUT (45)```
This async command doesn't carry any data. This just indicate to the local session that the module command is requesting to hook the tcp data input from the client. when the tcp input is hooked, all data sent from the client is redirected to the command object/process that initiated the hook until reqested to unhook. If the command that initiated the hook terminates in anyway with an active hook, the hook will automatically be removed.
```ASYNC_UNHOOK (46)```
This async command doesn't carry any data. Any module command that sends it tells the local session to unhook the tcp input data from the client if there is an active hook. This doesn't need to come from the command that initiated the hook.
### 5.3 Open Sub-Channel List ###
An open sub-channel list is a binary data structure that string togeather up to 6 sub-channel combinations that indicate which channel id and sub id combinations are currently open. Each sub-channel are 9bytes long and the list itself maintians a fixed length of 54bytes so it is padded with 0x00 chars to maintain the fixed length (this padding can appear anywhere in 9byte increments within the list). Each sub-channel is formatted like this:
```
bytes[0-7] - 64bit LE unsigned int (channel id)
bytes[8] - 8bit LE unsigned int (sub id)
note: channel id 0 is not a valid id and the sub id cannot
be valid without a valid channel id.
```