18 KiB
3.1 Command Objects
ExternCommand
objects are QT/C++ classes used by the host to execute all logic related to the specific commands called by the client. It basically defines several QT signals and virtual functions that the host's internal CmdExecutor
object uses to process input data from the client and return data to the client or to other peers connected to the host. Each command callable by the client defines a seperate ExternCommand
object and it's life cycle is managed externally by the host's CmdExecutor
object.
3.2 Defined Variables in ExternCommand
Aside from the virtual functions and QT signals, the ExternCommand
object also defines a few public variables that can be of interest:
cmdId
This is a quint16
command id that the command object was assigned to when it was built. Changing it at any time does nothing upstream but it is reset to it's proper value every time the procBin()
function is called. the MRCI protocol use assigned command ids to call certain command objects currently loaded into the CmdExecutor
object. It is unique to each command object and makes it possible for the client to call a command with only 2 bytes of data instead of a variable number of bytes for a command name. This variable exist to make it possible for the internal logic of the command object to be made aware of it's assigned command id.
internCommands
This is a QHash<QString, ExternCommand*>
containing a list of pointers to internal command objects built to be used from within this command object. It is filled by the internRequest()
function (section 3.3). Internal commands differ from external commands like this by having direct access to the host database and less restrictive access to various host functions. This variable is useful if you want access to such functions without the chance of causing a session crash or database corruption.
errSent
This is a bool
that simply indicates if the command has sent error message to the client using the errTxt()
non-virtual function. This is useful if you want to determine of the last run of the command was successful or not but only if the internal logic used the aforementioned function to send the error. The CmdExecutor
does reset it to false before calling the procBin()
function.
inLoopMode
This is a bool
that indicates if the command object is currently in loop mode. This basically retains what was passed into the enableLoop()
signal when it is called. more info on this can be found in section 3.5.
inMoreInputMode
This is a bool
that indicates if the command object is currently in the more input state. It retains what was passed into the enableMoreInput()
signal when it is called. see section 3.5 for more info.
QString QObject::objectName()
This is not a variable but it is a function available to the ExternCommand
object from the QT API. The CmdExecutor
assigns the unique command name to this property that was assigned to this command when it was built. Just like cmdId
this makes the internal logic aware of it's assigned command name. Changing it using QObject::setObjectName()
does nothing upstream but also unlike cmdId
it is not reset upon calling procBin()
.
3.3 ExternCommand Virtual Functions
void procBin(SharedObjs,QByteArray,uchar)
This function is called by the host to process input data from the client passed in the form of a QByteArray
. Look at this as the main execution function of the command that can be called more than once if the loop state is enabled. The SharedObjs
parameter is passed by the CmdExecutor
to share information about the session with the command object as described in section 3.4 of this document. It is passed as a const because changing any of the objects within SharedObjs
in an unexpected way may cause undesired behaviour. The third uchar
parameter indicate what type of data is in the QByteArray
. Details on type ids can be found in the Type_IDs.md document.
bool handlesGenfile()
Command objects should return true on this function if your command object handles the GEN_FILE
data type in anyway. The host will use this to tell the client which commands support this data type which ones don't. The reason for this is because the GEN_FILE
data type require structured 2 way communication in a way between the host and client (see Type_IDs.md). This function is called only once shortly after the command is contructed.
QString shortText()
Command objects must return a short summary on what this command actually does. The host will use this to send help text to the client. How this text is displayed to the user depends entirely on the client.
QString ioText()
Just like shortText(), this is a help text function that describes what input/output data to expected to/from the command object. It follows a specific text format:
[] Brackets are used to indicate a block of data (text,binary,etc..).
Example: [text]
/ Seperates input and output data blocks to/from the command.
Example: [input_text]/[output_text]
- Indicates a argument.
Example: [-arg]/[text]
() Brackets indicate argument parameters/values.
Example: [-arg (text)]/[text]
{} Brackets indicate optional arguments or parameters.
Example: [-arg {(text)} {-optional}]/[text]
'or' Indicates optional input data blocks and/or possible output blocks.
Example: [-arg1 (text)] or [-arg2 (text)]/[output_text1] or [output_text2]
QString longText()
This is a help text function that is used by the host to send full detailed information about the command and it's usage. It's recommended to be as thorough as possible to help users understand proper usage of your command. The host will send it as BIG_TEXT
so it will be up to the client if it should word-wrap the text when displaying to the user.
QString libText()
Command objects can use this function to return the library/module name and version that the command object belongs to. This can also contain extra information that clients can use to further identify the command object; however, the text is limited to 64 chars or less. Any text returned by this function that is larger than 64 chars will be truncated.
QStringList internRequest()
After the command is successfully built, this function is called by the CmdExecutor
to fulfil any request to build internal command objects that can be used from within the object that was built. the QStringList
returned by this function just need to list any of the known internal command names and the CmdExecutor
will build them and add them to the internCommands
QHash
defined inside the ExternCommand
object (section 3.2). Here's a few notes to consider if you want to build internal commands within your own command.
- Your command object is assigned the parent of the internal commands.
- The internal commands built into internCommands have full access to the internal host batabase and functions that normal ExternCommands would otherwise not have access to.
- The output from the internal commands go directly to the client, peers or other objects. Nothing is passed through the parent object by default.
- Clients do not have direct access to these specific internal commands. Instead, they can only be called by running the
procBin()
function directly from within the parent object. - The internal commands inherit the parent command object's command id/name so output from these internal commands will appear as if it came from the parent object. This also includes the
enableLoop()
andenableMoreInput()
signals (section 3.5). - It will be up to the parent object to detect and execute the loop mode for these internal commands since
CmdExecutor::exeCmd()
will not call these objects directly. - Terminating the parent object also terminates all of the internal commands within it.
- It is safe to delete the internals commands but be sure to remove the deleted commands from the
internCommands
QHash
or it will must likely cause the session to crash. You normally should never have to do this anyway, theCmdExecutor
will safely delete these internal commands when the parent is about to get deleted.
void term()
This function is called by the host when the command needs to terminate what it is currently doing. Use this opportunity to reset and clean up any reasources so the command object can be ready to be called again in a reset state.
void aboutToDelete()
The host will call this function before calling the command object's deleteLater()
function. Use this opportunity to clean up anything the host may not be aware of in preparation for deletion. Avoid self deleting any ExternCommand
object at any time, doing so will must certainly cause the session to crash.
bool errState();
Return true or false on this function to indicate if the command object is currently in an error state. The default logic simply returns errSent
(section 3.2).
3.4 Shared Objects
The SharedObjs
class is used by the host's Session
and CmdExecutor
objects to share data with all command objects. It contains pointers to various objects related to the user's current session and command states. It is passed into the command via the ExternCommand::procBin()
function as a read only const. Below are all of the pointers defined within it:
sessionId
This is a QByteArray
containing the 224bit (28byte) sha3 hash id unique to the current session only. this does change upon reconnecting to the host.
p2pAccepted
This is a QList<QByteArray>
object that list all peer session ids that the user has accepted to be allowed to send/receive data when using the toPeer()
signal.
p2pPending
This is a QList<QByteArray>
object that list all peer session ids that sent a P2P_REQUEST
to/from the session and are awaiting a P2P_OPEN
. When a P2P_OPEN
is received, the session id sent by it is removed from this list and then added to p2pAccepted
.
chIds
This is a QByteArray
object that string togeather up to 6 channel-sub combinations that indicate which channel id and sub id combinations are currently open. Each channel-sub are 9bytes long and chIds itself maintians a fixed length of 54bytes. It is padded with 0x00 chars to maintain the fixed length (this padding can appear anywhere in 9byte increments within chIds). Channel-sub 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.
wrAbleChIds
This is a QByteArray
object formatted exactly like chIds
. It however list all channel-subs from chIds
that are 'writable.' This is what is actually used when casting data to peers while chIds
is used when receiving data from peers. This cannot list any channel-subs that are not also listed in chIds
.
chList
This is a QList<QString>
of channel names that the currently logged user is a member of. Unlike chIds
, this list doesn't care if the channel is open or not.
activeUpdate
This is a bool
object that indicate if the above chIds
contains an open active update channel. When a session is active updating it will respond to peer pings, PEER_INFO
and PEER_STAT
frames related to just the active update sub-channels.
chOwnerOverride
This is a bool
object that indicates if the user currently have the channel owner override flag active or not. The owner override flag allows the user to do anything a channel owner could do in a channel without actually being the owner of the channel. This is usually reserved for host administrators.
sessionAddr
This is a QString
representation of the IPv4 or IPv6 address of the TCP client.
userName
This is a QString
of the current user that is logged in on the current session. This is empty if no user is currently logged in.
groupName
This is a QString
of the group that the above userName
is a member of. it is also blank if no user is currently logged in.
displayName
This is a QString
of the user's desired display name. Clients are encouraged put more emphasis on this if displaying the user to the public.
appName
This is a QString
of the client's application name. It can also contain the application's version depending on the application itself. This is updated upon connecting to the host and normally does not change while the session is active.
clientMajor
This is a ushort
version major of the mrci protocol that the client is using.
clientMinor
This is a ushort
version minor of the mrci protocol that the client is using.
clientPatch
This is a ushort
version patch of the mrci protocol that the client is using.
userId
This is a QByteArray
containing the 256bit (32byte) Keccak hash unique to the current user. This is empty if no user is currently logged in. This remains constant even when the user name, or any other user information changes.
moreInputCmds
This is a QList<quint16>
of command ids that are currently in the more input state. Command objects in this state are simply requesting more input data from the client and should not be considered finished.
activeLoopCmds
This is a QList<quint16>
of command ids that are currently in the loop state. Command objects in this state will cause the CmdExecutor
to call ExternCommand::procBin()
in a loop until it is removed from this list.
pausedCmds
This is a QList<quint16>
containing a list of command ids that are blocked from looping. The commands listed here must also be listed in activeLoopCmds.
hostRank
This is a uint
that indicates the currently logged in user's host rank. The host rank determines the level of access to the host commands the user currently have. what those commands could be depends on how the host is configured. The lower the rank value, the higher the privilege level with 1 being the highest level. 0 is not considered a valid rank and it will initialized as that if no user is currently logged in.
cmdNames
This is a QHash<quint16,QString>
with command id quint16
keys that relate to QString
command names that are currently loaded for the session.
3.5 ExternCommand Signals
dataToClient(QByteArray data, uchar typeId)
This signal sends the data to CmdExecutor
passed as a QByteArray
with a uchar
indicating what TypeID is stored in that QByteArray
. The CmdExecutor
object inspects the type id and stops external commands from sending the following data types: PRIV_IPC
, PUB_IPC
, NEW_CMD
, PEER_STAT
, MY_INFO
, PEER_INFO
, HOST_CERT
, IDLE
, PING_PEERS
, P2P_REQUEST
, P2P_OPEN
, P2P_CLOSE
. If none of these type ids are caught, the data is then sent to the client as a mrci frame.
castToPeers(QByteArray data, uchar typeId)
This is used to broadcast data to all clients that have any matching sub-channels open. It takes the same parameters and have the same retrictions as dataToClient()
.
toPeer(QByteArray sessionId, QByteArray data, uchar typeId)
This signal is used to send data directly to a peer client without the need to open any sub-channels. Instead, the data is routed via the target peer's session id, given in the 1st QByteArray
parameter as 224bit (28byte) sha3 hash. The next 2 parameters are the same as dataToClient()
, however only the following data types are allowed until a connection is negotiated with the peer: P2P_REQUEST
, P2P_OPEN
or P2P_CLOSE
. More info on this can be found in Type_IDs.md, section 4.2. Except the P2P specific data types, the same retrictions for dataToClient()
also apply here.
closeChById(quint64 channelId, uchar subId), closeChByName(QString channelName, QString subName), openChById(quint64 channelId, uchar subId), openChByName(QString channelName, QString subName)
These signals open/close sub-channels via the channel and sub-channel names or ids. The CmdExecutor
does error checking on these so errors are returned to the client if the channel or sub-channel does not exists, is invalid or if the user doesn't have access to it.
enableLoop(bool state)
This takes a bool
value that enables or disables the command object's loop state. If the loop state is enabled, the procBin()
function will be called by the CmdExecutor
within it's own loop until the loop state is disabled. 3rd party module devs are highly recommended to use this rather than implementing their own long term loops. By letting the CmdExecutor
handle the looping structure it would be possible for it terminate/interrupt the command more gracefully from the outside.
enableMoreInput(bool state)
This takes a bool
value that enables or disables the command object's more input state. This state tells the CmdExecutor
that the command is requesting more data from the client and should hold off sending an IDLE
frame to the client because the command is not yet finished. if both loop and more input states are disabled, an IDLE
frame is sent to indicate to the client that the command is finished.
closeSession()
This closes the session from the host side. The TCP connection also closes.
cmdFinished()
This signal disables both loop and more input states. It also immediately sends the IDLE frame to the client to indicate that the command is finished. Normally, you should not have to emit this signal directly because the CmdExecutor
will automatically send the IDLE
frame if it detects that both the loop and more inputs states are disabled after calling procBin()
. This signal is only useful if you need to indicate that the command is finished outside of the procBin()
function.
logout()
This clears parameters in SharedObjs
related to the currently logged in user and puts the session in a reset state with no user currently logged in. Unlike closeSession()
, this does not close the TCP connection.