Locations of visitors to this page

DSAS - DynaSet Application Server

  DSAS is a simple server and client API to execute
  Lua code at server side. Client API mimics the Lua API.
  Yami is used as MiddleWare. For client side, a Lua module
  is supplied. All supplied binaries are compiled with
  gcc/g++. Some are shrinked with Upx.
  Working schema is something like:
  .--------.    .-------.   .--------.
  | Client |<-->| DSASC |<->|  YAMI  |><---(tcp/ip)----.
  .--------.    .-------.   .--------.                 |
  .------------------------.   .-------.   .-------.   |
  |    LUA APPLICATIONS    |<->| DSAS  |<->|  YAMI |><-.      
  .------------------------.   .-------.   .-------.
    |   |   |   |   |   |  
  |    wxSQLite3 etc.      |             (How is it? ;))
- Why?
  I was trying to add C/S to wxSQLite3; ended with this :)
  I'm sure there exists many similar tools, but it was/is
  fun to work on it.
- Implementation

    dsas.exe                  DSAS server
        options: -h            usage
                -p portnum    listening port [12340]
                -c            enable logging [off]
    dsas.lua                  main application loader
                               Note: Check DSASPATH before use
    authapp.lua                sample app
    luasqlite3app.lua          luasqlite3 app

    test.exe                  test client api
        options: -h            usage
                -s host       server addr []
                -p port       server port [12340]
    tests.lua                 api tests
    tests_dsasc.lua           luasqlite3 tests (uses luasqlite3_dsasc.lua)

- Used libraries web addresses & readme files are in related dirs.
  No make file is given, because I'm using different tools
  to compile required libraries.
  Please check & change directories before use:
    lua:           Code::Blocks Project file
    yami:          Code::Blocks Project file
    dsas:          Code::Blocks Project file
    luadsasc:       m_luadsasc.bat
    luawxsqlite3:   m_wxsqlite3.bat
    client/cpptest: Code::Blocks Project file

- Client C-API:

// dsasc_call result codes
const int DSASC_SUCCESS        =  0;
const int DSASC_FAILURE        = -1;
const int DSASC_USAGE_ERROR    = -2;
const int DSASC_INTERNAL_ERROR = -3;
const int DSASC_INVALID_STATE  = -4;
const int DSASC_NET_ERROR      = -5;

// result value types
const int DSASC_TNONE          =-1;
const int DSASC_TNIL           = 0;
const int DSASC_TBOOLEAN       = 1;
const int DSASC_TNUMBER        = 2;
const int DSASC_TSTRING        = 3;

typedef struct dsasc_state dsasc_state;

// before using any function this should be called
int          dsasc_netinitialize();

// this should be use last
int          dsasc_netfinalize();

// to connect to server; if not successfull returns NULL
dsasc_state* dsasc_opendomainobject(const char* domainname, const char* objectname, const char* host, int port);
dsasc_state* dsasc_open(const char* host, int port);

// to disconnect
void         dsasc_close(dsasc_state* S);

// to check connection
int          dsasc_isconnected(dsasc_state* S);

// wait timeout for each dsasc_call; default=60 sn
void         dsasc_settimeout(dsasc_state* S, size_t seconds);

// to run remote app's procedure; returns one of result codes
int          dsasc_call(dsasc_state* S, const char* appname, const char* procname);

// returns last error message
const char*  dsasc_errorstring(dsasc_state* S);

// proc argument handling ---------------------------------------------------

// clear argument array; dsasc_call uses before exit
void         dsasc_clearargs(dsasc_state* S);

// #of arguments
size_t       dsasc_nargs(dsasc_state* S);

// push value to argument array
void         dsasc_pushnil(dsasc_state* S);
void         dsasc_pushnumber(dsasc_state* S, double val);
void         dsasc_pushinteger(dsasc_state* S, int val);
void         dsasc_pushboolean(dsasc_state* S, int val);
void         dsasc_pushstring(dsasc_state* S, const char* val);
void         dsasc_pushlstring(dsasc_state* S, const char* val, size_t len);

// proc result handling -----------------------------------------------------
// Note: result array is 0 indexed

// clear results array; dsasc_call uses in enterance
void         dsasc_clearresults(dsasc_state* S);

// #of results
size_t       dsasc_nresults(dsasc_state* S);

// result type; returns one of the value types
int          dsasc_type(dsasc_state* S, size_t idx);

