From 74a28aa7125be6a603128ad600c98c4882f3b5c2 Mon Sep 17 00:00:00 2001 From: deva Date: Tue, 1 Jun 2010 12:58:32 +0000 Subject: From new_protocol branch. --- server/autogen.sh | 2 +- server/configure.in | 90 +++- server/etc/pracrod.conf | 3 + server/fieldnames.sql | 536 ++++---------------- server/src/.cvsignore | 3 +- server/src/Makefile.am | 272 ++-------- server/src/artefact.cc | 188 +++++++ server/src/artefact.h | 54 ++ server/src/configuration.cc | 18 +- server/src/configuration.h | 18 +- server/src/configurationparser.cc | 62 ++- server/src/connection.cc | 339 +++++++++++++ server/src/connection.h | 63 +++ server/src/connectionpool.cc | 162 ++++++ server/src/connectionpool.h | 226 +++++++++ server/src/debug.cc | 2 +- server/src/entitylist.cc | 331 +++++++++++++ server/src/entitylist.h | 91 ++++ server/src/environment.cc | 85 ++++ server/src/environment.h | 50 ++ server/src/inotify.cc | 549 +++++++++++++++++++++ server/src/inotify.h | 118 +++++ server/src/journal_commit.cc | 96 +--- server/src/journal_commit.h | 33 +- server/src/journalwriter.cc | 350 +++++++++++++ server/src/journalwriter.h | 67 +++ server/src/luaresume.cc | 30 +- server/src/luautil.cc | 312 ++++++++++++ server/src/luautil.h | 81 +++ server/src/macrolist.cc | 83 +--- server/src/macrolist.h | 41 +- server/src/mutex.cc | 76 ++- server/src/mutex.h | 10 + server/src/pracrod.cc | 53 +- server/src/queryhandlerpentominos.cc | 262 +++++++--- server/src/queryhandlerpentominos.h | 17 +- server/src/queryparser.cc | 168 +++++++ server/src/queryparser.h | 81 +++ server/src/resumeparser.cc | 3 +- server/src/saxparser.cc | 251 +++++----- server/src/semaphore.cc | 47 ++ server/src/semaphore.h | 44 ++ server/src/server.cc | 462 +++++------------ server/src/session.cc | 238 +++++++++ server/src/session.h | 109 ++++ server/src/sessionparser.cc | 110 +++++ server/src/sessionparser.h | 64 +++ server/src/sessionserialiser.cc | 200 ++++++++ server/src/sessionserialiser.h | 53 ++ server/src/tcpsocket.cc | 34 +- server/src/templatelist.cc | 82 +-- server/src/templatelist.h | 39 +- server/src/transactionhandler.cc | 287 +++++++++++ server/src/transactionhandler.h | 45 ++ server/src/transactionparser.cc | 148 +++--- server/src/widgetgenerator.cc | 28 +- server/xml/macros/cycloplegisk_refraktion-1.0.xml | 110 +---- server/xml/macros/egen_brille-1.0.xml | 2 +- server/xml/macros/manifest_refraktion-1.0.xml | 110 +---- server/xml/macros/ref-spaltelampe-1.0.xml | 215 ++------ server/xml/macros/ref_90d_linse-1.0.xml | 2 +- server/xml/macros/ref_aktuelle-1.0.xml | 3 +- .../ref_behandling-kirurgisk_procedure-1.0.xml | 250 ++-------- .../xml/macros/ref_efterkontrol-overskrift-1.0.xml | 1 - .../ref_foerstedagskontol-overskrift-1.0.xml | 1 - server/xml/macros/ref_forunders-konklusion-1.0.xml | 1 - server/xml/macros/test_metawidget.xml | 4 +- server/xml/macros/visus-autoref-1.0.xml | 4 +- server/xml/macros/visus-egen_korr-1.0.xml | 10 +- .../xml/macros/visus-manifest_refraktion-1.0.xml | 24 +- server/xml/macros/visus-ou-1.0.xml | 2 +- server/xml/macros/visus-template-1.0.xml | 16 +- server/xml/macros/visus-uden_korr-1.0.xml | 10 +- server/xml/templates/ref_behandling.xml | 2 +- server/xml/templates/ref_foerstedagskontrol.xml | 2 +- server/xml/templates/ref_forunders.xml | 2 +- 76 files changed, 5709 insertions(+), 2328 deletions(-) create mode 100644 server/src/artefact.cc create mode 100644 server/src/artefact.h create mode 100644 server/src/connection.cc create mode 100644 server/src/connection.h create mode 100644 server/src/connectionpool.cc create mode 100644 server/src/connectionpool.h create mode 100644 server/src/entitylist.cc create mode 100644 server/src/entitylist.h create mode 100644 server/src/environment.cc create mode 100644 server/src/environment.h create mode 100644 server/src/inotify.cc create mode 100644 server/src/inotify.h create mode 100644 server/src/journalwriter.cc create mode 100644 server/src/journalwriter.h create mode 100644 server/src/luautil.cc create mode 100644 server/src/luautil.h create mode 100644 server/src/queryparser.cc create mode 100644 server/src/queryparser.h create mode 100644 server/src/semaphore.cc create mode 100644 server/src/semaphore.h create mode 100644 server/src/session.cc create mode 100644 server/src/session.h create mode 100644 server/src/sessionparser.cc create mode 100644 server/src/sessionparser.h create mode 100644 server/src/sessionserialiser.cc create mode 100644 server/src/sessionserialiser.h create mode 100644 server/src/transactionhandler.cc create mode 100644 server/src/transactionhandler.h (limited to 'server') diff --git a/server/autogen.sh b/server/autogen.sh index 45ef969..412286b 100755 --- a/server/autogen.sh +++ b/server/autogen.sh @@ -62,7 +62,7 @@ aclocalinclude="$ACLOCAL_FLAGS"; \ autoheader; \ echo "done.") && \ (echo $_echo_n " + Running automake: $_echo_c"; \ - automake --gnu --add-missing --copy; \ + automake --gnu --add-missing --copy;\ echo "done.") && \ (echo $_echo_n " + Running autoconf: $_echo_c"; \ autoconf; \ diff --git a/server/configure.in b/server/configure.in index b6beada..23a7172 100644 --- a/server/configure.in +++ b/server/configure.in @@ -1,7 +1,7 @@ # Filename: configure.in AC_INIT(src/pracrod.cc) -AM_INIT_AUTOMAKE( pracrod, 1.2.0 ) +AM_INIT_AUTOMAKE( pracrod, 1.1.0 ) dnl ====================== dnl Compile with debug options @@ -17,15 +17,17 @@ if test x$with_debug == xyes; then fi dnl ====================== -dnl Compile without pentominos support +dnl Compile with artefact support dnl ====================== -AC_ARG_WITH(pentominos, - [ --with-pentominos build with pentominos support (default=yes)], +AC_ARG_WITH(artefact, + [ --with-artefact build with artefact support (default=yes)], [], - [with_pentominos=yes]) -if test x$with_pentominos == xno; then - AC_MSG_WARN([*** Building without pentominos support!]) - AC_DEFINE_UNQUOTED(WITHOUT_PENTOMINOS, , [The project is configured not to use pentomimos]) + [with_artefact=yes]) +if test x$with_artefact == xyes; then + PKG_CHECK_MODULES(ATF, libartefact >= 0.0.2) +else + AC_MSG_WARN([*** Building without artefact support!]) + AC_DEFINE_UNQUOTED(WITHOUT_ARTEFACT, , [The project is configured not to use artefact]) fi dnl ====================== @@ -57,6 +59,23 @@ else PKG_CHECK_MODULES(PQXX, libpqxx >= 2.6.8) fi +dnl ====================== +dnl Compile with ssl support? +dnl ====================== +AC_ARG_WITH(ssl, + [ --with-ssl build with ssl support, requires microhttpd to be build with ssl support (default=yes)], + [], + [with_ssl=yes]) +if test x$with_ssl == xno; then + AC_MSG_WARN([*** Building without ssl support!]) + AC_DEFINE_UNQUOTED(WITHOUT_SSL, , [The project is configured not to use ssl]) +else + AC_MSG_WARN([*** Building with ssl support!]) + dnl ====================== + dnl TODO: Check for ssl support in microhttpd + dnl ====================== +fi + AC_PROG_CXX AC_PROG_LIBTOOL @@ -126,20 +145,59 @@ dnl ====================== PKG_CHECK_MODULES(CONFIG, libconfig++ >= 1.0.1) dnl ====================== -dnl Check for libartefact +dnl Check for libmicrohttpd dnl ====================== -PKG_CHECK_MODULES(ATF, libartefact >= 0.1.0) +PKG_CHECK_MODULES(HTTPD, libmicrohttpd >= 0.4.4) dnl ====================== dnl Check for eXpat library dnl ====================== +tmp_CXXFLAGS="$CXXFLAGS" +tmp_CPPFLAGS="$CPPFLAGS" +tmp_CFLAGS="$CFLAGS" +tmp_LDFLAGS="$LDFLAGS" +tmp_LIBS="$LIBS" +CXXFLAGS="" +CPPFLAGS="" +CFLAGS="" +LDFLAGS="" +LIBS="" AC_CHECK_HEADER(expat.h, , AC_MSG_ERROR([*** eXpat header file not found!])) -AC_CHECK_LIB(expat, XML_ParserCreate, , AC_MSG_ERROR([*** eXpat library not found!])) - -AC_SUBST(CFLAGS) -AC_SUBST(CPPFLAGS) -AC_SUBST(CXXFLAGS) -AC_SUBST(LDFLAGS) +AC_CHECK_LIB(expat, XML_ParserCreate, , AC_MSG_ERROR([*** eXpat library not found!])) +EXPAT_CFLAGS="$CXXFLAGS $CPPFLAGS $CFLAGS" +EXPAT_LIBS="$LDFLAGS $LIBS" +CXXFLAGS="$tmp_CXXFLAGS" +CPPFLAGS="$tmp_CPPFLAGS" +CFLAGS="$tmp_CFLAGS" +LDFLAGS="$tmp_LDFLAGS" +LIBS="$tmp_LIBS" +AC_SUBST(EXPAT_CFLAGS) +AC_SUBST(EXPAT_LIBS) + +dnl ====================== +dnl Check for the pthread library +dnl ====================== +tmp_CXXFLAGS="$CXXFLAGS" +tmp_CPPFLAGS="$CPPFLAGS" +tmp_CFLAGS="$CFLAGS" +tmp_LDFLAGS="$LDFLAGS" +tmp_LIBS="$LIBS" +CXXFLAGS="" +CPPFLAGS="" +CFLAGS="" +LDFLAGS="" +LIBS="" +AC_CHECK_HEADER(pthread.h, , AC_MSG_ERROR([*** pthread header file not found!])) +AC_CHECK_LIB(pthread, pthread_mutex_init, , AC_MSG_ERROR([*** pthread library not found!])) +PTHREAD_CFLAGS="$CXXFLAGS $CPPFLAGS $CFLAGS" +PTHREAD_LIBS="$LDFLAGS $LIBS" +CXXFLAGS="$tmp_CXXFLAGS" +CPPFLAGS="$tmp_CPPFLAGS" +CFLAGS="$tmp_CFLAGS" +LDFLAGS="$tmp_LDFLAGS" +LIBS="$tmp_LIBS" +AC_SUBST(PTHREAD_CFLAGS) +AC_SUBST(PTHREAD_LIBS) AC_OUTPUT( Makefile diff --git a/server/etc/pracrod.conf b/server/etc/pracrod.conf index 6d97619..5fb7494 100644 --- a/server/etc/pracrod.conf +++ b/server/etc/pracrod.conf @@ -2,3 +2,6 @@ port = 12345; journal_commit_addr = "localhost"; journal_commit_port = 18112; + +artefact_addr = "localhost"; +artefact_port = 11108; diff --git a/server/fieldnames.sql b/server/fieldnames.sql index ecb21bc..9f52646 100644 --- a/server/fieldnames.sql +++ b/server/fieldnames.sql @@ -2,7 +2,7 @@ -- PostgreSQL database dump -- -SET client_encoding = 'SQL_ASCII'; +SET client_encoding = 'UTF8'; SET standard_conforming_strings = off; SET check_function_bodies = false; SET client_min_messages = warning; @@ -32,433 +32,113 @@ ALTER TABLE public.fieldnames OWNER TO pracro; -- COPY fieldnames (name, description, "timestamp") FROM stdin; -journal.resume Contains all macro generated journal resumes 1258638989 -90d_linse.mangler.odxt No description 1258711741 -90d_linse.indblik.odxt No description 1258711741 -90d_linse.implikation.odxt No description 1258711741 -90d_linse.randbloedninger.odxt No description 1258711741 -90d_linse.exsudaterater.odxt No description 1258711741 -retinal_haevelse_odxt No description 1258711741 -90d_linse.mangler.osin No description 1258711741 -90d_linse.indblik.osin No description 1258711741 -90d_linse.implikation.osin No description 1258711741 -90d_linse.randbloedninger.osin No description 1258711741 -90d_linse.exsudaterater.osin No description 1258711741 -retinal_haevelse_osin No description 1258711741 -90d_linse.yderligere No description 1258711741 -akselaengde.mangler.odxt No description 1258711741 -akselaengde.laengde.odxt No description 1258711741 -akselaengde.mangler.osin No description 1258711741 -akselaengde.laengde.osin No description 1258711741 -observeret_odxt No description 1258711741 -dato_odxt No description 1258711741 -aktuelle_entry_odxt No description 1258711741 -aktuelle.symptomer.odxt No description 1258711741 -observeret_osin No description 1258711741 -dato_osin No description 1258711741 -aktuelle_entry_osin No description 1258711741 -aktuelle.symptomer.osin No description 1258711741 -aktuelle.opstaaet No description 1258711741 -aktuelle.efterfoelgende No description 1258711741 -evolution No description 1258711741 -cave_multilist No description 1258711741 -cave No description 1258711741 -amd_behandling.begynd No description 1258711741 -amd.indikation.oeje No description 1258711741 -amd.indikation No description 1258711741 -amd.indikation.oeje No description 1258711741 -amd.indikation No description 1258711741 -amd_kontrolunders.begynd No description 1258711741 -lucentis_behandling.oeje No description 1258711741 -autorefraktion.mangler.odxt No description 1258711741 -autorefraktion.sf.odxt No description 1258711741 -autorefraktion.cyl.odxt No description 1258711741 -autorefraktion.grader.odxt No description 1258711741 -autorefraktion.mangler.osin No description 1258711741 -autorefraktion.sf.osin No description 1258711741 -autorefraktion.cyl.osin No description 1258711741 -autorefraktion.grader.osin No description 1258711741 -central_corneatykkelse.mangler.odxt No description 1258711741 -central_corneatykkelse.tykkelse.odxt No description 1258711741 -central_corneatykkelse.mangler.osin No description 1258711741 -central_corneatykkelse.tykkelse.osin No description 1258711741 -central_corneatykkelse.metode No description 1258711741 -cycloplegisk_refraktion.mangler.odxt No description 1258711741 -cycloplegisk_refraktion.sf.odxt No description 1258711741 -cycloplegisk_refraktion.cyl.odxt No description 1258711742 -cycloplegisk_refraktion.grader.odxt No description 1258711742 -cycloplegisk_refraktion.mangler.osin No description 1258711742 -cycloplegisk_refraktion.sf.osin No description 1258711742 -cycloplegisk_refraktion.cyl.osin No description 1258711742 -cycloplegisk_refraktion.grader.osin No description 1258711742 -de_5_trin.checkbox No description 1258711742 -brillemaaler.mangler.odxt No description 1258711742 -brillemaaler.sf.odxt No description 1258711742 -brillemaaler.cyl.odxt No description 1258711742 -brillemaaler.grader.odxt No description 1258711742 -brillemaaler.mangler.osin No description 1258711742 -brillemaaler.sf.osin No description 1258711742 -brillemaaler.cyl.osin No description 1258711742 -brillemaaler.grader.osin No description 1258711742 -fluorescens.oeje No description 1258711742 -fluorescens.tidlige_faser No description 1258711742 -fluorescens.angiografi_faser No description 1258711742 -fluorescens_injektion.oeje No description 1258711742 -fluorescens_injektion.initialer No description 1258711742 -fluorescens.konklusion.oeje No description 1258711742 -fluorescens.konklusion No description 1258711742 -fluorescens.membran.position No description 1258711742 -fluorescens.membran.stoerrelse No description 1258711742 -de_fem_trin No description 1258711742 -gravid_ammende No description 1258711742 -header.name No description 1258711742 -header.cpr No description 1258711742 -henvisning.laege No description 1258711742 -henvisning.diagnose_kode No description 1258711742 -henvisning.diagnose No description 1258711742 -henvisning.laege No description 1258711742 -henvisning.diagnose_kode No description 1258711742 -henvisning.diagnose No description 1258711742 -amd.information No description 1258711742 -amd.samtykke No description 1258711742 -amd.aftaler No description 1258711742 -intravitreal.initialer No description 1258711742 -keratometri.mangler.odxt No description 1258711742 -keratometri.r1.odxt No description 1258711742 -keratometri.r2.odxt No description 1258711742 -keratometri.x1.odxt No description 1258711742 -keratometri.mangler.osin No description 1258711742 -keratometri.r1.osin No description 1258711742 -keratometri.r2.osin No description 1258711742 -keratometri.x1.osin No description 1258711742 -manifest_refraktion.mangler.odxt No description 1258711742 -manifest_refraktion.sf.odxt No description 1258711742 -manifest_refraktion.cyl.odxt No description 1258711742 -manifest_refraktion.grader.odxt No description 1258711742 -manifest_refraktion.mangler.osin No description 1258711742 -manifest_refraktion.sf.osin No description 1258711742 -manifest_refraktion.cyl.osin No description 1258711742 -manifest_refraktion.grader.osin No description 1258711742 -medicin_list No description 1258711742 -medicin No description 1258711742 -oct.mangler.odxt No description 1258711742 -oct.tykkelse.odxt No description 1258711742 -oct.beskrivelse.odxt No description 1258711742 -oct.mangler.osin No description 1258711742 -oct.tykkelse.osin No description 1258711742 -oct.beskrivelse.osin No description 1258711742 -oct.kommentarer No description 1258711742 -oct.mangler.odxt No description 1258711742 -oct.tykkelse.odxt No description 1258711742 -oct.mangler.osin No description 1258711742 -oct.tykkelse.osin No description 1258711742 -oejendrypning.ocgtt.preparation No description 1258711742 -oejendrypning.ocgtt.initialer No description 1258711742 -oejendrypning.ocgtt.dato No description 1258711742 -tonometri.mangler.odxt No description 1258711742 -tonometri.tryk.odxt No description 1258711742 -tonometri.mangler.osin No description 1258711742 -tonometri.tryk.osin No description 1258711742 -tonometri.apparat No description 1258711742 -pupilstoerrelse.mangler.odxt No description 1258711742 -pupilstoerrelse.diameter.odxt No description 1258711742 -pupilstoerrelse.mangler.osin No description 1258711742 -pupilstoerrelse.diameter.osin No description 1258711742 -pupilstoerrelse.metode No description 1258711742 -spaltelampe.mangler.odxt No description 1258711742 -spaltelampe.konjuktiva.odxt No description 1258711742 -spaltelampe.epitel.intakt.odxt No description 1258711742 -spaltelampe.epitel.central_epiteldefekt.odxt No description 1258711742 -spaltelampe.epitel.toerhedsforandringer.odxt No description 1258711742 -spaltelampe.stroma.odxt No description 1258711742 -spaltelampe.flap.odxt No description 1258711742 -spaltelampe.folder.odxt No description 1258711742 -spaltelampe.interface.partikler.odxt No description 1258711742 -spaltelampe.interface.epitelindvaekst.odxt No description 1258711742 -spaltelampe.endothel.odxt No description 1258711742 -spaltelampe.lens.odxt No description 1258711742 -spaltelampe.supplerende.odxt No description 1258711742 -spaltelampe.mangler.osin No description 1258711743 -spaltelampe.konjuktiva.osin No description 1258711743 -spaltelampe.epitel.intakt.osin No description 1258711743 -spaltelampe.epitel.central_epiteldefekt.osin No description 1258711743 -spaltelampe.epitel.toerhedsforandringer.osin No description 1258711743 -spaltelampe.stroma.osin No description 1258711743 -spaltelampe.flap.osin No description 1258711743 -spaltelampe.folder.osin No description 1258711743 -spaltelampe.partikler.osin No description 1258711743 -spaltelampe.epitelindvaekst.osin No description 1258711743 -spaltelampe.endothel.osin No description 1258711743 -spaltelampe.lens.osin No description 1258711743 -spaltelampe.supplerende.osin No description 1258711743 -90d_linse.mangler.odxt No description 1258711743 -90d_linse.indblik.odxt No description 1258711743 -90d_linse.papil.odxt No description 1258711743 -90d_linse.makula.odxt No description 1258711743 -90d_linse.periferi.odxt No description 1258711743 -90d_linse.hul_eller_rift_kl.odxt No description 1258711743 -90d_linse.supplerende.odxt No description 1258711743 -90d_linse.mangler.osin No description 1258711743 -90d_linse.indblik.osin No description 1258711743 -90d_linse.papil.osin No description 1258711743 -90d_linse.makula.osin No description 1258711743 -90d_linse.periferi.osin No description 1258711743 -90d_linse.hul_eller_rift_kl.osin No description 1258711743 -90d_linse.supplerende.osin No description 1258711743 -ref_aktuelle.bruger_nu No description 1258711743 -ref_aktuelle.stabilitet No description 1258711743 -ref_aktuelle.yderligere_kommentarer No description 1258711743 -ref_aktuelle.forventninger No description 1258711743 -ref_behandling.kirurgisk_procedure.type No description 1258711743 -ref_behandling.kirurgisk_procedure.oeje No description 1258711743 -ref_behandling.kirurgisk_procedure.lasik.metode No description 1258711743 -ref_behandling.kirurgisk_procedure.lasik.flapdiameter No description 1258711743 -ref_behandling.kirurgisk_procedure.lasik.flaptykkelse No description 1258711743 -ref_behandling.kirurgisk_procedure.lasik.kantprofil No description 1258711743 -ref_behandling.kirurgisk_procedure.prk.part1 No description 1258711743 -ref_behandling.kirurgisk_procedure.relasik.part1 No description 1258711743 -ref_behandling.kirurgisk_procedure.lasek.part1 No description 1258711743 -ref_behandling.kirurgisk_procedure.fotoablation.algoritme No description 1258711743 -ref_behandling.kirurgisk_procedure.fotoablation.sf No description 1258711743 -ref_behandling.kirurgisk_procedure.fotoablation.cyl No description 1258711743 -ref_behandling.kirurgisk_procedure.fotoablation.grader No description 1258711743 -ref_behandling.kirurgisk_procedure.fotoablation.ablationsdiameter No description 1258711743 -ref_behandling.kirurgisk_procedure.fotoablation.ablationsdybde No description 1258711743 -ref_behandling.kirurgisk_procedure.lasik.part2 No description 1258711743 -ref_behandling.kirurgisk_procedure.prk.part2 No description 1258711743 -ref_behandling.kirurgisk_procedure.relasik.part2 No description 1258711743 -ref_behandling.kirurgisk_procedure.lasek.part2 No description 1258711743 -ref_behandling.kirurgisk_procedure.drypperegime No description 1258711743 -ref_behandling.kirurgisk_procedure.komplikationer No description 1258711743 -ref_behandling.klargoering.initialer No description 1258711743 -ref_efterkontrol.aktuelle.afstandssyn No description 1258711743 -ref_efterkontrol.aktuelle.nattesyn No description 1258711743 -ref_efterkontrol.aktuelle.oejengener No description 1258711743 -ref_efterkontrol.aktuelle.tilfredshed No description 1258711743 -ref_efterkontrol.aktuelle.yderligere_kommentarer No description 1258711743 -ref_efterkontrol.informeret_samtykke.informeret_samtykke No description 1258711743 -ref_efterkontrol.informeret_samtykke.yderligere_kommentarer No description 1258711743 -ref_efterkontrol.konklusion.konklusion No description 1258711743 -ref_efterkontrol.konklusion.rebehandling No description 1258711743 -ref_efterkontrol.konklusion.oeje No description 1258711743 -ref_efterkontrol.konklusion.yderligere_kommentarer No description 1258711743 -ref_efterkontrol.overskrift.type No description 1258711743 -ref_efterkontrol.overskrift.maaneder No description 1258711743 -ref_foerstedagskontrol.overskrift.type No description 1258711743 -ref_forunders.informeret_samtykke.informeret_samtykke No description 1258711743 -ref_forunders.informeret_samtykke.yderligere_kommentarer No description 1258711743 -ref_forunders.konklusion.konklusion No description 1258711743 -ref_forunders.konklusion.behandling No description 1258711743 -ref_forunders.konklusion.oeje No description 1258711743 -ref_forunders.konklusion.maal No description 1258711743 -ref_forunders.konklusion.yderligere_kommentarer No description 1258711743 -ref.komplikationer No description 1258711743 -ref.kontrol No description 1258711743 -ref.oejendrypning.drypperegime No description 1258711743 -ref.oejendrypning.ordinering No description 1258711743 -ref.oejendrypning.mod_smerter No description 1258711743 -ref.subjektivt.smerter No description 1258711743 -ref.subjektivt.syn No description 1258711743 -spaltelampe.mangler.odxt No description 1258711743 -spaltelampe.observation.odxt No description 1258711743 -spaltelampe.yderligere.odxt No description 1258711743 -spaltelampe.mangler.osin No description 1258711743 -spaltelampe.observation.osin No description 1258711743 -spaltelampe.yderligere.osin No description 1258711743 -spaltelampe.mangler.odxt No description 1258711743 -spaltelampe.konjuktiva.odxt No description 1258711743 -spaltelampe.epitel.intakt.odxt No description 1258711743 -spaltelampe.epitel.central_epiteldefekt.odxt No description 1258711743 -spaltelampe.epitel.toerhedsforandringer.odxt No description 1258711743 -spaltelampe.stroma.odxt No description 1258711743 -spaltelampe.flap.odxt No description 1258711744 -spaltelampe.folder.odxt No description 1258711744 -spaltelampe.interface.partikler.odxt No description 1258711744 -spaltelampe.interface.epitelindvaekst.odxt No description 1258711744 -spaltelampe.endothel.odxt No description 1258711744 -spaltelampe.lens.odxt No description 1258711744 -spaltelampe.supplerende.odxt No description 1258711744 -spaltelampe.mangler.osin No description 1258711744 -spaltelampe.konjuktiva.osin No description 1258711744 -spaltelampe.epitel.intakt.osin No description 1258711744 -spaltelampe.epitel.central_epiteldefekt.osin No description 1258711744 -spaltelampe.epitel.toerhedsforandringer.osin No description 1258711744 -spaltelampe.stroma.osin No description 1258711744 -spaltelampe.flap.osin No description 1258711744 -spaltelampe.folder.osin No description 1258711744 -spaltelampe.partikler.osin No description 1258711744 -spaltelampe.epitelindvaekst.osin No description 1258711744 -spaltelampe.endothel.osin No description 1258711744 -spaltelampe.lens.osin No description 1258711744 -spaltelampe.supplerende.osin No description 1258711744 -amd.subjektiv_evaluering No description 1258711744 -supplerende No description 1258711744 -detaljer No description 1258711744 -tidligere_almene_sygdomme No description 1258711744 -detaljer No description 1258711744 -tidligere_oejensygdomme No description 1258711744 -missing_eye_odxt No description 1258711744 -missing_eye_osin No description 1258711744 -tobak.forbrug No description 1258711744 -tonometri.mangler.odxt No description 1258711744 -tonometri.tryk.odxt No description 1258711744 -tonometri.mangler.osin No description 1258711744 -tonometri.tryk.osin No description 1258711744 -tonometri.metode No description 1258711744 -topografi.metode No description 1258711744 -topografi.mangler.odxt No description 1258711744 -topografi.bedoemmelse.odxt No description 1258711744 -topografi.mangler.osin No description 1258711744 -topografi.bedoemmelse.osin No description 1258711744 -snellen.mangler.odxt No description 1258711744 -snellen.odxt No description 1258711744 -etdrs.odxt No description 1258711744 -snellen.korr.basis.odxt No description 1258711744 -snellen.korr.sf.odxt No description 1258711744 -snellen.korr.cyl.odxt No description 1258711744 -snellen.korr.grader.odxt No description 1258711744 -snellen.mangler.osin No description 1258711744 -snellen.osin No description 1258711744 -etdrs.osin No description 1258711744 -snellen.korr.basis.osin No description 1258711744 -snellen.korr.sf.osin No description 1258711744 -snellen.korr.cyl.osin No description 1258711744 -snellen.korr.grader.osin No description 1258711744 -visus.autoref.mangler.odxt No description 1258711744 -visus.autoref.kontrast.odxt No description 1258711744 -visus.autoref.st_hul.odxt No description 1258711744 -visus.autoref.snellen.odxt No description 1258711744 -visus.autoref.etdrs.odxt No description 1258711744 -visus.autoref.korr.sf.odxt No description 1258711744 -visus.autoref.korr.cyl.odxt No description 1258711744 -visus.autoref.korr.grader.odxt No description 1258711744 -visus.autoref.mangler.osin No description 1258711744 -visus.autoref.kontrast.osin No description 1258711744 -visus.autoref.st_hul.osin No description 1258711744 -visus.autoref.snellen.osin No description 1258711744 -visus.autoref.etdrs.osin No description 1258711744 -visus.autoref.korr.sf.osin No description 1258711744 -visus.autoref.korr.cyl.osin No description 1258711744 -visus.autoref.korr.grader.osin No description 1258711744 -visus.egen_korr.mangler.odxt No description 1258711744 -visus.egen_korr.kontrast.odxt No description 1258711744 -visus.egen_korr.snellen.odxt No description 1258711744 -visus.egen_korr.etdrs.odxt No description 1258711744 -visus.egen_korr.korr.sf.odxt No description 1258711744 -visus.egen_korr.korr.cyl.odxt No description 1258711744 -visus.egen_korr.korr.grader.odxt No description 1258711744 -visus.egen_korr.st_hul.odxt No description 1258711744 -visus.egen_korr.st_hul.snellen.odxt No description 1258711744 -visus.egen_korr.st_hul.etdrs.odxt No description 1258711744 -visus.egen_korr.mangler.osin No description 1258711744 -visus.egen_korr.kontrast.osin No description 1258711744 -visus.egen_korr.snellen.osin No description 1258711744 -visus.egen_korr.etdrs.osin No description 1258711744 -visus.egen_korr.korr.sf.osin No description 1258711744 -visus.egen_korr.korr.cyl.osin No description 1258711744 -visus.egen_korr.korr.grader.osin No description 1258711744 -visus.egen_korr.st_hul.osin No description 1258711744 -visus.egen_korr.st_hul.snellen.osin No description 1258711744 -visus.egen_korr.st_hul.etdrs.osin No description 1258711744 -visus.egen_korr.ou No description 1258711744 -visus.egen_korr.kontrast.ou No description 1258711744 -visus.egen_korr.snellen.ou No description 1258711744 -visus.egen_korr.etdrs.ou No description 1258711744 -visus.manifest_refraktion.mangler.odxt No description 1258711745 -visus.manifest_refraktion.kontrast.odxt No description 1258711745 -visus.manifest_refraktion.snellen.odxt No description 1258711745 -visus.manifest_refraktion.etdrs.odxt No description 1258711745 -visus.manifest_refraktion.korr.sf.odxt No description 1258711745 -visus.manifest_refraktion.korr.cyl.odxt No description 1258711745 -visus.manifest_refraktion.korr.grader.odxt No description 1258711745 -visus.manifest_refraktion.st_hul.odxt No description 1258711745 -visus.manifest_refraktion.st_hul.snellen.odxt No description 1258711745 -visus.manifest_refraktion.st_hul.etdrs.odxt No description 1258711745 -visus.manifest_refraktion.mangler.osin No description 1258711745 -visus.manifest_refraktion.kontrast.osin No description 1258711745 -visus.manifest_refraktion.snellen.osin No description 1258711745 -visus.manifest_refraktion.etdrs.osin No description 1258711745 -visus.manifest_refraktion.korr.sf.osin No description 1258711745 -visus.manifest_refraktion.korr.cyl.osin No description 1258711745 -visus.manifest_refraktion.korr.grader.osin No description 1258711745 -visus.manifest_refraktion.st_hul.osin No description 1258711745 -visus.manifest_refraktion.st_hul.snellen.osin No description 1258711745 -visus.manifest_refraktion.st_hul.etdrs.osin No description 1258711745 -visus.manifest_refraktion.ou No description 1258711745 -visus.manifest_refraktion.kontrast.ou No description 1258711745 -visus.manifest_refraktion.snellen.ou No description 1258711745 -visus.manifest_refraktion.etdrs.ou No description 1258711745 -visus.ou.kontrast No description 1258711745 -visus.ou.st_hul No description 1258711745 -visus.ou.snellen No description 1258711745 -visus.ou.etdrs No description 1258711745 -visus.ou.korr.sf No description 1258711745 -visus.ou.korr.cyl No description 1258711745 -visus.ou.korr.grader No description 1258711745 -visus.template.mangler.odxt No description 1258711745 -visus.template.kontrast.odxt No description 1258711745 -visus.template.snellen.odxt No description 1258711745 -visus.template.etdrs.odxt No description 1258711745 -visus.template.korr.sf.odxt No description 1258711745 -visus.template.korr.cyl.odxt No description 1258711745 -visus.template.korr.grader.odxt No description 1258711745 -visus.template.add.sf.odxt No description 1258711745 -visus.template.add.cyl.odxt No description 1258711745 -visus.template.add.grader.odxt No description 1258711745 -visus.template.st_hul.odxt No description 1258711745 -visus.template.st_hul.snellen.odxt No description 1258711745 -visus.template.st_hul.etdrs.odxt No description 1258711745 -visus.template.mangler.osin No description 1258711745 -visus.template.kontrast.osin No description 1258711745 -visus.template.snellen.osin No description 1258711745 -visus.template.etdrs.osin No description 1258711745 -visus.template.korr.sf.osin No description 1258711745 -visus.template.korr.cyl.osin No description 1258711745 -visus.template.korr.grader.osin No description 1258711745 -visus.template.add.sf.osin No description 1258711745 -visus.template.add.cyl.osin No description 1258711745 -visus.template.add.grader.osin No description 1258711745 -visus.template.st_hul.osin No description 1258711745 -visus.template.st_hul.snellen.osin No description 1258711745 -visus.template.st_hul.etdrs.osin No description 1258711745 -visus.template.ou No description 1258711745 -visus.template.kontrast.ou No description 1258711745 -visus.template.snellen.ou No description 1258711745 -visus.template.etdrs.ou No description 1258711745 -visus.uden_korr.mangler.odxt No description 1258711745 -visus.uden_korr.kontrast.odxt No description 1258711745 -visus.uden_korr.snellen.odxt No description 1258711745 -visus.uden_korr.etdrs.odxt No description 1258711745 -visus.uden_korr.st_hul.odxt No description 1258711745 -visus.uden_korr.st_hul.snellen.odxt No description 1258711745 -visus.uden_korr.st_hul.etdrs.odxt No description 1258711745 -visus.uden_korr.mangler.osin No description 1258711745 -visus.uden_korr.kontrast.osin No description 1258711745 -visus.uden_korr.snellen.osin No description 1258711745 -visus.uden_korr.etdrs.osin No description 1258711745 -visus.uden_korr.st_hul.osin No description 1258711745 -visus.uden_korr.st_hul.snellen.osin No description 1258711745 -visus.uden_korr.st_hul.etdrs.osin No description 1258711745 -visus.uden_korr.ou No description 1258711745 -visus.uden_korr.kontrast.ou No description 1258711745 -visus.uden_korr.snellen.ou No description 1258711745 -visus.uden_korr.etdrs.ou No description 1258711745 -fundus.kilde No description 1258711745 -fundus.randhaemorrhagier No description 1258711745 -fundus.exsudater No description 1258711745 -amd_preop.konklusion.oeje No description 1258711745 -amd_preop.konklusion No description 1258711745 -amd_preop.konklusion.yderligere No description 1258711745 -amd_preop.konklusion.afsluttes No description 1258711745 -boelgefront.odxt No description 1260355433 -boelgefront.osin No description 1260355438 -boelgefront.aberration.odxt No description 1260355451 -boelgefront.aberration.osin No description 1260355454 -boelgefront.pupilstoerrelse.odxt No description 1260355463 -boelgefront.pupilstoerrelse.osin No description 1260355467 -boelgefront.mangler.odxt No description 1260355482 -boelgefront.mangler.osin No description 1260355487 -90d_linse.hul_eller_rift_kl.odxt No description 1265799742 +cave Listen over medicintyper og reaktioner som en patient er overfølsom overfor. 0 +medicin Liste over medicin som patienten i forvejen modtager (og som har relevans for undersøgelsen). 0 +previous_common_diseases Liste over tidligere almene sygdomme. 0 +amd.consent Har patienten givet sit samtykke til AMD behandling? 0 +amd.indication Indikation for AMD. 0 +amd.information Har patienten modtaget en informationsfolder om AMD forløbet? 0 +tobacco Information om patientens rygevaner. 0 +previous_eye_diseases Tidligere øjensygdomme som har relevans for aktuelle. 0 +snellen.left Snellen tavle værdi for venstre øje. 0 +snellen.right Snellen tavle værdi for højre øje. 0 +etdrs.left ETDRS værdi for venstre øje. 0 +etdrs.right ETDRS værdi for højre øje. 0 +lensmeter.left.sphere Lensmeter sphere pÃ¥ venstre brille. 0 +lensmeter.left.cyl Lensmeter cylinder pÃ¥ venstre brille. 0 +lensmeter.left.axis Lensmeter akse pÃ¥ venstre brille. 0 +lensmeter.right.sphere Lensmeter sphere pÃ¥ højre brille. 0 +lensmeter.right.cyl Lensmeter cylinder pÃ¥ højre brille. 0 +lensmeter.right.axis Lensmeter akse pÃ¥ højre brille. 0 +autorefractor.left.sphere Autorefraktor sphere pÃ¥ venstre øje. 0 +autorefractor.left.cyl Autorefraktor cylinder pÃ¥ venstre øje. 0 +autorefractor.left.axis Autorefraktor akse pÃ¥ venstre øje. 0 +autorefractor.right.sphere Autorefraktor sphere pÃ¥ højre øje. 0 +autorefractor.right.cyl Autorefraktor cylinder pÃ¥ højre øje. 0 +autorefractor.right.axis Autorefraktor akse pÃ¥ højre øje. 0 +tonometer.pressure.left Tonometer trykmÃ¥l pÃ¥ venstre øje. 0 +tonometer.pressure.right Tonometer trykmÃ¥l pÃ¥ højre øje. 0 +tonometer.device Tonometer apparatur benyttet til mÃ¥lingen. 0 +oct.left.thickness OCT tykkelse pÃ¥ venstre øje. 0 +oct.left.description OCT beskrivelse pÃ¥ vrnstre øje. 0 +oct.right.thickness OCT tykkelse pÃ¥ højre øje. 0 +oct.comments OCT kommentarer. 0 +oct.right.description OCT beskrivelse pÃ¥ højre øje. 0 +slit_lamp.left.observation Spaltelampe observation, venstre øje. 0 +slit_lamp.left.additional Spaltelampe supplerende information, venstre øje. 0 +slit_lamp.right.observation Spaltelampe observation, højre øje. 0 +slit_lamp.right.additional Spaltelampe supplerende information, højre øje. 0 +90D_lens.implications 90D linse implikationsliste. 0 +90D_lens.right.fundus_visibility Indblik til fundusbaggrunden, højre øje. 0 +90D_lens.left.fundus_visibility Indblik til fundusbaggrunden, venstre øje. 0 +amd_preop.conclusion_terminated AMD forundersøgelse, afsluttes. 0 +amd_preop.conclusion_additional AMD forundersøgelse, bemærkninger. 0 +amd_preop.conclusion AMD forundersøgelse, konklusion. 0 +fluorescens.early_fases Fluorescens tidlige faser. 0 +fluorescens.angiografic_fases Fluorescens angiografiske faser. 0 +ocgtt.preparation Det/de ogctt præparat der er dryppet med. 0 +ocgtt.initials Initialer pÃ¥ den person som har foretaget ocgtt drypning. 0 +fluorescens.conclusion Konklusion pÃ¥ fluoresces undersøgelsen. 0 +fluorescens.additional_info Yderligere information til fluorescens konklusion (membran størrelse og placering) 0 +ocgtt.date Tidspunkt for drypning i unixtime (UTC). 0 +missing_eye_left Indikerer at der ikke kan mÃ¥les pÃ¥ det venstre øje. 0 +missing_eye_right Indikerer at der ikke kan mÃ¥les pÃ¥ det højre øje. 0 +test1 \N \N +test2 \N \N +snellen.left.missing Den venstre snellen mÃ¥ling er ikke foretaget. 0 +snellen.right.missing Den højre snellen mÃ¥ling er ikke foretaget. 0 +lensmeter.left.missing Den venstre lensmeter mÃ¥ling er ikke foretaget. 0 +lensmeter.right.missing Den højre lensmeter mÃ¥ling er ikke foretaget. 0 +journal.resume Journal resume text 1234274034 +fluorescein_injection.eye Indikation af hvilket øje der injiceres. 0 +fluorescein_injection.initials Initialer pÃ¥ den person som har injiceret fluorescein. 0 +fluorescens.eye Indikation af hvilket øje der beskrives. 0 +fluorescens.conclusion.eye Indikation af hvilket øje der konkluderes pÃ¥. 0 +amd.indication.eye Indikation af hvilket øje der stilles behandlings indikation pÃ¥. 0 +amd.agreements Felt til yderligere aftaler med patienten 0 +slit_lamp.right.missing Manglende højre øje, ved spaltelampeundersøgelse. 0 +slit_lamp.left.missing Manglende venstre øje, ved spaltelampeundersøgelse. 0 +tonometer.right.missing Manglende højre øje, ved tonometerundersøgelse. 0 +fluorescens.conclusion.other Fluorescens membran kommentar. 0 +tonometer.left.missing Manglende venstre øje, ved tonometerundersøgelse. 0 +oct.left.missing Manglende venstre øje, ved OCT undersøgelse. 0 +autorefractor.left.missing Manglende venstre øje, ved autorefractor undersøgelse. 0 +oct.right.missing Manglende højre øje, ved OCT undersøgelse. 0 +autorefractor.right.missing Manglende højre øje, ved autorefractor undersøgelse. 0 +fluorescens.membrane.size Fluorescens membran størrelse. 0 +fluorescens.membrane.position Fluorescens membran position. 0 +current.when Aktuelle opstÃ¥et 0 +current.then Aktuelle udvikling 0 +intravitreal.initials Initialier pÃ¥ den person som ar udført intravitreal injicering. 0 +lucentis_treatment.eye Lucentis behandlig af hvilket øje? 0 +five_steps Gennemgang af de 5 trin. 0 +current.symptoms.right Aktuelle symptomer (liste) pÃ¥ højre øje. 0 +current.symptoms.left Aktuelle symptomer (liste) pÃ¥ venstre øje. 0 +amd.subjective_evaluation Subjektiv evaluering siden sidst. 0 +fundus.source Kilde for fundus evaluering 0 +fundus.randh Findes der Randhæmorrhagier 0 +fundus.exsud Findes der Exsudater 0 +90D_lens.right.implikation Hvad observeres pÃ¥ højre øje? 0 +90D_lens.left.implikation Hvad observeres pÃ¥ venstre øje? 0 +90D_lens.right.randbl Er der randblødning pÃ¥ højre øje? 0 +90D_lens.left.randbl Er der randblødning pÃ¥ venstre øje? 0 +90D_lens.right.exsudater Er der exhudater pÃ¥ højre øje? 0 +90D_lens.left.exsudater Er der exhudater pÃ¥ venstre øje? 0 +90D_lens.additional Supplerende oplysninger om 90D linse undersøgelsen 0 +90D_lens.left.missing Manglende venstre øje, ved 90D linse undersøglesen \N +90D_lens.right.missing Manglende højre øje, ved 90D linse undersøglesen \N +snellen.right.corr.cyl \N \N +snellen.right.corr.sph \N \N +snellen.right.corr.basis \N \N +snellen.left.corr.cyl \N \N +snellen.left.corr.sph \N \N +snellen.left.corr.basis \N \N +snellen.right.corr.axis \N \N +snellen.left.corr.axis \N \N +referral.doctor \N \N +referral.diagnose \N \N +referral.diagnosecode \N \N +amd_preop.conclusion.eye AMD preop konklusinens øje 0 \. diff --git a/server/src/.cvsignore b/server/src/.cvsignore index e7654ee..6fa7094 100644 --- a/server/src/.cvsignore +++ b/server/src/.cvsignore @@ -4,4 +4,5 @@ Makefile.in Makefile .libs .deps -test_* \ No newline at end of file +test_* +tests.make \ No newline at end of file diff --git a/server/src/Makefile.am b/server/src/Makefile.am index 98a154e..942ced5 100644 --- a/server/src/Makefile.am +++ b/server/src/Makefile.am @@ -2,25 +2,33 @@ bin_PROGRAMS = pracrod macrotool pracrod_LDADD = $(LD_EFENCE) $(PQXX_LIBS) $(CONFIG_LIBS) \ - $(LUA_LIBS) $(HTTPD_LIBS) -lpthread $(ATF_LIBS) + $(LUA_LIBS) $(HTTPD_LIBS) $(PTHREAD_LIBS) \ + $(EXPAT_LIBS) $(ATF_LIBS) pracrod_CXXFLAGS = $(PQXX_CXXFLAGS) $(CONFIG_CXXFLAGS) \ - $(LUA_CXXFLAGS) $(HTTPD_CFLAGS) $(ATF_CFLAGS) + $(LUA_CXXFLAGS) $(HTTPD_CFLAGS) $(EXPAT_CFLAGS) \ + $(PTHREAD_CFLAGS) $(ATF_CFLAGS) pracrod_SOURCES = \ pracrod.cc \ + artefact.cc \ daemon.cc \ database.cc \ configuration.cc \ configurationparser.cc \ + connection.cc \ + connectionpool.cc \ debug.cc \ + entitylist.cc \ + environment.cc \ exception.cc \ - queryhandlerpentominos.cc \ - queryhandlerpracro.cc \ + inotify.cc \ journal_commit.cc \ + journalwriter.cc \ log.cc \ luaquerymapper.cc \ luaresume.cc \ + luautil.cc \ macroheaderparser.cc \ macrolist.cc \ macroparser.cc \ @@ -28,12 +36,20 @@ pracrod_SOURCES = \ pracrodao.cc \ pracrodaopgsql.cc \ pracrodaotest.cc \ + queryhandlerpentominos.cc \ + queryhandlerpracro.cc \ + queryparser.cc \ resumeparser.cc \ saxparser.cc \ + semaphore.cc \ server.cc \ + session.cc \ + sessionparser.cc \ + sessionserialiser.cc \ templatelist.cc \ templateheaderparser.cc \ templateparser.cc \ + transactionhandler.cc \ transactionparser.cc \ tcpsocket.cc \ utf8.cc \ @@ -41,9 +57,11 @@ pracrod_SOURCES = \ widgetgenerator.cc \ xml_encode_decode.cc -macrotool_LDADD = $(LD_EFENCE) $(PQXX_LIBS) $(CONFIG_LIBS) $(LUA_LIBS) -lpthread +macrotool_LDADD = $(LD_EFENCE) $(PQXX_LIBS) $(CONFIG_LIBS) \ + $(LUA_LIBS) $(PTHREAD_LIBS) $(EXPAT_LIBS) -macrotool_CXXFLAGS = $(PQXX_CXXFLAGS) $(CONFIG_CXXFLAGS) $(LUA_CXXFLAGS) +macrotool_CXXFLAGS = $(PQXX_CXXFLAGS) $(CONFIG_CXXFLAGS) \ + $(LUA_CXXFLAGS) $(PTHREAD_CFLAGS) $(EXPAT_CFLAGS) macrotool_SOURCES = \ macrotool.cc \ @@ -51,7 +69,9 @@ macrotool_SOURCES = \ configuration.cc \ configurationparser.cc \ database.cc \ + entitylist.cc \ exception.cc \ + inotify.cc \ log.cc \ macroheaderparser.cc \ macrolist.cc \ @@ -69,20 +89,25 @@ macrotool_SOURCES = \ versionstr.cc EXTRA_DIST = \ + artefact.h \ configuration.h \ configurationparser.h \ + connection.h \ + connectionpool.h \ daemon.h \ database.h \ dbtypes.h \ debug.h \ + environment.h \ + entitylist.h \ exception.h \ - queryhandler.h \ - queryhandlerpentominos.h \ - queryhandlerpracro.h \ + inotify.h \ journal_commit.h \ + journalwriter.h \ log.h \ luaquerymapper.h \ luaresume.h \ + luautil.h \ macroheaderparser.h \ macrolist.h \ macroparser.h \ @@ -94,15 +119,21 @@ EXTRA_DIST = \ pracrodao.h \ pracrodaopgsql.h \ pracrodaotest.h \ - queryresult.h \ + queryhandler.h \ + queryhandlerpentominos.h \ + queryhandlerpracro.h \ + queryparser.h \ resumeparser.h \ saxparser.h \ + semaphore.h \ server.h \ - template.h \ + session.h \ + sessionparser.h \ + sessionserialiser.h \ templatelist.h \ templateheaderparser.h \ templateparser.h \ - transaction.h \ + transactionhandler.h \ transactionparser.h \ tcpsocket.h \ utf8.h \ @@ -114,217 +145,10 @@ EXTRA_DIST = \ # Test Section # ################ -TESTFILES = \ - test_tcpsocket \ - test_pracrodaotest \ - test_widgetgenerator \ - test_configurationparser \ - test_exception \ - test_templateheaderparser \ - test_macroheaderparser \ - test_templatelist \ - test_saxparser \ - test_transactionparser \ - test_versionstr \ - test_macrolist \ - test_queryhandlerpentominos \ - test_queryhandlerpracro \ - test_luaquerymapper \ - test_templateparser \ - test_server \ - test_pracrodaopgsql \ - test_macroparser \ - test_xml_encode_decode \ - test_journal_commit - -TESTLOGS = `for F in ${TESTFILES}; do echo $$F.log; done` - -BASICFILES = exception.cc log.cc debug.cc configuration.cc utf8.cc -BASICFLAGS = -I.. -DHAVE_CONFIG_H $(CONFIG_CXXFLAGS) $(CONFIG_LIBS) - -PARSERFILES = saxparser.cc -PARSERFLAGS = -lexpat - -DBFILES = database.cc pracrodao.cc pracrodaopgsql.cc pracrodaotest.cc mutex.cc -DBFLAGS = $(PQXX_LIBS) $(PQXX_CXXFLAGS) - -test: $(TESTFILES) - @echo "All tests done." - -test_clean: - rm -f $(TESTFILES) $(TESTLOGS) - -TEST_TCPSOCKET_FILES = \ - tcpsocket.cc \ - $(BASICFILES) -test_tcpsocket: $(TEST_TCPSOCKET_FILES) - @../../tools/test $(TEST_TCPSOCKET_FILES) $(BASICFLAGS) - -TEST_PRACRODAOTEST_FILES = \ - pracrodaotest.cc \ - pracrodao.cc \ - $(BASICFILES) -test_pracrodaotest: $(TEST_PRACRODAOTEST_FILES) - @../../tools/test $(TEST_PRACRODAOTEST_FILES) $(BASICFLAGS) - -TEST_WIDGETGENERATOR_FILES = \ - widgetgenerator.cc \ - xml_encode_decode.cc \ - luaquerymapper.cc \ - $(BASICFILES) \ - $(DBFILES) -test_widgetgenerator: $(TEST_WIDGETGENERATOR_FILES) - @../../tools/test $(TEST_WIDGETGENERATOR_FILES) $(BASICFLAGS) $(LUA_LIBS) $(DBFLAGS) - -TEST_CONFIGURATIONPARSER_FILES = \ - configurationparser.cc \ - configuration.cc \ - exception.cc \ - log.cc -test_configurationparser: $(TEST_CONFIGURATIONPARSER_FILES) - @../../tools/test $(TEST_CONFIGURATIONPARSER_FILES) $(BASICFLAGS) - -TEST_EXCEPTION_FILES = \ - exception.cc \ - log.cc -test_exception: $(TEST_EXCEPTION_FILES) - @../../tools/test $(TEST_EXCEPTION_FILES) - -TEST_TEMPLATEHEADERPARSER_FILES = \ - templateheaderparser.cc \ - $(PARSERFILES) \ - $(BASICFILES) -test_templateheaderparser: $(TEST_TEMPLATEHEADERPARSER_FILES) - @../../tools/test $(TEST_TEMPLATEHEADERPARSER_FILES) $(BASICFLAGS) $(PARSERFLAGS) - -TEST_MACROHEADERPARSER_FILES = \ - macroheaderparser.cc \ - $(PARSERFILES) \ - $(BASICFILES) -test_macroheaderparser: $(TEST_MACROHEADERPARSER_FILES) - @../../tools/test $(TEST_MACROHEADERPARSER_FILES) $(BASICFLAGS) $(PARSERFLAGS) - -TEST_TEMPLATELIST_FILES = \ - templatelist.cc \ - versionstr.cc \ - templateheaderparser.cc \ - $(PARSERFILES) \ - $(BASICFILES) -test_templatelist: $(TEST_TEMPLATELIST_FILES) - @../../tools/test $(TEST_TEMPLATELIST_FILES) $(PARSERFLAGS) $(BASICFLAGS) - -TEST_MACROLIST_FILES = \ - macrolist.cc \ - versionstr.cc \ - macroheaderparser.cc \ - $(PARSERFILES) \ - $(BASICFILES) -test_macrolist: $(TEST_MACROLIST_FILES) - @../../tools/test $(TEST_MACROLIST_FILES) $(PARSERFLAGS) $(BASICFLAGS) - -TEST_SAXPARSER_FILES = \ - saxparser.cc \ - $(BASICFILES) -test_saxparser: $(TEST_SAXPARSER_FILES) - @../../tools/test $(TEST_SAXPARSER_FILES) $(BASICFLAGS) $(PARSERFLAGS) - -TEST_TRANSACTIONPARSER_FILES = \ - transactionparser.cc \ - $(BASICFILES) \ - $(PARSERFILES) -test_transactionparser: $(TEST_TRANSACTIONPARSER_FILES) - @../../tools/test $(TEST_TRANSACTIONPARSER_FILES) $(BASICFLAGS) $(PARSERFLAGS) - -TEST_VERSIONSTR_FILES = \ - versionstr.cc \ - $(BASICFILES) -test_versionstr: $(TEST_VERSIONSTR_FILES) - @../../tools/test $(TEST_VERSIONSTR_FILES) $(BASICFLAGS) - -TEST_QUERYHANDLERPENTOMINOS_FILES = \ - queryhandlerpentominos.cc \ - tcpsocket.cc \ - $(PARSERFILES) \ - $(BASICFILES) -test_queryhandlerpentominos: $(TEST_QUERYHANDLERPENTOMINOS_FILES) - @../../tools/test $(TEST_QUERYHANDLERPENTOMINOS_FILES) $(PARSERFLAGS) $(BASICFLAGS) $(ATF_CFLAGS) $(ATF_LIBS) +TEST_SOURCE_DEPS = ${pracrod_SOURCES} ${macrotool_SOURCES} \ + ${EXTRA_DIST} +TEST_SCRIPT_DIR = $(top_srcdir)/../tools -TEST_QUERYHANDLERPRACRO_FILES = \ - queryhandlerpracro.cc \ - tcpsocket.cc \ - $(DBFILES) \ - $(PARSERFILES) \ - $(BASICFILES) -test_queryhandlerpracro: $(TEST_QUERYHANDLERPRACRO_FILES) - @../../tools/test $(TEST_QUERYHANDLERPRACRO_FILES) $(DBFLAGS) $(PARSERFLAGS) $(BASICFLAGS) - -TEST_LUAQUERMAPPER_FILES = \ - luaquerymapper.cc \ - $(BASICFILES) -test_luaquerymapper: $(TEST_LUAQUERMAPPER_FILES) - @../../tools/test $(TEST_LUAQUERMAPPER_FILES) $(LUA_LIBS) $(BASICFLAGS) - -TEST_TEMPLATEPARSER_FILES = \ - templateparser.cc \ - $(PARSERFILES) \ - $(BASICFILES) -test_templateparser: $(TEST_TEMPLATEPARSER_FILES) - @../../tools/test $(TEST_TEMPLATEPARSER_FILES) $(BASICFLAGS) $(PARSERFLAGS) - -TEST_MACROPARSER_FILES = \ - macroparser.cc \ - $(PARSERFILES) \ - $(BASICFILES) -test_macroparser: $(TEST_MACROPARSER_FILES) - @../../tools/test $(TEST_MACROPARSER_FILES) $(BASICFLAGS) $(PARSERFLAGS) - -TEST_SERVER_FILES = \ - server.cc \ - templateparser.cc \ - templatelist.cc \ - templateheaderparser.cc \ - queryhandlerpentominos.cc \ - journal_commit.cc \ - macrolist.cc \ - queryhandlerpracro.cc \ - macroheaderparser.cc \ - versionstr.cc \ - resumeparser.cc \ - luaquerymapper.cc \ - tcpsocket.cc \ - transactionparser.cc \ - widgetgenerator.cc \ - database.cc \ - pracrodao.cc \ - pracrodaotest.cc \ - pracrodaopgsql.cc \ - luaresume.cc \ - macroparser.cc \ - mutex.cc \ - xml_encode_decode.cc \ - $(PARSERFILES) \ - $(BASICFILES) -test_server: $(TEST_SERVER_FILES) - @../../tools/test $(TEST_SERVER_FILES) $(BASICFLAGS) $(LUA_LIBS) $(DBFLAGS) $(PARSERFLAGS) $(HTTPD_LIBS) $(HTTPD_CFLAGS) - -TEST_PRACRODAOPGSQL_FILES = \ - pracrodaopgsql.cc \ - pracrodao.cc \ - $(BASICFILES) -test_pracrodaopgsql: $(TEST_PRACRODAOPGSQL_FILES) - @../../tools/test $(TEST_PRACRODAOPGSQL_FILES) $(DBFLAGS) $(BASICFLAGS) - -TEST_XMLENCODEDECODE_FILES = \ - xml_encode_decode.cc -test_xml_encode_decode: $(TEST_XMLENCODEDECODE_FILES) - @../../tools/test $(TEST_XMLENCODEDECODE_FILES) - -TEST_JOURNALCOMMIT_FILES = \ - journal_commit.cc \ - templateparser.cc \ - $(PARSERFILES) \ - $(BASICFILES) -test_journal_commit: $(TEST_JOURNALCOMMIT_FILES) - @../../tools/test $(TEST_JOURNALCOMMIT_FILES) $(PARSERFLAGS) $(BASICFLAGS) +include ${TEST_SCRIPT_DIR}/Makefile.am.test -CLEANFILES = $(TESTFILES) $(TESTLOGS) *~ +include Makefile.am.test \ No newline at end of file diff --git a/server/src/artefact.cc b/server/src/artefact.cc new file mode 100644 index 0000000..f3e739d --- /dev/null +++ b/server/src/artefact.cc @@ -0,0 +1,188 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set et sw=2 ts=2: */ +/*************************************************************************** + * artefact.cc + * + * Tue Jan 5 14:45:34 CET 2010 + * Copyright 2010 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 "artefact.h" + +#include "debug.h" +#include "configuration.h" + +#include "queryparser.h" + +Artefact::Artefact() +{ +#ifndef WITHOUT_ARTEFACT + + PRACRO_DEBUG(artefact, "Creating artefact connection %s : %d\n", + Conf::artefact_addr.c_str(), Conf::artefact_port); + + atfh = atf_init(); + if(!atfh) PRACRO_ERR(artefact, "Out of memory!\n"); + + conn = atf_connect(atfh, + Conf::artefact_addr.c_str(), + Conf::artefact_port, + Conf::artefact_use_ssl); + +#endif/*WITHOUT_ARTEFACT*/ +} + +Artefact::~Artefact() +{ +#ifndef WITHOUT_ARTEFACT + + atf_disconnect(conn); + atf_close(atfh); + +#endif/*WITHOUT_ARTEFACT*/ +} + +#ifndef WITHOUT_ARTEFACT +static QueryResult node2result(atf_result_node_t *node, time_t timestamp) +{ + QueryResult rnode; + rnode.timestamp = timestamp; + rnode.source = "artefact"; + + if(!node) return rnode; + + struct _atf_result_node_t *child = node->child; + while(child) { + if(child->value == NULL) { + rnode.groups[child->name] = node2result(child, timestamp); + } else { + rnode.values[child->name] = child->value; + } + child = child->next; + } + + return rnode; +} +#endif/*WITHOUT_ARTEFACT*/ + +QueryResult Artefact::exec(Query &query, + std::string patientid, + std::string user) +{ + QueryResult rroot; + rroot.timestamp = 0; + rroot.source = "pentominos"; + +#ifndef WITHOUT_ARTEFACT + + atf_transaction_t* atft = NULL; + atf_reply_t *reply = NULL; + atf_result_t *result = NULL; + atf_result_node_t *root = NULL; + atf_status_t status; + time_t timestamp; + atf_id id; + + if(query.attributes.find("class") == query.attributes.end()) { + PRACRO_ERR(artefact, "Missing 'class' attribute!\n"); + goto aaarg; + } + + atft = atf_new_transaction(conn, patientid.c_str()); + if(!atft) goto aaarg; + + id = atf_add_query(atft, query.attributes["class"].c_str(), + FILTER_LATEST, USE_NONE, 0, 0); + if(!atft) goto aaarg; + + reply = atf_commit(atft); + if(!reply) goto aaarg; + + if(atf_get_num_results(reply, id) != 1) goto aaarg; + + result = atf_get_result(reply, id, 0); + if(!result) goto aaarg; + + status = atf_get_result_status(result, NULL, 0); + if(status != ATF_STATUS_OK) goto aaarg; + + timestamp = atf_get_result_timestamp(result); + rroot.timestamp = timestamp; + + root = atf_get_result_node(result); + if(!root) goto aaarg; + + { + QueryResult qresult = node2result(root, timestamp); + rroot.groups[query.attributes["class"]] = qresult; + } + + goto cleanup; + + aaarg: + PRACRO_ERR(artefact, "Artefact comm error (%d)!\n", atf_get_last_error(atfh)); + + cleanup: + if(root) atf_free_result_node(root); + if(reply) atf_free_reply(reply); + if(atft) atf_free_transaction(atft); + +#endif/*WITHOUT_ARTEFACT*/ + + return rroot; +} + + +#ifdef TEST_ARTEFACT +//deps: configuration.cc debug.cc +//cflags: $(ATF_CFLAGS) -I.. +//libs: $(ATF_LIBS) +#include "test.h" + +TEST_BEGIN; + +pracro_debug_init(); +pracro_debug_parse("+all"); + +{ + Artefact atf; + Query q; + q.attributes["class"] = "echo"; + QueryResult res = atf.exec(q, "1505050505", "me"); + + res.print(); +} + +{ + Conf::artefact_addr = "nowhere_at_all.com"; + Conf::artefact_port = 10000; + + Artefact atf; + Query q; + q.attributes["class"] = "echo"; + QueryResult res = atf.exec(q, "1505050505", "me"); + + res.print(); +} + +TEST_END; + +#endif/*TEST_ARTEFACT*/ diff --git a/server/src/artefact.h b/server/src/artefact.h new file mode 100644 index 0000000..fa1602d --- /dev/null +++ b/server/src/artefact.h @@ -0,0 +1,54 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set et sw=2 ts=2: */ +/*************************************************************************** + * artefact.h + * + * Tue Jan 5 14:45:34 CET 2010 + * Copyright 2010 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_ARTEFACT_H__ +#define __PRACRO_ARTEFACT_H__ + +#include "template.h" +#include "queryresult.h" + +#ifndef WITHOUT_ARTEFACT +#include +#endif/*WITHOUT_ARTEFACT*/ + +class Artefact { +public: + Artefact(); + ~Artefact(); + + QueryResult exec(Query &query, + std::string patientid, + std::string user); + +private: +#ifndef WITHOUT_ARTEFACT + atf_handle_t *atfh; + atf_connection_t *conn; +#endif/*WITHOUT_ARTEFACT*/ +}; + +#endif/*__PRACRO_ARTEFACT_H__*/ diff --git a/server/src/configuration.cc b/server/src/configuration.cc index c1dcab1..b222639 100644 --- a/server/src/configuration.cc +++ b/server/src/configuration.cc @@ -38,12 +38,26 @@ port_t Conf::journal_commit_port = 18112; time_t Conf::db_max_ttl = 7 * 60 * 60 * 24; time_t Conf::pentominos_max_ttl = 7 * 60 * 60 * 24; -std::string Conf::pentominos_addr = "localhost"; -port_t Conf::pentominos_port = 11108; +std::string Conf::artefact_addr = "localhost"; +port_t Conf::artefact_port = 11108; +bool Conf::artefact_use_ssl = false; + +int Conf::artefact_poolsize = 1; std::string Conf::database_backend = "pgsql"; std::string Conf::database_addr = "localhost"; std::string Conf::database_user = "pracro"; std::string Conf::database_passwd = "pracro"; +int Conf::database_poolsize = 2; + std::string Conf::xml_basedir = XML; + +bool Conf::use_ssl = false; +std::string Conf::ssl_key = ""; +std::string Conf::ssl_cert = ""; + +int Conf::connection_limit = 42; +int Conf::connection_timeout = 0; + +std::string Conf::session_path = "/tmp"; diff --git a/server/src/configuration.h b/server/src/configuration.h index 3d9f7f1..8980bfd 100644 --- a/server/src/configuration.h +++ b/server/src/configuration.h @@ -45,15 +45,29 @@ namespace Conf { extern time_t db_max_ttl; extern time_t pentominos_max_ttl; - extern std::string pentominos_addr; - extern port_t pentominos_port; + extern std::string artefact_addr; + extern port_t artefact_port; + extern bool artefact_use_ssl; + + extern int artefact_poolsize; extern std::string database_backend; extern std::string database_addr; extern std::string database_user; extern std::string database_passwd; + extern int database_poolsize; + extern std::string xml_basedir; + + extern bool use_ssl; + extern std::string ssl_key; + extern std::string ssl_cert; + + extern int connection_limit; + extern int connection_timeout; + + extern std::string session_path; }; #endif/*__ARTEFACT_CONFIGURATION_H__*/ diff --git a/server/src/configurationparser.cc b/server/src/configurationparser.cc index 8247a45..bc10e2b 100644 --- a/server/src/configurationparser.cc +++ b/server/src/configurationparser.cc @@ -93,14 +93,26 @@ void ConfigurationParser::reload() } try { - std::string a = lookup("pentominos_addr"); - Conf::pentominos_addr = a; + std::string s = lookup("artefact_addr"); + Conf::artefact_addr = s; } catch( ... ) { } try { - int p = lookup("pentominos_port"); - Conf::pentominos_port = p; + int i = lookup("artefact_port"); + Conf::artefact_port = i; + } catch( ... ) { + } + + try { + bool b = lookup("artefact_use_ssl"); + Conf::artefact_use_ssl = b; + } catch( ... ) { + } + + try { + int i = lookup("artefact_poolsize"); + Conf::artefact_poolsize = i; } catch( ... ) { } @@ -128,11 +140,53 @@ void ConfigurationParser::reload() } catch( ... ) { } + try { + int i = lookup("database_poolsize"); + Conf::database_poolsize = i; + } catch( ... ) { + } + try { std::string p = lookup("xml_basedir"); Conf::xml_basedir = p; } catch( ... ) { } + + try { + bool b = lookup("use_ssl"); + Conf::use_ssl = b; + } catch( ... ) { + } + + try { + std::string s = lookup("ssl_key"); + Conf::ssl_key = s; + } catch( ... ) { + } + + try { + std::string s = lookup("ssl_cert"); + Conf::ssl_cert = s; + } catch( ... ) { + } + + try { + int i = lookup("connection_limit"); + Conf::connection_limit = i; + } catch( ... ) { + } + + try { + int i = lookup("connection_timeout"); + Conf::connection_timeout = i; + } catch( ... ) { + } + + try { + std::string s = lookup("session_path"); + Conf::session_path = s; + } catch( ... ) { + } } #ifdef TEST_CONFIGURATIONPARSER diff --git a/server/src/connection.cc b/server/src/connection.cc new file mode 100644 index 0000000..ed5a7a9 --- /dev/null +++ b/server/src/connection.cc @@ -0,0 +1,339 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set et sw=2 ts=2: */ +/*************************************************************************** + * connection.cc + * + * Fri May 7 11:35:44 CEST 2010 + * Copyright 2010 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 "connection.h" + +#include "transactionhandler.h" +#include "xml_encode_decode.h" + +static std::string error_box(std::string message) +{ + std::string errorbox = + "\n" + "\n" + " " + message + "\n" + "\n"; + return errorbox; +} + +#ifdef TEST_CONNECTION +static bool did_commit = false; +#endif + +Connection::Connection(Environment &e, std::string sid, bool c, bool d) + : env(e), parser(&transaction) +{ + PRACRO_DEBUG(connection, "[%p] CREATE\n", this); + + sessionid = sid; + docommit = c; + dodiscard = d; + +#ifdef TEST_CONNECTION + did_commit = false; +#endif + +} + +Connection::~Connection() +{ + PRACRO_DEBUG(connection, "[%p] DESTROY\n", this); +} + +void Connection::commit(Session *session) +{ + if(docommit) { + session->commit(); + env.sessions.deleteSession(session->id()); + sessionid = ""; +#ifdef TEST_CONNECTION + did_commit = true; +#endif + } +} + +void Connection::discard(Session *session) +{ + if(dodiscard) { + session->discard(); + env.sessions.deleteSession(session->id()); + sessionid = ""; + } +} + +bool Connection::handle(const char *data, size_t size) +{ + Session *session = NULL; + if(sessionid == "") { + // Create new session + session = env.sessions.newSession(); + } else { + // Attach to old session + session = env.sessions.session(sessionid); + + // Session didn't exist - create a new one anyway. + if(session == NULL) session = env.sessions.newSession(); + } + + if(session == NULL) { + PRACRO_ERR(connection, "New session could not be created."); + response = error_box(xml_encode("New session could not be created.")); + return true; + } + + sessionid = session->id(); + + try { + + if(!data || !size) { + commit(session); + discard(session); + return true; + } + + if(parser.parse(data, size)) { + { + SessionAutolock lock(*session); + response = handleTransaction(transaction, env, *session); + } + + commit(session); + discard(session); + return true; + } + } catch(...) { + PRACRO_ERR(server, "Failed to parse data!\n"); + response = error_box(xml_encode("XML Parse error.")); + return true; + } + + return false; +} + +std::string Connection::getResponse() +{ + return response; +} + +std::string Connection::getSessionID() +{ + return sessionid; +} + +#ifdef TEST_CONNECTION +//deps: debug.cc transactionparser.cc session.cc xml_encode_decode.cc saxparser.cc transactionhandler.cc journalwriter.cc mutex.cc templateparser.cc exception.cc configuration.cc macroparser.cc semaphore.cc entitylist.cc luaquerymapper.cc inotify.cc log.cc queryhandlerpentominos.cc widgetgenerator.cc queryhandlerpracro.cc resumeparser.cc journal_commit.cc versionstr.cc luaresume.cc luautil.cc artefact.cc environment.cc database.cc macrolist.cc templatelist.cc pracrodao.cc templateheaderparser.cc macroheaderparser.cc pracrodaotest.cc pracrodaopgsql.cc +//cflags: -DWITHOUT_DATABASE -DWITHOUT_ARTEFACT -I.. $(LUA_CFLAGS) $(EXPAT_CFLAGS) $(PTHREAD_CFLAGS) $(PQXX_CXXFLAGS) +//libs: $(LUA_LIBS) $(EXPAT_LIBS) $(PTHREAD_LIBS) $(PQXX_LIBS) +#include "test.h" + +static char xml_request[] = +"\n" +"\n" +" \n" +"\n" + ; + +static char xml_commit[] = +"\n" +"\n" +" \n" +" \n" +" \n" +" \n" +" \n" +"\n" + ; + +static char xml_commit_p1[] = +"\n" +"\n" +" \n" +" \n" +" \n" +" \n" +"\n" + ; + +TEST_BEGIN; + +Environment env; +std::string sid; + +// Without data +{ + Connection con(env, "", false); + TEST_TRUE(con.handle("", 0), "Test handler return value."); + TEST_EQUAL_STR(con.getResponse(), "", "Test response value."); + sid = con.getSessionID(); + TEST_NOTEQUAL_STR(sid, "", "Test new session id."); + TEST_FALSE(did_commit, "No commit."); +} + +{ + Connection con(env, sid, false); + TEST_TRUE(con.handle("", 0), "Test handler return value."); + TEST_EQUAL_STR(con.getResponse(), "", "Test response value."); + TEST_NOTEQUAL_STR(con.getSessionID(), "", "Test existing session id."); + TEST_EQUAL_STR(con.getSessionID(), sid, "Test existing session id."); + TEST_FALSE(did_commit, "No commit."); +} + +{ + Connection con(env, sid, true); + TEST_TRUE(con.handle("", 0), "Test handler return value."); + TEST_EQUAL_STR(con.getResponse(), "", "Test response value."); + TEST_EQUAL_STR(con.getSessionID(), "", "Test existing session id."); + TEST_TRUE(did_commit, "Commit."); +} + +{ + Connection con(env, sid, false); + TEST_TRUE(con.handle("", 0), "Test handler return value."); + TEST_EQUAL_STR(con.getResponse(), "", "Test response value."); + TEST_NOTEQUAL_STR(con.getSessionID(), "", "Test existing session id."); + TEST_NOTEQUAL_STR(con.getSessionID(), sid, "Test new session id."); + TEST_FALSE(did_commit, "No commit."); +} + +// With commit partial data +{ + Connection con(env, "", false); + TEST_FALSE(con.handle(xml_commit_p1, sizeof(xml_commit_p1) - 1), + "Test handler return value."); + sid = con.getSessionID(); + TEST_NOTEQUAL_STR(sid, "", "Test new session id."); + TEST_FALSE(did_commit, "No commit."); + TEST_EQUAL_STR(con.getResponse(), "", "Test response value."); + TEST_TRUE(con.handle(xml_commit_p2, sizeof(xml_commit_p2) - 1), + "Test handler return value."); + TEST_EQUAL_STR(con.getSessionID(), sid, "Test session id."); + TEST_NOTEQUAL_STR(con.getResponse(), "", "Test response value."); + TEST_FALSE(did_commit, "No commit."); +} + +// With commit partial data and journal commit +{ + Connection con(env, "", true); + TEST_FALSE(con.handle(xml_commit_p1, sizeof(xml_commit_p1) - 1), + "Test handler return value."); + sid = con.getSessionID(); + TEST_NOTEQUAL_STR(sid, "", "Test new session id."); + TEST_EQUAL_STR(con.getResponse(), "", "Test response value."); + TEST_FALSE(did_commit, "No commit."); + TEST_TRUE(con.handle(xml_commit_p2, sizeof(xml_commit_p2) - 1), + "Test handler return value."); + TEST_EQUAL_STR(con.getSessionID(), "", "Test session id."); + TEST_TRUE(did_commit, "No commit."); + TEST_NOTEQUAL_STR(con.getResponse(), "", "Test response value."); +} + +// With commit data +{ + Connection con(env, "", false); + TEST_TRUE(con.handle(xml_commit, sizeof(xml_commit) - 1), + "Test handler return value."); + sid = con.getSessionID(); + TEST_NOTEQUAL_STR(sid, "", "Test new session id."); + TEST_NOTEQUAL_STR(con.getResponse(), "", "Test response value."); + TEST_FALSE(did_commit, "No commit."); +} + +{ + Connection con(env, sid, false); + TEST_TRUE(con.handle(xml_commit, sizeof(xml_commit) - 1), + "Test handler return value."); + TEST_NOTEQUAL_STR(con.getResponse(), "", "Test response value."); + TEST_NOTEQUAL_STR(con.getSessionID(), "", "Test existing session id."); + TEST_EQUAL_STR(con.getSessionID(), sid, "Test existing session id."); + TEST_FALSE(did_commit, "No commit."); +} + +{ + Connection con(env, sid, true); + TEST_TRUE(con.handle(xml_commit, sizeof(xml_commit) - 1), + "Test handler return value."); + TEST_NOTEQUAL_STR(con.getResponse(), "", "Test response value."); + TEST_EQUAL_STR(con.getSessionID(), "", "Test existing session id."); + TEST_TRUE(did_commit, "Commit."); +} + +{ + Connection con(env, sid, false); + TEST_TRUE(con.handle(xml_commit, sizeof(xml_commit) - 1), + "Test handler return value."); + TEST_NOTEQUAL_STR(con.getResponse(), "", "Test response value."); + TEST_NOTEQUAL_STR(con.getSessionID(), "", "Test existing session id."); + TEST_NOTEQUAL_STR(con.getSessionID(), sid, "Test new session id."); + TEST_FALSE(did_commit, "No commit."); +} + +// With request data +{ + Connection con(env, "", false); + TEST_TRUE(con.handle(xml_request, sizeof(xml_request) - 1), + "Test handler return value."); + TEST_NOTEQUAL_STR(con.getResponse(), "", "Test response value."); + sid = con.getSessionID(); + TEST_NOTEQUAL_STR(sid, "", "Test new session id."); + TEST_FALSE(did_commit, "No commit."); +} + +{ + Connection con(env, sid, false); + TEST_TRUE(con.handle(xml_request, sizeof(xml_request) - 1), + "Test handler return value."); + TEST_NOTEQUAL_STR(con.getResponse(), "", "Test response value."); + TEST_NOTEQUAL_STR(con.getSessionID(), "", "Test existing session id."); + TEST_EQUAL_STR(con.getSessionID(), sid, "Test existing session id."); + TEST_FALSE(did_commit, "No commit."); +} + +{ + Connection con(env, sid, true); + TEST_TRUE(con.handle(xml_request, sizeof(xml_request) - 1), + "Test handler return value."); + TEST_NOTEQUAL_STR(con.getResponse(), "", "Test response value."); + TEST_EQUAL_STR(con.getSessionID(), "", "Test existing session id."); + TEST_TRUE(did_commit, "Commit."); +} + +{ + Connection con(env, sid, false); + TEST_TRUE(con.handle(xml_request, sizeof(xml_request) - 1), + "Test handler return value."); + TEST_NOTEQUAL_STR(con.getSessionID(), "", "Test existing session id."); + TEST_NOTEQUAL_STR(con.getSessionID(), sid, "Test new session id."); + TEST_FALSE(did_commit, "No commit."); +} + +TEST_END; + +#endif/*TEST_CONNECTION*/ diff --git a/server/src/connection.h b/server/src/connection.h new file mode 100644 index 0000000..61997da --- /dev/null +++ b/server/src/connection.h @@ -0,0 +1,63 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set et sw=2 ts=2: */ +/*************************************************************************** + * connection.h + * + * Fri May 7 11:35:43 CEST 2010 + * Copyright 2010 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_CONNECTION_H__ +#define __PRACRO_CONNECTION_H__ + +#include +#include "environment.h" +#include "transaction.h" +#include "transactionparser.h" + +class Session; + +class Connection { +public: + Connection(Environment &e, std::string sessionid, bool commit, bool discard); + ~Connection(); + + bool handle(const char *data, size_t size); + + std::string getResponse(); + std::string getSessionID(); + +private: + void commit(Session *session); + void discard(Session *session); + + std::string sessionid; + bool docommit; + bool dodiscard; + Environment &env; + + Transaction transaction; + TransactionParser parser; + + std::string response; +}; + +#endif/*__PRACRO_CONNECTION_H__*/ diff --git a/server/src/connectionpool.cc b/server/src/connectionpool.cc new file mode 100644 index 0000000..e2b6bfc --- /dev/null +++ b/server/src/connectionpool.cc @@ -0,0 +1,162 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set et sw=2 ts=2: */ +/*************************************************************************** + * connectionpool.cc + * + * Wed Dec 16 12:20:44 CET 2009 + * Copyright 2009 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 "connectionpool.h" + +// +// Implementation is in the header file. +// + +#ifdef TEST_CONNECTIONPOOL +//deps: mutex.cc semaphore.cc +//cflags: $(PTHREAD_CFLAGS) +//libs: $(PTHREAD_LIBS) +#include +#include +#include + +static void* thread_run(void *data) +{ + ConnectionPool *pool = (ConnectionPool*)data; + + int db1 = pool->borrow(); + int db2 = pool->borrow(); + int db3 = pool->borrow(); + int db4 = pool->borrow(); + + usleep(100); + + pool->giveBack(db1); + pool->giveBack(db2); + pool->giveBack(db3); + pool->giveBack(db4); + + return NULL; +} + +static void* thread_run_clear_test(void *data) +{ + ConnectionPool *pool = (ConnectionPool*)data; + pool->giveBack(1); + pool->giveBack(2); + + sleep(1); + + pool->giveBack(3); + pool->giveBack(4); + + return NULL; +} + +TEST_BEGIN; + +ConnectionPool pool; + +int db1 = 1; +int db2 = 2; +int db3 = 3; +int db4 = 4; + +pool.add(db1); +pool.add(db2); +pool.add(db3); +pool.add(db4); + +TEST_TRUE(pool.testFree(db1), "Testing if db1 is free."); +TEST_TRUE(pool.testFree(db2), "Testing if db2 is free."); +TEST_TRUE(pool.testFree(db3), "Testing if db3 is free."); +TEST_TRUE(pool.testFree(db4), "Testing if db4 is free."); +TEST_EQUAL(pool.numFree(), 4, "Testing number of free databases."); + +int b_db1 = pool.borrow(); +TEST_FALSE(pool.testFree(b_db1), "Testing if borrowed db is free."); + +int b_db2 = pool.borrow(); +TEST_NOTEQUAL(b_db1, b_db2, "Testing if borrowed db is unique."); + +pool.giveBack(b_db1); +TEST_TRUE(pool.testFree(b_db1), "Testing if returned db is free."); +pool.giveBack(b_db2); + +TEST_EQUAL(pool.numFree(), 4, "Testing number of free databases."); + +{ + pthread_attr_t attr; + pthread_t tid; + pthread_attr_init(&attr); + pthread_create(&tid, &attr, thread_run, &pool); + + while(pool.numFree() > 0) { usleep(10); } + + int b_db3 = pool.borrow(); + TEST_FALSE(pool.testFree(b_db3), "Testing if returned db is free (semaphore test)."); + pool.giveBack(db3); + + pthread_join(tid, NULL); + pthread_attr_destroy(&attr); +} + +TEST_EQUAL(pool.numFree(), 4, "Testing if all database are now available again"); + +{ + TEST_EQUAL(pool.numFree(), 4, "Testing if autoborrower has not yet borrowed a db."); + AutoBorrower b(pool); + TEST_EQUAL(pool.numFree(), 3, "Testing if autoborrower has borrowed a db."); + TEST_FALSE(pool.testFree(b.get()), "Testing if the autoborrowed db is actually taken."); +} +TEST_EQUAL(pool.numFree(), 4, "Testing if autoborrower has returned the db."); + +// Force remove all elements. +pool.borrow(); +pool.clear(true); +TEST_EQUAL(pool.numFree(), 0, "Testing number of free databases."); + +// Add them again. +pool.add(db1); +pool.add(db2); +pool.add(db3); +pool.add(db4); +TEST_EQUAL(pool.numFree(), 4, "Testing number of free databases."); + +pool.borrow(); +pool.borrow(); +pool.borrow(); +pool.borrow(); + +{ + pthread_attr_t attr; + pthread_t tid; + pthread_attr_init(&attr); + pthread_create(&tid, &attr, thread_run_clear_test, &pool); + pool.clear(false); + pthread_join(tid, NULL); + pthread_attr_destroy(&attr); +} + +TEST_END; + +#endif/*TEST_CONNECTIONPOOL*/ diff --git a/server/src/connectionpool.h b/server/src/connectionpool.h new file mode 100644 index 0000000..33473e5 --- /dev/null +++ b/server/src/connectionpool.h @@ -0,0 +1,226 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set et sw=2 ts=2: */ +/*************************************************************************** + * connectionpool.h + * + * Wed Dec 16 12:20:44 CET 2009 + * Copyright 2009 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_CONNECTIONPOOL_H__ +#define __PRACRO_CONNECTIONPOOL_H__ + +#include + +#include "mutex.h" +#include "semaphore.h" + +template +class ConnectionPool { +public: + void add(T t); + void remove(T t); + + bool testFree(T t); + int numFree(); + + T borrow(); + void giveBack(T t); + + std::list clear(bool force = true); + +private: + bool contains(std::list &list, T t); + + Semaphore semaphore; + Mutex mutex; + std::list active; + std::list passive; +}; + +template +class AutoBorrower { +public: + AutoBorrower(ConnectionPool &pool); + ~AutoBorrower(); + + T get(); + +private: + ConnectionPool &pool; + T t; +}; + + +// +// Implementation is below +// + +template +void ConnectionPool::add(T t) +{ + MutexAutolock lock(mutex); + + passive.push_back(t); + semaphore.post(); + +} + +template +bool ConnectionPool::contains(std::list &list, T t) +{ + typename std::list::iterator i = list.begin(); + while(i != list.end()) { + if(*i == t) return true; + i++; + } + + return false; +} + +template +void ConnectionPool::remove(T t) +{ + MutexAutolock lock(mutex); + + if(contains(passive, t)) { + semaphore.post(); + passive.remove(t); + } + +} + +template +bool ConnectionPool::testFree(T t) +{ + bool testfree = false; + + MutexAutolock lock(mutex); + testfree = contains(passive, t); + + return testfree; +} + +template +int ConnectionPool::numFree() +{ + int num; + + MutexAutolock lock(mutex); + num = passive.size(); + + return num; +} + +template +T ConnectionPool::borrow() +{ + T t = NULL; + + semaphore.wait(); + + { + MutexAutolock lock(mutex); + + t = passive.front(); + passive.remove(t); + active.push_back(t); + } + + return t; +} + +template +void ConnectionPool::giveBack(T t) +{ + MutexAutolock lock(mutex); + + if(contains(active, t)) { + active.remove(t); + passive.push_back(t); + semaphore.post(); + } +} + +template +std::list ConnectionPool::clear(bool force) +{ + typename std::list lst; + + if(force == false) { + size_t num = 0; + { + MutexAutolock lock(mutex); + num = active.size() + passive.size(); + } + + while(num) { + borrow(); + num--; + } + } + + { + MutexAutolock lock(mutex); + + typename std::list::iterator i; + + i = active.begin(); + while(i != active.end()) { + lst.push_back(*i); + // i = active.erase(i); + semaphore.post(); + i++; + } + active.clear(); + + i = passive.begin(); + while(i != passive.end()) { + lst.push_back(*i); + // i = passive.erase(i); + i++; + } + passive.clear(); + } + + return lst; +} + +template +AutoBorrower::AutoBorrower(ConnectionPool &p) + : pool(p) +{ + t = pool.borrow(); +} + +template +AutoBorrower::~AutoBorrower() +{ + pool.giveBack(t); +} + +template +T AutoBorrower::get() +{ + return t; +} + +#endif/*__PRACRO_CONNECTIONPOOL_H__*/ diff --git a/server/src/debug.cc b/server/src/debug.cc index 54a2191..8bb45db 100644 --- a/server/src/debug.cc +++ b/server/src/debug.cc @@ -37,7 +37,7 @@ #define NELEM(x) (sizeof(x)/sizeof((x)[0])) struct __pracro_debug_channel { - char name[16]; + char name[64]; unsigned flags; }; diff --git a/server/src/entitylist.cc b/server/src/entitylist.cc new file mode 100644 index 0000000..3ec15a5 --- /dev/null +++ b/server/src/entitylist.cc @@ -0,0 +1,331 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set et sw=2 ts=2: */ +/*************************************************************************** + * entitylist.cc + * + * Thu Jan 14 14:17:34 CET 2010 + * Copyright 2010 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 "entitylist.h" + +#include +#include +#include +#include + +#include + +#include "debug.h" + +static inline bool isdir(std::string name) +{ + struct stat s; + stat(name.c_str(), &s); + return S_ISDIR(s.st_mode); +} + +static inline bool isfile(std::string name) +{ + struct stat s; + stat(name.c_str(), &s); + return S_ISREG(s.st_mode); +} + +static std::vector listdir(std::string path) +{ + std::vector files; + + DIR* dir = opendir(path.c_str()); + if(!dir) { + PRACRO_ERR(entitylist, "Could not open directory: %s\n", path.c_str()); + return files; + } + + struct dirent *d; + while((d = readdir(dir)) != 0) { + std::string name = d->d_name; + + if(name == "." || name == "..") continue; + + if(isdir(path + "/" + name)) { + std::vector sub = listdir(path + "/" + name); + files.insert(files.end(), sub.begin(), sub.end()); + continue; + } + + if(isfile(path + "/" + name)) { + if(name.length() >= 4 && name.substr(name.length() - 4) == ".xml") + files.push_back(path + "/" + name); + } + } + closedir(dir); + + return files; +} + +EntityList::EntityList(std::string entitypath, std::string entityname) +{ + MutexAutolock lock(mutex); + + this->entityname = entityname; + this->entitypath = entitypath; +} + +EntityList::~EntityList() +{ +} + +void EntityList::rescan() +{ + clear(); + inotify.clear(); + + inotify.addDirectory(entitypath, WATCH_DEEP_FOLLOW, + IN_CLOSE_WRITE | + IN_MOVED_FROM | IN_MOVED_TO | IN_MOVE_SELF | + IN_DELETE | IN_DELETE_SELF | + IN_CREATE); + + std::vector entitys = listdir(entitypath); + std::vector::iterator i = entitys.begin(); + while(i != entitys.end()) { + addFile(*i); + i++; + } + + { + iterator i = begin(); + while(i != end()) { + EntityListItem::iterator j = i->second.begin(); + while(j != i->second.end()) { + PRACRO_DEBUG(entitylist, "%s - v%s file: %s\n", + i->first.c_str(), + ((std::string)j->first).c_str(), + j->second.c_str()); + j++; + } + i++; + } + } +} + +bool EntityList::removeFile(std::string file) +{ + // Check if the file is already in the tree. + iterator i = begin(); + while(i != end()) { + EntityListItem::iterator j = i->second.begin(); + while(j != i->second.end()) { + if(file == j->second) { + PRACRO_DEBUG(entitylist, "Removing file: %s\n", file.c_str()); + i->second.erase(j); + if(i->second.size() == 0) erase(i); + return true; + } + j++; + } + i++; + } + + return false; +} + +void EntityList::updateFile(std::string file) +{ + removeFile(file); + addFile(file); +} + +void EntityList::updateList() +{ + while(inotify.hasEvents()) { + INotify::Event event = inotify.getNextEvent(); + + PRACRO_DEBUG(entitylist, "Handling event %s on %s, with param %s\n", + event.maskstr().c_str(), + event.name().c_str(), + event.file().c_str()); + + if(event.isDir()) { + if(event.isCreateEvent()) { + // A new directory was ceated. Scan it for files. + std::vector entitys = listdir(event.name()+"/"+event.file()); + std::vector::iterator i = entitys.begin(); + while(i != entitys.end()) { + updateFile(*i); + i++; + } + } + + if(event.isMoveSelfEvent()) rescan(); + if(event.isDeleteSelfEvent()) rescan(); + if(event.isDeleteEvent()) rescan(); + if(event.isMovedFromEvent()) rescan(); + if(event.isMovedToEvent()) rescan(); + + } else { + if(event.isCloseWriteEvent()) updateFile(event.name()+"/"+event.file()); + if(event.isMovedFromEvent()) removeFile(event.name()+"/"+event.file()); + if(event.isMovedToEvent()) updateFile(event.name()+"/"+event.file()); + if(event.isDeleteEvent()) removeFile(event.name()+"/"+event.file()); + } + } +} + +std::string EntityList::getLatestVersion(std::string entity) throw(Exception) +{ + MutexAutolock lock(mutex); + + updateList(); + + if(find(entity) == end()) { + throw Exception("Entity ("+entityname+") ["+entity+"] does not exist"); + } + + EntityListItem mli = (*this)[entity]; + if(mli.size() == 0) { + throw Exception("Entity ("+entityname+") ["+entity+"] does not exist."); + } + + PRACRO_DEBUG(entitylist, "Search for %s - found %s v%s\n", + entity.c_str(), + mli.begin()->second.c_str(), + ((std::string)mli.begin()->first).c_str()); + + return mli.begin()->second; +} + +void EntityList::insertEntity(std::string entity, std::string version, std::string file) +{ + std::pair p(VersionStr(version), file); + (*this)[entity].insert(p); +} + +#ifdef TEST_ENTITYLIST +//deps: inotify.cc debug.cc mutex.cc exception.cc versionstr.cc log.cc +//cflags: -I.. $(PTHREAD_CFLAGS) +//libs: $(PTHREAD_LIBS) +#include "test.h" + +#include + +#define _DIR "/tmp/entitylist_test_dir" + +class TestList : public EntityList { +public: + TestList(std::string path) : EntityList(path, "test") { rescan(); } + +private: + void addFile(std::string file) + { + char version[32]; + FILE *fp = fopen(file.c_str(), "r"); + if(!fp) return; + memset(version, 0, sizeof(version)); + fread(version, sizeof(version), 1, fp); + fclose(fp); + + fprintf(stderr, "Inserting: %s\n", version); + insertEntity("test", version, file); + } +}; + +bool createfile(TestList &lst, std::string filename, + std::string name, std::string version) +{ + FILE *fp = fopen(filename.c_str(), "w"); + if(!fp) return false; + fprintf(fp, "%s", version.c_str()); + fclose(fp); + return true; +} + +TEST_BEGIN; + +pracro_debug_parse("-all,+entitylist"); + +if(mkdir(_DIR, 0777) == -1) TEST_FATAL("Could not create test dir."); + +TestList lst(_DIR); + +TEST_EXCEPTION(lst.getLatestVersion("test"), Exception, + "Test lookup of macro in empty tree."); + +if(!createfile(lst, _DIR"/file1.xml", "test", "1.0")) + TEST_FATAL("Unable to write to the file"); + +TEST_EQUAL_STR(lst.getLatestVersion("test"), _DIR"/file1.xml", "Test"); + +if(!createfile(lst, _DIR"/file2.xml", "test", "2.0")) + TEST_FATAL("Unable to write to the file"); + +TEST_EQUAL_STR(lst.getLatestVersion("test"), _DIR"/file2.xml", "Test"); + +unlink(_DIR"/file2.xml"); + +TEST_EQUAL_STR(lst.getLatestVersion("test"), _DIR"/file1.xml", "Test"); + +if(mkdir(_DIR"/more", 0777) == -1) TEST_FATAL("Could not create test dir."); + +if(!createfile(lst, _DIR"/more/file1.xml", "test", "3.0")) + TEST_FATAL("Unable to write to the file"); + +TEST_EQUAL_STR(lst.getLatestVersion("test"), _DIR"/more/file1.xml", "Test"); + +if(!createfile(lst, _DIR"/more/file2.xml", "test", "4.0")) + TEST_FATAL("Unable to write to the file"); + +TEST_EQUAL_STR(lst.getLatestVersion("test"), _DIR"/more/file2.xml", "Test"); + +unlink(_DIR"/more/file2.xml"); + +TEST_EQUAL_STR(lst.getLatestVersion("test"), _DIR"/more/file1.xml", "Test"); + +rename(_DIR"/more/file1.xml", _DIR"/more/file2.xml"); + +TEST_EQUAL_STR(lst.getLatestVersion("test"), _DIR"/more/file2.xml", "Test"); + +rename(_DIR"/more", _DIR"/more2"); + +TEST_EQUAL_STR(lst.getLatestVersion("test"), _DIR"/more2/file2.xml", "Test"); + +rename(_DIR"/more2/file2.xml", _DIR"/file3.xml"); + +TEST_EQUAL_STR(lst.getLatestVersion("test"), _DIR"/file3.xml", "Test"); + +unlink(_DIR"/file3.xml"); + +rmdir(_DIR"/more2"); + +TEST_EQUAL_STR(lst.getLatestVersion("test"), _DIR"/file1.xml", "Test"); + +unlink(_DIR"/file1.xml"); + +TEST_EXCEPTION(lst.getLatestVersion("test"), Exception, "Test lookup of missing macro."); + +rmdir(_DIR); + +TEST_EXCEPTION(lst.getLatestVersion("test"), Exception, "Test lookup in missing folder."); + +TEST_END; + +#endif/*TEST_ENTITYLIST*/ diff --git a/server/src/entitylist.h b/server/src/entitylist.h new file mode 100644 index 0000000..3bcdfd0 --- /dev/null +++ b/server/src/entitylist.h @@ -0,0 +1,91 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set et sw=2 ts=2: */ +/*************************************************************************** + * entitylist.h + * + * Thu Jan 14 14:17:34 CET 2010 + * Copyright 2010 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_ENTITYLIST_H__ +#define __PRACRO_ENTITYLIST_H__ + +#include +#include + +#include "versionstr.h" +#include "mutex.h" + +#include "inotify.h" + +#include "exception.h" + +/** + * The Items contained in the EntityList. + */ +typedef std::multimap EntityListItem; + +/** + * The EntityList class is intended for entity file caching, so that all entitys + * do not need to be parsed on each entity query. + * It builds a list of entitys and versions based on the informations read from + * the EntityHeaderParser. + * This means that just because a entity gets into the list doesn't means that it + * will validate as a correct entity (not even nessecarily correct XML). + */ +class EntityList : public std::map { +public: + /** + * Constructor. + * @param entitypath A std::string containing the path in which we should look + * for xml files. + */ + EntityList(std::string entitypath, std::string entityname); + virtual ~EntityList(); + + /** + * Convenience method, to gain the filename of the latest version of a given entity. + * This method throws an Exception if the entity does not exist in the tree. + * @param entity A std::string containing the name of the wanted entity. + * @return A std::string containing the file containing the entity with full path + * included. + */ + std::string getLatestVersion(std::string entity) throw(Exception); + +protected: + void rescan(); + void insertEntity(std::string entity, std::string version, std::string file); + +private: + virtual void addFile(std::string file) = 0; + + bool removeFile(std::string file); + void updateFile(std::string file); + void updateList(); + + Mutex mutex; + INotify inotify; + + std::string entityname; + std::string entitypath; +}; + +#endif/*__PRACRO_ENTITYLIST_H__*/ diff --git a/server/src/environment.cc b/server/src/environment.cc new file mode 100644 index 0000000..9904afc --- /dev/null +++ b/server/src/environment.cc @@ -0,0 +1,85 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set et sw=2 ts=2: */ +/*************************************************************************** + * environment.cc + * + * Tue Jan 5 11:41:23 CET 2010 + * Copyright 2010 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 "environment.h" + +#include "configuration.h" +#include "database.h" + +Environment::Environment() + : macrolist(Conf::xml_basedir + "/macros"), + templatelist(Conf::xml_basedir + "/templates") +{ + for(int i = 0; i < Conf::database_poolsize; i++) { + dbpool.add(new Database(Conf::database_backend, Conf::database_addr, + "", Conf::database_user, Conf::database_passwd, "")); + } + + for(int i = 0; i < Conf::artefact_poolsize; i++) { + atfpool.add(new Artefact); + } +} + +Environment::~Environment() +{ + // Remove, but wait until resources are released + std::list dblst = dbpool.clear(false); + std::list::iterator i = dblst.begin(); + while(i != dblst.end()) { + delete *i; + i++; + } + + // Remove, but wait until resources are released + std::list atflst = atfpool.clear(false); + std::list::iterator j = atflst.begin(); + while(j != atflst.end()) { + delete *j; + j++; + } +} + +#ifdef TEST_ENVIRONMENT +//deps: configuration.cc database.cc artefact.cc pracrodao.cc session.cc mutex.cc semaphore.cc debug.cc pracrodaotest.cc pracrodaopgsql.cc journalwriter.cc journal_commit.cc entitylist.cc inotify.cc exception.cc versionstr.cc tcpsocket.cc macrolist.cc templatelist.cc saxparser.cc log.cc macroheaderparser.cc templateheaderparser.cc +//cflags: -DWITHOUT_ARTEFACT -I.. $(PQXX_CXXFLAGS) $(PTHREAD_CFLAGS) $(EXPAT_CFLAGS) +//libs: $(PQXX_LIBS) -lpthread $(EXPAT_LIBS) $(PTHREAD_LIBS) +#include "test.h" + +TEST_BEGIN; + +Conf::database_backend = "testdb"; +Conf::database_poolsize = 1; + +Conf::artefact_poolsize = 1; + +Conf::xml_basedir = "/tmp"; + +TEST_NOEXCEPTION(Environment env, "Check if the Enviroment can be created."); + +TEST_END; + +#endif/*TEST_ENVIRONMENT*/ diff --git a/server/src/environment.h b/server/src/environment.h new file mode 100644 index 0000000..a7b9677 --- /dev/null +++ b/server/src/environment.h @@ -0,0 +1,50 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set et sw=2 ts=2: */ +/*************************************************************************** + * environment.h + * + * Tue Jan 5 11:41:23 CET 2010 + * Copyright 2010 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_ENVIRONMENT_H__ +#define __PRACRO_ENVIRONMENT_H__ + +#include "database.h" +#include "artefact.h" +#include "connectionpool.h" +#include "session.h" +#include "templatelist.h" +#include "macrolist.h" + +class Environment { +public: + Environment(); + ~Environment(); + + ConnectionPool dbpool; + ConnectionPool atfpool; + Sessions sessions; + MacroList macrolist; + TemplateList templatelist; +}; + +#endif/*__PRACRO_ENVIRONMENT_H__*/ diff --git a/server/src/inotify.cc b/server/src/inotify.cc new file mode 100644 index 0000000..1515387 --- /dev/null +++ b/server/src/inotify.cc @@ -0,0 +1,549 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set et sw=2 ts=2: */ +/*************************************************************************** + * inotify.cc + * + * Wed Jan 6 09:58:47 CET 2010 + * Copyright 2010 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 "inotify.h" + +#include "debug.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define TEST(x, m) ((x & m) == m) + +#ifdef WITH_DEBUG +#define STEST(x, m) (TEST(x, m)?#m" ":"") + +static std::string mask2asc(uint32_t mask) +{ + std::string str; + + str += STEST(mask, IN_ACCESS); + str += STEST(mask, IN_ATTRIB); + str += STEST(mask, IN_CLOSE_WRITE); + str += STEST(mask, IN_CLOSE_NOWRITE); + str += STEST(mask, IN_CREATE); + str += STEST(mask, IN_DELETE); + str += STEST(mask, IN_DELETE_SELF); + str += STEST(mask, IN_MODIFY); + str += STEST(mask, IN_MOVE_SELF); + str += STEST(mask, IN_MOVED_FROM); + str += STEST(mask, IN_MOVED_TO); + str += STEST(mask, IN_OPEN); + + str += STEST(mask, IN_ALL_EVENTS); + str += STEST(mask, IN_CLOSE); + str += STEST(mask, IN_MOVE); + + str += STEST(mask, IN_DONT_FOLLOW); + str += STEST(mask, IN_MASK_ADD); + str += STEST(mask, IN_ONESHOT); + str += STEST(mask, IN_ONLYDIR); + + str += STEST(mask, IN_IGNORED); + str += STEST(mask, IN_ISDIR); + str += STEST(mask, IN_Q_OVERFLOW); + str += STEST(mask, IN_UNMOUNT); + + return str; +} +#endif + +static inline bool isdir(const char *name) +{ + struct stat s; + stat(name, &s); + return S_ISDIR(s.st_mode); +} + +INotify::Event::Event(struct inotify_event *event, std::string name) +{ + this->_name = name; + if(event) { + this->_mask = event->mask; + this->_file = event->name; + } else { + this->_mask = 0; + this->_file = ""; + } + + PRACRO_DEBUG(inotify, "Event [%s] %s (%s)\n", + mask2asc(_mask).c_str(), + _name.c_str(), + _file.c_str()); +} + +bool INotify::Event::isAttributeChangeEvent() +{ + return TEST(_mask, IN_ATTRIB); +} + +bool INotify::Event::isCloseEvent() +{ + return isCloseWriteEvent() || isCloseNoWriteEvent(); +} + +bool INotify::Event::isCloseWriteEvent() +{ + return TEST(_mask, IN_CLOSE_WRITE); +} + +bool INotify::Event::isCloseNoWriteEvent() +{ + return TEST(_mask, IN_CLOSE_NOWRITE); +} + +bool INotify::Event::isCreateEvent() +{ + return TEST(_mask, IN_CREATE); +} + +bool INotify::Event::isOpenEvent() +{ + return TEST(_mask, IN_OPEN); +} + +bool INotify::Event::isModifyEvent() +{ + return TEST(_mask, IN_MODIFY); +} + +bool INotify::Event::isAccessEvent() +{ + return TEST(_mask, IN_ACCESS); +} + +bool INotify::Event::isDeleteEvent() +{ + return TEST(_mask, IN_DELETE); +} + +bool INotify::Event::isDeleteSelfEvent() +{ + return TEST(_mask, IN_DELETE_SELF); +} + +bool INotify::Event::isIgnoredEvent() +{ + return TEST(_mask, IN_IGNORED); +} + +bool INotify::Event::isMoveSelfEvent() +{ + return TEST(_mask, IN_MOVE_SELF); +} + +bool INotify::Event::isMovedFromEvent() +{ + return TEST(_mask, IN_MOVED_FROM); +} + +bool INotify::Event::isMovedToEvent() +{ + return TEST(_mask, IN_MOVED_TO); +} + +bool INotify::Event::isDir() +{ + return TEST(_mask, IN_ISDIR); +} + +std::string INotify::Event::name() +{ + return _name; +} + +std::string INotify::Event::file() +{ + return _file; +} + +uint32_t INotify::Event::mask() +{ + return _mask; +} + +std::string INotify::Event::maskstr() +{ + return mask2asc(_mask); +} + +INotify::INotify() +{ + ifd = inotify_init1(O_NONBLOCK); + if(ifd == -1) { + perror("Inotify init failed.\n"); + return; + } +} + +INotify::~INotify() +{ + if(ifd != -1) close(ifd); +} + +void INotify::addFile(std::string name, uint32_t mask) +{ + // Extra mask bitflags: + //IN_DONT_FOLLOW (since Linux 2.6.15) + // Don't dereference pathname if it is a symbolic link. + //IN_MASK_ADD + // Add (OR) events to watch mask for this pathname if it already + // exists (instead of replacing mask). + //IN_ONESHOT + // Monitor pathname for one event, then remove from watch list. + //IN_ONLYDIR (since Linux 2.6.15) + // Only watch pathname if it is a directory. + + int wd = inotify_add_watch(ifd, name.c_str(), mask); + if(wd == -1) { + perror("INotify: Add watch failed!"); + return; + } + + Watch w; + w.mask = mask; + w.name = name; + w.depth = WATCH_SINGLE; + dirmap[wd] = w; +} + +static inline bool isdir(std::string name) +{ + struct stat s; + stat(name.c_str(), &s); + return S_ISDIR(s.st_mode); +} + +void INotify::addDirectory(std::string name, depth_t depth, uint32_t mask) +{ + PRACRO_DEBUG(inotify, "Adding dir: %s\n", name.c_str()); + + int depth_mask = 0; + if(depth == WATCH_DEEP || depth == WATCH_DEEP_FOLLOW) { + depth_mask = IN_CREATE; // We need to watch for create in order to catch + // creation of new subdirs. + + DIR *dir = opendir(name.c_str()); + if(!dir) { + PRACRO_ERR(inotify, "Could not open directory: %s - %s\n", + name.c_str(), strerror(errno)); + return; + } + + struct dirent *dirent; + while( (dirent = readdir(dir)) != NULL ) { + + if(std::string(dirent->d_name) == "." || + std::string(dirent->d_name) == "..") + continue; + + if(isdir(name+"/"+dirent->d_name)) + addDirectory(name+"/"+dirent->d_name, depth, mask); + } + + closedir(dir); + } + + int wd = inotify_add_watch(ifd, name.c_str(), mask | IN_ONLYDIR | depth_mask); + if(wd == -1) { + PRACRO_ERR(inotify, "INotify: Add watch failed on %s\n", name.c_str()); + return; + } + + Watch w; + w.mask = mask; + w.name = name; + w.depth = depth; + dirmap[wd] = w; +} + +void INotify::remove(int wd) +{ + if(inotify_rm_watch(ifd, wd) == -1) { + perror("inotify_rm_watch failed"); + return; + } + dirmap.erase(wd); +} + +void INotify::remove(std::string name) +{ + std::map::iterator i = dirmap.begin(); + while(i != dirmap.end()) { + Watch w = i->second; + if(w.name == name) this->remove(i->first); + i++; + } +} + +void INotify::readEvents() +{ + size_t size = 64; + char *buf = (char*)malloc(size); + + ssize_t r; + while( ((r = read(ifd, buf, size)) == -1 && errno == EINVAL) || r == 0 ) { + // fprintf(stderr, "Doubling buffer size: %d\n", size); + size *= 2; + buf = (char*)realloc(buf, size); + } + + int p = 0; + while(p < r) { + struct inotify_event *event = (struct inotify_event*)(buf + p); + p += sizeof(struct inotify_event) + event->len; + + /* + switch(event.mask) { + case IN_IGNORED: + //Watch was removed explicitly (inotify_rm_watch(2)) or automatically + // (file was deleted, or file system was unmounted). + case IN_ISDIR: + //Subject of this event is a directory. + case IN_Q_OVERFLOW: + //Event queue overflowed (wd is -1 for this event). + case IN_UNMOUNT: + //File system containing watched object was unmounted. + break; + default: + break; + } + */ + + // TODO: We need to figure out what the new filename/destination is... + if(TEST(event->mask, IN_MOVE_SELF)) dirmap[event->wd].name = "????????"; + + if(dirmap[event->wd].depth == WATCH_DEEP_FOLLOW && + TEST(event->mask, IN_CREATE) && + TEST(event->mask, IN_ISDIR)) + addDirectory(dirmap[event->wd].name + "/" + event->name, + dirmap[event->wd].depth, dirmap[event->wd].mask); + + if(TEST(event->mask, IN_CREATE) && + !TEST(dirmap[event->wd].mask, IN_CREATE)) { + // Ignore this event, it was not requested by the user. + } else { + eventlist.push_back(INotify::Event(event, dirmap[event->wd].name)); + } + + if(TEST(event->mask, IN_IGNORED)) dirmap.erase(event->wd); + } + + free(buf); +} + +bool INotify::hasEvents() +{ + readEvents(); + return eventlist.size() > 0; +} + +INotify::Event INotify::getNextEvent() +{ + readEvents(); + if(eventlist.size() == 0) return Event(NULL, ""); + Event e = eventlist.front(); + eventlist.pop_front(); + return e; +} + +void INotify::clear() +{ + if(ifd != -1) close(ifd); + ifd = inotify_init1(O_NONBLOCK); + if(ifd == -1) { + perror("Inotify init failed.\n"); + } +} + +#ifdef TEST_INOTIFY +//deps: debug.cc +//cflags: -I.. +//libs: +#include "test.h" + +#include + +#define _BASEDIR "/tmp" +#define _DIR _BASEDIR"/inotify_test_dir" +#define _FILE _BASEDIR"/inotify_test" + +TEST_BEGIN; + +pracro_debug_parse("+all"); + +INotify inotify; + +// Create file +FILE *fp = fopen(_FILE, "w"); +if(!fp) TEST_FATAL("Unable to write to the file"); +fprintf(fp, "something"); +fclose(fp); + +inotify.addFile(_FILE); + +TEST_MSG("Positive tests on file watch."); + +// Append to file +fp = fopen(_FILE, "r"); +if(!fp) TEST_FATAL("Unable to read from the file"); +TEST_TRUE(inotify.hasEvents(), "Test if the open event was triggered."); +TEST_TRUE(inotify.getNextEvent().isOpenEvent(), "Test if the event was an open event."); + +char buf[32]; +fread(buf, sizeof(buf), 1, fp); +TEST_TRUE(inotify.hasEvents(), "Test if the read event was triggered."); +TEST_TRUE(inotify.getNextEvent().isAccessEvent(), "Test if the event was a access event."); + +fclose(fp); +TEST_TRUE(inotify.hasEvents(), "Test if the close event was triggered."); +TEST_TRUE(inotify.getNextEvent().isCloseNoWriteEvent(), "Test if the event was a close-nowrite event."); + + +// Append to file +fp = fopen(_FILE, "a"); +if(!fp) TEST_FATAL("Unable to write to the file"); +TEST_TRUE(inotify.hasEvents(), "Test if the open event was triggered."); +TEST_TRUE(inotify.getNextEvent().isOpenEvent(), "Test if the event was an open event."); + +fprintf(fp, "else"); fflush(fp); +TEST_TRUE(inotify.hasEvents(), "Test if the append event was triggered."); +TEST_TRUE(inotify.getNextEvent().isModifyEvent(), "Test if the event was a modified event."); + +fclose(fp); +TEST_TRUE(inotify.hasEvents(), "Test if the close event was triggered."); +TEST_TRUE(inotify.getNextEvent().isCloseWriteEvent(), "Test if the event was a close event."); + + +// Overwrite file +fp = fopen(_FILE, "w"); +if(!fp) TEST_FATAL("Unable to write to the file"); + +// Open for write initially empties the file content, thus provoking a changed event. +TEST_TRUE(inotify.hasEvents(), "Test if the modified event was triggered."); +TEST_TRUE(inotify.getNextEvent().isModifyEvent(), "Test if the event was a modified event."); + +TEST_TRUE(inotify.hasEvents(), "Test if the open event was triggered."); +TEST_TRUE(inotify.getNextEvent().isOpenEvent(), "Test if the event was an open event."); + +fprintf(fp, "else"); fflush(fp); +TEST_TRUE(inotify.hasEvents(), "Test if the write event was triggered."); +TEST_TRUE(inotify.getNextEvent().isModifyEvent(), "Test if the event was a modified event."); + +fclose(fp); +TEST_TRUE(inotify.hasEvents(), "Test if the close event was triggered."); +TEST_TRUE(inotify.getNextEvent().isCloseWriteEvent(), "Test if the event was a close event."); + +// Rename file +rename(_FILE, _FILE"2"); +TEST_TRUE(inotify.hasEvents(), "Test if the rename event was triggered."); +TEST_TRUE(inotify.getNextEvent().isMoveSelfEvent(), "Test if the event was a move self event."); + +// Delete file +unlink(_FILE"2"); + +// Unlink initially counts down the link counter, which provokes an attributes changed event. +TEST_TRUE(inotify.hasEvents(), "Test if the delete event was triggered."); +TEST_TRUE(inotify.getNextEvent().isAttributeChangeEvent(), "Test if the event was an attribute change event."); + +// Since the linkcount should now be zero, the file should be deleted. +TEST_TRUE(inotify.hasEvents(), "Test if the delete event was triggered."); +TEST_TRUE(inotify.getNextEvent().isDeleteSelfEvent(), "Test if the event was a delete self event."); + +// Watch is removed upon delete. +//inotify.remove(_FILE); + +TEST_TRUE(inotify.hasEvents(), "Test if the delete event triggered an ignored event."); +TEST_TRUE(inotify.getNextEvent().isIgnoredEvent(), "Test if the event was an ignored event."); + +// Create file again +fp = fopen(_FILE, "w"); +if(!fp) TEST_FATAL("Unable to write to the file"); +fprintf(fp, "something"); +fclose(fp); + +inotify.addFile(_FILE); +inotify.remove(_FILE); + +TEST_TRUE(inotify.hasEvents(), "Test if the call to remove triggered an ignored event."); +TEST_TRUE(inotify.getNextEvent().isIgnoredEvent(), "Test if the event was an ignored event."); + +// Delete file +unlink(_FILE); +inotify.getNextEvent(); +TEST_FALSE(inotify.hasEvents(), "Test if the delete event was ignored."); + +TEST_FALSE(inotify.hasEvents(), "Test if the event queue is now empty."); + +TEST_MSG("Positive tests on directory watch."); + +if(mkdir(_DIR, 0777) == -1) TEST_FATAL("Could not create test dir."); +inotify.addDirectory(_DIR, WATCH_DEEP_FOLLOW); + +// Create file again +fp = fopen(_DIR"/file1", "w"); +if(!fp) TEST_FATAL("Unable to write to the file"); +fprintf(fp, "something"); +fclose(fp); + +TEST_TRUE(inotify.hasEvents(), "Test if the file creation triggered events."); +TEST_TRUE(inotify.getNextEvent().isCreateEvent(), "..."); +TEST_TRUE(inotify.getNextEvent().isOpenEvent(), "..."); +TEST_TRUE(inotify.getNextEvent().isModifyEvent(), "..."); +TEST_TRUE(inotify.getNextEvent().isCloseWriteEvent(), "..."); + +rename(_DIR"/file1", _DIR"/file2"); +TEST_TRUE(inotify.hasEvents(), "Test if the file renaming triggered events."); +TEST_TRUE(inotify.getNextEvent().isMovedFromEvent(), "..."); +TEST_TRUE(inotify.getNextEvent().isMovedToEvent(), "..."); + +unlink(_DIR"/file2"); + +if(mkdir(_DIR"/dir", 0777) == -1) TEST_FATAL("Could not create test dir."); + +if(mkdir(_DIR"/dir/anotherdir", 0777) == -1) TEST_FATAL("Could not create test dir."); + +while(inotify.hasEvents()) inotify.getNextEvent(); + +rmdir(_DIR"/dir/anotherdir"); + +rmdir(_DIR"/dir"); + +rmdir(_DIR); + +while(inotify.hasEvents()) inotify.getNextEvent(); + +TEST_END; + +#endif/*TEST_INOTIFY*/ diff --git a/server/src/inotify.h b/server/src/inotify.h new file mode 100644 index 0000000..d63e384 --- /dev/null +++ b/server/src/inotify.h @@ -0,0 +1,118 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set et sw=2 ts=2: */ +/*************************************************************************** + * inotify.h + * + * Wed Jan 6 09:58:47 CET 2010 + * Copyright 2010 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_INOTIFY_H__ +#define __PRACRO_INOTIFY_H__ + +#include +#include + +#include +#include +#include + +typedef enum { + WATCH_SINGLE, // Watch only the specified directory. + WATCH_DEEP, // Watch all current subdirs as well + WATCH_DEEP_FOLLOW // Watch all current subdir as well as subdirs + // being created after the watch is initiated +} depth_t; + + +class INotify { +public: + class Event { + public: + Event(struct inotify_event *event, std::string name); + + bool isAttributeChangeEvent(); + bool isCreateEvent(); + bool isOpenEvent(); + bool isCloseEvent(); + bool isCloseWriteEvent(); + bool isCloseNoWriteEvent(); + bool isModifyEvent(); + bool isAccessEvent(); + bool isDeleteEvent(); + bool isDeleteSelfEvent(); + bool isIgnoredEvent(); + bool isMoveSelfEvent(); + bool isMovedFromEvent(); + bool isMovedToEvent(); + + bool isDir(); + + std::string name(); + std::string file(); + uint32_t mask(); + std::string maskstr(); + + private: + std::string _name; + std::string _file; + uint32_t _mask; + }; + + INotify(); + ~INotify(); + + void addFile(std::string name, uint32_t mask = IN_ALL_EVENTS); + + /** + * WARNING: If a directory is added with WATCH_DEEP_FOLLOW, newly + * created folders will not be added to the watch before the next call + * to hasEvents or getNextEvent. thie means that any files created in + * that folder prior to htese calls will not be caught. This will need + * to be done mnually by a recursive scan. + */ + void addDirectory(std::string name, + depth_t depth = WATCH_SINGLE, + uint32_t mask = IN_ALL_EVENTS); + void remove(std::string name); + void remove(int fd); + + bool hasEvents(); + Event getNextEvent(); + + void clear(); + +private: + class Watch { + public: + std::string name; + uint32_t mask; + depth_t depth; + }; + + void readEvents(); + + int ifd; + std::map dirmap; + std::list eventlist; +}; + +#endif/*__PRACRO_INOTIFY_H__*/ diff --git a/server/src/journal_commit.cc b/server/src/journal_commit.cc index a94f1d4..56e7baf 100644 --- a/server/src/journal_commit.cc +++ b/server/src/journal_commit.cc @@ -51,8 +51,8 @@ #include "template.h" #include "templateparser.h" -#include "xml_encode_decode.h" +#if 0 static inline bool iswhitespace(char c) { return c == ' ' || c == '\n' || c == '\t'; @@ -110,6 +110,7 @@ static std::string addNewlines(std::string str, size_t width) return output; } +#endif static int mwrite(int sock, const char *fmt, ...) { @@ -201,103 +202,10 @@ int journal_commit(const char *cpr, const char *user, return 0; } -JournalWriter::JournalWriter(std::string host, unsigned short int port) -{ - this->host = host; - this->port = port; -} - -void JournalWriter::addEntry(Transaction &transaction, Commit &commit, - std::string resume, Template *templ) -{ - size_t index = 0; - std::vector< Macro >::iterator i = templ->macros.begin(); - while(i != templ->macros.end()) { - Macro &m = *i; - if(commit.macro == m.attributes["name"]) break; - index++; - i++; - } - - if(index >= templ->macros.size()) { - PRACRO_ERR(journal, "Could not find macro %s in template %s\n", - commit.macro.c_str(), templ->attributes["name"].c_str()); - // return; - } else { - PRACRO_DEBUG(journal, "Found macro %s as index %u in template %s\n", - commit.macro.c_str(), index, templ->attributes["name"].c_str()); - } - - // First run - initialize username and cpr. - if(currentuser == "" && entrylist.size() == 0) currentuser = transaction.user; - if(currentcpr == "" && entrylist.size() == 0) currentcpr = transaction.cpr; - - PRACRO_DEBUG(journal, "addEntry: template(%s)\n", templ->attributes["name"].c_str()); - - // Add the template resume as the header (ie. first entry) of the journal entry. - if(entrylist.size() == 0 && templ->attributes["name"] != "") { - std::string template_resume = templ->attributes["resume"]; - - PRACRO_DEBUG(journal, "TemplateResume: %s\n", template_resume.c_str()); - - if(template_resume != "") { - ResumeEntry re; - re.resume = template_resume; - re.macro = "template_header"; - entrylist[-1] = re; // Make sure it comes first. - } - } - - // Test if the username or the cpr has changed... if so, commit and clear the list. - if(currentuser != transaction.user || currentcpr != transaction.cpr) { - this->commit(); - entrylist.clear(); - } - - // Strip trailing whitespace, and add newlines. - std::string r = stripTrailingWhitepace(addNewlines(xml_decode(resume), 60)); - std::string m = commit.macro; - - ResumeEntry re; - re.resume = r; - re.macro = m; - entrylist[index] = re; -} - -void JournalWriter::commit() -{ - std::string resume; - - // Iterate through all resumes, and create a string containing them all. - std::map< int, ResumeEntry >::iterator i = entrylist.begin(); - while(i != entrylist.end()) { - if(resume != "") resume += "\n\n"; - // resume += i->macro + "\n"; - resume += i->second.resume; - i++; - } - - if(resume == "") return; - - // Connect to praxisuploadserver and commit all resumes in one bulk. - journal_commit(currentcpr.c_str(), currentuser.c_str(), - host.c_str(), port, - resume.c_str(), resume.size()); -} - - #ifdef TEST_JOURNAL_COMMIT int main() { - std::string text = "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do\neiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. \n\n \t"; - - std::string resume = stripTrailingWhitepace(addNewlines(text, 60)); - printf("[%s]\n", resume.c_str()); - - resume = stripTrailingWhitepace(addNewlines("", 60)); - printf("[%s]\n", resume.c_str()); - return 0; } diff --git a/server/src/journal_commit.h b/server/src/journal_commit.h index 4f7f211..1bc8086 100644 --- a/server/src/journal_commit.h +++ b/server/src/journal_commit.h @@ -27,35 +27,10 @@ #ifndef __PRACRO_JOURNAL_COMMIT_H__ #define __PRACRO_JOURNAL_COMMIT_H__ -#include -#include +#include -#include "transaction.h" -#include "template.h" - -class JournalWriter { -public: - JournalWriter(std::string host, unsigned short int port); - - void addEntry(Transaction &transaction, Commit &commit, - std::string resume, Template *templ); - - void commit(); - -private: - std::string host; - unsigned short int port; - - std::string currentuser; - std::string currentcpr; - - class ResumeEntry { - public: - std::string resume; - std::string macro; - }; - - std::map< int, ResumeEntry > entrylist; -}; +int journal_commit(const char *cpr, const char *user, + const char *addr, unsigned short int port, + const char *buf, size_t size); #endif/*__PRACRO_JOURNAL_COMMIT_H__*/ diff --git a/server/src/journalwriter.cc b/server/src/journalwriter.cc new file mode 100644 index 0000000..4b2b4be --- /dev/null +++ b/server/src/journalwriter.cc @@ -0,0 +1,350 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; coding: utf-8 -*- */ +/* vim: set et sw=2 ts=2: */ +/*************************************************************************** + * journalwriter.cc + * + * Tue Jan 5 15:52:54 CET 2010 + * Copyright 2010 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 "journalwriter.h" + +#include "debug.h" +#include "journal_commit.h" + +static inline bool iswhitespace(char c) +{ + return c == ' ' || c == '\n' || c == '\t' || c == '\r'; +} + +/** + * Remove all spaces, tabs and newline trailing the string. + */ +static std::string stripTrailingWhitepace(const std::string &str) +{ + if(str == "") return str; + + ssize_t end = str.size() - 1; + + while(end >= 0 && iswhitespace(str[end])) end--; + end++; + + return str.substr(0, end); +} + +static bool isInsideUTF8(const std::string &str, size_t idx) +{ + // Two byte character + if(idx > 0 && + (str[idx] & 0xC0 ) == 0x80 && + (str[idx - 1] & 0xE0) == 0xC0) + return true; + + // Three byte character + if(idx > 1 && + (str[idx] & 0xC0 ) == 0x80 && + (str[idx - 1] & 0xC0 ) == 0x80 && + (str[idx - 2] & 0xF0) == 0xE0) + return true; + + if(idx > 0 && + (str[idx] & 0xC0 ) == 0x80 && + (str[idx - 1] & 0xF0) == 0xE0) + return true; + + // Four byte character + if(idx > 2 && + (str[idx] & 0xC0 ) == 0x80 && + (str[idx - 1] & 0xC0 ) == 0x80 && + (str[idx - 2] & 0xC0 ) == 0x80 && + (str[idx - 3] & 0xF8) == 0xF0) + return true; + + if(idx > 1 && + (str[idx] & 0xC0 ) == 0x80 && + (str[idx - 1] & 0xC0 ) == 0x80 && + (str[idx - 2] & 0xF8) == 0xF0) + return true; + + if(idx > 0 && + (str[idx] & 0xC0 ) == 0x80 && + (str[idx - 1] & 0xF8) == 0xF0) + return true; + + return false; +} + +static size_t UTF8Length(const std::string &str) +{ + size_t size = 0; + for(size_t i = 0; i < str.size(); i++) { + if(!isInsideUTF8(str, i)) size++; + } + return size; +} + +/** + * Find all lines longer than 'width', and insert a newline in the + * first backward occurring space. Force split any lines without a space. + */ +static std::string addNewlines(const std::string &str, size_t width) +{ + std::string output; + size_t len = 0; + for(size_t i = 0; i < str.size(); i++) { + char c = str[i]; + + /* + fprintf(stderr, "i: %d, char: '%c', width: %d, len: %d, output: '%s'\n", + i, c, width, len, output.c_str()); + */ + + output += c; + + if(isInsideUTF8(str, i)) continue; + + len++; + if(c == '\n') len = 0; + + // Try to split line at whitespace. + if(len > width) { + size_t p = 0; + while(p < width) { + p++; + + size_t pos = output.size() - p; + + if(isInsideUTF8(output, pos)) continue; + + if(iswhitespace(output[pos])) { + output[pos] = '\n'; + len = UTF8Length(output.substr(pos+1)); + break; + } + } + } + + // Force split line at current pos. + if(len > width) { + // replace last char with a newline, and append the character again, after the newline. + output[output.size()-1] = '\n'; + output += c; + len = 1; + } + } + + return output; +} + +JournalWriter::JournalWriter(std::string host, unsigned short int port) +{ + this->host = host; + this->port = port; +} + +void JournalWriter::addEntry(Transaction &transaction, Commit &commit, + std::string resume, Template *templ) +{ + size_t index = 0; + std::vector< Macro >::iterator i = templ->macros.begin(); + while(i != templ->macros.end()) { + Macro &m = *i; + if(commit.macro == m.attributes["name"]) break; + index++; + i++; + } + + if(index >= templ->macros.size()) { + PRACRO_ERR(journal, "Could not find macro %s in template %s\n", + commit.macro.c_str(), templ->attributes["name"].c_str()); + // return; + } else { + PRACRO_DEBUG(journal, "Found macro %s as index %u in template %s\n", + commit.macro.c_str(), index, templ->attributes["name"].c_str()); + } + + // First run - initialize username and cpr. + if(currentuser == "" && entrylist.size() == 0) currentuser = transaction.user; + if(currentcpr == "" && entrylist.size() == 0) currentcpr = transaction.cpr; + + PRACRO_DEBUG(journal, "addEntry: template(%s)\n", templ->attributes["name"].c_str()); + +#if 0 // this feature is no longer nessecary... + // Add the template resume as the header (ie. first entry) + // of the journal entry. + if(entrylist.size() == 0 && templ->attributes["name"] != "") { + std::string template_resume = templ->attributes["resume"]; + + PRACRO_DEBUG(journal, "TemplateResume: %s\n", template_resume.c_str()); + + if(template_resume != "") { + ResumeEntry re; + re.resume = template_resume; + re.macro = "template_header"; + entrylist[-1] = re; // Make sure it comes first. + } + } +#endif + + // Test if the username or the cpr has changed... + // if so, commit and clear the list. + if(currentuser != transaction.user || currentcpr != transaction.cpr) { + this->commit(); + entrylist.clear(); + } + + addEntry(resume, commit.macro, index); +} + +void JournalWriter::addEntry(std::string resume, std::string macro, int index) +{ + // Strip trailing whitespace, and add newlines. + std::string r = stripTrailingWhitepace(addNewlines(resume, 60)); + std::string m = macro; + + ResumeEntry re; + re.resume = r; + re.macro = m; + entrylist[index] = re; +} + +void JournalWriter::commit() +{ + std::string resume; + + // Iterate through all resumes, and create a string containing them all. + std::map< int, ResumeEntry >::iterator i = entrylist.begin(); + while(i != entrylist.end()) { + if(resume != "") resume += "\n\n"; + // resume += i->macro + "\n"; + resume += i->second.resume; + i++; + } + + if(resume == "") return; + + // Connect to praxisuploadserver and commit all resumes in one bulk. + journal_commit(currentcpr.c_str(), currentuser.c_str(), + host.c_str(), port, + resume.c_str(), resume.size()); +} + +#ifdef TEST_JOURNALWRITER +//deps: debug.cc journal_commit.cc +//cflags: -I.. +//libs: +#include "test.h" + +#define LONG "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do\neiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. \n\n \t"; + +TEST_BEGIN; + +TEST_EQUAL_STR(stripTrailingWhitepace + ("Lorem ipsum dolor sit amet. \n\n \t"), + "Lorem ipsum dolor sit amet.", "Test wspace remover."); + +TEST_EQUAL_STR(stripTrailingWhitepace(""), "", "Test wspace remover on empty string."); + +TEST_EQUAL_STR(stripTrailingWhitepace("\n\t "), "", "Test wspace remover on wspace-only string."); + +TEST_EQUAL_STR(stripTrailingWhitepace("\n"), "", "Test wspace remover on newline only."); +TEST_EQUAL_STR(stripTrailingWhitepace("\t"), "", "Test wspace remover on tab only."); +TEST_EQUAL_STR(stripTrailingWhitepace("\r"), "", "Test wspace remover on space only."); +TEST_EQUAL_STR(stripTrailingWhitepace(" "), "", "Test wspace remover on space only."); + +TEST_EQUAL_STR(stripTrailingWhitepace("ø "), "ø", "Test wspace remover on utf-8 char."); +TEST_EQUAL_STR(stripTrailingWhitepace("ø"), "ø", "Test wspace remover on utf-8 char only."); + +TEST_EQUAL_STR(stripTrailingWhitepace("a "), "a", "Test wspace remover on single char only."); +TEST_EQUAL_STR(stripTrailingWhitepace("a"), "a", "Test wspace remover on single char only."); + +TEST_EQUAL_STR(addNewlines + ("Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do.", 60), + "Lorem ipsum dolor sit amet, consectetur adipisicing elit,\nsed do.", + "Test single linesplit."); + +TEST_EQUAL_STR(addNewlines + ("Lorem ipsum dolor sit amet, consectetur adipisicing elit, øsed do.", 60), + "Lorem ipsum dolor sit amet, consectetur adipisicing elit,\nøsed do.", + "Test single linesplit around utf-8 char."); + +TEST_EQUAL_STR(addNewlines + ("Lorem ipsum dolor sit amet, consectetur adipisicing elitø, sed do.", 60), + "Lorem ipsum dolor sit amet, consectetur adipisicing elitø,\nsed do.", + "Test single linesplit around utf-8 char."); + +TEST_EQUAL_STR(addNewlines + ("Lorem\nipsum dolor sit amet.", 12), + "Lorem\nipsum dolor\nsit amet.", + "Test single linesplit with contained newline."); + +TEST_EQUAL_STR(addNewlines + ("Lorem ipsum dolor sitan met.", 11), + "Lorem ipsum\ndolor sitan\nmet.", + "Test single linesplit on exact border."); + +TEST_EQUAL_STR(addNewlines + ("Loremipsum", 6), + "Loremi\npsum", + "Test single linesplit inside word."); + +TEST_EQUAL_STR(addNewlines + ("abc Loremipsum", 6), + "abc\nLoremi\npsum", + "Test single linesplit inside word."); + +TEST_TRUE(isInsideUTF8("ø", 1), "Test positive utf8 match."); +TEST_TRUE(isInsideUTF8("aæb", 2), "Test positive utf8 match."); +TEST_TRUE(isInsideUTF8("aøb", 2), "Test positive utf8 match."); +TEST_TRUE(isInsideUTF8("aÃ¥b", 2), "Test positive utf8 match."); +TEST_TRUE(isInsideUTF8("aÆb", 2), "Test positive utf8 match."); +TEST_TRUE(isInsideUTF8("aØb", 2), "Test positive utf8 match."); +TEST_TRUE(isInsideUTF8("aÃ…b", 2), "Test positive utf8 match."); +TEST_FALSE(isInsideUTF8("ø", 0), "Test negative utf8 match."); +TEST_FALSE(isInsideUTF8("aæøb", 3), "Test negative utf8 match (between two utf8 chars)."); +TEST_FALSE(isInsideUTF8("aøb", 0), "Test negative utf8 match (before utf8 char)."); + +TEST_FALSE(isInsideUTF8("𤭢", 0), "Test positive utf8 match, len 4."); +TEST_TRUE(isInsideUTF8("𤭢", 1), "Test positive utf8 match, len 4."); +TEST_TRUE(isInsideUTF8("𤭢", 2), "Test positive utf8 match, len 4."); +TEST_TRUE(isInsideUTF8("𤭢", 3), "Test positive utf8 match, len 4."); + +TEST_FALSE(isInsideUTF8("€", 0), "Test positive utf8 match, len 3."); +TEST_TRUE(isInsideUTF8("€", 1), "Test positive utf8 match, len 3."); +TEST_TRUE(isInsideUTF8("€", 2), "Test positive utf8 match, len 3."); + +TEST_FALSE(isInsideUTF8("¢", 0), "Test positive utf8 match, len 2."); +TEST_TRUE(isInsideUTF8("¢", 1), "Test positive utf8 match, len 2."); + +TEST_EQUAL_INT(UTF8Length("ø"), 1, "Test utf8 string length."); +TEST_EQUAL_INT(UTF8Length("æø"), 2, "Test utf8 string length."); +TEST_EQUAL_INT(UTF8Length(""), 0, "Test utf8 string length."); +TEST_EQUAL_INT(UTF8Length("a"), 1, "Test utf8 string length."); +TEST_EQUAL_INT(UTF8Length("aø"), 2, "Test utf8 string length."); +TEST_EQUAL_INT(UTF8Length("aøb"), 3, "Test utf8 string length."); + +TEST_EQUAL_INT(UTF8Length("a𤭢€¢ø𤭢€¢øa"), 10, "Test utf8 string length, combi."); + +TEST_EQUAL_STR(stripTrailingWhitepace(addNewlines("", 60)), "", "Test on empty input."); + +TEST_END; + +#endif/*TEST_JOURNALWRITER*/ diff --git a/server/src/journalwriter.h b/server/src/journalwriter.h new file mode 100644 index 0000000..2cd191d --- /dev/null +++ b/server/src/journalwriter.h @@ -0,0 +1,67 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set et sw=2 ts=2: */ +/*************************************************************************** + * journalwriter.h + * + * Tue Jan 5 15:52:54 CET 2010 + * Copyright 2010 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_JOURNALWRITER_H__ +#define __PRACRO_JOURNALWRITER_H__ + +#include +#include + +#include "transaction.h" +#include "template.h" + +class SessionSerialiser; + +class JournalWriter { + friend class SessionSerialiser; +public: + JournalWriter(std::string host, unsigned short int port); + + void addEntry(Transaction &transaction, Commit &commit, + std::string resume, Template *templ); + + void addEntry(std::string resume, std::string macro, int index); + + void commit(); + +private: + std::string host; + unsigned short int port; + + std::string currentuser; + std::string currentcpr; + + class ResumeEntry { + public: + std::string resume; + std::string macro; + }; + + std::map< int, ResumeEntry > entrylist; +}; + +#endif/*__PRACRO_JOURNALWRITER_H__*/ diff --git a/server/src/luaresume.cc b/server/src/luaresume.cc index b7e7348..099c3bd 100644 --- a/server/src/luaresume.cc +++ b/server/src/luaresume.cc @@ -26,6 +26,8 @@ */ #include "luaresume.h" +#include "luautil.h" + #include "debug.h" #include @@ -34,14 +36,9 @@ static int _getValue(lua_State *L) { - int n = lua_gettop(L); // number of arguments - if(n != 1) { - char errstr[512]; - sprintf(errstr, "Number of args expected 0, got %d", n); - lua_pushstring(L, errstr); - lua_error(L); - return 1; - } + Pracro::checkParameters(L, + Pracro::T_STRING, + Pracro::T_END); std::string name = lua_tostring(L, lua_gettop(L)); @@ -65,7 +62,7 @@ LUAResume::LUAResume(Commit &c) { L = luaL_newstate(); if(L == NULL) { - error("Could not create LUA state."); + PRACRO_ERR(luaresume, "Could not create LUA state.\n"); return; } @@ -85,7 +82,7 @@ LUAResume::~LUAResume() std::string LUAResume::getValue(std::string name) { if(commit.fields.find(name) == commit.fields.end()) { - error("LUAResume: No such field '" + name + "'"); + PRACRO_ERR(luaresume, "LUAResume: No such field '%s'\n", name.c_str()); return ""; } @@ -95,7 +92,7 @@ std::string LUAResume::getValue(std::string name) std::string LUAResume::run(std::string program) { if(L == NULL) { - error("LUA state not initialized!"); + PRACRO_ERR(luaresume, "LUA state not initialized!"); return false; } @@ -111,24 +108,25 @@ std::string LUAResume::run(std::string program) int top = lua_gettop(L); - if(luaL_loadbuffer(L, program.c_str(), program.size(), "lua resume generator")) { - error(lua_tostring(L, lua_gettop(L))); + if(luaL_loadbuffer(L, program.c_str(), program.size(), + "lua resume generator")) { + PRACRO_ERR(luaresume, "loadbufer: %s\n", lua_tostring(L, lua_gettop(L))); return false; } // Run the loaded code if(lua_pcall(L, 0, LUA_MULTRET, 0)) { - error(lua_tostring(L, lua_gettop(L))); + PRACRO_ERR(luaresume, "pcall: %s\n" , lua_tostring(L, lua_gettop(L))); return false; } if(top != lua_gettop(L) - 1) { - error("Program did not return a single value.\n"); + PRACRO_ERR(luaresume, "Program did not return a single value.\n"); return false; } if(lua_isstring(L, lua_gettop(L)) == false) { - error("Program did not return a string value.\n"); + PRACRO_ERR(luaresume, "Program did not return a string value.\n"); return false; } diff --git a/server/src/luautil.cc b/server/src/luautil.cc new file mode 100644 index 0000000..116d219 --- /dev/null +++ b/server/src/luautil.cc @@ -0,0 +1,312 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/*************************************************************************** + * luautil.cc + * + * Fri Apr 13 14:38:53 CEST 2007 + * Copyright 2007 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 "luautil.h" + +#include "debug.h" + +#include + +#include + +std::vector< void * > pointers; + +// for ntohl and htonl +#include + +#define GLOBAL_PREFIX "magic_global_" + +// +// Get the (somewhat hacky) global pointer to the parser object. +// It is set in the preload method. +// +void *Pracro::getGlobal(lua_State *L, std::string name) +{ + unsigned int top; + unsigned int index; + + std::string var = std::string(GLOBAL_PREFIX) + name; + + lua_getfield(L, LUA_GLOBALSINDEX, var.c_str()); + top = lua_gettop(L); + index = lua_tointeger(L, top); + + return pointers.at(index); +} + +void Pracro::setGlobal(lua_State *L, std::string name, void *p) +{ + // Put the value of this in the globals + char value_of_this[256]; + + std::string val = std::string(GLOBAL_PREFIX) + name; + + /* + unsigned int parser = (unsigned int)p; + parser = htonl(parser); + */ + + pointers.push_back(p); + unsigned int index = pointers.size() - 1; + + sprintf(value_of_this, "%s = %u\n", val.c_str(), index); + int s = luaL_loadstring(L, value_of_this); + switch(s) { + case 0: //no errors; + break; + case LUA_ERRSYNTAX: //syntax error during pre-compilation; + case LUA_ERRMEM: //memory allocation error. + fprintf(stderr, "Error: %s\n", lua_tostring(L, lua_gettop(L))); + default: + fprintf(stderr, "Unknown return value of luaL_loadstring.\n"); + } + + // Run program (init) + s = lua_pcall(L, 0, LUA_MULTRET, 0); + // Check for errors + switch(s) { + case 0: // Success + break; + case LUA_ERRRUN:// a runtime error. + case LUA_ERRMEM:// memory allocation error. + // For such errors, Lua does not call the error handler function. + case LUA_ERRERR:// error while running the error handler function. + fprintf(stderr, "Error: %s\n", lua_tostring(L, lua_gettop(L))); + break; + default: + fprintf(stderr, "Error: Unknown return value of lua_pcall.\n"); + break; + } +} + +void Pracro::call(lua_State *L, std::string function, int numargs) +{ + // Get function + lua_getglobal(L, function.c_str()); + + // Call it + int s = lua_pcall(L, numargs, LUA_MULTRET, 0); + + // Check for errors + switch(s) { + case 0: // Success + break; + case LUA_ERRRUN:// a runtime error. + case LUA_ERRMEM:// memory allocation error. + // For such errors, Lua does not call the error handler function. + case LUA_ERRERR:// error while running the error handler function. + fprintf(stderr, "Error: %s\n", lua_tostring(L, lua_gettop(L))); + break; + default: + fprintf(stderr, "Error: Unknown return value of lua_pcall.\n"); + break; + } +} + + +/* +lua_isboolean +lua_iscfunction +lua_isfunction +lua_islightuserdata +lua_isnil +lua_isnone +lua_isnoneornil +lua_isnumber +lua_isstring +lua_istable +lua_isthread +lua_isuserdata +*/ +int Pracro::checkParameters(lua_State *L, ...) +{ + va_list ap; + va_start(ap, L); + + size_t nargs = lua_gettop(L); // number of arguments + + size_t size = 0; + int t; + while(1) { + t = va_arg(ap, int); + if(t == T_END) break; + + switch(t) { + case T_STRING: + case T_NUMBER: + case T_BOOLEAN: + break; + + default: + return luaL_error(L,"Unknown type specifier [%d] at position %d. " + "Missing TYPE_END?", t, size+1); + } + + size++; + } + + va_end(ap); + + if(nargs != size) { + return luaL_error(L, "Number of args expected %d, got %d", size, nargs); + } + + va_start(ap, L); + + size_t idx = 0; + while(1) { + t = va_arg(ap, int); + if(t == T_END) break; + + switch(t) { + case T_STRING: + if(lua_isstring(L, lua_gettop(L)-(size-idx-1)) == 0) { + va_end(ap); + return luaL_error(L, "Parameter %d should be of type string.", idx+1); + } + break; + + case T_NUMBER: + if(lua_isnumber(L, lua_gettop(L)-(size-idx-1)) == 0) { + va_end(ap); + return luaL_error(L, "Parameter %d should be of type number.", idx+1); + } + break; + + case T_BOOLEAN: + if(lua_isboolean(L, lua_gettop(L)-(size-idx-1)) == 0) { + va_end(ap); + return luaL_error(L, "Parameter %d should be of type boolean.", idx+1); + } + break; + + default: + va_end(ap); + return luaL_error(L,"Unknown type specifier [%d] at position %d. " + "Missing TYPE_END?", t, idx+1); + } + + idx++; + } + + va_end(ap); + + return 0; +} + +#ifdef TEST_LUAUTIL +//deps: +//cflags: $(LUA_CFLAGS) -I.. +//libs: $(LUA_LIBS) +#include "test.h" + +#define LUAPROG \ + "testfunc('a string', 42, true)" + +#define LUAPROG_BAD1 \ + "testfunc('a string', 42)" + +#define LUAPROG_BAD2 \ + "testfunc('a string', 42, true, 'another one')" + +#define LUAPROG_BAD3 \ + "testfunc(false, 42, 'string')" + +#define LUAPROG_MISSING_END \ + "testfunc_bad('a string', 42, true, 1)" + +static int testfunc(lua_State *L) +{ + Pracro::checkParameters(L, + Pracro::T_STRING, + Pracro::T_NUMBER, + Pracro::T_BOOLEAN, + Pracro::T_END); + return 0; +} + +static int testfunc_bad(lua_State *L) +{ + Pracro::checkParameters(L, + Pracro::T_STRING, + Pracro::T_NUMBER, + Pracro::T_BOOLEAN, + Pracro::T_NUMBER); + return 0; +} + + +TEST_BEGIN; + +int a, b, c; + +lua_State *L; +L = luaL_newstate(); +if(L == NULL) TEST_FATAL("Could not allocate lua state."); +luaL_openlibs(L); + +Pracro::setGlobal(L, "a", &a); +Pracro::setGlobal(L, "b", &b); +Pracro::setGlobal(L, "c", &c); + +TEST_EQUAL(Pracro::getGlobal(L, "b"), &b, "Test get global"); +TEST_EQUAL(Pracro::getGlobal(L, "c"), &c, "Test get global"); +TEST_EQUAL(Pracro::getGlobal(L, "a"), &a, "Test get global"); + +lua_register(L, "testfunc", testfunc); + +if(luaL_loadstring(L, LUAPROG)) { + TEST_FATAL(lua_tostring(L, lua_gettop(L))) +} +TEST_EQUAL_INT(lua_pcall(L, 0, LUA_MULTRET, 0), 0, "Good one"); + +if(luaL_loadstring(L, LUAPROG_BAD1)) { + TEST_FATAL(lua_tostring(L, lua_gettop(L))) +} +TEST_NOTEQUAL_INT(lua_pcall(L, 0, LUA_MULTRET, 0), 0, "Too short one"); + +if(luaL_loadstring(L, LUAPROG_BAD2)) { + TEST_FATAL(lua_tostring(L, lua_gettop(L))) +} +TEST_NOTEQUAL_INT(lua_pcall(L, 0, LUA_MULTRET, 0), 0, "Too long one"); + +if(luaL_loadstring(L, LUAPROG_BAD3)) { + TEST_FATAL(lua_tostring(L, lua_gettop(L))) +} +TEST_NOTEQUAL_INT(lua_pcall(L, 0, LUA_MULTRET, 0), 0, "Plain wrong"); + + +lua_register(L, "testfunc_bad", testfunc_bad); +if(luaL_loadstring(L, LUAPROG_MISSING_END)) { + TEST_FATAL(lua_tostring(L, lua_gettop(L))) +} +TEST_NOTEQUAL_INT(lua_pcall(L, 0, LUA_MULTRET, 0), 0, "Missing T_END"); + +lua_close(L); + +TEST_END; + +#endif/*TEST_LUAUTIL*/ diff --git a/server/src/luautil.h b/server/src/luautil.h new file mode 100644 index 0000000..ebbba45 --- /dev/null +++ b/server/src/luautil.h @@ -0,0 +1,81 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/*************************************************************************** + * luautil.h + * + * Fri Apr 13 14:38:53 CEST 2007 + * Copyright 2007 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_LUAUTIL_H__ +#define __PRACRO_LUAUTIL_H__ + +#include +#include + +#include + +namespace Pracro { + + /** + * Set a global pointer that can be reaced from the cFunctions at a later time, + * using the getGlobal function. + * @param L The lua_State (active program) from which to get the pointer. + * @param name The symbolic name in which to store the pointer. + * @param p The pointer to set. + */ + void setGlobal(lua_State *L, std::string name, void *p); + + /** + * Get a global pointer set by the setGlobal function. + * @param L The lua_State (active program) in which to set the pointer. + * @param name The symbolic name in which the pointer is stored. + * @return The pointer. + */ + void *getGlobal(lua_State *L, std::string name); + + /** + * Call a function in a lua program. + * @param L The lua_State (active program) in which to set the function resides. + * @param function The name of the function to be called. + */ + void call(lua_State *L, std::string function, int numargs = 0); + + typedef enum { + T_STRING, + T_NUMBER, + T_BOOLEAN, + T_END + } types_t; + + /** + * Check parameter types and number. + * @param L The lua_State (active program) in which to set the function resides. + * @param types The type list (c-vector), describing the required types + * on the stack. The last type must be a terminating T_END. + * @return 0 on success. On error a long jump is made through lua_error, thus + * the function never returns. + */ + // int checkParameters(lua_State *L, types_t types[]); + int checkParameters(lua_State *L, ...); + +}; + +#endif/*__PRACRO_LUAUTIL_H__*/ diff --git a/server/src/macrolist.cc b/server/src/macrolist.cc index b67f239..908de1e 100644 --- a/server/src/macrolist.cc +++ b/server/src/macrolist.cc @@ -27,80 +27,39 @@ */ #include "macrolist.h" -#include -#include +#include -#include "debug.h" #include "macroheaderparser.h" -static std::vector listdir(std::string path) -{ - std::vector files; - - DIR* dir = opendir(path.c_str()); - if(!dir) { - PRACRO_ERR(dump, "Could not open directory: %s\n", path.c_str()); - return files; - } - - struct dirent *d; - while((d = readdir(dir)) != 0) { - //if(d->d_type == DT_DIR) { - std::string name = d->d_name; - if(name.length() >= 4 && name.substr(name.length() - 4) == ".xml") - files.push_back(name); - //} - } - closedir(dir); +#include "debug.h" - return files; +MacroList::MacroList(std::string path) + : EntityList(path, "macro") +{ + rescan(); } -MacroList::MacroList(std::string macropath) + +void MacroList::addFile(std::string file) { - this->macropath = macropath; - std::vector macros = listdir(macropath); - std::vector::iterator i = macros.begin(); - while(i != macros.end()) { - MacroHeaderParser parser(macropath + "/" + *i); - try { - parser.parse(); - Macro *macro = parser.getMacro(); - (*this)[macro->attributes["name"]][VersionStr(macro->attributes["version"])] = *i; - } catch(Exception &e) { - PRACRO_WARN(macrolist, "Skipping %s: %s\n", i->c_str(), e.what()); - } - i++; + if(file.substr(file.size() - 4) != ".xml") { + PRACRO_DEBUG(macrolist, "Skipping file: %s\n", file.c_str()); + return; } - { - iterator i = begin(); - while(i != end()) { - MacroListItem::iterator j = i->second.begin(); - while(j != i->second.end()) { - PRACRO_DEBUG(macrolist, "%s - v%s file: %s\n", - i->first.c_str(), - ((std::string)j->first).c_str(), - j->second.c_str()); - j++; - } - i++; - } + PRACRO_DEBUG(macrolist, "Adding file: %s\n", file.c_str()); + MacroHeaderParser parser(file); + try { + parser.parse(); + Macro *macro = parser.getMacro(); + insertEntity(macro->attributes["name"], + macro->attributes["version"], + file); + } catch(Exception &e) { + PRACRO_WARN(macrolist, "Skipping %s: %s\n", file.c_str(), e.what()); } } -std::string MacroList::getLatestVersion(std::string macro) throw(Exception) -{ - if(find(macro) == end()) throw Exception("Macro ["+macro+"] does not exist"); - MacroListItem mli = (*this)[macro]; - if(mli.size() == 0) return ""; - PRACRO_DEBUG(macrolist, "Search for %s - found %s v%s\n", - macro.c_str(), - (macropath + "/" + mli.begin()->second).c_str(), - ((std::string)mli.begin()->first).c_str()); - return macropath + "/" + mli.begin()->second; -} - #ifdef TEST_MACROLIST #define MACRODIR "/home" // We assume this directory exists and does not contain any xml files! diff --git a/server/src/macrolist.h b/server/src/macrolist.h index 9b9b0d2..51a30ec 100644 --- a/server/src/macrolist.h +++ b/server/src/macrolist.h @@ -28,45 +28,14 @@ #ifndef __PRACRO_MACROLIST_H__ #define __PRACRO_MACROLIST_H__ -#include -#include -#include "versionstr.h" +#include "entitylist.h" -#include "exception.h" - -/** - * The Items contained in the MacroList. - */ -typedef std::map MacroListItem; - -/** - * The MacroList class is intended for macro file caching, so that all macros - * do not need to be parsed on each macro query. - * It builds a list of macros and versions based on the informations read from - * the MacroHeaderParser. - * This means that just because a macro gets into the list doesn't means that it - * will validate as a correct macro (not even nessecarily correct XML). - */ -class MacroList : public std::map { +class MacroList : public EntityList { public: - /** - * Constructor. - * @param macropath A std::string containing the path in which we should look - * for xml files. - */ - MacroList(std::string macropath); - - /** - * Convenience method, to gain the filename of the latest version of a given macro. - * This method throws an Exception if the macro does not exist in the tree. - * @param macro A std::string containing the name of the wanted macro. - * @return A std::string containing the file containing the macro with full path - * included. - */ - std::string getLatestVersion(std::string macro) throw(Exception); + MacroList(std::string path); -private: - std::string macropath; +protected: + void addFile(std::string file); }; #endif/*__PRACRO_MACROLIST_H__*/ diff --git a/server/src/mutex.cc b/server/src/mutex.cc index 2cc75cc..ec0d0e8 100644 --- a/server/src/mutex.cc +++ b/server/src/mutex.cc @@ -37,21 +37,89 @@ Mutex::~Mutex() pthread_mutex_destroy(&mutex); } +bool Mutex::trylock() +{ + return pthread_mutex_trylock(&mutex) == 0; +} + void Mutex::lock() { - pthread_mutex_lock( &mutex ); + pthread_mutex_lock(&mutex); } void Mutex::unlock() { - pthread_mutex_unlock( &mutex ); + pthread_mutex_unlock(&mutex); +} + + +MutexAutolock::MutexAutolock(Mutex &m) + : mutex(m) +{ + mutex.lock(); +} + +MutexAutolock::~MutexAutolock() +{ + mutex.unlock(); } #ifdef TEST_MUTEX +//deps: +//cflags: $(PTHREAD_CFLAGS) +//libs: $(PTHREAD_LIBS) +#include -int main() +#include + +volatile int cnt = 0; + +static void* thread_run(void *data) { - return 0; + Mutex *mutex = (Mutex*)data; + mutex->lock(); + cnt++; + mutex->unlock(); + return NULL; } +TEST_BEGIN; + +Mutex mutex; + +mutex.lock(); +TEST_FALSE(mutex.trylock(), "Testing if trylock works negative."); +mutex.unlock(); +TEST_TRUE(mutex.trylock(), "Testing if trylock works positive."); +mutex.unlock(); + +mutex.lock(); + +pthread_attr_t attr; +pthread_t tid; +pthread_attr_init(&attr); +pthread_create(&tid, &attr, thread_run, &mutex); + +sleep(1); +TEST_EQUAL_INT(cnt, 0, "Testing if lock prevent cnt from increasing."); +mutex.unlock(); + +sleep(1); +TEST_EQUAL_INT(cnt, 1, "Testing if unlock makes cnt increase."); + +pthread_join(tid, NULL); +pthread_attr_destroy(&attr); + +{ + TEST_TRUE(mutex.trylock(), "Testing if autolock has not yet locked the mutex."); + mutex.unlock(); + MutexAutolock mlock(mutex); + TEST_FALSE(mutex.trylock(), "Testing if autolock worked."); +} + +TEST_TRUE(mutex.trylock(), "Testing if autolock has released the lock on the mutex."); +mutex.unlock(); + +TEST_END; + #endif/*TEST_MUTEX*/ diff --git a/server/src/mutex.h b/server/src/mutex.h index 8b35042..cf052ad 100644 --- a/server/src/mutex.h +++ b/server/src/mutex.h @@ -35,6 +35,7 @@ public: Mutex(); ~Mutex(); + bool trylock(); void lock(); void unlock(); @@ -42,4 +43,13 @@ private: pthread_mutex_t mutex; }; +class MutexAutolock { +public: + MutexAutolock(Mutex &mutex); + ~MutexAutolock(); + +private: + Mutex &mutex; +}; + #endif/*__PRACRO_MUTEX_H__*/ diff --git a/server/src/pracrod.cc b/server/src/pracrod.cc index d17001c..e15b0f0 100644 --- a/server/src/pracrod.cc +++ b/server/src/pracrod.cc @@ -89,6 +89,7 @@ static const char usage_str[] = " -h, --help Print this message and exit.\n" " -D, --debug ddd Enable debug messages on 'ddd'; see documentation for details\n" " -d --database db Use db as the database backend. Can be one of pgsql or testdb (default pgsql).\n" +" -s, --ssl keyfile Enable ssl encryption with the key stored in keyfile.\n" ; ConfigurationParser *configparser = NULL; @@ -137,6 +138,39 @@ int PracroDaemon::daemon_main() return 0; } +#define CERT "\ +-----BEGIN CERTIFICATE-----\n\ +MIICFTCCAX6gAwIBAgIBAjANBgkqhkiG9w0BAQUFADBVMRswGQYDVQQKExJBcGFj\n\ +aGUgSFRUUCBTZXJ2ZXIxIjAgBgNVBAsTGUZvciB0ZXN0aW5nIHB1cnBvc2VzIG9u\n\ +bHkxEjAQBgNVBAMTCWxvY2FsaG9zdDAeFw0wNzA2MjEwODE4MzZaFw0wODA2MjAw\n\ +ODE4MzZaMEwxGzAZBgNVBAoTEkFwYWNoZSBIVFRQIFNlcnZlcjEZMBcGA1UECxMQ\n\ +VGVzdCBDZXJ0aWZpY2F0ZTESMBAGA1UEAxMJbG9jYWxob3N0MIGfMA0GCSqGSIb3\n\ +DQEBAQUAA4GNADCBiQKBgQDWTACKSoxd5cL06w7RtPIhFqY1l3UE/aRGmPmh8gEo\n\ +w3zNf+gWxco2yjQgBTQhGww1ybOsAUtXPIsUOSFAGvPUKJZf8ibZMiJEzl2919uz\n\ +IcV9+cUm7k3jFPQx4ALQEalbV++o/lfT5lhgsSiH1t1eln2omVrGCjI/1HeYrw7X\n\ +owIDAQABMA0GCSqGSIb3DQEBBQUAA4GBALVFzprK6rYkWVZZZwq85w2lCYJpEl9a\n\ +66IMzIwNNRfyZMoc9D9PSwsXKYfYOg1RpMt7RhWT/bpggGlsFqctsAgJSv8Ol5Cz\n\ +DqTXhpV+8WOG6l4xDYZz3U3ajiu2jth2+aaMuWKy9Wkr8bzHGDufltToLalucne2\n\ +npM7yCJ83Ana\n\ +-----END CERTIFICATE-----" + +#define KEY "\ +-----BEGIN RSA PRIVATE KEY-----\n\ +MIICXAIBAAKBgQDWTACKSoxd5cL06w7RtPIhFqY1l3UE/aRGmPmh8gEow3zNf+gW\n\ +xco2yjQgBTQhGww1ybOsAUtXPIsUOSFAGvPUKJZf8ibZMiJEzl2919uzIcV9+cUm\n\ +7k3jFPQx4ALQEalbV++o/lfT5lhgsSiH1t1eln2omVrGCjI/1HeYrw7XowIDAQAB\n\ +AoGANUXHjJljs6P+hyw4DuHQn3El+ISiTo9PW02EIUIsD5opWFzHsYGR93Tk6GDi\n\ +yKgUrPprdAMOW61tVaWuImWQ32R2xyrJogjGYo9XE2xAej9N37jM0AGBtn/vd4Dr\n\ +LsYfpjNaM3gqIChD73iYfO+CrNbdLqTxIdG53g/u05GJ4cECQQD0vMm5+a8N82Jb\n\ +oHJgE2jb83WqaYBHe0O03ujtiq3+hPZHoVV3iJWmA/aMlgdtunkJT3PdEsVfQNkH\n\ +fvzR9JhbAkEA4CiZRk5Gcz7cEqyogDTMQYtmrE8hbgofISLuz1rpTEzd8hFAcerU\n\ +nuwFIT3go3hO7oIHMlKU1H5iT1BsFvegWQJBAOSa6A+5A+STIKAX+l52Iu+5tYKN\n\ +885RfMgZpBgm/yoMxwPX1r7GLYsajpV5mszLbz3cIo0xeH3mVBOlccEoqZsCQECP\n\ +8PWq/eebp09Jo46pplsKh5wBfqNvDuBAa4AVszRiv1pFVcZ52JudZyzX4aezsyhH\n\ +E0OPPYamkDI/+6Hx2KECQHF9xV1XatyXuFmfRAInK2BtfGY5UIvJaLxVD3Z1+i6q\n\ +/enz7/wUwvC6G4FSWNMYgAYJOfwZ3BerdkqcRNxyR/Q=\n\ +-----END RSA PRIVATE KEY-----" + int main(int argc, char *argv[]) { int c; @@ -163,10 +197,11 @@ int main(int argc, char *argv[]) {"xml-basedir", required_argument, 0, 'x'}, {"debug", required_argument, 0, 'D'}, {"database", required_argument, 0, 'd'}, + {"ssl", required_argument, 0, 's'}, {0, 0, 0, 0} }; - c = getopt_long (argc, argv, "D:hvfc:u:g:x:d:", long_options, &option_index); + c = getopt_long (argc, argv, "D:hvfc:u:g:x:d:s:", long_options, &option_index); if (c == -1) break; @@ -200,6 +235,17 @@ int main(int argc, char *argv[]) debugstr = strdup(optarg); break; + case 's': +#ifdef WITHOUT_SSL + PRACRO_ERR(server, "Pracro was not compiled with SSL support!\n"); + return 1; +#else + Conf::use_ssl = true; + Conf::ssl_key = KEY; + Conf::ssl_cert = CERT; +#endif + break; + case '?': case 'h': printf("%s", version_str); @@ -228,6 +274,11 @@ int main(int argc, char *argv[]) Conf::database_backend = database; } + if(Conf::database_backend == "testdb") { + // Test db (memory only db) does not work in plural. + Conf::database_poolsize = 1; + } + if(!user) { user = strdup(Conf::server_user.c_str()); } diff --git a/server/src/queryhandlerpentominos.cc b/server/src/queryhandlerpentominos.cc index c5450b3..b67f731 100644 --- a/server/src/queryhandlerpentominos.cc +++ b/server/src/queryhandlerpentominos.cc @@ -28,103 +28,241 @@ #include "debug.h" -#include "configuration.h" +#include -QueryHandlerPentominos::QueryHandlerPentominos(std::string cpr) - : QueryHandler() +// For time +#include + +#include +#include +#include + +// For getpid +#include +#include + +// For time +#include + +// For strerror and errno +#include + +// For socket and friends +#include +#include +#include +#include + +// For ioctl +#include + +#include "queryparser.h" + +typedef struct { + in_addr_t ip; + time_t time; + pid_t pid; + unsigned short int count; +} UID; + +#define SIOCGIFCONF 0x8912 // get iface list +/* +static in_addr_t getIP(const char *interface) { - this->cpr = cpr; + in_addr_t ret = 0; + int numreqs = 30, sd, n; + struct ifconf ifc; + struct ifreq *ifr; + struct in_addr *ia; - atfh = atf_init(); + sd = socket(AF_INET, SOCK_STREAM, 0); + if(sd == -1) { + // throw Pentominos::UIDCouldNotConnectException(strerror(errno)); + } + + ifc.ifc_buf = NULL; + ifc.ifc_len = sizeof(struct ifreq) * numreqs; + + ifc.ifc_buf = (char*)malloc(ifc.ifc_len); + if(ifc.ifc_buf == NULL) { + // throw Pentominos::UIDOutOfMemoryException(); + } + + if (ioctl(sd, SIOCGIFCONF, &ifc) < 0) { + // throw Pentominos::UIDInterfaceListException(strerror(errno)); + } - bool use_https = false; - atfc = atf_connect(atfh, Conf::pentominos_addr.c_str(), - Conf::pentominos_port, use_https); + ifr = ifc.ifc_req; + for (n = 0; n < ifc.ifc_len; n += sizeof(struct ifreq)) { + ia = (struct in_addr *)((ifr->ifr_ifru.ifru_addr.sa_data)+2); + if(!strcmp(ifr->ifr_ifrn.ifrn_name, interface)) { + ret = *(in_addr_t*)ia; + } + ifr++; + } + if(!ret) { // Still no interface... We're fucked! + // throw Pentominos::UIDInterfaceException(interface); + } + + free(ifc.ifc_buf); + return ret; } -QueryHandlerPentominos::~QueryHandlerPentominos() + +static unsigned short counter = 0; +static unsigned short getCounter() { - atf_disconnect(atfc); - atf_close(atfh); + return counter++; } -static QueryResult node2result(atf_result_node_t *node, time_t timestamp) + +static UID uid = {0,0,0,0}; +static std::string getUID(const char *interface) { - QueryResult rnode; - rnode.timestamp = timestamp; - rnode.source = "pentominos"; - - if(!node) return rnode; - - struct _atf_result_node_t *child = node->child; - while(child) { - if(child->value == NULL) { - rnode.groups[child->name] = node2result(child, timestamp); - } else { - rnode.values[child->name] = child->value; - } - child = child->next; - } + if(!uid.ip) uid.ip = getIP(interface); + + time_t t = time(NULL); + if(uid.time != t) counter = 0; // If time differes, reset the counter + uid.time = t; // We need this value every time. + + if(!uid.pid) uid.pid = getpid(); - return rnode; + uid.count = getCounter(); + + char buf[32]; + sprintf(buf, "%08x%08x%04x%04x", uid.ip, (unsigned int)uid.time, uid.pid, uid.count); + return std::string(buf); +} +*/ + +QueryHandlerPentominos::QueryHandlerPentominos(Artefact &atf, + std::string patientid, + std::string user) + : QueryHandler(), artefact(atf) +{ + this->patientid = patientid; + this->user = user; } QueryResult QueryHandlerPentominos::exec(Query &query) { - atf_transaction_t* atft = NULL; - atf_reply_t *reply = NULL; - atf_result_t *result = NULL; - atf_result_node_t *root = NULL; - atf_status_t status; - time_t timestamp; - atf_id id; + return artefact.exec(query, patientid, user); + +#if 0 + time_t timestamp = time(NULL); + std::string uid = getUID("eth0"); - QueryResult rroot; - rroot.timestamp = timestamp; - rroot.source = "pentominos"; + char buf[512]; + char header[] = + "\n" + "\n"; +#ifndef WITHOUT_PENTOMINOS + artefact.socket.write(header, strlen(header)); +#endif/*WITHOUT_PENTOMINOS*/ - atft = atf_new_transaction(atfc, cpr.c_str()); - if(!atft) goto aaarg; + PRACRO_DEBUG(queryhandler, "%s", header); - id = atf_add_query(atft, query.attributes["class"].c_str(), - FILTER_LATEST, USE_NONE, 0, 0); - if(!atft) goto aaarg; + sprintf(buf, " \n", + cpr.c_str(), + "pracro", +#ifndef WITHOUT_PENTOMINOS + artefact.socket.srcaddr().c_str(), + artefact.socket.dstaddr().c_str(), +#else + "127.0.0.1", + "127.0.0.1", +#endif/*WITHOUT_PENTOMINOS*/ + (unsigned int)timestamp, + uid.c_str()); +#ifndef WITHOUT_PENTOMINOS + artefact.socket.write(buf, strlen(buf)); +#endif/*WITHOUT_PENTOMINOS*/ - reply = atf_commit(atft); - if(!reply) goto aaarg; + PRACRO_DEBUG(queryhandler, "%s", buf); - if(atf_get_num_results(reply, id) != 1) goto aaarg; + sprintf(buf, " \n", + query.attributes["class"].c_str(), + query.attributes["class"].c_str()); + +#ifndef WITHOUT_PENTOMINOS + artefact.socket.write(buf, strlen(buf)); +#endif/*WITHOUT_PENTOMINOS*/ - result = atf_get_result(reply, id, 0); - if(!result) goto aaarg; + PRACRO_DEBUG(queryhandler, "%s", buf); - status = atf_get_result_status(result, NULL, 0); - if(status != ATF_STATUS_OK) goto aaarg; - - timestamp = atf_get_result_timestamp(result); + sprintf(buf, ""); - root = atf_get_result_node(result); - if(!root) goto aaarg; +#ifndef WITHOUT_PENTOMINOS + artefact.socket.write(buf, strlen(buf)); +#endif/*WITHOUT_PENTOMINOS*/ - { - QueryResult qresult = node2result(root, timestamp); - rroot.groups[query.attributes["class"]] = qresult; + PRACRO_DEBUG(queryhandler, "%s", buf); + + QueryResult result; + +#ifndef WITHOUT_PENTOMINOS + QueryParser parser; + + ssize_t size; + + // Read until we've got the entire result. + while((size = artefact.socket.read(buf, sizeof(buf))) > 0) { + // fwrite(buf, size, 1, stdout); fflush(stdout); + if(parser.parse(buf, size)) break; } - aaarg: - if(root) atf_free_result_node(root); - if(reply) atf_free_reply(reply); - if(atft) atf_free_transaction(atft); + result = parser.result; +#endif/*WITHOUT_PENTOMINOS*/ + + PRACRO_INFO(queryhandler, "Done handling query\n"); + + result.print(); - return rroot; + return result; +#endif + return QueryResult(); } #ifdef TEST_QUERYHANDLERPENTOMINOS int main() { +#ifdef WITHOUT_PENTOMINOS + printf("The project need to be configured for use of Pentominos in order to run this test.\n"); return 1; +#endif/*WITHOUT_PENTOMINOS*/ + + TCPSocket s; + try { + s.connect("localhost", 11108); + } catch(Exception &e) { + printf("ERROR: %s\n", e.what()); + printf("A running instance of the artefact server in needed on localhost, port 11108 in order for this test to run.\n"); + return 1; + } + + QueryHandlerPentominos qh(s, "2003791613"); + + Query q1; + q1.attributes["device_id"] = "lensmeter"; + q1.attributes["device_type"] = "lensmeter"; + QueryResult res = qh.exec(q1); + res.print(); + + return 0; } #endif/*TEST_QUERYHANDLERPENTOMINOS*/ diff --git a/server/src/queryhandlerpentominos.h b/server/src/queryhandlerpentominos.h index 53b01ad..b96c097 100644 --- a/server/src/queryhandlerpentominos.h +++ b/server/src/queryhandlerpentominos.h @@ -29,29 +29,30 @@ #include "queryhandler.h" +#include "artefact.h" #include "template.h" #include "queryresult.h" +#include #include -#include - /** * This class handles the query of external data. */ class QueryHandlerPentominos : public QueryHandler { public: - QueryHandlerPentominos(std::string cpr); - ~QueryHandlerPentominos(); + QueryHandlerPentominos(Artefact &artefact, + std::string patientid, + std::string user); + ~QueryHandlerPentominos() {} // Execute all queries. QueryResult exec(Query &query); private: - atf_handle_t *atfh; - atf_connection_t *atfc; - - std::string cpr; + Artefact &artefact; + std::string patientid; + std::string user; }; #endif/*__PRACRO_QUERYHANDLERPENTOMINOS_H__*/ diff --git a/server/src/queryparser.cc b/server/src/queryparser.cc new file mode 100644 index 0000000..db562ae --- /dev/null +++ b/server/src/queryparser.cc @@ -0,0 +1,168 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/*************************************************************************** + * queryparser.cc + * + * Tue May 6 17:02:37 CEST 2008 + * Copyright 2008 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 "queryparser.h" + +QueryParser::QueryParser() +{ + this->timestamp = 0; + + p = 0; + stack.push_back(&result); +} + +void QueryParser::startTag(std::string name, std::map< std::string, std::string> attributes) +{ + + if(name == "results") { + // What to do here!? + } + + if(name == "result") { + this->timestamp = atol(attributes["timestamp"].c_str()); + + QueryResult q; + q.source = "pentominos"; + q.timestamp = this->timestamp; + stack.back()->groups[attributes["class"]] = q; + stack.push_back(&stack.back()->groups[attributes["class"]]); + } + + if(name == "group") { + QueryResult q; + q.timestamp = this->timestamp; + stack.back()->groups[attributes["name"]] = q; + stack.push_back(&stack.back()->groups[attributes["name"]]); + } + + if(name == "value") { + stack.back()->values[attributes["name"]] = utf8.decode(attributes["value"]); + } + +} + +void QueryParser::endTag(std::string name) +{ + if(name == "group" || name == "result") stack.pop_back(); +} + +void QueryParser::parseError(const char *buf, size_t len, std::string error, int lineno) +{ + fprintf(stderr, "QueryParser error at line %d: %s\n", lineno, error.c_str()); + fprintf(stderr, "\tBuffer %u bytes: [", len); + if(fwrite(buf, len, 1, stderr) != len) {} + fprintf(stderr, "]\n"); + fflush(stderr); + + char *slineno; + if(asprintf(&slineno, " at line %d\n", lineno) != -1) { + throw Exception(error + slineno); + free(slineno); + } + +} + +#ifdef TEST_QUERYPARSER + +#include + +static char xml[] = + "\n" + "\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + "\n" +; + +static char badxml[] = + "\n" + "\n" + "\n" +; + +static std::string loadresultstring(QueryResult &res, std::string group = "") +{ + std::string s; + + std::map< std::string, std::string >::iterator v = res.values.begin(); + while(v != res.values.end()) { + s += group + (*v).first + " = \"" + (*v).second + "\"\n"; + v++; + } + + std::map< std::string, QueryResult >::iterator g = res.groups.begin(); + while(g != res.groups.end()) { + s += group + (*g).first + " = {}\n"; + s += loadresultstring((*g).second, group + (*g).first + "."); + g++; + } + + return s; +} + +int main() +{ + // Parse something + { + QueryParser parser; + parser.parse(xml, strlen(xml)); + printf("%s\n", loadresultstring(parser.result).c_str()); + } + + // Parse something, and fail! + try { + QueryParser parser; + parser.parse(badxml, strlen(badxml)); + printf("%s\n", loadresultstring(parser.result).c_str()); + } catch(Exception &e) { + printf("ERROR: %s\n", e.what()); + goto weitergehen; + } + return 1; + weitergehen: + + return 0; +} + +#endif/*TEST_QUERYPARSER*/ diff --git a/server/src/queryparser.h b/server/src/queryparser.h new file mode 100644 index 0000000..f901d2c --- /dev/null +++ b/server/src/queryparser.h @@ -0,0 +1,81 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/*************************************************************************** + * queryparser.h + * + * Tue May 6 17:02:36 CEST 2008 + * Copyright 2008 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_QUERYPARSER_H__ +#define __PRACRO_QUERYPARSER_H__ + +#include "saxparser.h" + +#include +#include + +#include "queryresult.h" +#include "utf8.h" +#include "exception.h" + +/** + * This class parses xml entities into a QueryResult structure. + * Call the parent (SAXParser) method parse in order to actually parse something. + * If the parser fails (syntax error) it will throw an Exception. + * @see QueryResult result, in order to get the parsed data. + */ +class QueryParser : public SAXParser { +public: + /** + * Constructor. + */ + QueryParser(); + + /** + * The object will contain the result when the parsing is done. + */ + QueryResult result; + + /** + * Private parser callback. + */ + void startTag(std::string name, std::map< std::string, std::string> attributes); + + /** + * Private parser callback. + */ + void endTag(std::string name); + + /** + * Private parser callback. + */ + void parseError(const char *buf, size_t len, std::string error, int lineno); + +private: + // For read + int p; + std::string document; + time_t timestamp; + std::vector< QueryResult * > stack; + UTF8 utf8; +}; + +#endif/*__PRACRO_QUERYPARSER_H__*/ diff --git a/server/src/resumeparser.cc b/server/src/resumeparser.cc index bf3483e..4d514ac 100644 --- a/server/src/resumeparser.cc +++ b/server/src/resumeparser.cc @@ -26,9 +26,10 @@ */ #include "resumeparser.h" -#include "luaresume.h" #include +#include "luaresume.h" + static std::string resume_parser_format(Resume &r, Commit &commit) { const char* format = r.attributes["format"].c_str(); diff --git a/server/src/saxparser.cc b/server/src/saxparser.cc index 9072ab6..f26c965 100644 --- a/server/src/saxparser.cc +++ b/server/src/saxparser.cc @@ -74,7 +74,7 @@ SAXParser::SAXParser() { p = XML_ParserCreate(NULL); if(!p) { - PRACRO_ERR_LOG(sax, "Couldn't allocate memory for parser\n"); + PRACRO_ERR(sax, "Couldn't allocate memory for parser\n"); // throw Exception(...); return; } @@ -103,7 +103,8 @@ int SAXParser::parse() do { len = readData(buf, sizeof(buf) - 1); if (! XML_Parse(p, buf, len, len == 0)) { - parseError(buf, len, XML_ErrorString(XML_GetErrorCode(p)), (int)XML_GetCurrentLineNumber(p)); + parseError(buf, len, XML_ErrorString(XML_GetErrorCode(p)), + (int)XML_GetCurrentLineNumber(p)); return 1; } @@ -123,35 +124,43 @@ static bool iswhitespace(const char *buf, size_t size) bool SAXParser::parse(const char *data, size_t size) { - PRACRO_DEBUG(sax, "parse %d bytes\n", size); + std::string xml; + xml.append(data, size); + PRACRO_DEBUG(sax, "parse %d bytes [%s]\n", size, xml.c_str()); bufferbytes = size; totalbytes += bufferbytes; if(! XML_Parse(p, data, size, false) ) { if(XML_GetErrorCode(p) == XML_ERROR_JUNK_AFTER_DOC_ELEMENT) return true; - if(XML_GetErrorCode(p) == XML_ERROR_FINISHED && iswhitespace(data, size)) return true; + if(XML_GetErrorCode(p) == XML_ERROR_FINISHED && + iswhitespace(data, size)) return true; if(done && XML_GetErrorCode(p) == XML_ERROR_UNCLOSED_TOKEN) return true; - parseError(data, size, XML_ErrorString(XML_GetErrorCode(p)), (int)XML_GetCurrentLineNumber(p)); + parseError(data, size, XML_ErrorString(XML_GetErrorCode(p)), + (int)XML_GetCurrentLineNumber(p)); return false; } if(done) { if(! XML_Parse(p, data, 0, true) ) { if(XML_GetErrorCode(p) == XML_ERROR_JUNK_AFTER_DOC_ELEMENT) return true; - if(XML_GetErrorCode(p) == XML_ERROR_FINISHED && iswhitespace(data, size)) return true; + if(XML_GetErrorCode(p) == XML_ERROR_FINISHED && + iswhitespace(data, size)) return true; if(XML_GetErrorCode(p) == XML_ERROR_UNCLOSED_TOKEN) return true; - parseError(data, 0, XML_ErrorString(XML_GetErrorCode(p)), (int)XML_GetCurrentLineNumber(p)); + parseError(data, 0, XML_ErrorString(XML_GetErrorCode(p)), + (int)XML_GetCurrentLineNumber(p)); return false; } } - if(done) PRACRO_DEBUG(sax, "Got END_OF_DOCUMENT [%s] at %ld\n", outertag.c_str(), XML_GetCurrentByteIndex(p)); + if(done) PRACRO_DEBUG(sax, "Got END_OF_DOCUMENT [%s] at %ld\n", + outertag.c_str(), XML_GetCurrentByteIndex(p)); return done; } -void SAXParser::parseError(const char *buf, size_t len, std::string error, int lineno) +void SAXParser::parseError(const char *buf, size_t len, + std::string error, int lineno) { fprintf(stderr, "SAXParser error at line %d: %s\n", lineno, error.c_str()); fprintf(stderr, "\tBuffer %u bytes: [", len); @@ -167,6 +176,10 @@ unsigned int SAXParser::usedBytes() #ifdef TEST_SAXPARSER +//deps: log.cc debug.cc exception.cc +//cflags: -I.. +//libs: -lexpat +#include #define XMLFILE "/tmp/saxparsertest.xml" @@ -253,139 +266,125 @@ public: } }; -int main(int argc, char *argv[]) -{ - FILE *fp = fopen(XMLFILE, "w"); - if(!fp) { - printf("Could not write to %s\n", XMLFILE); - return 1; - } - fprintf(fp, xml); - fclose(fp); +TEST_BEGIN; - // Test callback parser - { - MyFileParser parser(XMLFILE); - parser.parse(); - } +FILE *fp = fopen(XMLFILE, "w"); +TEST_NOTEQUAL(fp, NULL, "Test if file \""XMLFILE"\" could be written."); +if(!fp) TEST_FATAL("Could not write "XMLFILE); +fprintf(fp, "%s", xml); +fclose(fp); - // Test buffer parser - for(size_t sz = 1; sz < 1000; sz++) { - bool test = false; - MyBufferParser parser; - std::string buf = xml; - size_t pos = 0; - while(pos < buf.length()) { - std::string substr = buf.substr(pos, sz); - - try { - test |= parser.parse((char*)substr.c_str(), substr.length()); - } catch(Exception &e) { - printf("Buffer parser failed on size %d: %s [%s]\n", sz, e.what(), substr.c_str()); - } - pos += sz; - } +TEST_MSG("Test callback parser."); +{ + MyFileParser parser(XMLFILE); + parser.parse(); +} - if(!test) { - printf("Buffer parser failed on size %d\n", sz); - return 1; +TEST_MSG("Test buffer parser."); +for(size_t sz = 1; sz < 1000; sz++) { + bool test = false; + MyBufferParser parser; + std::string buf = xml; + size_t pos = 0; + while(pos < buf.length()) { + std::string substr = buf.substr(pos, sz); + + try { + test |= parser.parse((char*)substr.c_str(), substr.length()); + } catch(Exception &e) { + TEST_TRUE(true, "Buffer parser failed on size %d: %s [%s]", + sz, e.what(), substr.c_str()); } + pos += sz; } + + TEST_TRUE(test, "Test buffer parser on %d bytes", sz); + } - fp = fopen(XMLFILE, "w"); - if(!fp) { - printf("Could not write to %s\n", XMLFILE); - return 1; - } - fprintf(fp, xml_notrailingwhitespace); - fprintf(fp, xml_notrailingwhitespace); - fclose(fp); - // Test buffer parser with multiple documents in the same buffer - { - fp = fopen(XMLFILE, "r"); - if(!fp) { - printf("Could not write to %s\n", XMLFILE); - return 1; - } - for(size_t sz = 1; sz < 1000; sz++) { - MyBufferParser *parser = NULL; - rewind(fp); - size_t numdocs = 0; - char *buf = new char[sz + 1]; - memset(buf, 0, sz + 1); - size_t size; - while( (size = fread(buf, 1, sz, fp)) > 0) { - while(size) { - if(parser == NULL) { - parser = new MyBufferParser(); - } - if(parser->parse(buf, size)) { - - // Got one - numdocs++; - - size = size - parser->usedBytes(); - strcpy(buf, buf + parser->usedBytes()); - delete parser; parser = NULL; - } else { - size = 0; - memset(buf, 0, sz + 1); - } +fp = fopen(XMLFILE, "w"); +TEST_NOTEQUAL(fp, NULL, "Test if file \""XMLFILE"\" could be written."); +if(!fp) TEST_FATAL("Could not write "XMLFILE); +fprintf(fp, "%s", xml_notrailingwhitespace); +fprintf(fp, "%s", xml_notrailingwhitespace); +fclose(fp); + +TEST_MSG("Test buffer parser with multiple documents in the same buffer."); +{ + fp = fopen(XMLFILE, "r"); + TEST_NOTEQUAL(fp, NULL, "Test if file \""XMLFILE"\" could be read."); + if(!fp) TEST_FATAL("Could not read from "XMLFILE); + + for(size_t sz = 1; sz < 1000; sz++) { + MyBufferParser *parser = NULL; + rewind(fp); + size_t numdocs = 0; + char *buf = new char[sz + 1]; + memset(buf, 0, sz + 1); + size_t size; + while( (size = fread(buf, 1, sz, fp)) > 0) { + while(size) { + if(parser == NULL) { + parser = new MyBufferParser(); + } + if(parser->parse(buf, size)) { + + // Got one + numdocs++; + + size = size - parser->usedBytes(); + strcpy(buf, buf + parser->usedBytes()); + delete parser; parser = NULL; + } else { + size = 0; + memset(buf, 0, sz + 1); } } - if(numdocs != 2) { - printf("Failed to parse two documents.\n"); - return 1; - } - if(parser) delete parser; parser = NULL; - delete[] buf; } - fclose(fp); - } - - fp = fopen(XMLFILE, "w"); - if(!fp) { - printf("Could not write to %s\n", XMLFILE); - return 1; + TEST_EQUAL(numdocs, 2, "Test if 2 documents were parsed on docsize %d.", sz); + if(parser) delete parser; parser = NULL; + delete[] buf; } - fprintf(fp, xml_fail); fclose(fp); +} - // Test failure - { - MyFileParser parser(XMLFILE); - try { - parser.parse(); - } catch(Exception &e) { - goto goon; - } - printf("This test should fail...\n"); - return 1; - } - goon: +fp = fopen(XMLFILE, "w"); +TEST_NOTEQUAL(fp, NULL, "Test if file \""XMLFILE"\" could be written."); +if(!fp) TEST_FATAL("Could not write "XMLFILE); +fprintf(fp, "%s", xml_fail); +fclose(fp); - fp = fopen(XMLFILE, "w"); - if(!fp) { - printf("Could not write to %s\n", XMLFILE); - return 1; +TEST_MSG("Test failure"); +{ + MyFileParser parser(XMLFILE); + try { + parser.parse(); + } catch(Exception &e) { + goto goon; } - fprintf(fp, xml_fail2); - fclose(fp); + TEST_TRUE(false, "This test should fail...\n"); +} +goon: - // Test failure - { - MyFileParser parser(XMLFILE); - try { - parser.parse(); - } catch(Exception &e) { - goto goonagain; - } - printf("This test should fail...\n"); - return 1; - } - goonagain: +fp = fopen(XMLFILE, "w"); +TEST_NOTEQUAL(fp, NULL, "Test if file \""XMLFILE"\" could be written."); +if(!fp) TEST_FATAL("Could not write "XMLFILE); +fprintf(fp, "%s", xml_fail2); +fclose(fp); - unlink(XMLFILE); +// Test failure +{ + MyFileParser parser(XMLFILE); + try { + parser.parse(); + } catch(Exception &e) { + goto goonagain; + } + TEST_TRUE(false, "This test should fail...\n"); } +goonagain: + +unlink(XMLFILE); + +TEST_END; #endif/*TEST_SAXPARSER*/ diff --git a/server/src/semaphore.cc b/server/src/semaphore.cc new file mode 100644 index 0000000..e5f1f31 --- /dev/null +++ b/server/src/semaphore.cc @@ -0,0 +1,47 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/*************************************************************************** + * semaphore.cc + * + * Sat Oct 8 17:44:13 CEST 2005 + * Copyright 2005 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 "semaphore.h" + +Semaphore::Semaphore() +{ + sem_init(&semaphore, 0, 0); +} + +Semaphore::~Semaphore() +{ + sem_destroy(&semaphore); +} + +void Semaphore::post() +{ + sem_post(&semaphore); +} + +void Semaphore::wait() +{ + sem_wait(&semaphore); +} diff --git a/server/src/semaphore.h b/server/src/semaphore.h new file mode 100644 index 0000000..72121f9 --- /dev/null +++ b/server/src/semaphore.h @@ -0,0 +1,44 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/*************************************************************************** + * semaphore.h + * + * Sat Oct 8 17:44:13 CEST 2005 + * Copyright 2005 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_SEMAPHORE_H__ +#define __PRACRO_SEMAPHORE_H__ + +#include + +class Semaphore { +public: + Semaphore(); + ~Semaphore(); + + void post(); + void wait(); + +private: + sem_t semaphore; +}; + +#endif/*__PRACRO_SEMAPHORE_H__*/ diff --git a/server/src/server.cc b/server/src/server.cc index 727ac28..1f85479 100644 --- a/server/src/server.cc +++ b/server/src/server.cc @@ -26,6 +26,8 @@ */ #include "server.h" +#include + #include "tcpsocket.h" #include @@ -36,388 +38,153 @@ #include #include +#include + #include "configuration.h" -#include "transaction.h" -#include "transactionparser.h" -#include "templateparser.h" -#include "macroparser.h" - -#include "queryhandler.h" -#include "queryhandlerpracro.h" -#include "queryhandlerpentominos.h" - -#include "luaquerymapper.h" -#include "database.h" -#include "widgetgenerator.h" -#include "resumeparser.h" -#include "journal_commit.h" -#include "xml_encode_decode.h" - -#include "macrolist.h" -#include "templatelist.h" -#include "versionstr.h" - -static std::string error_box(std::string message) +#include "connection.h" +#include "log.h" + +static int handle_request_callback(void *cls, + struct MHD_Connection *con, + const char *url, + const char *method, + const char *version, + const char *data, + unsigned int *data_size, + void **con_cls) { - std::string errorbox = - "\n" - "\n" - " \n" - "\n"; - return errorbox; -} + int ret = MHD_YES; -class NotFoundException : public Exception { -public: - NotFoundException(Request &r) - : Exception("Macro " + r.macro + " not found in template " + r.templ) {} -}; + Connection *connection = (Connection*)*con_cls; + PRACRO_DEBUG(httpd, "handle_request_callback con:%p condata:%p\n", + con, *con_cls); -static std::string handleCommits(Transaction *transaction, Database &db, - JournalWriter &journalwriter, MacroList ¯olist, - TemplateList &templatelist) -{ - std::string answer; + // Test for new connection + if(connection == NULL) { + std::string sessionid; + const char *sid = MHD_lookup_connection_value(con, MHD_HEADER_KIND, + "SessionID"); + if(sid) sessionid = sid; - Commits::iterator i = transaction->commits.begin(); - while(i != transaction->commits.end()) { - Commit &commit = *i; - - MacroParser mp(macrolist.getLatestVersion(commit.macro)); - mp.parse(); - Macro *macro = mp.getMacro(); - - std::string resume = resume_parser(macro->resume, commit); - commit.fields["journal.resume"] = resume; - db.commitTransaction(transaction->user, transaction->cpr, *macro, commit.fields); - - if(resume != "") { + const char *scm = MHD_lookup_connection_value(con, MHD_HEADER_KIND, + "SessionCommit"); - TemplateParser tp(templatelist.getLatestVersion(commit.templ)); - tp.parse(); - Template *templ = tp.getTemplate(); + const char *sdc = MHD_lookup_connection_value(con, MHD_HEADER_KIND, + "SessionDiscard"); - journalwriter.addEntry(*transaction, commit, resume, templ); - } - - i++; + Environment *env = (Environment *)cls; + connection = new Connection(*env, sessionid, scm != NULL, sdc != NULL); + *con_cls = connection; } - return answer; -} - - -static std::string handleRequest(Transaction *transaction, - Database &db, - JournalWriter &journalwriter, - MacroList ¯olist, - TemplateList &templatelist) -{ - std::string answer; - - // Reuse connection throughout entire template. - QueryHandlerPentominos qh(transaction->cpr); + if(!connection) return MHD_NO; - Requests::iterator i = transaction->requests.begin(); - while(i != transaction->requests.end()) { - Request &request = *i; + if(connection->handle(data, *data_size)) { + std::string response = connection->getResponse(); - PRACRO_DEBUG(server, "Handling request - macro: %s, template: %s\n", - request.macro.c_str(), request.templ.c_str()); - - // Read and parse the template file. - TemplateParser tp(templatelist.getLatestVersion(request.templ)); - tp.parse(); + PRACRO_DEBUG(httpd, "Sending response: [[%s]]\n", response.c_str()); + + struct MHD_Response *rsp = + MHD_create_response_from_data(response.size(), + (void*)response.data(), + MHD_NO, // must free + MHD_YES); // must copy - Template *templ = tp.getTemplate(); + MHD_add_response_header(rsp, MHD_HTTP_HEADER_CONTENT_TYPE, + "text/plain; charset=UTF-8"); - answer += " \n"; - - i++; + delete connection; + *con_cls = NULL; } - return answer; + *data_size = 0; + + return ret; } -static std::string handleTransaction(Transaction *transaction, - Database &db, - JournalWriter &journalwriter, - MacroList ¯olist, - TemplateList &templatelist) +void requestCompletedCallback(void *cls, + struct MHD_Connection *con, + void **con_cls, + enum MHD_RequestTerminationCode toe) { - std::string answer; - answer += "\n"; - answer += "\n"; - - try { - answer += handleCommits(transaction, db, journalwriter, macrolist, templatelist); - } catch( std::exception &e ) { - PRACRO_ERR(server, "Commit error: %s\n", e.what()); - return error_box(xml_encode(e.what())); - } + PRACRO_DEBUG(httpd, "requestCompletedCallback %p\n", con); - try { - answer += handleRequest(transaction, db, journalwriter, - macrolist, templatelist); - } catch( std::exception &e ) { - PRACRO_ERR(server, "Request error: %s\n", e.what()); - return error_box(xml_encode(e.what())); + // If connection was interrupted prematurely delete the content data here. + if(*con_cls) { + Connection *connection = (Connection*)*con_cls; + delete connection; + *con_cls = NULL; } - - answer += "\n"; - - PRACRO_DEBUG(server, "Done handling transaction\n"); - PRACRO_DEBUG(serverxml, "%s\n", answer.c_str()); - return answer; } - -static void handleConnection(TCPSocket *socket) +static void httpderr(void *arg, const char *fmt, va_list ap) { - Database db(Conf::database_backend, Conf::database_addr, "", Conf::database_user, Conf::database_passwd, ""); - - JournalWriter journalwriter(Conf::journal_commit_addr.c_str(), Conf::journal_commit_port); - - MacroList macrolist(Conf::xml_basedir + "/macros"); - TemplateList templatelist(Conf::xml_basedir + "/templates"); - - ssize_t size; - char buf[4096]; - - Transaction *transaction = NULL; - TransactionParser *parser = NULL; - - // while( (size = socket->read(buf, sizeof(buf))) != -1) { - while( (size = socket->read(buf, sizeof(buf))) > 0) { - - PRACRO_DEBUG(server, "Read %d bytes from network\n", size); - - while(size) { - - if(transaction == NULL) { - transaction = new Transaction(); - } - - if(parser == NULL) { - parser = new TransactionParser(transaction); - } - - PRACRO_DEBUG(server, "Got %d bytes in read loop\n", size); - if(parser->parse(buf, size)) { - PRACRO_DEBUG(server, "Got complete XML document %d bytes used, %d bytes in current buffer.\n", parser->usedBytes(), size); - - socket->write(handleTransaction(transaction, db, journalwriter, - macrolist, templatelist)); - size = size - parser->usedBytes(); - if(size) { - strcpy(buf, buf + parser->usedBytes()); - PRACRO_DEBUG(server, "Replaying %d bytes.\n", size); - } - - delete transaction; transaction = NULL; - delete parser; parser = NULL; - } else { - size = 0; - memset(buf, 0, sizeof(buf)); - } - } - } - - if(transaction) { - delete transaction; - transaction = NULL; - } - - if(parser) { - delete parser; - parser = NULL; - } - - journalwriter.commit(); - - PRACRO_DEBUG(server, "Out of read loop!\n"); + PRACRO_ERR_VA(server, fmt, ap); } -//#define NON_FORKING -#include extern bool pracro_is_running; void server() { + srand(time(NULL)); + + // bool forceshutdown = false; port_t port = Conf::server_port; - TCPSocket *socket = NULL; - - try { - socket = new TCPSocket("Listen socket"); - socket->listen(port); - } catch (Exception &e) { - PRACRO_ERR_LOG(server, "Error in listen:\n%s\n", e.what()); - delete socket; - socket = NULL; + + int flags = MHD_USE_DEBUG | MHD_USE_SELECT_INTERNALLY; + // | MHD_USE_PEDANTIC_CHECKS +#ifndef WITHOUT_SSL + if(Conf::use_ssl) flags |= MHD_USE_SSL; +#endif + + PRACRO_DEBUG(server, "Server running on port %d.\n", port); + + Environment env; + + struct MHD_Daemon *d; + d = MHD_start_daemon(flags, port, NULL, NULL, + handle_request_callback, &env, + MHD_OPTION_NOTIFY_COMPLETED, + requestCompletedCallback, NULL, + MHD_OPTION_CONNECTION_LIMIT, Conf::connection_limit, +#ifndef WITHOUT_SSL + MHD_OPTION_HTTPS_MEM_KEY, Conf::ssl_key.c_str(), + MHD_OPTION_HTTPS_MEM_CERT, Conf::ssl_cert.c_str(), +#endif + MHD_OPTION_CONNECTION_TIMEOUT, Conf::connection_timeout, + MHD_OPTION_EXTERNAL_LOGGER, httpderr, NULL, + MHD_OPTION_END); + + if(!d) { + PRACRO_ERR(server, "Failed to initialise MHD_start_daemon!\n"); return; } - - while(pracro_is_running && socket->connected()) { - - { // Reload if new port is assigned. - int old_port = port; - port = Conf::server_port; - - if(port != old_port) { - // Start listening on the new port - delete socket; - socket = new TCPSocket("Listen socket (reloaded)"); - socket->listen(port); - } - } - - TCPSocket *child = socket->accept(); - if(child) { - -#ifndef NON_FORKING - switch(fork()) { - case -1: // error - PRACRO_ERR_LOG(server, "Could not fork: %s\n", strerror(errno)); - break; - - case 0: // child - delete socket; -#endif/*NON_FORKING*/ - handleConnection(child); - delete child; -#ifndef NON_FORKING - return; - - default: // parent - delete child; - break; - } -#endif/*NON_FORKING*/ - + // again: + while(pracro_is_running) sleep(1); + /* + if(!forceshutdown && env.sessions.size() != 0) { + char *errbuf; + if(asprintf(&errbuf, "There are %d live sessions." + " Kill again to force shutdown.\n", + env.sessions.size()) != -1) { + PRACRO_ERR_LOG(server, "%s", errbuf); + log(errbuf); + free(errbuf); } + pracro_is_running = true; + forceshutdown = true; + goto again; } + */ + env.sessions.store(); - //socket->shutdown(); - delete socket; + MHD_stop_daemon(d); PRACRO_DEBUG(server, "Server gracefully shut down.\n"); } @@ -439,10 +206,11 @@ char request[] = int main() { Conf::xml_basedir = "../xml/"; - Conf::server_port = 32100; // Make sure wo don't interrupt an already running server. + // Make sure wo don't interrupt an already running server. + Conf::server_port = 32100; Conf::database_backend = "testdb"; pid_t pid = fork(); - + switch(pid) { case -1: // error perror("fork() failed!\n"); diff --git a/server/src/session.cc b/server/src/session.cc new file mode 100644 index 0000000..803a515 --- /dev/null +++ b/server/src/session.cc @@ -0,0 +1,238 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set et sw=2 ts=2: */ +/*************************************************************************** + * session.cc + * + * Tue Dec 15 13:36:49 CET 2009 + * Copyright 2009 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 "session.h" + +#include + +// for stat +#include +#include +#include +#include + +#include "journalwriter.h" +#include "configuration.h" +#include "connectionpool.h" +#include "sessionserialiser.h" + +Session::Session(std::string sessionid) +{ + _id = sessionid; + _journal = NULL; +} + +Session::~Session() +{ + if(_journal) delete _journal; +} + +std::string Session::id() +{ + return _id; +} + +void Session::lock() +{ + mutex.lock(); +} + +void Session::unlock() +{ + mutex.unlock(); +} + +void Session::commit() +{ + if(_journal != NULL) { + _journal->commit(); + delete _journal; + _journal = NULL; + } +} + +void Session::discard() +{ + if(_journal) { + delete _journal; + _journal = NULL; + } +} + +JournalWriter *Session::journal() +{ + if(_journal == NULL) { + _journal = + new JournalWriter(Conf::journal_commit_addr, Conf::journal_commit_port); + } + return _journal; +} + +Sessions::Sessions() +{ +} + +static bool fexists(const std::string &f) +{ + bool ret; + +/* + struct stat sbuf; + int n = stat(f.c_str(), &sbuf); + if(n != -1) ret = true; + ret = errno != ENOENT; +*/ + + FILE *fp = fopen(f.c_str(), "r"); + ret = fp != NULL; + if(fp) fclose(fp); + + return ret; +} + +Session *Sessions::newSession() +{ + char sessionid[32]; + std::string filename; + do { + snprintf(sessionid, sizeof(sessionid)-1, "%d", rand()); + filename = getSessionFilename(Conf::session_path, sessionid); + } while(sessions.find(sessionid) != sessions.end() || fexists(filename)); + + Session *session = new Session(sessionid); + sessions[session->id()] = session; + return session; +} + +Session *Sessions::session(std::string sessionid) +{ + if(sessions.find(sessionid) != sessions.end()) + return sessions[sessionid]; + + std::string filename = getSessionFilename(Conf::session_path, sessionid); + if(fexists(filename)) { + Session *s = new Session(sessionid); + SessionSerialiser ser(Conf::session_path, s); + ser.load(); + sessions[s->id()] = s; + + fprintf(stderr, "s: %p\n",s); + + return s; + } + + return NULL; +} + +Session *Sessions::takeSession(std::string sessionid) +{ + Session *s = NULL; + if(sessions.find(sessionid) != sessions.end()) { + s = sessions[sessionid]; + } + + if(s) { + sessions.erase(sessionid); + } + + return s; +} + +void Sessions::deleteSession(std::string sessionid) +{ + Session *s = takeSession(sessionid); + if(s) delete s; +} + +size_t Sessions::size() +{ + return sessions.size(); +} + +void Sessions::store() +{ + std::map::iterator i = sessions.begin(); + while(i != sessions.end()) { + SessionSerialiser ser(Conf::session_path, i->second); + ser.save(); + delete i->second; + sessions.erase(i); + i++; + } + sessions.clear(); +} + +SessionAutolock::SessionAutolock(Session &s) + : session(s) +{ + session.lock(); +} + +SessionAutolock::~SessionAutolock() +{ + session.unlock(); +} + +#ifdef TEST_SESSION +//deps: configuration.cc journalwriter.cc journal_commit.cc mutex.cc debug.cc sessionserialiser.cc sessionparser.cc saxparser.cc +//cflags: -I.. $(PTHREAD_CFLAGS) $(EXPAT_CFLAGS) +//libs: $(PTHREAD_LIBS) $(EXPAT_LIBS) +#include + +TEST_BEGIN; +Sessions sessions; + +Conf::session_path = "/tmp"; + +srand(0); // force seed +Session *s1 = sessions.newSession(); +srand(0); // force seed +Session *s2 = sessions.newSession(); + +TEST_NOTEQUAL(s1->id(), s2->id(), "Testing if IDs are unique."); + +TEST_EQUAL(sessions.size(), 2, "Testing if size match."); + +std::string sessionid = s1->id(); +SessionSerialiser ser(Conf::session_path, s1); +ser.save(); + +sessions.deleteSession(sessionid); +TEST_EQUAL(sessions.size(), 1, "Testing if size match."); + +s1 = sessions.session(sessionid); +TEST_NOTEQUAL(s1, NULL, "Did we reload the session from disk?"); + +sessions.store(); +TEST_EQUAL(sessions.size(), 0, "Testing if size match."); + +s1 = sessions.session(sessionid); +TEST_NOTEQUAL(s1, NULL, "Did we reload the session from disk?"); + +TEST_END; + +#endif/*TEST_SESSION*/ diff --git a/server/src/session.h b/server/src/session.h new file mode 100644 index 0000000..6c614c7 --- /dev/null +++ b/server/src/session.h @@ -0,0 +1,109 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set et sw=2 ts=2: */ +/*************************************************************************** + * session.h + * + * Tue Dec 15 13:36:49 CET 2009 + * Copyright 2009 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_SESSION_H__ +#define __PRACRO_SESSION_H__ + +#include +#include + +#include "mutex.h" + +class JournalWriter; + +class Session { +public: + Session(std::string sessionid); + ~Session(); + + std::string id(); + + void lock(); + void unlock(); + + void commit(); + void discard(); + + JournalWriter *journal(); + +private: + JournalWriter *_journal; + std::string _id; + Mutex mutex; +}; + +class Sessions { +public: + Sessions(); + + /** + * Create a new session, with a unique id. Insert it into the session list, + * and return its pointer. + */ + Session *newSession(); + + /** + * Lookup session in session list. Returns the session or NULL if no session + * exists with that sessionid. + */ + Session *session(std::string sessionid); + + /** + * Remove session from the session list and return its pointer. It is up to + * the caller to delete it. + */ + Session *takeSession(std::string sessionid); + + /** + * Remove session from the session list and delete it. + */ + void deleteSession(std::string sessionid); + + /** + * Return number of active sessions. + */ + size_t size(); + + /** + * Write all active sessions to disc. + */ + void store(); + +private: + std::map sessions; +}; + +class SessionAutolock { +public: + SessionAutolock(Session &session); + ~SessionAutolock(); + +private: + Session &session; +}; + +#endif/*__PRACRO_SESSION_H__*/ diff --git a/server/src/sessionparser.cc b/server/src/sessionparser.cc new file mode 100644 index 0000000..ba3693d --- /dev/null +++ b/server/src/sessionparser.cc @@ -0,0 +1,110 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set et sw=2 ts=2: */ +/*************************************************************************** + * sessionparser.cc + * + * Thu May 20 14:30:23 CEST 2010 + * Copyright 2010 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 "sessionparser.h" + +#include "debug.h" + +SessionParser::SessionParser() +{ + done = false; + totalbytes = 0; + inresume = false; +} + +SessionParser::~SessionParser() +{ +} + +void SessionParser::characterData(std::string &data) +{ + if(inresume) { + entries[entries.size()-1].resume += data; + } +} + +void SessionParser::startTag(std::string name, + std::map attributes) +{ + PRACRO_DEBUG(sessionparser, "<%s>\n", name.c_str()); + + if(name == "session") { + sessionid = attributes["id"]; + } + + if(name == "journal") { + patientid = attributes["patientid"]; + userid = attributes["userid"]; + } + + if(name == "entry") { + Entry e; + e.index = atoi(attributes["index"].c_str()); + e.macro = attributes["macro"]; + entries.push_back(e); + } + + if(name == "resume") { + inresume = true; + } +} + +void SessionParser::endTag(std::string name) +{ + if(name == "resume") { + inresume = false; + } +} + +void SessionParser::parseError(const char *buf, size_t len, + std::string error, int lineno) +{ + PRACRO_ERR(sessionnparser, "SessionParser error at line %d: %s\n", + lineno, error.c_str()); + + std::string xml; + xml.append(buf, len); + + PRACRO_ERR(sessionparser, "\tBuffer %u bytes: [%s]\n", + len, xml.c_str()); + + throw std::exception(); +} + +#ifdef TEST_SESSIONPARSER +//deps: +//cflags: +//libs: +#include "test.h" + +TEST_BEGIN; + +#error "Put some testcode here (see test.h for usable macros)." + +TEST_END; + +#endif/*TEST_SESSIONPARSER*/ diff --git a/server/src/sessionparser.h b/server/src/sessionparser.h new file mode 100644 index 0000000..37899aa --- /dev/null +++ b/server/src/sessionparser.h @@ -0,0 +1,64 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set et sw=2 ts=2: */ +/*************************************************************************** + * sessionparser.h + * + * Thu May 20 14:30:23 CEST 2010 + * Copyright 2010 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_SESSIONPARSER_H__ +#define __PRACRO_SESSIONPARSER_H__ + +#include "saxparser.h" + +#include +#include + +class SessionParser : public SAXParser { +public: + SessionParser(); + ~SessionParser(); + + void characterData(std::string &data); + void startTag(std::string name, + std::map< std::string, std::string> attributes); + void endTag(std::string name); + void parseError(const char *buf, size_t len, std::string error, int lineno); + + std::string sessionid; + std::string patientid; + std::string userid; + + class Entry { + public: + int index; + std::string macro; + std::string resume; + }; + + std::vector entries; + +private: + bool inresume; +}; + +#endif/*__PRACRO_SESSIONPARSER_H__*/ diff --git a/server/src/sessionserialiser.cc b/server/src/sessionserialiser.cc new file mode 100644 index 0000000..10d449d --- /dev/null +++ b/server/src/sessionserialiser.cc @@ -0,0 +1,200 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set et sw=2 ts=2: */ +/*************************************************************************** + * sessionserialiser.cc + * + * Thu May 20 11:26:18 CEST 2010 + * Copyright 2010 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 "sessionserialiser.h" + +#include "journalwriter.h" + +#include "sessionparser.h" + +#include +#include + +std::string getSessionFilename(const std::string &path, + const std::string &sessionid) +{ + return path + "/pracro_session." + sessionid; +} + + +static std::string itostr(int i) +{ + char sid[32]; + snprintf(sid, sizeof(sid), "%d", i); + return sid; +} + +SessionSerialiser::SessionSerialiser(std::string path, Session *session) +{ + this->session = session; + this->path = path; +} + +void SessionSerialiser::loadStr(const std::string &xml) +{ + // SessionAutolock lock(*session); + SessionParser parser; + parser.parse(xml.data(), xml.length()); + JournalWriter *j = session->journal(); + j->currentuser = parser.userid; + j->currentcpr = parser.patientid; + std::vector::iterator i = parser.entries.begin(); + while(i != parser.entries.end()) { + j->addEntry(i->resume, i->macro, i->index); + i++; + } +} + +std::string SessionSerialiser::saveStr() +{ + // SessionAutolock lock(*session); + + std::string xml; + + xml += "\n"; + xml += "id()+"\">\n"; + + JournalWriter *journal = session->journal(); + + xml += " currentcpr + + "\" userid=\"" + journal->currentuser + "\">\n"; + + std::map< int, JournalWriter::ResumeEntry >::iterator i = + journal->entrylist.begin(); + while(i != journal->entrylist.end()) { + + xml += " first) + "\"" + " macro=\"" + i->second.macro + "\">\n"; + xml += " " + i->second.resume + "\n"; + xml += " \n"; + + i++; + } + + xml += " \n"; + xml += "\n"; + + return xml; +} + +void SessionSerialiser::load() +{ + // read xml from file + std::string filename = getSessionFilename(path, session->id()); + + FILE *fp = fopen(filename.c_str(), "r"); + char xml[2048]; + memset(xml, 0, sizeof(xml)); + fread(xml, sizeof(xml), 1, fp); + fclose(fp); + + loadStr(xml); + + // delete file + unlink(filename.c_str()); + +} + +void SessionSerialiser::save() +{ + std::string filename = getSessionFilename(path, session->id()); + + std::string xml = saveStr(); + + // write xml to file + FILE *fp = fopen(filename.c_str(), "w"); + fwrite(xml.data(), xml.size(), 1, fp); + fclose(fp); +} + +#ifdef TEST_SESSIONSERIALISER +//deps: session.cc journalwriter.cc debug.cc configuration.cc mutex.cc journal_commit.cc sessionparser.cc saxparser.cc +//cflags: -I.. $(PTHREAD_CFLAGS) $(EXPAT_CFLAGS) +//libs: $(PTHREAD_LIBS) $(EXPAT_LIBS) +#include "test.h" + +#define SID "42" +#define SPATH "/tmp" + +TEST_BEGIN; + +std::string xml; + +{ + Session session(SID); + JournalWriter *j = session.journal(); + j->addEntry("some text", "macro1", 0); + j->addEntry("some more text", "macro2", 2); + j->addEntry("yet some more text", "macro3", 1); + SessionSerialiser s(SPATH, &session); + xml = s.saveStr(); + s.loadStr(xml); + std::string xml2 = s.saveStr(); + TEST_EQUAL_STR(xml, xml2, "Compare"); +} + +{ + Session session(SID); + JournalWriter *j = session.journal(); + j->addEntry("some text", "macro1", 0); + j->addEntry("some more text", "macro2", 2); + j->addEntry("yet some more text", "macro3", 1); + SessionSerialiser s(SPATH, &session); + xml = s.saveStr(); +} + +{ + Session session(SID); + SessionSerialiser s(SPATH, &session); + s.loadStr(xml); + std::string xml2 = s.saveStr(); + TEST_EQUAL_STR(xml, xml2, "Compare"); +} + +{ + Session session(SID); + JournalWriter *j = session.journal(); + j->addEntry("some text", "macro1", 0); + j->addEntry("some more text", "macro2", 2); + j->addEntry("yet some more text", "macro3", 1); + SessionSerialiser s(SPATH, &session); + s.save(); +} + +{ + Session session(SID); + SessionSerialiser s(SPATH, &session); + s.load(); + std::string xml2 = s.saveStr(); + TEST_EQUAL_STR(xml, xml2, "Compare"); +} + + +TEST_END; + +#endif/*TEST_SESSIONSERIALISER*/ diff --git a/server/src/sessionserialiser.h b/server/src/sessionserialiser.h new file mode 100644 index 0000000..4002760 --- /dev/null +++ b/server/src/sessionserialiser.h @@ -0,0 +1,53 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set et sw=2 ts=2: */ +/*************************************************************************** + * sessionserialiser.h + * + * Thu May 20 11:26:18 CEST 2010 + * Copyright 2010 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_SESSIONSERIALISER_H__ +#define __PRACRO_SESSIONSERIALISER_H__ + +#include + +#include "session.h" + +class SessionSerialiser { +public: + SessionSerialiser(std::string path, Session *session); + + void loadStr(const std::string &xml); + std::string saveStr(); + + void load(); + void save(); + +private: + Session *session; + std::string path; +}; + +std::string getSessionFilename(const std::string &path, + const std::string &sessionid); + +#endif/*__PRACRO_SESSIONSERIALISER_H__*/ diff --git a/server/src/tcpsocket.cc b/server/src/tcpsocket.cc index 818934e..f748e0a 100644 --- a/server/src/tcpsocket.cc +++ b/server/src/tcpsocket.cc @@ -90,14 +90,12 @@ TCPSocket::TCPSocket(std::string name, int sock) isconnected = false; this->sock = sock; - PRACRO_DEBUG(socket, "TCPSocket %s: %p %d (%d)\n", name.c_str(), - this, sock, getpid()); + PRACRO_DEBUG(socket, "TCPSocket %s: %p %d (%d)\n", name.c_str(), this, sock, getpid()); } TCPSocket::~TCPSocket() { - PRACRO_DEBUG(socket, "~TCPSocket %s: %p %d (%d)\n", name.c_str(), - this, sock, getpid()); + PRACRO_DEBUG(socket, "~TCPSocket %s: %p %d (%d)\n", name.c_str(), this, sock, getpid()); disconnect(); } @@ -111,7 +109,7 @@ void TCPSocket::listen(unsigned short int port) if(isconnected) throw TCPListenException("Socket alread connected."); struct sockaddr_in socketaddr; - memset((char *) &socketaddr, 0, sizeof(socketaddr)); + memset((char *) &socketaddr, sizeof(socketaddr), 0); socketaddr.sin_family = AF_INET; socketaddr.sin_port = htons(port); socketaddr.sin_addr.s_addr = htonl(INADDR_ANY); @@ -161,32 +159,27 @@ TCPSocket *TCPSocket::accept() } } if(FD_ISSET(sock, &fset)) { - int csock = _accept(sock, (struct sockaddr*)&ssocketaddr, - (socklen_t*)&csalen); + int csock = _accept(sock, (struct sockaddr*)&ssocketaddr, (socklen_t*)&csalen); TCPSocket *child = new TCPSocket(name + "-child", csock); if (child->sock == -1) { - throw TCPAcceptException(std::string("accept failed - ") + - strerror(errno)); + throw TCPAcceptException(std::string("accept failed - ") + strerror(errno)); } child->isconnected = true; return child; } else { - PRACRO_ERR_LOG(socket, "Accept returned with no socket" - " - This should not happen!\n"); + PRACRO_ERR_LOG(socket, "Accept returned with no socket - This should not happen!\n"); return NULL; } } -static int _connect(int sockfd, const struct sockaddr *serv_addr, - socklen_t addrlen) +static int _connect(int sockfd, const struct sockaddr *serv_addr, socklen_t addrlen) {return connect(sockfd, serv_addr, addrlen);} void TCPSocket::connect(std::string addr, unsigned short int port) throw(TCPConnectException) { - if(isconnected) - throw TCPConnectException("Socket already connected.", "", ""); + if(isconnected) throw TCPConnectException("Socket already connected.", "", ""); #ifndef BYPASS_STATICALLOCATIONS // Do DNS lookup @@ -198,8 +191,7 @@ void TCPSocket::connect(std::string addr, unsigned short int port) char portno[32]; sprintf(portno, "%d", port); throw TCPConnectException(addr, portno, - std::string("host lookup failed: ") + - hstrerror(h_errno)); + std::string("host lookup failed: ") + hstrerror(h_errno)); } addr_list = (struct in_addr **)he->h_addr_list; @@ -210,7 +202,7 @@ void TCPSocket::connect(std::string addr, unsigned short int port) #endif/*BYPASS_STATICALLOCATIONS*/ struct sockaddr_in socketaddr; - memset((char *) &socketaddr, 0, sizeof(socketaddr)); + memset((char *) &socketaddr, sizeof(socketaddr), 0); socketaddr.sin_family = AF_INET; socketaddr.sin_port = htons(port); socketaddr.sin_addr.s_addr = inet_addr(ip); @@ -227,8 +219,7 @@ void TCPSocket::connect(std::string addr, unsigned short int port) void TCPSocket::disconnect() { if(sock != -1) { - PRACRO_DEBUG(socket, "Closing TCPSocket %s: %p %d (%d)\n", - name.c_str(), this, sock, getpid()); + PRACRO_DEBUG(socket, "Closing TCPSocket %s: %p %d (%d)\n", name.c_str(), this, sock, getpid()); int ret = close(sock); if(ret == -1) { perror(name.c_str()); @@ -305,8 +296,7 @@ int TCPSocket::read(char *buf, int size, long timeout) return res; } -ssize_t _write(int fd, const void *buf, size_t count) -{ return write(fd, buf, count); } +ssize_t _write(int fd, const void *buf, size_t count) { return write(fd, buf, count); } int TCPSocket::write(char *data, int size) throw(TCPWriteException) { diff --git a/server/src/templatelist.cc b/server/src/templatelist.cc index cdf2b4b..af03586 100644 --- a/server/src/templatelist.cc +++ b/server/src/templatelist.cc @@ -27,80 +27,34 @@ */ #include "templatelist.h" -#include -#include +#include "templateheaderparser.h" #include "debug.h" -#include "templateheaderparser.h" -static std::vector listdir(std::string path) +TemplateList::TemplateList(std::string path) + : EntityList(path, "template") { - std::vector files; - - DIR* dir = opendir(path.c_str()); - if(!dir) { - PRACRO_ERR(dump, "Could not open directory: %s\n", path.c_str()); - return files; - } - - struct dirent *d; - while((d = readdir(dir)) != 0) { - //if(d->d_type == DT_DIR) { - std::string name = d->d_name; - if(name.length() >= 4 && name.substr(name.length() - 4) == ".xml") - files.push_back(name); - //} - } - closedir(dir); - - return files; + rescan(); } -TemplateList::TemplateList(std::string templatepath) +void TemplateList::addFile(std::string file) { - this->templatepath = templatepath; - std::vector templates = listdir(templatepath); - std::vector::iterator i = templates.begin(); - while(i != templates.end()) { - TemplateHeaderParser parser(templatepath + "/" + *i); - try { - parser.parse(); - Template *templ = parser.getTemplate(); - (*this)[templ->attributes["name"]][VersionStr(templ->attributes["version"])] = *i; - } catch(Exception &e) { - PRACRO_WARN(templatelist, "Skipping %s: %s\n", i->c_str(), e.what()); - } - - i++; + if(file.substr(file.size() - 4) != ".xml") { + PRACRO_DEBUG(templatelist, "Skipping file: %s\n", file.c_str()); + return; } - { - iterator i = begin(); - while(i != end()) { - TemplateListItem::iterator j = i->second.begin(); - while(j != i->second.end()) { - PRACRO_DEBUG(templatelist, "%s - v%s file: %s\n", - i->first.c_str(), - ((std::string)j->first).c_str(), - j->second.c_str()); - j++; - } - i++; - } + PRACRO_DEBUG(templatelist, "Adding file: %s\n", file.c_str()); + TemplateHeaderParser parser(file); + try { + parser.parse(); + Template *templ = parser.getTemplate(); + insertEntity(templ->attributes["name"], + templ->attributes["version"], + file); + } catch(Exception &e) { + PRACRO_WARN(templatelist, "Skipping %s: %s\n", file.c_str(), e.what()); } - -} - -std::string TemplateList::getLatestVersion(std::string templ) throw(Exception) -{ - if(find(templ) == end()) throw Exception("Template ["+templ+"] does not exist"); - TemplateListItem mli = (*this)[templ]; - if(mli.size() == 0) return ""; - PRACRO_DEBUG(templatelist, "Search for %s - found %s v%s\n", - templ.c_str(), - (templatepath + "/" + mli.begin()->second).c_str(), - ((std::string)mli.begin()->first).c_str()); - return templatepath + "/" + mli.begin()->second; } #ifdef TEST_TEMPLATELIST diff --git a/server/src/templatelist.h b/server/src/templatelist.h index bcf22f1..ce2d1b3 100644 --- a/server/src/templatelist.h +++ b/server/src/templatelist.h @@ -28,45 +28,14 @@ #ifndef __PRACRO_TEMPLATELIST_H__ #define __PRACRO_TEMPLATELIST_H__ -#include -#include -#include "versionstr.h" +#include "entitylist.h" -#include "exception.h" - -/** - * The Items contained in the TemplateList. - */ -typedef std::map TemplateListItem; - -/** - * The TemplateList class is intended for template file caching, so that all templates - * do not need to be parsed on each template query. - * It builds a list of templates and versions based on the informations read from - * the TemplateHeaderParser. - * This means that just because a template gets into the list doesn't means that it - * will validate as a correct template (not even nessecarily correct XML). - */ -class TemplateList : public std::map { +class TemplateList : public EntityList { public: - /** - * Constructor. - * @param templatepath A std::string containing the path in which we should look - * for xml files. - */ - TemplateList(std::string templatepath); - - /** - * Convenience method, to gain the filename of the latest version of a given template. - * This method throws an Exception if the template does not exist in the tree. - * @param template A std::string containing the name of the wanted template. - * @return A std::string containing the file containing the template with full path - * included. - */ - std::string getLatestVersion(std::string templ) throw(Exception); + TemplateList(std::string path); private: - std::string templatepath; + void addFile(std::string file); }; #endif/*__PRACRO_TEMPLATELIST_H__*/ diff --git a/server/src/transactionhandler.cc b/server/src/transactionhandler.cc new file mode 100644 index 0000000..c9c58b6 --- /dev/null +++ b/server/src/transactionhandler.cc @@ -0,0 +1,287 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set et sw=2 ts=2: */ +/*************************************************************************** + * transactionhandler.cc + * + * Fri Dec 18 10:00:50 CET 2009 + * Copyright 2009 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 "transactionhandler.h" + +#include "macroparser.h" +#include "resumeparser.h" +#include "templateparser.h" +#include "configuration.h" +#include "luaquerymapper.h" +#include "queryhandlerpentominos.h" +#include "queryhandlerpracro.h" +#include "xml_encode_decode.h" +#include "widgetgenerator.h" +#include "journalwriter.h" + +static std::string error_box(std::string message) +{ + std::string errorbox = + "\n" + "\n" + " " + message + "\n" + "\n"; + return errorbox; +} + +static std::string handleCommits(Transaction &transaction, Environment &env, + Session &session) +{ + std::string answer; + + if(transaction.commits.size() > 0) { + AutoBorrower borrower(env.dbpool); + Database *db = borrower.get(); + + Commits::iterator i = transaction.commits.begin(); + while(i != transaction.commits.end()) { + Commit &commit = *i; + + MacroParser mp(env.macrolist.getLatestVersion(commit.macro)); + mp.parse(); + Macro *macro = mp.getMacro(); + + std::string resume = resume_parser(macro->resume, commit); + commit.fields["journal.resume"] = resume; + db->commitTransaction(transaction.user, transaction.cpr, *macro, + commit.fields); + + if(resume != "") { + + TemplateParser tp(env.templatelist.getLatestVersion(commit.templ)); + tp.parse(); + Template *templ = tp.getTemplate(); + + session.journal()->addEntry(transaction, commit, resume, templ); + } + + i++; + } + } + + return answer; +} + +static std::string handleRequest(Transaction &transaction, Environment &env, + Session &session) +{ + std::string answer; + + if(transaction.requests.size() > 0) { + + AutoBorrower borrower(env.dbpool); + Database *db = borrower.get(); + + Requests::iterator i = transaction.requests.begin(); + while(i != transaction.requests.end()) { + Request &request = *i; + + PRACRO_DEBUG(server, "Handling request - macro: %s, template: %s\n", + request.macro.c_str(), request.templ.c_str()); + + // Read and parse the template file. + TemplateParser tp(env.templatelist.getLatestVersion(request.templ)); + tp.parse(); + + Template *templ = tp.getTemplate(); + + answer += " \n"; + + i++; + } + } + + return answer; +} + +std::string handleTransaction(Transaction &transaction, Environment &env, + Session &session) +{ + std::string answer; + + answer += "\n"; + answer += "\n"; + + try { + answer += handleCommits(transaction, env, session); + } catch( std::exception &e ) { + PRACRO_ERR(server, "Commit error: %s\n", e.what()); + return error_box(xml_encode(e.what())); + } + + try { + answer += handleRequest(transaction, env, session); + } catch( std::exception &e ) { + PRACRO_ERR(server, "Request error: %s\n", e.what()); + return error_box(xml_encode(e.what())); + } + + answer += "\n"; + + PRACRO_DEBUG(server, "Done handling transaction\n"); + PRACRO_DEBUG(serverxml, "%s\n", answer.c_str()); + + return answer; +} + +#ifdef TEST_TRANSACTIONHANDLER +//deps: +//cflags: -I.. +//libs: +#include "test.h" + +TEST_BEGIN; + +#error TODO: Put some testcode here (see test.h for usable macros). + +TEST_END; + +#endif/*TEST_TRANSACTIONHANDLER*/ diff --git a/server/src/transactionhandler.h b/server/src/transactionhandler.h new file mode 100644 index 0000000..ae1857c --- /dev/null +++ b/server/src/transactionhandler.h @@ -0,0 +1,45 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set et sw=2 ts=2: */ +/*************************************************************************** + * transactionhandler.h + * + * Fri Dec 18 10:00:50 CET 2009 + * Copyright 2009 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_TRANSACTIONHANDLER_H__ +#define __PRACRO_TRANSACTIONHANDLER_H__ + +#include "transaction.h" +#include "session.h" +#include "environment.h" + +#include "exception.h" + +class NotFoundException : public Exception { +public: + NotFoundException(Request &r) + : Exception("Macro " + r.macro + " not found in template " + r.templ) {} +}; + +std::string handleTransaction(Transaction &transaction, Environment &env, Session &session); + +#endif/*__PRACRO_TRANSACTIONHANDLER_H__*/ diff --git a/server/src/transactionparser.cc b/server/src/transactionparser.cc index f1f79c6..b33cac6 100644 --- a/server/src/transactionparser.cc +++ b/server/src/transactionparser.cc @@ -36,31 +36,6 @@ #include "debug.h" #include "exception.h" -static void error(const char* fmt, ...) -{ - PRACRO_ERR_LOG(transactionparser, "Error in TransactionParser: "); - - { - va_list argp; - va_start(argp, fmt); - PRACRO_ERR_LOG_VA(macro, fmt, argp); - va_end(argp); - - fprintf(stderr, "\n"); - } - - { - char *p; - va_list argp; - va_start(argp, fmt); - if(vasprintf(&p, fmt, argp) != -1) { - throw Exception("Error in TransactionParser: " + std::string(p)); - free(p); - } - va_end(argp); - } -} - TransactionParser::TransactionParser(Transaction *transaction) { this->transaction = transaction; @@ -68,8 +43,11 @@ TransactionParser::TransactionParser(Transaction *transaction) totalbytes = 0; } -void TransactionParser::startTag(std::string name, std::map< std::string, std::string> attributes) +void TransactionParser::startTag(std::string name, + std::map attributes) { + PRACRO_DEBUG(transactionparser, "<%s>\n", name.c_str()); + if(name == "pracro") { transaction->user = attributes["user"]; transaction->cpr = attributes["cpr"]; @@ -92,29 +70,46 @@ void TransactionParser::startTag(std::string name, std::map< std::string, std::s } if(name == "field") { - if(!transaction->commits.size()) error("Field without a commit tag!"); - if(attributes.find("name") == attributes.end()) error("Field is missing 'name' attribute"); - if(attributes.find("value") == attributes.end()) error("Field is missing 'value' attribute"); - transaction->commits.back().fields[attributes["name"]] = attributes["value"]; + if(!transaction->commits.size()) { + PRACRO_ERR(transactionparser, "Field without a commit tag!"); + throw std::exception(); + } + + if(attributes.find("name") == attributes.end()) { + PRACRO_ERR(transactionparser, "Field is missing 'name' attribute"); + throw std::exception(); + } + + if(attributes.find("value") == attributes.end()) { + PRACRO_ERR(transactionparser, "Field is missing 'value' attribute"); + throw std::exception(); + } + + transaction->commits.back().fields[attributes["name"]] = + attributes["value"]; } } -void TransactionParser::parseError(const char *buf, size_t len, std::string error, int lineno) +void TransactionParser::parseError(const char *buf, size_t len, + std::string error, int lineno) { - PRACRO_ERR_LOG(transactionparser, "TransactionParser error at line %d: %s\n", - lineno, error.c_str()); - PRACRO_ERR_LOG(transactionparser, "\tBuffer %u bytes: [", len); - if(fwrite(buf, len, 1, stderr) != len) {} - PRACRO_ERR_LOG(transactionparser, "]\n"); - - char *slineno; - if(asprintf(&slineno, " at line %d\n", lineno) != -1) { - throw Exception(error + slineno); - free(slineno); - } + PRACRO_ERR(transactionparser, "TransactionParser error at line %d: %s\n", + lineno, error.c_str()); + + std::string xml; + xml.append(buf, len); + + PRACRO_ERR(transactionparser, "\tBuffer %u bytes: [%s]\n", + len, xml.c_str()); + + throw std::exception(); } #ifdef TEST_TRANSACTIONPARSER +//deps: saxparser.cc debug.cc exception.cc log.cc +//cflags: -I.. $(EXPAT_CFLAGS) +//libs: $(EXPAT_LIBS) +#include "test.h" static char xml_minimal[] = "\n" @@ -146,53 +141,36 @@ static char xml_fail[] = "\n" ; -int main() -{ - // Test minimal - try { - Transaction transaction; - TransactionParser parser(&transaction); - parser.parse(xml_minimal, strlen(xml_minimal)); - } catch(Exception &e) { - printf("ERROR: %s\n", e.what()); - return 1; - } +TEST_BEGIN; - // Test request - try { - Transaction transaction; - TransactionParser parser(&transaction); - parser.parse(xml_request, strlen(xml_request)); - } catch(Exception &e) { - printf("ERROR: %s\n", e.what()); - return 1; - } - - // Test commit - try { - Transaction transaction; - TransactionParser parser(&transaction); - parser.parse(xml_commit, strlen(xml_commit)); - } catch(Exception &e) { - printf("ERROR: %s\n", e.what()); - return 1; - } +// Test minimal +{ + Transaction transaction; + TransactionParser parser(&transaction); + TEST_NOEXCEPTION(parser.parse(xml_minimal, sizeof(xml_minimal)-1), "minimal"); +} - // Test parse error (should throw an exception) - try { - Transaction transaction; - TransactionParser parser(&transaction); - parser.parse(xml_fail, strlen(xml_fail)); - } catch(Exception &e) { - printf("ERROR: %s\n", e.what()); - goto onandon; - } - printf("We should fail here...\n"); - return 1; +// Test request +{ + Transaction transaction; + TransactionParser parser(&transaction); + TEST_NOEXCEPTION(parser.parse(xml_request, sizeof(xml_request)-1), "request"); +} - onandon: +// Test commit +{ + Transaction transaction; + TransactionParser parser(&transaction); + TEST_NOEXCEPTION(parser.parse(xml_commit, sizeof(xml_commit)-1), "commit"); +} - return 0; +// Test parse error (should throw an exception) +{ + Transaction transaction; + TransactionParser parser(&transaction); + TEST_EXCEPTION(parser.parse(xml_fail, sizeof(xml_fail)-1), std::exception, "parse error"); } +TEST_END; + #endif/*TEST_TRANSACTIONPARSER*/ diff --git a/server/src/widgetgenerator.cc b/server/src/widgetgenerator.cc index 9fdacd2..425c71e 100644 --- a/server/src/widgetgenerator.cc +++ b/server/src/widgetgenerator.cc @@ -40,8 +40,7 @@ static std::string automap(std::string name) if(name[i] == '.') groupcheck += " and " + group; else groupcheck += name[i]; } - groupcheck += " and " + name + ".value and " + name + - ".timestamp and " + name + ".source"; + groupcheck += " and " + name + ".value and " + name + ".timestamp and " + name + ".source"; groupcheck += ")\n"; std::string automapstring = @@ -74,12 +73,9 @@ static std::string send_macro_widget(Macro ¯o, std::string prefilled; time_t timestamp = 0; time_t now = time(NULL); - /* - if(widget.attributes.find("value") != widget.attributes.end()) { - widget.attributes["value"] = ""; - } - */ + result = tabs + "<" + widget.attributes["tagname"]; + std::map< std::string, std::string >::iterator p = widget.attributes.begin(); PRACRO_DEBUG(prefill, "%s: %s\n", widget.attributes["tagname"].c_str(), @@ -113,9 +109,9 @@ static std::string send_macro_widget(Macro ¯o, if(luamap != "") { Value value = mapper.map(luamap); if(value.timestamp > now - Conf::pentominos_max_ttl) { - widget.attributes["value"] = xml_encode(value.value); + widget.attributes["value"] = value.value; timestamp = value.timestamp; - prefilled = xml_encode(value.source); + prefilled = value.source; } PRACRO_DEBUG(prefill, "map: (%s, %d)\n", @@ -141,8 +137,7 @@ static std::string send_macro_widget(Macro ¯o, if(values[widget.attributes["name"]].timestamp > timestamp) { if(values[widget.attributes["name"]].timestamp > now - Conf::db_max_ttl) { - widget.attributes["value"] = - xml_encode(values[widget.attributes["name"]].value); + widget.attributes["value"] = values[widget.attributes["name"]].value; timestamp = values[widget.attributes["name"]].timestamp; prefilled = "pracro"; } @@ -154,7 +149,6 @@ static std::string send_macro_widget(Macro ¯o, widget.attributes["value"].c_str(), (int)timestamp); - std::map< std::string, std::string >::iterator p = widget.attributes.begin(); while(p != widget.attributes.end()) { if(p->first != "tagname" && p->first != "map") { if( ! (p->first == "name" && p->second == "") ) @@ -184,12 +178,9 @@ static std::string send_macro_widget(Macro ¯o, static void get_fields(Widget &widget, Fieldnames &fields) { - // if(widget.attributes.find("value") != widget.attributes.end()) { - if(widget.attributes.find("name") != widget.attributes.end()) { - if(widget.attributes["name"] != "") - fields.push_back(widget.attributes["name"]); + if(widget.attributes.find("value") != widget.attributes.end()) { + if(widget.attributes["name"] != "") fields.push_back(widget.attributes["name"]); } - // } std::vector< Widget >::iterator w = widget.widgets.begin(); while(w != widget.widgets.end()) { @@ -198,8 +189,7 @@ static void get_fields(Widget &widget, Fieldnames &fields) } } -std::string widgetgenerator(std::string cpr, Macro ¯o, - LUAQueryMapper &mapper, Database &db) +std::string widgetgenerator(std::string cpr, Macro ¯o, LUAQueryMapper &mapper, Database &db) { Fieldnames fields; get_fields(macro.widgets, fields); diff --git a/server/xml/macros/cycloplegisk_refraktion-1.0.xml b/server/xml/macros/cycloplegisk_refraktion-1.0.xml index 7c66cf3..cdef363 100644 --- a/server/xml/macros/cycloplegisk_refraktion-1.0.xml +++ b/server/xml/macros/cycloplegisk_refraktion-1.0.xml @@ -35,7 +35,7 @@ return out - + @@ -76,102 +76,6 @@ end return value, timestamp, source - - -- Returning 0, 0 invalidates the result - value = 0 - timestamp = 0 - source = 0 - - if(visutron900plus and visutron900plus.osin and visutron900plus.osin.sph_near and visutron900plus.osin.sph_near.value and visutron900plus.osin.sph_near.timestamp) - then - value = visutron900plus.osin.sph_near.value - -- convert . to , - value = string.gsub(value, '[.]', ',') - timestamp = visutron900plus.osin.sph_near.timestamp - source = visutron900plus.osin.sph_near.source - end - return value, timestamp, source - - - -- Returning 0, 0 invalidates the result - value = 0 - timestamp = 0 - source = 0 - - if(visutron900plus and visutron900plus.osin and visutron900plus.osin.cyl and visutron900plus.osin.cyl.value and visutron900plus.osin.cyl.timestamp) - then - value = visutron900plus.osin.cyl.value - -- convert . to , - value = string.gsub(value, '[.]', ',') - timestamp = visutron900plus.osin.cyl.timestamp - source = visutron900plus.osin.cyl.source - end - return value, timestamp, source - - - -- Returning 0, 0 invalidates the result - value = 0 - timestamp = 0 - source = 0 - - if(visutron900plus and visutron900plus.osin and visutron900plus.osin.axis and visutron900plus.osin.axis.value and visutron900plus.osin.axis.timestamp) - then - value = visutron900plus.osin.axis.value - -- convert . to , - value = string.gsub(value, '[.]', ',') - timestamp = visutron900plus.osin.axis.timestamp - source = visutron900plus.osin.axis.source - end - return value, timestamp, source - - - -- Returning 0, 0 invalidates the result - value = 0 - timestamp = 0 - source = 0 - - if(visutron900plus and visutron900plus.odxt and visutron900plus.odxt.sph_near and visutron900plus.odxt.sph_near.value and visutron900plus.odxt.sph_near.timestamp) - then - value = visutron900plus.odxt.sph_near.value - -- convert . to , - value = string.gsub(value, '[.]', ',') - timestamp = visutron900plus.odxt.sph_near.timestamp - source = visutron900plus.odxt.sph_near.source - end - return value, timestamp, source - - - -- Returning 0, 0 invalidates the result - value = 0 - timestamp = 0 - source = 0 - - if(visutron900plus and visutron900plus.odxt and visutron900plus.odxt.cyl and visutron900plus.odxt.cyl.value and visutron900plus.odxt.cyl.timestamp) - then - value = visutron900plus.odxt.cyl.value - -- convert . to , - value = string.gsub(value, '[.]', ',') - timestamp = visutron900plus.odxt.cyl.timestamp - source = visutron900plus.odxt.cyl.source - end - return value, timestamp, source - - - -- Returning 0, 0 invalidates the result - value = 0 - timestamp = 0 - source = 0 - - if(visutron900plus and visutron900plus.odxt and visutron900plus.odxt.axis and visutron900plus.odxt.axis.value and visutron900plus.odxt.axis.timestamp) - then - value = visutron900plus.odxt.axis.value - -- convert . to , - value = string.gsub(value, '[.]', ',') - timestamp = visutron900plus.odxt.axis.timestamp - source = visutron900plus.odxt.axis.source - end - return value, timestamp, source - - - - @@ -374,12 +280,11 @@ -