Skip to content

Applications

Pavel Kraynyukhov edited this page Aug 3, 2019 · 26 revisions

Basics

There are two interfaces for LAppS applications (hearafter services) available: Standalone and Reactive. Every service may have several running copies (instances), all working parallel on the same task.

Standalone

Standalone services are not communicating with clients directly. These services are LUA modules which run indefinitely (until a shutdown is requested) and doing some jobs that may be required by other services.

These services are expected to comply with the following interface:

  1. Provide methods init() and run() with no arguments.
  2. Call must_stop() on regular basis to check if LAppS wants to shut down.

Here is an example service (time_broadcast) which may be found in the examples folder of LAppS distribution (broadcasts string with time on CID 0).

time_broadcast={}
time_broadcast.__index=time_broadcast

time_broadcast.init=function()
  bcast:create(1000);
  time_broadcast.nap=nap:new();
end

time_broadcast.run=function()
  print("running")
  local oon=nljson.decode([[{
      "cid" : 5,
      "message" : [ "" ]
  }]]);
  while not must_stop()
  do
    time_broadcast.nap:usleep(1000000);
    local timenow=os.time();
    local timestr=os.date("%c",timenow);
    oon.message[1]="Server time: "..timestr;
    bcast:send(1000,oon);
  end
end

return time_broadcast;

NOTE: Standalone services are declared in service descriptors or within lapps.json by setting the value of the attribute standalone to true.

Reactive services

Reactive services are responding to clients' requests, though NOT limited to request-response schema of communications if using LAppS protocol. Every reactive service instance will have its own set of clients. No clients are shared between these services.

Reactive services are expected to comply to following interface:

  1. Provide methods onStart(), onShutdown() - without arguments
  2. For RAW protocol provide method onMessage(handler,opcode, message), Where handler is a WebSocket handler - an integer value; opcode - WebSocket opcode (an integer value); message - lua string value is sent by client (may contain binary data with opcode equal 2 - binary).
  3. For LAppS protocol provide method onMessage(handler,msg_type, message). The only difference from above is the msg_type - an integer value from 1 to 4; and the message an nljson_object, - see Embedded modules API for details.
  4. onDisconnect(handler) - this method will be called when the client is disconnected, and its handler will be provided for your service.

Here is an example of a reactive service skeleton:

myapp = {}
  
myapp.__index = myapp;

myapp.onStart=function()
  -- do something on start
end

myapp.onDisconnect=function(handler)
  -- handler - is a unique client identifier
  -- react on client disconnect
end

myapp.onShutdown=function()
  -- do something on shutdown
end

myapp.onMessage=function(handler,opcode, message)
  -- it is an echo, - we return back the same message 
  local result, errmsg=ws:send(handler,opcode,message);
  if(not result)
  then
    print("myapp::OnMessage(): "..errmsg);
  end
  return result;
end

return myapp;

Here is an example of the onMessage method for LAppS protocol:

--[[
--  @param handler - io handler to use for ws:send and ws:close
--  @param msg_type - helper enum defining type of message:
--    1 - Client Notification Message as defined in LAppS Specification 1.0 (without params)
--    2 - Client Notification Message with params attribute
--    3 - Request as defined in LAppS Specification 1.0 (without params)
--    4 - Request with params attribute
--  @param message - an nljson userdata object
--]]
console.onMessage = function(handler,msg_type, message)
  local switch={
    [1] = function() -- a CN without params 
            local method=methods._cn_wo_params_method[message.method] or console.method_not_found;
          end,
    [2] = function() -- a CN with params 
            local method=methods._cn_w_params_method[message.method] or console.method_not_found;
            method(handler,message.params,message.cid);
          end,
    [3] = function() -- request without params
            local method=methods._request_wo_params_method[message.method] or console.method_not_found;
            method(handler);
          end,
    [4] = function()
            local method=methods._request_w_params_method[message.method] or console.method_not_found;
            method(handler,message.params);
          end
  }
  switch[msg_type]();

  return true;
end
Clone this wiki locally