// string representation of result type:
// "nil", "boolean", "number", "string"
const char*  dsasc_typename(dsasc_state* S, int tp);

// result type checking
int          dsasc_isnil(dsasc_state* S, size_t idx);
int          dsasc_isnumber(dsasc_state* S, size_t idx);
int          dsasc_isboolean(dsasc_state* S, size_t idx);
int          dsasc_isstring(dsasc_state* S, size_t idx);
int          dsasc_islstring(dsasc_state* S, size_t idx);  // having embedded 0'es?

// result value
double       dsasc_tonumber(dsasc_state* S, size_t idx);
int          dsasc_tointeger(dsasc_state* S, size_t idx);
int          dsasc_toboolean(dsasc_state* S, size_t idx);
const char*  dsasc_tostring(dsasc_state* S, size_t idx);
const char*  dsasc_tolstring(dsasc_state* S, size_t idx, size_t* len);

- Client Lua-API:

{ S }  = dsasc("host", port)
bool   = S:isconnected()
int    = S:call("appname", "procname")
string = S:errorstring()
int    = S:nargs()
int    = S:nresults()
value  = S:result(idx)
string = S:resulttype(idx)
bool   = S:isnil(idx)
bool   = S:isnumber(idx)
bool   = S:isboolean(idx)
bool   = S:isstring(idx)
bool   = S:isbinary(idx)

- Usage:

- DSAS Application example: './server/apps/authapp.lua'

-- start of authapp.lua ----------------------------------------------------

local appname = "authapp"
module(appname, package.seeall)

_G[appname].Register = function()
    local R = {}
    R.objs  = {}
    R.procs = {}

    -- args table structure:
    --   args[-2] : procedure name
    --   args[-1] : args count
    --   args[0]..: real arguments

    R.procs.Login = function(R, args)
            local usr = args[0]
            local pwd = args[1]
            assert(usr, "invalid user name")
            assert(pwd, "invalid password")
            -- here we can check user ...
            -- returning userid, etc.
            return 123, "Hello, "..usr.."!"
    R.procs.Logout = function(R, args)
            local usrid = args[0]
            assert(usrid, "invalid user id")
            return 1, "Bye!"

    _G[appname].registry = R

_G[appname].UnRegister = function()
    _G[appname].registry = nil

_G[appname].GetRegistry = function()
    if not _G[appname].registry then
    return _G[appname].registry

-- dispatcher: called by DSAS
function runproc(args)
    local procname = args[-2]
    local nargs    = args[-1]
    local R        = _G[appname].GetRegistry()
    local proc     = R.procs[procname]

    assert(proc, "unknown proc")
    return proc(R, args)

-- end of authapp.lua --------------------------------------------------------

- To register authapp, add a 'require' line to './server/dsas.lua' as:

    require("authapp")         -- Sample application

- DSAS Lua Client example: from './client/luatest/tests.lua'

-- start of tests.lua ---------------------------------------------------------

require("luadsasc") --dsas client library

local S = dsasc("", 12340) -- connect to localhost, with port:12340
assert(S, "couldn't connect")

--test Login proc--
S:push("myusername") --1st arg
S:push("mypassword") --2nd arg
local rc = S:call("authapp", "Login") --call remote proc
-- If successful rc==0, else rc<0. Use S:errorstring() to get error message
S:result(0) --remote proc results
--test Logout proc--
local rc = S:call("authapp", "Logout")

-- end of tests.lua -----------------------------------------------------------

- DSAS cpp Client example: from './client/cpptest/test.cpp'

-- start of test.cpp ---------------------------------------------------------

#include "dsasc.h"

int main()
  if (DSASC_SUCCESS != dsasc_netinitialize()) return EXIT_FAILURE;
  dsasc_state* S = dsasc_open("", 12340);
  if (!S) return EXIT_FAILURE;
  dsasc_pushstring(S, "myusername");
  dsasc_pushstring(S, "mypassword");
  int rc = dsasc_call(S, "authapp", "Login");
  if (rc != DSASC_SUCCESS)
     cout << dsasc_errorstring(S);
    cout << dsasc_tointeger(S, 0)
         << dsasc_tostring(S, 1)
  return EXIT_SUCCESS;

-- end of test.cpp -----------------------------------------------------------

- License
  I don't understand license terms, so choosed one: wxWidgets
- Thanks to:
- Comments and suggestions are welcome.