summaryrefslogtreecommitdiff
path: root/rhnop-server
diff options
context:
space:
mode:
authorChristian Pointner <equinox@helsinki.at>2011-03-30 01:13:17 (GMT)
committerChristian Pointner <equinox@helsinki.at>2011-03-30 01:13:17 (GMT)
commita4f9323b1550715446453c6015a4e2df48f98855 (patch)
tree21c4e2e21dfc5c7fee3a68c4db2a833d777961ea /rhnop-server
parent3af25a5734457ff5aca954b2452cd32d274dbd26 (diff)
moved to new names (rhnop-client and server)
Diffstat (limited to 'rhnop-server')
-rw-r--r--rhnop-server/Makefile91
-rw-r--r--rhnop-server/conf.lua33
-rwxr-xr-xrhnop-server/configure190
-rw-r--r--rhnop-server/l_pipe.c137
-rw-r--r--rhnop-server/l_pipe.h33
-rwxr-xr-xrhnop-server/noprml59
-rw-r--r--rhnop-server/nopsyncd.c165
-rw-r--r--rhnop-server/nopsyncd.conf15
-rw-r--r--rhnop-server/playlog.lua90
-rwxr-xr-xrhnop-server/qlistener.lua89
-rw-r--r--rhnop-server/rddb.lua75
-rwxr-xr-xrhnop-server/tcpserver.lua128
12 files changed, 1105 insertions, 0 deletions
diff --git a/rhnop-server/Makefile b/rhnop-server/Makefile
new file mode 100644
index 0000000..a540d77
--- /dev/null
+++ b/rhnop-server/Makefile
@@ -0,0 +1,91 @@
+##
+## rhnop
+##
+## Copyright (C) 2011 Christian Pointner <equinox@helsinki.at>
+##
+## This file is part of rhnop.
+##
+## rhnop 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 3 of the License, or
+## any later version.
+##
+## rhnop 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 rhnop. If not, see <http://www.gnu.org/licenses/>.
+##
+
+ifneq ($(MAKECMDGOALS),distclean)
+include include.mk
+endif
+
+EXECUTABLE := nopsyncd
+
+C_OBJS := l_pipe.o \
+ nopsyncd.o
+
+C_SRCS := $(C_OBJS:%.o=%.c)
+
+.PHONY: clean distclean install install-bin install-etc uninstall remove purge
+
+all: $(EXECUTABLE)
+
+%.d: %.c
+ @set -e; rm -f $@; \
+ $(CC) -MM $(CFLAGS) $< > $@.$$$$; \
+ sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \
+ rm -f $@.$$$$; echo '(re)building $@'
+
+ifneq ($(MAKECMDGOALS),distclean)
+-include $(C_SRCS:%.c=%.d)
+endif
+
+$(EXECUTABLE): $(C_OBJS)
+ $(CC) $(C_OBJS) -o $@ $(LDFLAGS)
+
+%.o: %.c
+ $(CC) $(CFLAGS) -c $<
+
+strip: $(EXECUTABLE)
+ $(STRIP) -s $(EXECUTABLE)
+
+
+distclean: clean
+ find . -name *.o -exec rm -f {} \;
+ find . -name "*.\~*" -exec rm -rf {} \;
+ rm -f include.mk
+
+clean:
+ rm -f *.o
+ rm -f *.d
+ rm -f *.d.*
+ rm -f $(EXECUTABLE)
+
+INSTALL_TARGETS := install-bin install-etc
+REMOVE_TARGETS := remove-bin remove-etc
+
+install: all $(INSTALL_TARGETS)
+
+install-bin: $(EXECUTABLE)
+ $(INSTALL) -d $(DESTDIR)$(BINDIR)
+ $(INSTALL) -m 755 $(EXECUTABLE) $(DESTDIR)$(BINDIR)
+
+install-etc:
+ $(INSTALL) -d $(DESTDIR)$(ETCDIR)/$(EXECUTABLE)
+
+uninstall: remove
+
+remove: $(REMOVE_TARGETS)
+
+remove-bin:
+ rm -f $(DESTDIR)$(BINDIR)/$(EXECUTABLE)
+
+remove-etc:
+ rm -f $(DESTDIR)$(ETCDIR)/init.d/$(EXECUTABLE)
+
+purge: remove
+ rm -rf $(DESTDIR)$(ETCDIR)/$(EXECUTABLE)/
diff --git a/rhnop-server/conf.lua b/rhnop-server/conf.lua
new file mode 100644
index 0000000..83257b5
--- /dev/null
+++ b/rhnop-server/conf.lua
@@ -0,0 +1,33 @@
+--
+-- rhnop
+--
+-- Copyright (C) 2011 Christian Pointner <equinox@helsinki.at>
+--
+-- This file is part of rhnop.
+--
+-- rhnop 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 3 of the License, or
+-- any later version.
+--
+-- rhnop 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 rhnop. If not, see <http://www.gnu.org/licenses/>.
+--
+
+local conf = {}
+
+local file = assert(io.open("nopsyncd.conf", "r"))
+for line in file:lines() do
+ local k,v = string.match(line, "^([^=#]+)=(.*)$")
+ if k and v and v ~= "" then
+ conf[k] = v
+ end
+end
+file:close()
+
+return conf
diff --git a/rhnop-server/configure b/rhnop-server/configure
new file mode 100755
index 0000000..30145f2
--- /dev/null
+++ b/rhnop-server/configure
@@ -0,0 +1,190 @@
+#!/bin/sh
+#
+# rhnop
+#
+# Copyright (C) 2011 Christian Pointner <equinox@helsinki.at>
+#
+# This file is part of rhnop.
+#
+# rhnop 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 3 of the License, or
+# any later version.
+#
+# rhnop 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 rhnop. If not, see <http://www.gnu.org/licenses/>.
+#
+
+TARGET=`uname -s`
+EBUILD_COMPAT=0
+
+CFLAGS='-g -O2'
+LDFLAGS='-g -Wall -O2 -lpthread'
+
+LUA_DIR=''
+LUA=''
+
+PREFIX='/usr/local'
+BINDIR=''
+ETCDIR=''
+
+print_usage() {
+ echo "configure --help print this"
+ echo " --target=<TARGET> build target i.e. Linux (default: autodetect)"
+ echo " --prefix=<PREFIX> the installation prefix (default: /usr/local)"
+ echo " --bindir=<DIR> the path to the bin directory (default: $PREFIX/bin)"
+ echo " --sysconfdir=<DIR> the path to the system configuration directory (default: $PREFIX/etc)"
+ echo " --with-lua=<DIR> use this lua tree instead of system default"
+}
+
+for arg
+do
+ case $arg in
+ --target=*)
+ TARGET=${arg#--target=}
+ ;;
+ --prefix=*)
+ PREFIX=${arg#--prefix=}
+ ;;
+ --bindir=*)
+ BINDIR=${arg#--bindir=}
+ ;;
+ --sysconfdir=*)
+ ETCDIR=${arg#--sysconfdir=}
+ ;;
+ --with-lua=*)
+ LUA_DIR=${arg#--with-lua=}
+ ;;
+ --ebuild-compat)
+ EBUILD_COMPAT=1
+ ;;
+ --help)
+ print_usage
+ exit 0
+ ;;
+ *)
+ ERRORS="$ERRORS $arg"
+ ;;
+ esac
+done
+
+if [ -n "$ERRORS" ] && [ $EBUILD_COMPAT -ne 1 ]; then
+ for error in $ERRORS; do
+ echo "Unknown argument: $error"
+ done
+
+ print_usage
+ exit 1
+fi
+
+rm -f include.mk
+case $TARGET in
+ Linux)
+ LDFLAGS=$LDFLAGS' -ldl'
+ ;;
+ *)
+ echo "platform not supported"
+ exit 1;
+ ;;
+esac
+
+
+test_lua_version()
+{
+ LUA_VERSION=`cat $1 | grep "#define LUA_VERSION[ ]" | cut -f2- | tr -d '"' | sed -e 's/Lua \([0-9][0-9.]*\)/\1/'`
+ LUA_VERSION_NUM=`cat $1 | grep "#define LUA_VERSION_NUM" | awk '{ print $3 }'`
+ LUA_RELEASE=`cat $1 | grep "#define LUA_RELEASE[ ]" | cut -f2-`
+
+ if [ $LUA_VERSION_NUM -ge 501 ]; then
+ return 1;
+ else
+ return 0;
+ fi
+}
+
+if [ -z "$LUA_DIR" ]; then
+ for prefix in /usr /usr/local; do
+ if [ -e $prefix/include/lua.h ]; then
+ test_lua_version $prefix/include/lua.h
+ if [ $? -eq 1 ]; then
+ echo "using Lua $LUA_VERSION ($LUA_RELEASE) found at $prefix/include"
+ CFLAGS="$CFLAGS -I'$prefix/include'"
+ LDFLAGS="$LDFLAGS -L'$prefix/lib' -llua"
+ LUA=$prefix/lua
+ LUAC=$prefix/luac
+ break
+ fi
+ else
+ for dir in `ls -d $prefix/include/lua* 2> /dev/null`; do
+ if [ -e $dir/lua.h ]; then
+ test_lua_version $dir/lua.h
+ if [ $? -eq 1 ]; then
+ echo "using Lua $LUA_VERSION ($LUA_RELEASE) found at $dir"
+ CFLAGS="$CFLAGS -I$dir"
+ if [ -x "$prefix/bin/lua$LUA_VERSION" ]; then
+ LDFLAGS="$LDFLAGS -L'$prefix/lib' -llua$LUA_VERSION"
+ LUA=$prefix/bin/lua$LUA_VERSION
+ LUAC=$prefix/bin/luac$LUA_VERSION
+ elif [ -x "$prefix/bin/lua-$LUA_VERSION" ]; then
+ LDFLAGS="$LDFLAGS -L'$prefix/lib' -llua-$LUA_VERSION"
+ LUA=$prefix/bin/lua-$LUA_VERSION
+ LUAC=$prefix/bin/luac-$LUA_VERSION
+ else
+ echo "ERROR: found lua.h at $dir/lua.h but no matching lua and luac"
+ return 1
+ fi
+ break
+ fi
+ fi
+ done
+ if [ -n "$LUAC" ]; then
+ break
+ fi
+ fi
+ done
+
+ if [ -z "$LUAC" ]; then
+ echo "ERROR: no suitable lua found .. please install lua 5.1 or higher or use --with-lua"
+ return 1
+ fi
+
+else
+ CFLAGS="$CFLAGS -I'$LUA_DIR/include'"
+ LDFLAGS="$LDFLAGS '$LUA_DIR/lib/liblua.a'"
+ LUA=$LUA_DIR/bin/lua
+ LUAC=$LUA_DIR/bin/luac
+fi
+
+if [ -z "$BINDIR" ]; then
+ BINDIR=$PREFIX/bin
+fi
+
+if [ -z "$ETCDIR" ]; then
+ ETCDIR=$PREFIX/etc
+fi
+
+cat > include.mk <<EOF
+# this file was created automatically
+# do not edit this file directly
+# use ./configure instead
+
+TARGET := '$TARGET'
+CC := gcc
+CFLAGS := $CFLAGS
+LDFLAGS := $LDFLAGS
+LUA := '$LUA'
+LUAC := '$LUAC'
+STRIP := strip
+INSTALL := install
+
+PREFIX := '$PREFIX'
+BINDIR := '$BINDIR'
+ETCDIR := '$ETCDIR'
+EOF
+
+exit 0
diff --git a/rhnop-server/l_pipe.c b/rhnop-server/l_pipe.c
new file mode 100644
index 0000000..6b769a5
--- /dev/null
+++ b/rhnop-server/l_pipe.c
@@ -0,0 +1,137 @@
+/*
+ * rhnop
+ *
+ * Copyright (C) 2011 Christian Pointner <equinox@helsinki.at>
+ *
+ * This file is part of rhnop.
+ *
+ * rhnop 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 3 of the License, or
+ * any later version.
+ *
+ * rhnop 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 rhnop. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <lua.h>
+#include <lauxlib.h>
+
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+
+#include "l_pipe.h"
+
+static int pipefds_[2];
+
+int pipe_init()
+{
+ return pipe(pipefds_);
+}
+
+void pipe_close()
+{
+ close(pipefds_[0]);
+ close(pipefds_[1]);
+}
+
+static int l_pipe_signal(lua_State *L)
+{
+ size_t len = 0, written = 0;
+ const char* data = luaL_checklstring(L, 1, &len);
+ len++; // also send trailing zero
+
+ int ret = 0;
+ for(;;) {
+ ret = write(pipefds_[1], &(data[written]), len - written);
+ if(!ret) continue;
+ if(ret == -1 && (errno == EAGAIN || errno == EINTR)) continue;
+
+ written += ret;
+ if(written == len) break;
+
+ break;
+ }
+
+ lua_pushinteger(L, ret);
+ return 1;
+}
+
+static int l_pipe_getfd(lua_State *L)
+{
+ if(!lua_istable(L, -1))
+ luaL_error(L, "can't retreive pipe fd");
+
+ lua_pushliteral(L, "fd");
+ lua_gettable(L, -2);
+ return 1;
+}
+
+static int l_pipe_dirty(lua_State *L)
+{
+ lua_pushboolean(L, 0);
+ return 1;
+}
+
+static int l_pipe_getreadfd(lua_State *L)
+{
+ lua_newtable(L);
+ lua_pushliteral(L, "fd");
+ lua_pushinteger(L, pipefds_[0]);
+ lua_settable(L, -3);
+ lua_pushliteral(L, "getfd");
+ lua_pushcfunction(L, l_pipe_getfd);
+ lua_settable(L, -3);
+ lua_pushliteral(L, "dirty");
+ lua_pushcfunction(L, l_pipe_dirty);
+ lua_settable(L, -3);
+ return 1;
+}
+
+static int l_pipe_consume(lua_State *L)
+{
+ char data[17]; // 17 should be sufficient
+ size_t len = 0;
+
+ int ret = 0;
+ for(;;) {
+ ret = read(pipefds_[0], &(data[len]), 1);
+ if(ret == 0) break;
+ if(ret == -1 && (errno == EAGAIN || errno == EINTR)) continue;
+
+ if(data[len] == 0)
+ break;
+
+ len += ret;
+ if(len >= sizeof(data)) {
+ ret = 0;
+ break;
+ }
+ }
+
+ if(ret)
+ lua_pushstring(L, data);
+ else
+ lua_pushnil(L);
+
+ return 1;
+}
+
+static const struct luaL_reg pipe_funcs [] = {
+ { "signal", l_pipe_signal },
+ { "getreadfd", l_pipe_getreadfd },
+ { "consume", l_pipe_consume },
+ { NULL, NULL }
+};
+
+LUALIB_API int luaopen_pipe(lua_State *L)
+{
+ luaL_register(L, LUA_PIPELIBNAME, pipe_funcs);
+ return 1;
+}
diff --git a/rhnop-server/l_pipe.h b/rhnop-server/l_pipe.h
new file mode 100644
index 0000000..b67244b
--- /dev/null
+++ b/rhnop-server/l_pipe.h
@@ -0,0 +1,33 @@
+/*
+ * rhnop
+ *
+ * Copyright (C) 2011 Christian Pointner <equinox@helsinki.at>
+ *
+ * This file is part of rhnop.
+ *
+ * rhnop 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 3 of the License, or
+ * any later version.
+ *
+ * rhnop 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 rhnop. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef NOPSYNCD_l_pipe_h_INCLUDED
+#define NOPSYNCD_l_pipe_h_INCLUDED
+
+#include <lua.h>
+
+int pipe_init();
+void pipe_close();
+
+#define LUA_PIPELIBNAME "pipe"
+LUALIB_API int luaopen_pipe(lua_State *L);
+
+#endif
diff --git a/rhnop-server/noprml b/rhnop-server/noprml
new file mode 100755
index 0000000..31e8ab7
--- /dev/null
+++ b/rhnop-server/noprml
@@ -0,0 +1,59 @@
+#!/usr/bin/lua
+--
+-- rhnop
+--
+-- Copyright (C) 2011 Christian Pointner <equinox@helsinki.at>
+--
+-- This file is part of rhnop.
+--
+-- rhnop 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 3 of the License, or
+-- any later version.
+--
+-- rhnop 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 rhnop. If not, see <http://www.gnu.org/licenses/>.
+--
+--
+-- send now and next cart# and length to nopsyncd
+-- this script should be called by the now/next macro cart
+-- the arguments should be: now# nowlen next# nextlen
+--
+
+local queue_name = "/rhnop"
+
+mq = require "mq"
+
+-- reading timestamp (milliseconds since epoch)
+local p = assert(io.popen("/bin/date --utc '+%s %N'" , 'r'))
+local time = assert(p:read('*l'))
+p:close()
+local s, ns = assert(string.match(time, "([0-9]+) ([0-9]+)"))
+local timestamp = s*1000 + math.floor(ns/1000000)
+
+-- check arguments
+if #arg < 4 then
+ io.stderr:write("too few parameters\n")
+ os.exit(1)
+end
+
+-- open message queue
+local q, err = mq.create(queue_name, "wo")
+if q == nil then
+ io.stderr:write("creation of message queue failed: " .. err .. "\n")
+ os.exit(1)
+end
+
+-- send out message to nopsyncd
+local result, err = mq.send(q, timestamp .. " " .. arg[1] .. " " .. arg[2] .. " " .. arg[3] .. " " .. arg[4], 0)
+if result == nil then
+ io.stderr:write("sending message failed: " .. err .. "\n")
+ os.exit(2)
+end
+
+mq.close(q)
diff --git a/rhnop-server/nopsyncd.c b/rhnop-server/nopsyncd.c
new file mode 100644
index 0000000..63bef7f
--- /dev/null
+++ b/rhnop-server/nopsyncd.c
@@ -0,0 +1,165 @@
+/*
+ * rhnop
+ *
+ * Copyright (C) 2011 Christian Pointner <equinox@helsinki.at>
+ *
+ * This file is part of rhnop.
+ *
+ * rhnop 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 3 of the License, or
+ * any later version.
+ *
+ * rhnop 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 rhnop. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <pthread.h>
+
+#include <lua.h>
+#include <lualib.h>
+#include <lauxlib.h>
+
+#include "l_pipe.h"
+
+#define LUA_MAIN_LOOP_FUNC "main_loop"
+
+static const luaL_Reg nopsyncd_lualibs[] = {
+ {"", luaopen_base},
+ {LUA_LOADLIBNAME, luaopen_package},
+ {LUA_TABLIBNAME, luaopen_table},
+ {LUA_STRLIBNAME, luaopen_string},
+ {LUA_MATHLIBNAME, luaopen_math},
+ {LUA_MATHLIBNAME, luaopen_io},
+ {LUA_MATHLIBNAME, luaopen_os},
+ {LUA_MATHLIBNAME, luaopen_pipe},
+ {NULL, NULL}
+};
+
+int init_main_loop(lua_State *L, const char* filename)
+{
+ const luaL_Reg *lib = nopsyncd_lualibs;
+ for (; lib->func; lib++) {
+ lua_pushcfunction(L, lib->func);
+ lua_pushstring(L, lib->name);
+ lua_call(L, 1, 0);
+ }
+
+ int ret = luaL_loadfile(L, filename);
+ if(ret) {
+ const char* err_str = luaL_checkstring(L, -1);
+ switch(ret) {
+ case LUA_ERRSYNTAX: fprintf(stderr, "luaL_loadfile() syntax error: %s\n", err_str); break;
+ case LUA_ERRMEM: fprintf(stderr, "luaL_loadfile() malloc error: %s\n", err_str); break;
+ case LUA_ERRFILE: fprintf(stderr, "lauL_loadfile() error: %s\n", err_str); break;
+ default: fprintf(stderr, "luaL_loadfile() unknown error: %s\n", err_str); break;
+ }
+ return -1;
+ }
+
+ ret = lua_pcall(L, 0, 0, 0);
+ if(ret) {
+ const char* err_str = luaL_checkstring(L, -1);
+ switch(ret) {
+ case LUA_ERRRUN: fprintf(stderr, "lua_pcall() runtime error: %s\n", err_str); break;
+ case LUA_ERRMEM: fprintf(stderr, "lua_pcall() malloc error: %s\n", err_str); break;
+ case LUA_ERRERR: fprintf(stderr, "lua_pcall() error at error handler function: %s\n", err_str); break;
+ }
+ return -1;
+ }
+
+ return 0;
+}
+
+int call_main_loop(lua_State* L, const char* filename)
+{
+ lua_getglobal(L, LUA_MAIN_LOOP_FUNC);
+ if(!lua_isfunction(L, -1)) {
+ fprintf(stderr, "there is no function '%s' at file '%s'\n", LUA_MAIN_LOOP_FUNC, filename);
+ return -1;
+ };
+
+ int ret = lua_pcall(L, 0, 1, 0);
+ if(ret) {
+ const char* err_str = luaL_checkstring(L, -1);
+ switch(ret) {
+ case LUA_ERRRUN: fprintf(stderr, "lua_pcall(%s:%s) runtime error: %s\n", filename, LUA_MAIN_LOOP_FUNC, err_str); break;
+ case LUA_ERRMEM: fprintf(stderr, "lua_pcall(%s:%s) malloc error: %s\n", filename, LUA_MAIN_LOOP_FUNC, err_str); break;
+ case LUA_ERRERR: fprintf(stderr, "lua_pcall(%s:%s) error at error handler function: %s\n", filename, LUA_MAIN_LOOP_FUNC, err_str); break;
+ }
+ return -1;
+ }
+
+ ret = lua_tointeger(L, 1);
+ return ret;
+}
+
+void* main_loop(void* file)
+{
+ if(!file)
+ pthread_exit(NULL);
+
+
+ lua_State *L;
+ L = luaL_newstate();
+ if(!L) {
+ fprintf(stderr, "error creating lua state\n");
+ pthread_exit(NULL);
+ }
+
+ int ret = init_main_loop(L, (char*)file);
+ if(!ret)
+ ret = call_main_loop(L, (char*)file);
+
+ printf("%s returned with %d\n", (char*)file, ret);
+
+ lua_close(L);
+
+ /* this should bring down the other thread as well
+ at least this is true for the tcp-server thread */
+ pipe_close();
+
+ pthread_exit(NULL);
+}
+
+int main(int argc, char* argv[])
+{
+ printf("starting nopsyncd...\n");
+
+ pthread_t qlistener, tcpserver;
+
+ int ret = pipe_init();
+ if(ret) {
+ fprintf(stderr, "Error creating pipe: %s\n", strerror(errno));
+ return 1;
+ }
+
+ ret = pthread_create(&qlistener, NULL, main_loop, "qlistener.lua");
+ if(ret) {
+ fprintf(stderr, "Error creating qlistener thread (code: %d)\n", ret);
+ return 1;
+ }
+ pthread_detach(qlistener); /* can't kill this thread so don't join to it */
+
+ ret = pthread_create(&tcpserver, NULL, main_loop, "tcpserver.lua");
+ if(ret) {
+ fprintf(stderr, "Error creating qlistener thread (code: %d)\n", ret);
+ return 1;
+ }
+
+/* this thread can't be cancelled so don't wait for it */
+/* pthread_join(qlistener, NULL); */
+ pthread_join(tcpserver, NULL);
+
+ printf("stopping nopsyncd.\n");
+ return 0;
+}
diff --git a/rhnop-server/nopsyncd.conf b/rhnop-server/nopsyncd.conf
new file mode 100644
index 0000000..0338cb6
--- /dev/null
+++ b/rhnop-server/nopsyncd.conf
@@ -0,0 +1,15 @@
+queue_name=/rhnop
+tcp_host=*
+tcp_port=2345
+
+rddb_db=rivendell
+rddb_host=127.0.0.1
+#rddb_port=3306
+rddb_user=
+rddb_pwd=
+
+playlog_db=rhnop
+playlog_host=127.0.0.1
+#playlog_port=3306
+playlog_user=
+playlog_pwd=
diff --git a/rhnop-server/playlog.lua b/rhnop-server/playlog.lua
new file mode 100644
index 0000000..37b9ea6
--- /dev/null
+++ b/rhnop-server/playlog.lua
@@ -0,0 +1,90 @@
+--
+-- rhnop
+--
+-- Copyright (C) 2011 Christian Pointner <equinox@helsinki.at>
+--
+-- This file is part of rhnop.
+--
+-- rhnop 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 3 of the License, or
+-- any later version.
+--
+-- rhnop 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 rhnop. If not, see <http://www.gnu.org/licenses/>.
+--
+
+require "luasql.mysql"
+
+-- CREATE DATABASE rhnop
+-- GRANT select,insert,update ON rhnop.* TO 'nopsyncd' IDENTIFIED BY '123456';
+-- CREATE TABLE IF NOT EXISTS now (timestamp VARCHAR(16) PRIMARY KEY NOT NULL, cart INT NOT NULL, len INT, showtitle VARCHAR(255), title VARCHAR(255), artist VARCHAR(255), album VARCHAR(255), ismusic BOOLEAN)
+
+conf = require "conf"
+
+local playlog = {}
+
+function playlog:init()
+ local err
+
+ self.env, err = luasql.mysql()
+ if self.env == nil then
+ return nil, err
+ end
+
+ self.con, err = self.env:connect(conf.playlog_db, conf.playlog_user, conf.playlog_pwd, conf.playlog_host, conf.playlog_port)
+ if self.con == nil then
+ return nil, err
+ end
+
+ local ret, err = self.con:setautocommit(true)
+ if ret == nil then
+ return nil, err
+ end
+
+ return true
+end
+
+function playlog:getLastCart()
+ local cur, err = self.con:execute("SELECT cart FROM now WHERE timestamp = (SELECT MAX(timestamp) FROM now)")
+ if cur == nil then
+ return nil, err
+ end
+
+ local cart = cur:fetch()
+ if cart == nil then cart = 0 end
+ return cart
+end
+
+function playlog:insertNowMusic(timestamp, cart, len, title, artist, album)
+ cart = tonumber(cart)
+ len = tonumber(len)
+ if cart < 400000 or cart > 450000 then
+ poolnum = 0
+ else
+ poolnum = math.floor(cart/1000) - 399
+ end
+ local cur, err = self.con:execute("INSERT into now VALUES(" .. self.con:escape(timestamp) .. ", " .. cart .. ", " .. len .. ", 'Musikpool " .. poolnum .. "', '" .. self.con:escape(title) .. "', '" .. self.con:escape(artist) .."', '" .. self.con:escape(album) .. "', 1)")
+ if cur == nil then
+ return nil, err
+ end
+
+ return true
+end
+
+function playlog:close()
+ if self.con then
+ self.con:close()
+ end
+
+ if self.env then
+ self.env:close()
+ end
+end
+
+return playlog
diff --git a/rhnop-server/qlistener.lua b/rhnop-server/qlistener.lua
new file mode 100755
index 0000000..8f2c0e2
--- /dev/null
+++ b/rhnop-server/qlistener.lua
@@ -0,0 +1,89 @@
+--
+-- rhnop
+--
+-- Copyright (C) 2011 Christian Pointner <equinox@helsinki.at>
+--
+-- This file is part of rhnop.
+--
+-- rhnop 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 3 of the License, or
+-- any later version.
+--
+-- rhnop 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 rhnop. If not, see <http://www.gnu.org/licenses/>.
+--
+
+local last_cart = nil
+
+mq = require "mq"
+playlog = require "playlog"
+rddb = require "rddb"
+conf = require "conf"
+
+function handle_now(timestamp, nowcart, nowlen)
+ local results, err = rddb:getCartInfo(nowcart);
+ if results == nil then
+ io.stderr:write("can't fetch cart info: " .. err .. "\n")
+ else
+-- print(timestamp .. " Info: '" .. results.TITLE .. "' von '" .. results.ARTIST .. "' aus '" .. results.ALBUM .. "'")
+ local ret, err = playlog:insertNowMusic(timestamp, nowcart, nowlen, results.TITLE, results.ARTIST, results.ALBUM)
+ if ret == nil then
+ io.stderr:write("can't insert music info: " .. err .. "\n")
+ else
+ pipe.signal(timestamp)
+ end
+ end
+end
+
+function handle_message(msg)
+ local timestamp, nowcart, nowlen, nextcart, nextlen = string.match(msg, "^(%d+) (%d+) (%d+) (%d+) (%d+)$");
+ if not timestamp or not nowcart or not nowlen or not nextcart or not nextlen then
+ io.stderr:write("ignoring malformed message\n")
+ else
+ -- TODO better sanity checks: is now info new or just next?
+ if last_cart ~= nowcart then
+ last_cart = nowcart
+ handle_now(timestamp, nowcart, nowlen)
+ end
+ -- TODO handle next info
+ end
+end
+
+function main_loop()
+ local q, err = mq.create(conf.queue_name, "ro")
+ if q == nil then
+ io.stderr:write("creation of message queue failed: " .. err .. "\n")
+ os.exit(1)
+ end
+
+ local ret, err = playlog:init()
+ if ret == nil then
+ io.stderr:write("creation of playlog failed: " .. err .. "\n")
+ os.exit(1)
+ end
+ last_cart = assert(playlog:getLastCart())
+
+ local ret, err = rddb:init()
+ if ret == nil then
+ io.stderr:write("opening rivendell db failed: " .. err .. "\n")
+ playlog:close()
+ os.exit(1)
+ end
+
+ while true do
+ local msg, prio = mq.receive(q)
+ if msg == nil then
+ io.stderr:write("recv error: " .. prio .. "\n")
+ rddb:close()
+ playlog:close()
+ os.exit(2)
+ end
+ handle_message(msg)
+ end
+end \ No newline at end of file
diff --git a/rhnop-server/rddb.lua b/rhnop-server/rddb.lua
new file mode 100644
index 0000000..c8037a9
--- /dev/null
+++ b/rhnop-server/rddb.lua
@@ -0,0 +1,75 @@
+--
+-- rhnop
+--
+-- Copyright (C) 2011 Christian Pointner <equinox@helsinki.at>
+--
+-- This file is part of rhnop.
+--
+-- rhnop 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 3 of the License, or
+-- any later version.
+--
+-- rhnop 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 rhnop. If not, see <http://www.gnu.org/licenses/>.
+--
+
+require "luasql.mysql"
+
+conf = require "conf"
+
+local rddb = {}
+
+function rddb:init()
+ local err
+
+ self.env, err = luasql.mysql()
+ if self.env == nil then
+ return nil, err
+ end
+
+ self.con, err = self.env:connect(conf.rddb_db, conf.rddb_user, conf.rddb_pwd, conf.rddb_host, conf.rddb_port)
+ if self.con == nil then
+ return nil, err
+ end
+
+ return true
+end
+
+function rddb:getCartInfo(cartnum)
+ local cur, err = self.con:execute("select TITLE,ARTIST,ALBUM from CART where NUMBER = " .. self.con:escape(cartnum));
+ if cur == nil then
+ return nil, err
+ end
+
+ if cur:numrows() ~= 1 then
+ return nil, "nothing found in rivendell db"
+ end
+
+ local results = {}
+ results, err = cur:fetch(results, "a")
+ cur:close()
+
+ if results.TITLE == nil then results.TITLE = "" end
+ if results.ARTIST == nil then results.ARTIST = "" end
+ if results.ALBUM == nil then results.ALBUM = "" end
+
+ return results, err
+end
+
+function rddb:close()
+ if self.con then
+ self.con:close()
+ end
+
+ if self.env then
+ self.env:close()
+ end
+end
+
+return rddb
diff --git a/rhnop-server/tcpserver.lua b/rhnop-server/tcpserver.lua
new file mode 100755
index 0000000..bd945b6
--- /dev/null
+++ b/rhnop-server/tcpserver.lua
@@ -0,0 +1,128 @@
+--
+-- rhnop
+--
+-- Copyright (C) 2011 Christian Pointner <equinox@helsinki.at>
+--
+-- This file is part of rhnop.
+--
+-- rhnop 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 3 of the License, or
+-- any later version.
+--
+-- rhnop 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 rhnop. If not, see <http://www.gnu.org/licenses/>.
+--
+
+require "socket"
+
+conf = require "conf"
+
+function init_server()
+ local server = assert(socket.tcp())
+
+ assert(server:setoption('reuseaddr', true))
+ assert(server:bind(conf.tcp_host, conf.tcp_port))
+ assert(server:listen(5))
+
+ return server
+end
+
+local clients = {}
+
+function add_client(hdl)
+ -- print("new client(" .. hdl:getfd() .. ") from " .. hdl:getpeername())
+ local client = {}
+ client.buffer = ""
+ client.hdl = hdl
+ client.getfd = function() return hdl:getfd() end
+ client.dirty = function() return hdl:dirty() end
+ table.insert(clients, client)
+end
+
+function remove_client(c)
+ local idx = 0
+ for idx, client in ipairs(clients) do
+ if client == c then
+ break
+ end
+ end
+
+ -- print("removing client(" .. c.hdl:getfd() .. ")")
+ c.hdl:close()
+ table.remove(clients, idx)
+end
+
+function cleanup_clients()
+ for _, client in ipairs(clients) do
+ client:close()
+ end
+end
+
+function clients_get_writeables()
+ local fds = {}
+
+ for _, client in ipairs(clients) do
+ if client.buffer ~= "" then
+ table.insert(fds, client)
+ end
+ end
+
+ return fds
+end
+
+function clients_senddata(timestamp)
+ for _, client in ipairs(clients) do
+ client.buffer = client.buffer .. timestamp .. "\n"
+ end
+end
+
+function main_loop()
+ local pipefd = pipe.getreadfd()
+
+ server = init_server()
+ while true do
+ local readables, writeables, err = socket.select({ pipefd , server , unpack(clients) } , clients_get_writeables())
+ if err then
+ print("select returned with error: " .. err)
+ return -1
+ else
+ for _, input in ipairs(readables) do
+ if input == pipefd then
+ local timestamp = pipe.consume()
+ if timestamp == nil then
+ return 2
+ end
+ -- print("pipe was signaled with timestamp: " .. timestamp)
+ clients_senddata(timestamp)
+ elseif input == server then
+ local client = assert(server:accept())
+ add_client(client)
+ else
+ if input.hdl then
+ -- receive is insanely stupid, therefore we must always read one byte only
+ local _, err = input.hdl:receive(1)
+ if err then
+ remove_client(input)
+ end
+ end
+ end
+ end
+
+ for _, output in ipairs(writeables) do
+ local ret = assert(output.hdl:send(output.buffer))
+ output.buffer = string.sub(output.buffer, ret+1)
+ end
+ end
+ end
+
+ server:close()
+ cleanup_clients()
+
+ return 0
+end