From 4edae3f518353bb21a02fcda2dfcff83c5a72fc3 Mon Sep 17 00:00:00 2001 From: Bent Bisballe Nyeng Date: Thu, 26 Jan 2012 12:08:39 +0100 Subject: New onCommit scripting system. --- server/src/Makefile.am | 6 +- server/src/client_connection.cc | 19 ++- server/src/client_connection.h | 4 +- server/src/journal.cc | 24 ++- server/src/journal.h | 16 +- server/src/journal_commit.cc | 1 + server/src/journal_uploadserver.cc | 26 ++-- server/src/journal_uploadserver.h | 2 +- server/src/luaoncommit.cc | 70 +++++++++ server/src/luaoncommit.h | 44 ++++++ server/src/luaresume.cc | 121 ++------------- server/src/luaresume.h | 18 +-- server/src/luascript.cc | 303 +++++++++++++++++++++++++++++++++++++ server/src/luascript.h | 92 +++++++++++ server/src/macroparser.cc | 35 ++++- server/src/macroparser.h | 5 +- server/src/pracrodaopgsql.cc | 66 ++++++++ server/src/resumeparser.cc | 81 ---------- server/src/resumeparser.h | 36 ----- server/src/session.cc | 13 +- server/src/session.h | 5 +- server/src/sessionparser.cc | 71 +++++++++ server/src/sessionparser.h | 10 +- server/src/sessionserialiser.cc | 47 +++++- server/src/template.h | 1 + server/src/templateparser.cc | 4 +- server/src/transactionhandler.cc | 40 +++-- 27 files changed, 879 insertions(+), 281 deletions(-) create mode 100644 server/src/luaoncommit.cc create mode 100644 server/src/luaoncommit.h create mode 100644 server/src/luascript.cc create mode 100644 server/src/luascript.h delete mode 100644 server/src/resumeparser.cc delete mode 100644 server/src/resumeparser.h (limited to 'server') diff --git a/server/src/Makefile.am b/server/src/Makefile.am index 167f4e4..bb172bd 100644 --- a/server/src/Makefile.am +++ b/server/src/Makefile.am @@ -36,6 +36,8 @@ pracrod_SOURCES = \ journal.cc \ journal_uploadserver.cc \ log.cc \ + luascript.cc \ + luaoncommit.cc \ luapraxisd.cc \ luaquerymapper.cc \ luaresume.cc \ @@ -51,7 +53,6 @@ pracrod_SOURCES = \ queryhandlerpentominos.cc \ queryhandlerpracro.cc \ queryparser.cc \ - resumeparser.cc \ saxparser.cc \ semaphore.cc \ server.cc \ @@ -97,6 +98,8 @@ EXTRA_DIST = \ journal.h \ journal_uploadserver.h \ log.h \ + luascript.h \ + luaoncommit.h \ luapraxisd.h \ luaquerymapper.h \ luaresume.h \ @@ -114,7 +117,6 @@ EXTRA_DIST = \ queryhandlerpracro.h \ queryparser.h \ queryresult.h \ - resumeparser.h \ saxparser.h \ semaphore.h \ server.h \ diff --git a/server/src/client_connection.cc b/server/src/client_connection.cc index b9d17b9..c3de7b0 100644 --- a/server/src/client_connection.cc +++ b/server/src/client_connection.cc @@ -108,6 +108,7 @@ void ClientConnection::nocommit(Session *session) } void ClientConnection::commit(Session *session) + throw(LUAScript::Exception, Journal::Exception) { if(docommit) { if(session->isReadonly()) { // Commit of an empty session discards it. @@ -117,7 +118,13 @@ void ClientConnection::commit(Session *session) DEBUG(connection, "Commit (%s)\n", session->id().c_str()); std::string sid = session->id(); - session->commit(); + try { + session->commit(); + } catch(LUAScript::Exception &e) { + throw e; + } catch(Journal::Exception &e) { + throw e; + } env.sessions.deleteSession(sid); sessionid = ""; docommit = false; @@ -208,7 +215,15 @@ bool ClientConnection::handle() response = handleTransaction(request, transaction, env, *session); } - commit(session); + try { + commit(session); + } catch(LUAScript::Exception &e) { + response = error_box(xml_encode(e.msg)); + return true; + } catch(Journal::Exception &e) { + response = error_box(xml_encode(e.msg)); + return true; + } nocommit(session); discard(session); diff --git a/server/src/client_connection.h b/server/src/client_connection.h index b8f7836..0bfa2e4 100644 --- a/server/src/client_connection.h +++ b/server/src/client_connection.h @@ -36,6 +36,8 @@ #include "transaction.h" #include "transactionparser.h" +#include "luascript.h" + class Session; class ClientConnection : public Connection { @@ -55,7 +57,7 @@ public: void getReply(Httpd::Reply &reply); private: - void commit(Session *session); + void commit(Session *session) throw(LUAScript::Exception, Journal::Exception); void nocommit(Session *session); void discard(Session *session); diff --git a/server/src/journal.cc b/server/src/journal.cc index fc4203c..04b1459 100644 --- a/server/src/journal.cc +++ b/server/src/journal.cc @@ -32,7 +32,8 @@ Journal::Journal() {} void Journal::addEntry(Transaction &transaction, Commit &commit, - std::string resume, Template *templ) + std::string resume, Template *templ, + LUAOnCommit *oncommit) { size_t index = 0; std::vector< Macro >::iterator i = templ->macros.begin(); @@ -70,16 +71,17 @@ void Journal::addEntry(Transaction &transaction, Commit &commit, } #endif - addEntry(resume, commit.macro, transaction.user, index); + addEntry(resume, commit.macro, transaction.user, index, oncommit); } void Journal::addEntry(std::string resume, std::string macro, - std::string user, int index) + std::string user, int index, LUAOnCommit *oncommit) { DEBUG(journal, "Add: %p %s %s - %s\n", this, macro.c_str(), user.c_str(), resume.c_str()); ResumeEntry re; + re.oncommit = oncommit; re.resume = resume; re.macro = macro; re.user = user; @@ -148,6 +150,22 @@ std::string Journal::patientID() return _patientid; } +void Journal::runOnCommitScripts() throw(LUAScript::Exception) +{ + std::map< int, ResumeEntry >::iterator i = entrylist.begin(); + while(i != entrylist.end()) { + if(i->second.oncommit != NULL) { + try { + i->second.oncommit->run(); + } catch(LUAScript::Exception &e) { + throw e; + } + } + i++; + } +} + + #ifdef TEST_JOURNAL //deps: debug.cc log.cc journal_uploadserver.cc journal_commit.cc //cflags: -I.. diff --git a/server/src/journal.h b/server/src/journal.h index 573f252..d098756 100644 --- a/server/src/journal.h +++ b/server/src/journal.h @@ -33,22 +33,31 @@ #include "transaction.h" #include "template.h" +#include "luaoncommit.h" class SessionSerialiser; class Journal { friend class SessionSerialiser; public: + class Exception { + public: + Exception(std::string m) : msg(m) {} + std::string msg; + }; + Journal(); virtual ~Journal() {} void addEntry(Transaction &transaction, Commit &commit, - std::string resume, Template *templ); + std::string resume, Template *templ, LUAOnCommit *oncommit); void addEntry(std::string resume, std::string macro, - std::string user, int index); + std::string user, int index, LUAOnCommit *oncommit); + + void runOnCommitScripts() throw(LUAScript::Exception); - virtual void commit() = 0; + virtual void commit() throw(Exception) = 0; std::string getEntry(std::string macro); void removeEntry(std::string macro); @@ -65,6 +74,7 @@ protected: std::string resume; std::string macro; std::string user; + LUAOnCommit *oncommit; bool dirty; }; diff --git a/server/src/journal_commit.cc b/server/src/journal_commit.cc index 0c1a93d..d765ebb 100644 --- a/server/src/journal_commit.cc +++ b/server/src/journal_commit.cc @@ -132,6 +132,7 @@ int journal_commit(const char *cpr, const char *user, // send body if(sock != -1 && write(sock, resume.c_str(), resume.size()) != (ssize_t)resume.size()) { ERR_LOG(journal, "write did not write all the bytes in the buffer.\n"); + return -1; } DEBUG(journal, "%s\n", buf); diff --git a/server/src/journal_uploadserver.cc b/server/src/journal_uploadserver.cc index a1299ec..eac6cd5 100644 --- a/server/src/journal_uploadserver.cc +++ b/server/src/journal_uploadserver.cc @@ -163,7 +163,10 @@ JournalUploadServer::JournalUploadServer(std::string host, } void JournalUploadServer::commit() + throw(Journal::Exception) { + int ret = 0; + #ifdef USE_MULTIPLE_USERS std::string resume; std::string olduser; @@ -177,9 +180,12 @@ void JournalUploadServer::commit() } if(i->second.user != olduser && olduser != "" && resume != "") { - journal_commit(patientID().c_str(), olduser.c_str(), - host.c_str(), port, - resume.c_str(), resume.size()); + ret = journal_commit(patientID().c_str(), olduser.c_str(), + host.c_str(), port, + resume.c_str(), resume.size()); + + if(ret == -1) throw Journal::Exception("Journal Commit error."); + // FIXME - UGLY HACK: Avoid upload server spooling in the wrong order. usleep(200000); resume = ""; @@ -195,9 +201,9 @@ void JournalUploadServer::commit() if(resume == "") return; - journal_commit(patientID().c_str(), olduser.c_str(), - host.c_str(), port, - resume.c_str(), resume.size()); + ret = journal_commit(patientID().c_str(), olduser.c_str(), + host.c_str(), port, + resume.c_str(), resume.size()); #else std::string resume; std::string user; @@ -222,10 +228,12 @@ void JournalUploadServer::commit() if(resume == "") return; // Connect to praxisuploadserver and commit all resumes in one bulk. - journal_commit(patientID().c_str(), user.c_str(), - host.c_str(), port, - resume.c_str(), resume.size()); + ret = journal_commit(patientID().c_str(), user.c_str(), + host.c_str(), port, + resume.c_str(), resume.size()); #endif/*USE_MULTIPLE_USERS*/ + + if(ret == -1) throw Journal::Exception("Journal Commit error."); } diff --git a/server/src/journal_uploadserver.h b/server/src/journal_uploadserver.h index 2393709..3e2fab3 100644 --- a/server/src/journal_uploadserver.h +++ b/server/src/journal_uploadserver.h @@ -33,7 +33,7 @@ class JournalUploadServer : public Journal { public: JournalUploadServer(std::string host, unsigned short int port); - void commit(); + void commit() throw(Journal::Exception); private: std::string host; diff --git a/server/src/luaoncommit.cc b/server/src/luaoncommit.cc new file mode 100644 index 0000000..8e96066 --- /dev/null +++ b/server/src/luaoncommit.cc @@ -0,0 +1,70 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set et sw=2 ts=2: */ +/*************************************************************************** + * luaoncommit.cc + * + * Thu Jan 12 08:38:02 CET 2012 + * Copyright 2012 Bent Bisballe Nyeng + * deva@aasimon.org + ****************************************************************************/ + +/* + * This file is part of Pracro. + * + * Pracro is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * Pracro is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Pracro; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ +#include "luaoncommit.h" + +#include +#include + +#include "luautil.h" +#include "luapraxisd.h" + +#include "debug.h" + +#include + +LUAOnCommit::LUAOnCommit(Transaction &t, Commit &c) : LUAScript() +{ + setEnv(LUAScript::ENV_PATIENTID, t.patientid); + setEnv(LUAScript::ENV_TEMPLATE, c.templ); + setEnv(LUAScript::ENV_MACRO, c.macro); + setEnv(LUAScript::ENV_USER, t.user); + + std::map::iterator i = c.fields.begin(); + while(i != c.fields.end()) { + addValue(i->first, i->second); + i++; + } +} + +#ifdef TEST_LUAONCOMMIT +//Additional dependency files +//deps: +//Required cflags (autoconf vars may be used) +//cflags: +//Required link options (autoconf vars may be used) +//libs: +#include "test.h" + +TEST_BEGIN; + +// TODO: Put some testcode here (see test.h for usable macros). +TEST_TRUE(false, "No tests yet!"); + +TEST_END; + +#endif/*TEST_LUAONCOMMIT*/ diff --git a/server/src/luaoncommit.h b/server/src/luaoncommit.h new file mode 100644 index 0000000..b64e744 --- /dev/null +++ b/server/src/luaoncommit.h @@ -0,0 +1,44 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set et sw=2 ts=2: */ +/*************************************************************************** + * luaoncommit.h + * + * Thu Jan 12 08:38:02 CET 2012 + * Copyright 2012 Bent Bisballe Nyeng + * deva@aasimon.org + ****************************************************************************/ + +/* + * This file is part of Pracro. + * + * Pracro is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * Pracro is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Pracro; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ +#ifndef __PRACRO_LUAONCOMMIT_H__ +#define __PRACRO_LUAONCOMMIT_H__ + +#include "luascript.h" + +#include "transaction.h" +#include + +class LUAOnCommit : public LUAScript { +public: + LUAOnCommit() {} + LUAOnCommit(Transaction &transaction, Commit &commit); + + const char *name() { return "lua on commit"; } +}; + +#endif/*__PRACRO_LUAONCOMMIT_H__*/ diff --git a/server/src/luaresume.cc b/server/src/luaresume.cc index 49de8be..1db4fb3 100644 --- a/server/src/luaresume.cc +++ b/server/src/luaresume.cc @@ -26,122 +26,27 @@ */ #include "luaresume.h" +#include +#include + #include "luautil.h" -#include "luapraxisd.h" #include "debug.h" #include -#define GLOBAL_POINTER "_pracroGlobalLUAObjectPointerThisShouldBeANameThatIsNotAccidentallyOverwritten" - -static int _value(lua_State *L) -{ - Pracro::checkParameters(L, - Pracro::T_STRING, - Pracro::T_END); - - std::string name = lua_tostring(L, lua_gettop(L)); - - lua_getglobal(L, GLOBAL_POINTER); - LUAResume *lua = (LUAResume*)lua_touserdata(L, lua_gettop(L)); - - if(!lua) { - lua_pushstring(L, "No LUA pointer!"); - lua_error(L); - return 1; - } - - std::string value = lua->value(name); - lua_pushstring(L, value.c_str()); - - return 1; -} - -LUAResume::LUAResume(Commit &c) - : commit(c) -{ - L = luaL_newstate(); - if(L == NULL) { - ERR(luaresume, "Could not create LUA state.\n"); - return; - } - - luaL_openlibs(L); - - lua_pushlightuserdata(L, this); // Push the pointer to 'this' instance - lua_setglobal(L, GLOBAL_POINTER); // Assign it to a global lua var. - - lua_register(L, "value", _value); - - register_praxisd(L); -} - -LUAResume::~LUAResume() -{ - lua_close(L); -} - -std::string LUAResume::value(std::string name) +LUAResume::LUAResume(Transaction &t, Commit &c) : LUAScript() { - if(commit.fields.find(name) == commit.fields.end()) { - ERR(luaresume, "LUAResume: No such field '%s'\n", name.c_str()); - return ""; + setEnv(LUAScript::ENV_PATIENTID, t.patientid); + setEnv(LUAScript::ENV_TEMPLATE, c.templ); + setEnv(LUAScript::ENV_MACRO, c.macro); + setEnv(LUAScript::ENV_USER, t.user); + + std::map::iterator i = c.fields.begin(); + while(i != c.fields.end()) { + addValue(i->first, i->second); + i++; } - - return commit.fields[name]; -} - -std::string LUAResume::run(std::string program) -{ - if(L == NULL) { - ERR(luaresume, "LUA state not initialized!"); - return ""; - } - - DEBUG(luaresume, "Running %s\n", program.c_str()); - - /* - lua_pushstring(L, value.toStdString().c_str()); - lua_setglobal(L, "value"); - - lua_pushstring(L, name.toStdString().c_str()); - lua_setglobal(L, "name"); - */ - - int top = lua_gettop(L); - - if(luaL_loadbuffer(L, program.c_str(), program.size(), - "lua resume generator")) { - ERR(luaresume, "loadbufer: %s\n", lua_tostring(L, lua_gettop(L))); - return ""; - } - - // Run the loaded code - if(lua_pcall(L, 0, LUA_MULTRET, 0)) { - ERR(luaresume, "pcall: %s\n" , lua_tostring(L, lua_gettop(L))); - return ""; - } - - if(top != lua_gettop(L) - 1) { - ERR(luaresume, "Program did not return a single value.\n"); - return ""; - } - - if(lua_isstring(L, lua_gettop(L)) == false) { - ERR(luaresume, "Program did not return a string value.\n"); - return ""; - } - - std::string res = lua_tostring(L, lua_gettop(L)); - lua_pop(L, 1); - - return res; -} - -void LUAResume::error(std::string message) -{ - ERR(luaresume, "LUA ERROR: %s\n", message.c_str()); } #ifdef TEST_LUARESUME diff --git a/server/src/luaresume.h b/server/src/luaresume.h index 1132f26..47a7652 100644 --- a/server/src/luaresume.h +++ b/server/src/luaresume.h @@ -27,26 +27,16 @@ #ifndef __PRACRO_LUARESUME_H__ #define __PRACRO_LUARESUME_H__ -#include -#include +#include "luascript.h" #include "transaction.h" #include -class LUAResume { +class LUAResume : public LUAScript { public: - LUAResume(Commit &commit); - ~LUAResume(); - - std::string run(std::string program); + LUAResume(Transaction &transaction, Commit &commit); - std::string value(std::string name); - - void error(std::string message); - -private: - lua_State *L; - Commit &commit; + const char *name() { return "lua resume generator"; } }; #endif/*__PRACRO_LUARESUME_H__*/ diff --git a/server/src/luascript.cc b/server/src/luascript.cc new file mode 100644 index 0000000..f4aef40 --- /dev/null +++ b/server/src/luascript.cc @@ -0,0 +1,303 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set et sw=2 ts=2: */ +/*************************************************************************** + * luascript.cc + * + * Tue Jan 10 14:43:39 CET 2012 + * Copyright 2012 Bent Bisballe Nyeng + * deva@aasimon.org + ****************************************************************************/ + +/* + * This file is part of Pracro. + * + * Pracro is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * Pracro is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Pracro; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ +#include "luascript.h" + +#include "configuration.h" +#include "debug.h" + +#include "luautil.h" +#include "luapraxisd.h" + +#define GLOBAL_POINTER "_pracroGlobalLUAObjectPointerThisShouldBeANameThatIsNotAccidentallyOverwritten" + +static int _value(lua_State *L) +{ + Pracro::checkParameters(L, + Pracro::T_STRING, + Pracro::T_END); + + std::string name = lua_tostring(L, lua_gettop(L)); + + lua_getglobal(L, GLOBAL_POINTER); + LUAScript *lua = (LUAScript*)lua_touserdata(L, lua_gettop(L)); + + if(!lua) { + lua_pushstring(L, "No LUA pointer!"); + lua_error(L); + return 1; + } + + if(lua->hasValue(name)) { + lua_pushstring(L, lua->value(name).c_str()); + } else { + lua_pushnil(L); + } + + return 1; +} + +static int _patientid(lua_State *L) +{ + Pracro::checkParameters(L, Pracro::T_END); + + lua_getglobal(L, GLOBAL_POINTER); + LUAScript *lua = (LUAScript*)lua_touserdata(L, lua_gettop(L)); + + if(!lua) { + lua_pushstring(L, "No LUA pointer!"); + lua_error(L); + return 1; + } + + lua_pushstring(L, lua->env(LUAScript::ENV_PATIENTID).c_str()); + + return 1; +} + +static int _template(lua_State *L) +{ + Pracro::checkParameters(L, Pracro::T_END); + + lua_getglobal(L, GLOBAL_POINTER); + LUAScript *lua = (LUAScript*)lua_touserdata(L, lua_gettop(L)); + + if(!lua) { + lua_pushstring(L, "No LUA pointer!"); + lua_error(L); + return 1; + } + + lua_pushstring(L, lua->env(LUAScript::ENV_TEMPLATE).c_str()); + + return 1; +} + +static int _macro(lua_State *L) +{ + Pracro::checkParameters(L, Pracro::T_END); + + lua_getglobal(L, GLOBAL_POINTER); + LUAScript *lua = (LUAScript*)lua_touserdata(L, lua_gettop(L)); + + if(!lua) { + lua_pushstring(L, "No LUA pointer!"); + lua_error(L); + return 1; + } + + lua_pushstring(L, lua->env(LUAScript::ENV_MACRO).c_str()); + + return 1; +} + +static int _user(lua_State *L) +{ + Pracro::checkParameters(L, Pracro::T_END); + + lua_getglobal(L, GLOBAL_POINTER); + LUAScript *lua = (LUAScript*)lua_touserdata(L, lua_gettop(L)); + + if(!lua) { + lua_pushstring(L, "No LUA pointer!"); + lua_error(L); + return 1; + } + + lua_pushstring(L, lua->env(LUAScript::ENV_USER).c_str()); + + return 1; +} + +LUAScript::LUAScript() +{ + L = NULL; +} + +void LUAScript::init() + throw(Exception) +{ + if(L) return; + + L = luaL_newstate(); + if(L == NULL) { + ERR(luaresume, "Could not create LUA state.\n"); + throw Exception("Could not create LUA state."); + } + + luaL_openlibs(L); + + lua_pushlightuserdata(L, this); // Push the pointer to 'this' instance + lua_setglobal(L, GLOBAL_POINTER); // Assign it to a global lua var. + + lua_register(L, "value", _value); + lua_register(L, "patientid", _patientid); + lua_register(L, "template", _template); + lua_register(L, "macro", _macro); + lua_register(L, "user", _user); + + register_praxisd(L); +} + +void LUAScript::addFile(std::string src) +{ + std::string file = + Conf::xml_basedir + "/include/" + src; + FILE *fp = fopen(file.c_str(), "r"); + if(fp) { + char buf[64]; + size_t sz; + std::string inc; + while((sz = fread(buf, 1, sizeof(buf), fp)) != 0) { + inc.append(buf, sz); + } + fclose(fp); + addCode(inc, file); + } +} + +void LUAScript::addCode(std::string c, std::string name) +{ + scripts.push_back(std::make_pair(c, name)); +} + +void LUAScript::addValue(std::string name, const std::string &value) +{ + values[name] = value; +} + +void LUAScript::addScripts(std::vector< Script > &scripts) +{ + std::vector< Script >::iterator spi = scripts.begin(); + while(spi != scripts.end()) { + if(spi->attributes.find("src") != spi->attributes.end()) { + std::string src = spi->attributes["src"]; + addFile(src); + } else { + addCode(spi->code); + } + spi++; + } +} + +void LUAScript::run() + throw(Exception) +{ + try { + init(); + } catch(Exception &e) { + throw Exception(e.msg); + } + + if(L == NULL) { + ERR(luaresume, "LUA state not initialized!"); + return; + } + + top = lua_gettop(L); + + std::vector >::iterator i = + scripts.begin(); + while(i != scripts.end()) { + std::string program = i->first; + std::string codename = name(); + if(i->second != "") codename += ": " + i->second; + + DEBUG(luaresume, "Running %s: %s\n", codename.c_str(), program.c_str()); + + if(luaL_loadbuffer(L, program.c_str(), program.size(), codename.c_str())) { + ERR(luaresume, "loadbufer: %s\n", lua_tostring(L, lua_gettop(L))); + throw Exception(lua_tostring(L, lua_gettop(L))); + } + + // Run the loaded code + if(lua_pcall(L, 0, LUA_MULTRET, 0)) { + ERR(luaresume, "pcall: %s\n" , lua_tostring(L, lua_gettop(L))); + throw Exception(lua_tostring(L, lua_gettop(L))); + } + + i++; + } +} + +std::string LUAScript::resultString() throw(Exception) +{ + if(top != lua_gettop(L) - 1) { + ERR(luaresume, "Program did not return a single value.\n"); + throw Exception("Program did not return a single value."); + } + + if(lua_isstring(L, lua_gettop(L)) == false) { + ERR(luaresume, "Program did not return a string value.\n"); + throw Exception("Program did not return a string value."); + } + + std::string res = lua_tostring(L, lua_gettop(L)); + lua_pop(L, 1); + + return res; +} + +bool LUAScript::hasValue(std::string name) +{ + return values.find(name) != values.end(); +} + +std::string LUAScript::value(std::string name) +{ + if(values.find(name) != values.end()) return values[name]; + return ""; +} + +std::string LUAScript::env(LUAScript::env_t id) +{ + if(_env.find(id) == _env.end()) return ""; + return _env[id]; +} + +void LUAScript::setEnv(LUAScript::env_t id, std::string value) +{ + _env[id] = value; +} + +#ifdef TEST_LUASCRIPT +//Additional dependency files +//deps: +//Required cflags (autoconf vars may be used) +//cflags: +//Required link options (autoconf vars may be used) +//libs: +#include "test.h" + +TEST_BEGIN; + +// TODO: Put some testcode here (see test.h for usable macros). +TEST_TRUE(false, "No tests yet!"); + +TEST_END; + +#endif/*TEST_LUASCRIPT*/ diff --git a/server/src/luascript.h b/server/src/luascript.h new file mode 100644 index 0000000..ec6c95f --- /dev/null +++ b/server/src/luascript.h @@ -0,0 +1,92 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set et sw=2 ts=2: */ +/*************************************************************************** + * luascript.h + * + * Tue Jan 10 14:43:39 CET 2012 + * Copyright 2012 Bent Bisballe Nyeng + * deva@aasimon.org + ****************************************************************************/ + +/* + * This file is part of Pracro. + * + * Pracro is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * Pracro is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Pracro; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ +#ifndef __PRACRO_LUASCRIPT_H__ +#define __PRACRO_LUASCRIPT_H__ + +#include +#include + +#include +#include +#include + +#include "template.h" + +class LUAScript { + friend class SessionSerialiser; + friend class SessionParser; +public: + typedef enum { + ENV_PATIENTID, + ENV_TEMPLATE, + ENV_MACRO, + ENV_USER + } env_t; + + class Exception { + public: + Exception(std::string m) : msg(m) {} + std::string msg; + }; + + LUAScript(); + + virtual const char *name() { return ""; } + + void init() throw(Exception); + + void addFile(std::string file); + void addCode(std::string code, std::string codename = ""); + void addScripts(std::vector< Script > &scripts); + + void addValue(std::string name, const std::string &value); + + void run() throw(Exception); + + bool hasValue(std::string name); + std::string value(std::string value); + + std::string env(env_t id); + void setEnv(env_t id, std::string value); + + std::string resultString() throw(Exception); + +protected: + lua_State *L; + + std::map _env; + +private: + std::vector > scripts; + std::map values; + + int top; +}; + + +#endif/*__PRACRO_LUASCRIPT_H__*/ diff --git a/server/src/macroparser.cc b/server/src/macroparser.cc index 7d3f367..be781aa 100644 --- a/server/src/macroparser.cc +++ b/server/src/macroparser.cc @@ -116,6 +116,11 @@ void MacroParser::characterData(std::string &data) assert(current_script); // No script present! current_script->code.append(data); } + + if(state == COMMIT_SCRIPT) { + assert(current_commit_script); // No script present! + current_commit_script->code.append(data); + } } void MacroParser::startTag(std::string name, attributes_t &attr) @@ -147,6 +152,18 @@ void MacroParser::startTag(std::string name, attributes_t &attr) return; } + // Enable oncommit parsing + if(name == "oncommit") { + if(state != MACRO) error("oncommit found outside macro."); + state = COMMIT_SCRIPTS; + + m->resume.attributes = attr; + + assert(m); // No macro is currently available, cannot create resume! + + return; + } + // Enable Query parsing if(name == "queries") { if(state != MACRO) error("queries found outside macro."); @@ -232,8 +249,18 @@ void MacroParser::startTag(std::string name, attributes_t &attr) current_resume_script = &(m->resume_scripts.back()); } break; + case COMMIT_SCRIPTS: + { + state = COMMIT_SCRIPT; + + Script s; + s.attributes = attr; + m->commit_scripts.push_back(s); + current_commit_script = &(m->commit_scripts.back()); + } + break; default: - error("\n"; + si++; + } + xml += " \n"; + + xml += " \n"; + } xml += " \n"; i++; diff --git a/server/src/template.h b/server/src/template.h index e549ef3..853db3d 100644 --- a/server/src/template.h +++ b/server/src/template.h @@ -67,6 +67,7 @@ public: maps_t maps; std::vector< Script > scripts; std::vector< Script > resume_scripts; + std::vector< Script > commit_scripts; Widget widgets; Resume resume; diff --git a/server/src/templateparser.cc b/server/src/templateparser.cc index 704b215..8fc3eff 100644 --- a/server/src/templateparser.cc +++ b/server/src/templateparser.cc @@ -133,7 +133,7 @@ void TemplateParser::startTag(std::string name, attributes_t &attr) // Enable script parsing if(name == "scripts") { - if(state != MACRO) error("scripts found outside macro."); + if(state != TEMPLATE) error("scripts found outside template."); state = SCRIPTS; assert(t); // No template is currently available, cannot create maps! @@ -158,7 +158,7 @@ void TemplateParser::startTag(std::string name, attributes_t &attr) } break; default: - error("