party-fe

Party-fe

The code is located at https://github.com/tearust/tapp-sample-teaparty/tree/demo-code/party-fe. You can clone the code to a local repo to make it easier to go through.

This is a standard Vue application. We assume that readers are familar with VUE and front-end web technologies. Below we'll only focus on the TEA related parts.

bbs.vue common requests functions

This file https://github.com/tearust/tapp-sample-teaparty/blob/demo-code/party-fe/src/views/bbs.js handles most message-related user interactions.

For example, the code snippets below are handling a load message and send message request:

async loadMessageList(address, channel=default_channel){
    // F.top_log("Query message list...");
    const rs = await _axios.post('/tapp/loadMessageList', {
      tappId: F.getTappId(),
      channel: F.getChannel(channel),
      address: '',
    });

    // F.top_log(null);

    if(!rs) return [];

    return F.formatMessageList(JSON.parse(rs));

  },
  async updateTappProfile(address){
    const user = F.getUser(address);
    if(!user || !user.isLogin){
      throw 'not_login';
    }
    // TODO if user is not owner, return;

    const opts = {
      tappId: F.getTappId(),
      address,
      authB64: user.session_key,
      postMessageFee: 100,
    };
    const rs = await sync_request('updateTappProfile', opts);
    console.log('updateTappProfile => ', rs);
    return rs;
  },
  async sendMessage(address, msg, channel=default_channel, ttl=null){
    const user = F.getUser(address);
    if(!user || !user.isLogin){
      throw 'Not login';
    }
    
    msg = utils.forge.util.encodeUtf8(msg);
    const encrypted_message = utils.forge.util.encode64(msg);
    // console.log(121, utils.crypto.encode(address, msg));
    
    // const decode_msg = utils.crypto.decode(address, utils.forge.util.decode64(encrypted_message));
    // console.log('decode_msg => '+decode_msg);

    const opts = {
      tappId: F.getTappId(),
      address,
      channel: F.getChannel(channel),
      // message: msg
      encryptedMessage: encrypted_message,
      authB64: user.session_key,
      ttl,
    };
console.log('message => ', opts)
    let rs = null;
    if(opts.channel === 'test'){
      // free msg
      rs = await _axios.post('/tapp/postFreeMessage', {
        ...opts,
        uuid: uuid(),
      });
    }
    else{
      const txn = require('./txn').default;
      rs = await txn.txn_request('postMessage', opts);
    }
    
    return rs;
  },

You probably have noiticed that the most improtant line related to TEA is the line await _axios.post('/tapp/loadMessageList' for querying mesages, and this line `await txn.txn_request('postMessage', opts); for posting message.

You might have noticed that this line await _axios.post('/tapp/postFreeMessage', also looks like it's sending a command, but why is it not using txn.txn_request()? Well, posting a message does look like a command, but the free message doesn't cost anything. Therefore there is no state change (no money transfer). It can be comfortably handled by the hosting_cml alone without notifying the state machine. No matter if it's queries or commands, they are concepts related to the state machine and not your application.

txn_request

the _axios.post is a standard http call which doesn't need to be explained. We can focus on the txn.txn_request utility function.

The code is under views/txn.js. Almost the entire file is comprised of this function.

This is a big function, so let's dig into it step by step.

uuid

Before the first step, we generate a UUID. This is used for a future results query (ecause all txns are async calls). You're not supposed to get a response immediately. You have to query after a period of time, and then from time to time until you get the result: either success or fail. UUID is the handle for such queries.

Once the UUID is confirmed, it uses an http call to the hosting_cml like this:

The hosting_cml will handle this txn and run the back-end logic accordingly. If you are interested in that part, go to back_end_actor.

txn_hash

The result from step1 doesn't mean anything. It just says "hey I accepted your txn request". In order to query the result of such a txn, we need to have the hash of that txn. We don't know it at this moment. The only thing we know is the UUID. So the step2 should query the txn_hash using the UUID. You can see the code below:

The result of step2 is the txn_hash. Now the front-end has the txn hash and the back-end has sent the txn to the State_Machine. But we haven't got the result yet. In order to get the result, the front-end needs to ask the back_end_actor to initialize a series of queries to the State_Machine to get the result of the transaction. Step3 performs this "initialization" request.

Now, the back_end_actor receives the request and starts querying the State_Machine for the result. Because this is an async call, the back-end cannot get the result immediately. It will keep polling several times to get the result. When the back-end receives the result, it will cache it in memory for a short period of time, waiting for the front_end to fetch it. Step4 actually did the "fetching" job.

There are a few meaningful parameters in the step_ r_rs result. For example, do I need to wait and query again? This happens if the back_end_actor has not received the result from the State_Machine yet.

For most txns, as long as step4 has received the answer, the whole process is done. But for some txns, there are some follow-up tasks after the result. This is what step5 is supposed to do.

Now the whole txn workflow is completed.

Workflow

To make the workflow clear and visual, let's draw a sequence diagram.

Last updated