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:
- 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
./server/
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
./server/apps/
authapp.lua sample app
luasqlite3app.lua luasqlite3 app
./client/cpptest/
test.exe test client api
options: -h usage
-s host server addr [127.0.0.1]
-p port server port [12340]
./client/luatest/
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)
S:settimeout(seconds)
bool = S:isconnected()
int = S:call("appname", "procname")
string = S:errorstring()
int = S:nargs()
int = S:nresults()
S:push(value)
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.."!"
end
-------------------------------------------------------------------------
R.procs.Logout = function(R, args)
local usrid = args[0]
assert(usrid, "invalid user id")
return 1, "Bye!"
end
-------------------------------------------------------------------------
_G[appname].registry = R
end
_G[appname].UnRegister = function()
_G[appname].registry = nil
collectgarbage()
end
_G[appname].GetRegistry = function()
if not _G[appname].registry then
_G[appname].Register()
end
return _G[appname].registry
end
-- 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
-- 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("127.0.0.1", 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
S:result(1)
--
--test Logout proc--
S:push(2423)
local rc = S:call("authapp", "Logout")
S:result(0)
S:result(1)
--
-- 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("127.0.0.1", 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);
}
else
{
cout << dsasc_tointeger(S, 0)
<< dsasc_tostring(S, 1)
}
dsasc_close(S);
dsasc_netfinalize();
return EXIT_SUCCESS;
}
-- end of test.cpp -----------------------------------------------------------
- License
I don't understand license terms, so choosed one: wxWidgets
- Thanks to:
Lua
Yami
SQLite
luasqlite3
wxWidgets
wxSQLite3
Upx
- Comments and suggestions are welcome.
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? ;)) .------------------------.
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
./server/
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
./server/apps/
authapp.lua sample app
luasqlite3app.lua luasqlite3 app
./client/cpptest/
test.exe test client api
options: -h usage
-s host server addr [127.0.0.1]
-p port server port [12340]
./client/luatest/
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)
S:settimeout(seconds)
bool = S:isconnected()
int = S:call("appname", "procname")
string = S:errorstring()
int = S:nargs()
int = S:nresults()
S:push(value)
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.."!"
end
-------------------------------------------------------------------------
R.procs.Logout = function(R, args)
local usrid = args[0]
assert(usrid, "invalid user id")
return 1, "Bye!"
end
-------------------------------------------------------------------------
_G[appname].registry = R
end
_G[appname].UnRegister = function()
_G[appname].registry = nil
collectgarbage()
end
_G[appname].GetRegistry = function()
if not _G[appname].registry then
_G[appname].Register()
end
return _G[appname].registry
end
-- 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
-- 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("127.0.0.1", 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
S:result(1)
--
--test Logout proc--
S:push(2423)
local rc = S:call("authapp", "Logout")
S:result(0)
S:result(1)
--
-- 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("127.0.0.1", 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);
}
else
{
cout << dsasc_tointeger(S, 0)
<< dsasc_tostring(S, 1)
}
dsasc_close(S);
dsasc_netfinalize();
return EXIT_SUCCESS;
}
-- end of test.cpp -----------------------------------------------------------
- License
I don't understand license terms, so choosed one: wxWidgets
- Thanks to:
Lua
Yami
SQLite
luasqlite3
wxWidgets
wxSQLite3
Upx
- Comments and suggestions are welcome.