party-actor
Party-actor
handle_adapter_http_request
In the lib.rs file, you'll find the handle_adapter_http_request
function. All of these branches are messages that this actor can handle.
We use the http request function to handle user events because in the current version of the TEA Party, the front-end sends the back-end http requests.
Similar to handle_adapter_http_request
, we still have handle_adapter_request
which is an upper level handler. That's because all http requests are actually captured by the adapter first. Adapter is the sole component that a hosting CML can contact the outside world.
libp2p_back_message
Tea project uses a modified version of rust-based lib P2P protocol between nodes communication.
The hosting_cml use libp2p_back_message
to handle libP2P messages. In our Tea party sample code, the only usage of this function is to receive response message to its own memory cache help::set_mem_cache(&body.uuid, content)?;
.
The memory cache is used to temporarily store the response/error message from the state machine. When the front_end sends a query for the result of any command, the hosting CML's back end actor will check this temporary store to get recently received results and get back to the front_end.
Interaction with OrbitDB
Query OrbitDb example: load_message_list
Please take a look at the function pub fn load_message_list(req: &LoadMessageRequest) -> anyhow::Result<Vec<u8>>
in message.rs file
Focus on these lines:
First, generate the dbname which will be used later in the parameter get_message_data
of the future provider call bbs_GetMessage
.
The main function call is the provider call. tea_codec::ORBITDB_CAPABILITY_ID
is the ID of the OrbitDB provider. the bbs_GetMessage
is the API name to call. The parameter needs to encode_protobuf
so that the provider can decode it later. The response of this provider function call is a bytes buffer, so we have to issue orbitdb::OrbitBbsResponse::decode
to a regular res
data structure.
These lines are the typical way to call a provider. You can find such patterns everywhere in the TEA Project.
The rest of the code is easy to understand. The data response from the OrbitDB provider goes to the message_item list. This list is returned to the front_end caller. Finally, it shows in the UI in the browser.
Interaction with State Machine
Usually there are two kinds of requests that need to be sent to the state machine to handle. They're either queries or commands.
Command example: post_message
The function post_message
sends a txn (we sometimes call it sending Commands) to the state machine. The following code sends the txn:
In this function call, "post_message"
is the name of the API that state_machine_actor can handle. uuid
is the nonce that the back-end actor uses to check the execution result. txn_bytes
is the body of txn.
Let's follow the send_txn code in request.rs:
If we keep following the call stack we'll eventually find more interesting details but we have to stop here. Otherwise, this article would become very long.
The remaining logic would be described as follows:
Check the layer one, find the currently active state machine replicas, and their p2p addresses
Randomly select 2 (or more if you think necessary) state_machine_replicas. Send the txn in P2P message to them.
After the first txn P2P messages are sent out, record the time from the GPS atomic clock.
Use this time stamp in the followup message in the Ts field. Note, we only need the first txn's sent time, ignore the 2nd txn sent time.
Send out the followup message to those two state_machine_replicas (function
pub fn send_followup_via_p2p(fu: Followup, uuid: String)
).
Query example: query_balance
This function checks the user balance they've topped up to their TEA Party app account. "query_balance" => api::query_balance(&serde_json::from_slice(&req.payload)?),
You can find the main function here in user.rs
Finally the function call to send the P2P message is here inside p2p_send.rs:
You can follow how the hosting_cml finds the state_machine_replica nodes and sends out using the p2p_send_to_receive_actor function:
The a_nodes
is the internal name for state_machine_replica. target_conn_id
is the address that libp2p can use to find the destination nodes.
Query response after request
You may have noticed that no matter if it's Commands or queries, the caller will not get the response immediately (even for Queries that are not supposed to have to wait in the Conveyor. That's because all communication between nodes are asyncronous. However, you can always query the result using the uuid
when you generate the request.
The front-end can use http query_result
to get the result.
Please note, the front-end has no way to know when the result will be ready. It's common that the front-end needs to query several times to get the result. You can find the sample of how to query the result in the front_end code. In bbs.js
, the function is const sync_request = async (method, param, message_cb, sp_method='query_result', sp_uuid=null)
.
Last updated