Exchange messages with the Total Messaging Service
TMS (Total Messaging Service) is a small message bus on top of a WebSocket. Turn it on in the config file with $tms : true; the endpoint is /$tms/ and secret_tms is the token that every client must send in the x-token header (a wrong token closes the connection with code 4001, and an address that fails more than 5 times is blocked for a while). When a client connects it receives a meta message that lists what the app publishes, what it accepts and what it can do.
Three things can be exposed, each one described by a schema in the same name:Type format as an action input:
NEWPUBLISH(name, schema)declares a message the app sends;PUBLISH(name, value)sends it to every client that asked for it by sending{ type: 'subscribers', subscribers: [name] }.NEWSUBSCRIBE(name, schema, callback)declares a message the app receives: a client sends{ type: 'subscribe', id: name, data: {...} }andcallback(message, client)runs only when the data is valid. The validated data is inmessage.response(message.erroris alwaysnullthere) andclientis the sender.NEWCALL(name, schema, callback)declares a function the client calls: the client sends{ type: 'call', id: name, data: {...}, callbackid: '1' }, and the app answers with the same message carryingsuccess: trueand the result indata, orerror: truewhen the data is invalid.callback(data, done, client)produces the result withdone(null, result).
Passing null as the schema of NEWPUBLISH or NEWSUBSCRIBE removes the declaration. The official client of Total.js (TMSCLIENT) speaks this protocol for you from another Total.js app; any WebSocket client works.
UNSUBSCRIBE(name, [callback]) removes the listeners of a message that the app receives: only callback when you pass it, all of them when you do not. It returns true when it removed something and false when there was nothing to remove.
$tms : true
secret_tms : my-tms-tokenNEWPUBLISH('news', 'title:String');
NEWSUBSCRIBE('orders', 'id:String, qty:Number', function(message, client) {
MAIN.orders.push(message.response);
});
NEWCALL('sum', 'a:Number, b:Number', function(data, done) {
done(null, { total: data.a + data.b });
});
MAIN.orders = [];exports.install = function() {
ROUTE('POST /news/ @json', news);
ROUTE('GET /orders/', orders);
ROUTE('GET /unsubscribe/', unsubscribe);
};
function news($) {
PUBLISH('news', { title: $.body.title });
$.success();
}
function orders($) {
$.json(MAIN.orders);
}
function unsubscribe($) {
const first = UNSUBSCRIBE('orders');
const second = UNSUBSCRIBE('orders');
$.json({ first: first, second: second });
}