mirror of
https://github.com/tuxbox-neutrino/neutrino.git
synced 2025-08-27 15:32:59 +02:00
lua: implement "luaclient".
This allows for starting Lua scripts in neutrino context from the command line. Experimental, not fully regression-tested.
This commit is contained in:
@@ -140,6 +140,9 @@ TUXBOX_APPS_DIRECTORY_ONE(libdir,LIBDIR,libdir,/lib,/tuxbox,
|
||||
TUXBOX_APPS_DIRECTORY_ONE(plugindir,PLUGINDIR,libdir,/lib,/tuxbox/plugins,
|
||||
[--with-plugindir=PATH ],[where to find the plugins])
|
||||
|
||||
TUXBOX_APPS_DIRECTORY_ONE(luaplugindir,LUAPLUGINDIR,libdir,/lib,/tuxbox/luaplugins,
|
||||
[--with-luaplugindir=PATH ],[where to find Lua plugins])
|
||||
|
||||
TUXBOX_APPS_DIRECTORY_ONE(ucodedir,UCODEDIR,localstatedir,/var,/tuxbox/ucodes,
|
||||
[--with-ucodedir=PATH ],[where to find the ucodes])
|
||||
|
||||
@@ -167,6 +170,7 @@ AC_SUBST(GAMESDIR)
|
||||
AC_SUBST(LIBDIR)
|
||||
AC_SUBST(MNTDIR)
|
||||
AC_SUBST(PLUGINDIR)
|
||||
AC_SUBST(LUAPLUGINDIR)
|
||||
AC_SUBST(UCODEDIR)
|
||||
AC_SUBST(THEMESDIR)
|
||||
AC_SUBST(ICONSDIR)
|
||||
|
@@ -246,6 +246,7 @@ lib/libtuxtxt/Makefile
|
||||
lib/libdvbsub/Makefile
|
||||
lib/libupnpclient/Makefile
|
||||
lib/libiw/Makefile
|
||||
lib/luaclient/Makefile
|
||||
src/lcddisplay/Makefile
|
||||
src/nhttpd/Makefile
|
||||
src/nhttpd/web/Makefile
|
||||
|
@@ -9,7 +9,8 @@ SUBDIRS = \
|
||||
xmltree \
|
||||
libtuxtxt \
|
||||
libiw \
|
||||
libdvbsub
|
||||
libdvbsub \
|
||||
luaclient
|
||||
|
||||
if ENABLE_UPNP
|
||||
SUBDIRS += \
|
||||
|
13
lib/luaclient/Makefile.am
Normal file
13
lib/luaclient/Makefile.am
Normal file
@@ -0,0 +1,13 @@
|
||||
AM_CPPFLAGS = \
|
||||
-I$(top_srcdir)/lib \
|
||||
-I$(top_srcdir)/src \
|
||||
-I$(top_srcdir)/lib/luaclient \
|
||||
-I$(top_srcdir)/lib/connection
|
||||
|
||||
AM_CPPFLAGS += -fno-rtti -fno-exceptions
|
||||
|
||||
bin_PROGRAMS = luaclient
|
||||
|
||||
luaclient_SOURCES = luaclient.cpp
|
||||
luaclient_LDADD = \
|
||||
$(top_builddir)/lib/connection/libtuxbox-connection.a
|
110
lib/luaclient/luaclient.cpp
Normal file
110
lib/luaclient/luaclient.cpp
Normal file
@@ -0,0 +1,110 @@
|
||||
/*
|
||||
(C)2014 by martii
|
||||
|
||||
License: GPL
|
||||
|
||||
This program 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.
|
||||
|
||||
This program 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 this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <basicclient.h>
|
||||
|
||||
#include <luaclient.h>
|
||||
|
||||
|
||||
class CLuaClient : private CBasicClient
|
||||
{
|
||||
private:
|
||||
unsigned char getVersion () const { return LUACLIENT_VERSION; };
|
||||
const char * getSocketName() const { return LUACLIENT_UDS_NAME; };
|
||||
public:
|
||||
bool Send(const char *data, const size_t size) { return send(0, data, size);}
|
||||
bool Recv(char *data, const size_t size) { return receive_data(data, size, true); }
|
||||
~CLuaClient() { close_connection(); }
|
||||
};
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
char *cmd = strrchr(argv[0], '/');
|
||||
if (cmd)
|
||||
cmd++;
|
||||
else
|
||||
cmd = argv[0];
|
||||
if (!strcmp(cmd, "luaclient"))
|
||||
argv++, argc--;
|
||||
|
||||
if (!*argv) {
|
||||
fprintf(stderr,
|
||||
"Usage: luaclient [command [arguments ...]]\n"
|
||||
" or: command [arguments ...] (with command being a link to luaclient)\n");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
size_t len[argc];
|
||||
size_t size = 0;
|
||||
for (int i = 0; i < argc; i++) {
|
||||
len[i] = strlen(argv[i]) + 1;
|
||||
size += len[i];
|
||||
}
|
||||
|
||||
char data[size + sizeof(size)];
|
||||
char *b = data;
|
||||
memcpy(b, &size, sizeof(size));
|
||||
size += sizeof(size);
|
||||
b += sizeof(size);
|
||||
for (int i = 0; i < argc; i++) {
|
||||
memcpy(b, argv[i], len[i]);
|
||||
b += len[i];
|
||||
}
|
||||
|
||||
CLuaClient client;
|
||||
int res = -1;
|
||||
const char *fun = NULL;
|
||||
char *resp = NULL;
|
||||
|
||||
if (!client.Send(data, size)) {
|
||||
fun = "Send failed";
|
||||
goto fail;
|
||||
}
|
||||
if (!client.Recv((char *)&size, sizeof(size))) {
|
||||
fun = "Recv (1) failed";
|
||||
goto fail;
|
||||
}
|
||||
char result[size];
|
||||
if (!client.Recv(result, size)) {
|
||||
fun = "Recv (2) failed";
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (result[size - 1]) {
|
||||
fun = "unterminated result";
|
||||
goto fail;
|
||||
}
|
||||
res = atoi(result);
|
||||
resp = result + strlen(result) + 1;
|
||||
if (resp < result + size)
|
||||
printf("%s", resp);
|
||||
resp += strlen(resp) + 1;
|
||||
if (resp < result + size)
|
||||
fprintf(stderr, "%s", resp);
|
||||
exit(res);
|
||||
fail:
|
||||
if (fun)
|
||||
fprintf(stderr, "luaclient: %s.\n", fun);
|
||||
exit(-1);
|
||||
}
|
25
lib/luaclient/luaclient.h
Normal file
25
lib/luaclient/luaclient.h
Normal file
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
(C)2014 by martii
|
||||
|
||||
License: GPL
|
||||
|
||||
This program 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.
|
||||
|
||||
This program 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 this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#ifndef __LUACLIENT__H__
|
||||
#define __LUACLIENT__H__
|
||||
#define LUACLIENT_UDS_NAME "/tmp/luaclient.sock"
|
||||
#define LUACLIENT_VERSION 1
|
||||
#endif
|
@@ -24,15 +24,20 @@
|
||||
#include <unistd.h>
|
||||
|
||||
#include <global.h>
|
||||
#include <system/debug.h>
|
||||
#include <system/helpers.h>
|
||||
#include <system/settings.h>
|
||||
#include <system/set_threadname.h>
|
||||
#include <gui/widget/msgbox.h>
|
||||
#include <gui/widget/messagebox.h>
|
||||
#include <gui/filebrowser.h>
|
||||
#include <gui/movieplayer.h>
|
||||
#include <driver/pictureviewer/pictureviewer.h>
|
||||
#include <neutrino.h>
|
||||
#include <system/debug.h>
|
||||
#include <luaclient/luaclient.h>
|
||||
#include <connection/basicserver.h>
|
||||
#include <list>
|
||||
|
||||
#include "luainstance.h"
|
||||
#include <video.h>
|
||||
|
||||
@@ -2471,3 +2476,170 @@ int CLuaInstance::LuaConfigFileDelete(lua_State *L)
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------
|
||||
|
||||
#if 0
|
||||
For testing try:
|
||||
|
||||
cat <<EOT > /lib/tuxbox/luaplugins/test.lua
|
||||
for i,v in ipairs(arg) do
|
||||
print(tostring(i) .. "\t" .. tostring(v))
|
||||
end
|
||||
return "ok"
|
||||
EOT
|
||||
|
||||
followed by luaclient test a b c d
|
||||
#endif
|
||||
class luaserver_data
|
||||
{
|
||||
public:
|
||||
int fd;
|
||||
std::vector<std::string> argv;
|
||||
std::string script;
|
||||
|
||||
luaserver_data(int _fd, std::string &_script) {
|
||||
fd = dup(_fd);
|
||||
fcntl(fd, F_SETFD, FD_CLOEXEC);
|
||||
script = _script;
|
||||
}
|
||||
~luaserver_data(void) {
|
||||
close(fd);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
static int luaserver_count = 0;
|
||||
static pthread_mutex_t luaserver_mutex;
|
||||
|
||||
static void luaserver_lock(void)
|
||||
{
|
||||
pthread_mutex_lock(&luaserver_mutex);
|
||||
}
|
||||
|
||||
static void luaserver_unlock(void)
|
||||
{
|
||||
pthread_mutex_unlock(&luaserver_mutex);
|
||||
}
|
||||
|
||||
static void *luaserver_thread(void *arg) {
|
||||
set_threadname(__func__);
|
||||
luaserver_lock();
|
||||
luaserver_count++;
|
||||
luaserver_unlock();
|
||||
sem_post(&CNeutrinoApp::getInstance()->lua_did_run);
|
||||
|
||||
luaserver_data *lsd = (class luaserver_data *)arg;
|
||||
|
||||
CLuaInstance lua;
|
||||
std::string result_code;
|
||||
std::string result_string;
|
||||
std::string error_string;
|
||||
lua.runScript(lsd->script.c_str(), &lsd->argv, &result_code, &result_string, &error_string);
|
||||
size_t result_code_len = result_code.length() + 1;
|
||||
size_t result_string_len = result_string.length() + 1;
|
||||
size_t error_string_len = error_string.length() + 1;
|
||||
size_t size = result_code_len + result_string_len + error_string_len;
|
||||
char result[size + sizeof(size)];
|
||||
char *rp = result;
|
||||
memcpy(rp, &size, sizeof(size));
|
||||
rp += sizeof(size);
|
||||
size += sizeof(size);
|
||||
memcpy(rp, result_code.c_str(), result_code_len);
|
||||
rp += result_code_len;
|
||||
memcpy(rp, result_string.c_str(), result_string_len);
|
||||
rp += result_string_len;
|
||||
memcpy(rp, error_string.c_str(), error_string_len);
|
||||
rp += error_string_len;
|
||||
CBasicServer::send_data(lsd->fd, result, size);
|
||||
|
||||
delete lsd;
|
||||
luaserver_lock();
|
||||
luaserver_count--;
|
||||
if (!luaserver_count)
|
||||
sem_post(&CNeutrinoApp::getInstance()->lua_may_run);
|
||||
luaserver_unlock();
|
||||
pthread_exit(NULL);
|
||||
}
|
||||
|
||||
static bool luaserver_parse_command(CBasicMessage::Header &rmsg __attribute__((unused)), int connfd)
|
||||
{
|
||||
size_t size;
|
||||
|
||||
if (!CBasicServer::receive_data(connfd, &size, sizeof(size))) {
|
||||
fprintf(stderr, "%s %s %d: receive_data failed\n", __FILE__, __func__, __LINE__);
|
||||
return true;
|
||||
}
|
||||
char data[size];
|
||||
if (!CBasicServer::receive_data(connfd, data, size)) {
|
||||
fprintf(stderr, "%s %s %d: receive_data failed\n", __FILE__, __func__, __LINE__);
|
||||
return true;
|
||||
}
|
||||
if (data[size - 1]) {
|
||||
fprintf(stderr, "%s %s %d: unterminated string\n", __FILE__, __func__, __LINE__);
|
||||
return true;
|
||||
}
|
||||
std::string luascript(LUAPLUGINDIR "/");
|
||||
luascript += data;
|
||||
luascript += ".lua";
|
||||
if (access(luascript, R_OK)) {
|
||||
fprintf(stderr, "%s %s %d: %s not found\n", __FILE__, __func__, __LINE__, luascript.c_str());
|
||||
const char *result_code = "-1";
|
||||
const char *result_string = "";
|
||||
std::string error_string = luascript + " not found\n";
|
||||
size_t result_code_len = strlen(result_code) + 1;
|
||||
size_t result_string_len = strlen(result_string) + 1;
|
||||
size_t error_string_len = strlen(error_string.c_str()) + 1;
|
||||
size = result_code_len + result_string_len + error_string_len;
|
||||
char result[size + sizeof(size)];
|
||||
char *rp = result;
|
||||
memcpy(rp, &size, sizeof(size));
|
||||
rp += sizeof(size);
|
||||
size += sizeof(size);
|
||||
memcpy(rp, result_code, result_code_len);
|
||||
rp += result_code_len;
|
||||
memcpy(rp, result_string, result_string_len);
|
||||
rp += result_string_len;
|
||||
memcpy(rp, error_string.c_str(), error_string_len);
|
||||
rp += error_string_len;
|
||||
CBasicServer::send_data(connfd, result, size);
|
||||
return true;
|
||||
}
|
||||
luaserver_data *lsd = new luaserver_data(connfd, luascript);
|
||||
char *datap = data;
|
||||
while (size > 0) {
|
||||
lsd->argv.push_back(std::string(datap));
|
||||
size_t len = strlen(datap) + 1;
|
||||
datap += len;
|
||||
size -= len;
|
||||
}
|
||||
|
||||
luaserver_lock();
|
||||
if (!luaserver_count)
|
||||
sem_wait(&CNeutrinoApp::getInstance()->lua_may_run);
|
||||
luaserver_unlock();
|
||||
|
||||
pthread_t thr;
|
||||
pthread_create (&thr, NULL, luaserver_thread, (void *) lsd);
|
||||
pthread_detach(thr);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void *luaserver_main_thread(void *) {
|
||||
set_threadname(__func__);
|
||||
|
||||
CBasicServer server;
|
||||
if (!server.prepare(LUACLIENT_UDS_NAME)) {
|
||||
fprintf(stderr, "%s %s %d: prepare failed\n", __FILE__, __func__, __LINE__);
|
||||
pthread_exit(NULL);
|
||||
}
|
||||
|
||||
pthread_mutexattr_t attr;
|
||||
pthread_mutexattr_init(&attr);
|
||||
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK_NP);
|
||||
pthread_mutex_init(&luaserver_mutex, &attr);
|
||||
|
||||
server.run(luaserver_parse_command, LUACLIENT_VERSION);
|
||||
pthread_exit(NULL);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------
|
||||
|
@@ -149,6 +149,8 @@ static bool timerd_thread_started = false;
|
||||
|
||||
void * nhttpd_main_thread(void *data);
|
||||
|
||||
void * luaserver_main_thread(void *data);
|
||||
|
||||
//#define DISABLE_SECTIONSD
|
||||
|
||||
extern cVideo * videoDecoder;
|
||||
@@ -1947,6 +1949,10 @@ TIMER_START();
|
||||
if (!pthread_create (&nhttpd_thread, NULL, nhttpd_main_thread, (void *) NULL))
|
||||
pthread_detach (nhttpd_thread);
|
||||
|
||||
pthread_t luaserver_thread;
|
||||
pthread_create (&luaserver_thread, NULL, luaserver_main_thread, (void *) NULL);
|
||||
pthread_detach(luaserver_thread);
|
||||
|
||||
CStreamManager::getInstance()->Start();
|
||||
|
||||
#ifndef DISABLE_SECTIONSD
|
||||
@@ -2106,8 +2112,19 @@ void CNeutrinoApp::RealRun(CMenuWidget &mainMenu)
|
||||
|
||||
//cCA::GetInstance()->Ready(true);
|
||||
|
||||
sem_init(&lua_may_run, 0, 0);
|
||||
sem_init(&lua_did_run, 0, 0);
|
||||
|
||||
while( true ) {
|
||||
sem_post(&lua_may_run);
|
||||
g_RCInput->getMsg(&msg, &data, 100, ((g_settings.mode_left_right_key_tv == SNeutrinoSettings::VOLUME) && (g_RemoteControl->subChannels.size() < 1)) ? true : false); // 10 secs..
|
||||
sem_wait(&lua_may_run);
|
||||
if (!sem_trywait(&lua_did_run)) {
|
||||
if (msg != CRCInput::RC_timeout)
|
||||
g_RCInput->postMsg(msg, data);
|
||||
while (!sem_trywait(&lua_did_run));
|
||||
continue;
|
||||
}
|
||||
|
||||
if( ( mode == mode_tv ) || ( mode == mode_radio ) || ( mode == mode_webtv ) ) {
|
||||
if( (msg == NeutrinoMessages::SHOW_EPG) /* || (msg == CRCInput::RC_info) */ ) {
|
||||
@@ -4295,6 +4312,11 @@ void CNeutrinoApp::Cleanup()
|
||||
delete CEitManager::getInstance();
|
||||
printf("cleanup 6\n");fflush(stdout);
|
||||
delete CVFD::getInstance();
|
||||
|
||||
// FIXME -- wait for luaserver threads to terminate?
|
||||
sem_destroy(&lua_may_run);
|
||||
sem_destroy(&lua_did_run);
|
||||
|
||||
#ifdef __UCLIBC__
|
||||
malloc_stats(NULL);
|
||||
#else
|
||||
|
@@ -34,6 +34,7 @@
|
||||
#define __neutrino__
|
||||
|
||||
#include <configfile.h>
|
||||
#include <semaphore.h>
|
||||
|
||||
#include <neutrinoMessages.h>
|
||||
#include "driver/framebuffer.h"
|
||||
@@ -172,6 +173,9 @@ public:
|
||||
CChannelList *RADIOchannelList;
|
||||
CChannelList *channelList;
|
||||
|
||||
sem_t lua_may_run;
|
||||
sem_t lua_did_run;
|
||||
|
||||
static CNeutrinoApp* getInstance();
|
||||
|
||||
void channelsInit(bool bOnly = false);
|
||||
|
Reference in New Issue
Block a user