From 24e535dbaffb86e6be2ffbbf37084fa0fa80667d Mon Sep 17 00:00:00 2001 From: Aaron Blakely Date: Wed, 6 Mar 2024 02:50:22 -0600 Subject: [PATCH] made lua module use db.c for script list instead of scripts file --- lib/config.h | 3 +- lib/db.h | 23 ++++--- lib/module.h | 3 + mods/lua/lua.c | 167 ++++++++++++++++++++++++++++++++----------------- scripts/t1.lua | 0 src/config.c | 34 ++++++++-- src/db.c | 99 +++++++++++++++++++++++++---- src/main.c | 15 +++-- src/module.c | 11 ++++ test_db.c | 11 +++- testdb | Bin 22944 -> 27600 bytes xbot.db | Bin 151 -> 77 bytes 12 files changed, 274 insertions(+), 92 deletions(-) create mode 100755 scripts/t1.lua mode change 100644 => 100755 xbot.db diff --git a/lib/config.h b/lib/config.h index 5b682a1..e21bbfc 100755 --- a/lib/config.h +++ b/lib/config.h @@ -4,5 +4,6 @@ #include "irc.h" struct irc_conn read_config(struct irc_conn bot, char *file); +void run_autoload(struct irc_conn *bot); -#endif \ No newline at end of file +#endif diff --git a/lib/db.h b/lib/db.h index 3aecbf1..ca686af 100755 --- a/lib/db.h +++ b/lib/db.h @@ -7,7 +7,8 @@ enum db_type { DB_TYPE_CHAR, - DB_TYPE_INT + DB_TYPE_INT, + DB_TYPE_FLOAT }; struct db_hash @@ -29,17 +30,21 @@ struct db_table struct db_hash *hashes; }; -int write_db(struct db_table *db, char *fname); -struct db_table *read_db(char *fname); +int db_write(struct db_table *db, char *fname); +struct db_table *db_read(char *fname); -int db_add_hash(struct db_table *db, char *key, void *value); -int db_add_hash_char(struct db_table *db, char *key, char *value); -int db_add_hash_int(struct db_table *db, char *key, int value); +int db_set_hash(struct db_table *db, char *key, void *value); +int db_set_hash_char(struct db_table *db, char *key, char *value); +int db_set_hash_int(struct db_table *db, char *key, int value); +int db_set_hash_float(struct db_table *db, char *key, float value); int db_del_hash(struct db_table *db, char *key); -void *get_hash(struct db_table *db, char *key); -char *get_hash_char(struct db_table *db, char *key); -int get_hash_int(struct db_table *db, char *key); +void *db_get_hash(struct db_table *db, char *key); +int db_get_hash_type(struct db_table *db, char *key); + +char *db_get_hash_char(struct db_table *db, char *key); +int db_get_hash_int(struct db_table *db, char *key); +float db_get_hash_float(struct db_table *db, char *key); #endif diff --git a/lib/module.h b/lib/module.h index cf6efce..1da0d40 100755 --- a/lib/module.h +++ b/lib/module.h @@ -39,9 +39,12 @@ void load_module(struct irc_conn *bot, char *where, char *stype, char *file); void unload_module(struct irc_conn *bot, char *where, char *file); void list_modules(struct irc_conn *bot, char *where); void set_bot(struct irc_conn *b); +void set_bot_db(struct db_table *db); MY_API void register_module(char *name, char *author, char *version, char *description); MY_API void unregister_module(char *name); MY_API struct mods *get_mods(); MY_API struct irc_conn *get_bot(); +MY_API struct db_table *get_bot_db(); + #endif diff --git a/mods/lua/lua.c b/mods/lua/lua.c index 4faeb86..a8039fb 100755 --- a/mods/lua/lua.c +++ b/mods/lua/lua.c @@ -17,102 +17,106 @@ struct lua_interp lua; struct irc_conn *instance; -char *scriptsfile = "./mods/lua/scripts"; - int append_script(char *fname) { - int i; - FILE *fp; - char *buf = (char *)malloc(sizeof(char *) * 500); + char *scriptlist = db_get_hash_char(get_bot_db(), "lua.scripts"); + char *newlist = (char *)malloc(sizeof(char) * 500); + char *p = scriptlist; - // check if the file is already in the list - struct script_list list = get_scripts(); - - for (i = 0; i < list.count; i++) + if (scriptlist == NULL) { - if (strcmp(list.scripts[i], fname) == 0) - { - free(buf); - return 0; - } + db_set_hash_char(get_bot_db(), "lua.scripts", fname); + db_write(get_bot_db(), instance->db_file); + return 0; } - if ((fp = fopen(scriptsfile, "a")) == NULL) - { - free(buf); - return -1; - } + sprintf(newlist, "%s,%s", scriptlist, fname); + printf("newlist: %s\n", newlist); - sprintf(buf, "%s\n", fname); - fputs(buf, fp); - fclose(fp); + db_set_hash_char(get_bot_db(), "lua.scripts", newlist); + + db_write(get_bot_db(), instance->db_file); + + free(newlist); - free(buf); return 0; } int remove_script(char *fname) { - FILE *fp, *tmp; - char *buf = (char *)malloc(sizeof(char *) * 500); - char *tmpfile = "./mods/lua/scripts.tmp"; + char *scriptlist = db_get_hash_char(get_bot_db(), "lua.scripts"); + char *newlist = (char *)malloc(sizeof(char) * 500); + char *p = scriptlist; + char *q = newlist; + int len = strlen(fname); + int found = 0; - if ((fp = fopen(scriptsfile, "r")) == NULL) + if (scriptlist == NULL) { - free(buf); - return -1; + return 0; } - tmp = fopen(tmpfile, "w"); - - while (fgets(buf, 500, fp) != NULL) + while (*p != '\0') { - if (strcmp(buf, fname) != 0) + if (strncmp(p, fname, len) == 0) { - fputs(buf, tmp); + p = skip(p, ','); + found = 1; + continue; } + + *q = *p; + p++; + q++; } - fclose(fp); - fclose(tmp); + if (found == 0) + { + return 0; + } - remove(scriptsfile); - rename(tmpfile, scriptsfile); + *q = '\0'; + + // remove trailing , if it exists + + if (newlist[strlen(newlist) - 1] == ',') + { + newlist[strlen(newlist) - 1] = '\0'; + } + + db_set_hash_char(get_bot_db(), "lua.scripts", newlist); + db_write(get_bot_db(), instance->db_file); + + free(newlist); - free(buf); return 0; } struct script_list get_scripts() { - FILE *fp; - char *buf = (char *)malloc(sizeof(char *) * 500); - struct script_list list; + char *scriptlist = db_get_hash_char(get_bot_db(), "lua.scripts"); + printf("dbug: scriptlist: %s\n", scriptlist); + + // dbug: scriptlist: hello.lua,test.lua,youtube.lua + + struct script_list list = {0}; + char *p = scriptlist; int i = 0; - if ((fp = fopen(scriptsfile, "r")) == NULL) + if (scriptlist == NULL) { - free(buf); - - list.count = 0; return list; } - while (fgets(buf, 500, fp) != NULL) + while (*p != '\0') { - list.scripts[i] = (char *)malloc(sizeof(char *) * 150); - strlcpy(list.scripts[i], buf, 150); - - // remove newline - list.scripts[i][strlen(list.scripts[i]) - 1] = '\0'; - - + list.scripts[i] = p; + p = skip(p, ','); i++; } list.count = i; - free(buf); return list; } @@ -326,8 +330,10 @@ void mod_init() { int i; char *buf = (char *)malloc(sizeof(char *) * 500); - struct script_list list = get_scripts(); + struct script_list list = {0}; + instance = get_bot(); + list = get_scripts(); lua.scripts = calloc(512, sizeof(struct lua_script)); lua.events = calloc(1024, sizeof(struct lua_event)); @@ -360,9 +366,54 @@ void mod_init() { printf("Loading %s\n", list.scripts[i]); - sprintf(buf, "!load %s", list.scripts[i]); + sprintf(buf, "./scripts/%s", list.scripts[i]); + strlcpy(lua.scripts[lua.script_count].fname, buf, 150); - lua_load_script(instance, "lua", "localhost", "-stdio-", buf); + if (luaL_loadfile(lua.L, buf) != LUA_OK) + { + printf("Error loading lua script: %s\n", lua_tostring(lua.L, -1)); + continue; + } + + // execute the script + if (lua_pcall(lua.L, 0, 0, 0) != LUA_OK) + { + printf("Error executing lua script: %s\n", lua_tostring(lua.L, -1)); + continue; + } + + // get a ref to unload function if it exists and store it with luaL_ref + lua_getglobal(lua.L, "unload"); + + if (lua_isfunction(lua.L, -1)) + { + lua.scripts[lua.script_count].unload = luaL_ref(lua.L, LUA_REGISTRYINDEX); + printf("dbg: unload ref: %d\n", lua.scripts[lua.script_count].unload); + } + else + { + lua.scripts[lua.script_count].unload = -1; + printf("No unload() function in %s\n", list.scripts[i]); + } + + // call the load function if it exists + lua_getglobal(lua.L, "load"); + + if (lua_isfunction(lua.L, -1)) + { + if (lua_pcall(lua.L, 0, 0, 0) != LUA_OK) + { + printf("Error calling load() in %s: %s\n", buf, lua_tostring(lua.L, -1)); + continue; + } + + lua.script_count++; + printf("Loaded %s\n", list.scripts[i]); + } + else + { + printf("Error: No load() function in %s\n", buf); + } } printf("Lua module loaded\n"); diff --git a/scripts/t1.lua b/scripts/t1.lua new file mode 100755 index 0000000..e69de29 diff --git a/src/config.c b/src/config.c index 22698cc..f8b953a 100755 --- a/src/config.c +++ b/src/config.c @@ -44,6 +44,34 @@ struct irc_conn read_config(struct irc_conn bot, char *file) if (config_lookup_string(cf, "bot.db", &base)) strlcpy(bot.db_file, base, sizeof bot.db_file); + config_destroy(cf); + + return bot; +} + +void run_autoload(struct irc_conn *bot) +{ + int count, n; + config_t cfg, *cf; + const config_setting_t *autoload; + const char *base = (const char*)malloc(sizeof(char) * 1024); + const char *mod = NULL; + char *modpath = (char *)malloc(sizeof(char) * 500); + + cf = &cfg; + config_init(cf); + + if (!config_read_file(cf, "xbot.cfg")) + { + printf("[xbot.cfg:%d] Configuration error: %s\n", + config_error_line(cf), + config_error_text(cf) + ); + + config_destroy(cf); + exit(-1); + } + autoload = config_lookup(cf, "mods.autoload"); count = config_setting_length(autoload); @@ -51,14 +79,12 @@ struct irc_conn read_config(struct irc_conn bot, char *file) { mod = config_setting_get_string_elem(autoload, n); #ifdef _WIN32 - sprintf(modpath, "./mods/%s.dll", mod); + sprintf(modpath, "./mods/%s.dll", mod); #else sprintf(modpath, "./mods/%s.so", mod); #endif - load_module(&bot, "main", "runtime", modpath); + load_module(bot, "main", "runtime", modpath); } config_destroy(cf); - - return bot; } diff --git a/src/db.c b/src/db.c index 0c3eeaf..cebfcb0 100755 --- a/src/db.c +++ b/src/db.c @@ -6,7 +6,7 @@ #include #include -int write_db(struct db_table *db, char *fname) +int db_write(struct db_table *db, char *fname) { FILE *fp; int i; @@ -37,7 +37,7 @@ int write_db(struct db_table *db, char *fname) return 0; } -struct db_table *read_db(char *fname) +struct db_table *db_read(char *fname) { FILE *fp; struct db_table *db; @@ -89,15 +89,23 @@ struct db_table *read_db(char *fname) return db; } -int db_add_hash(struct db_table *db, char *key, void *value) +int db_set_hash(struct db_table *db, char *key, void *value) { int i; + // check if the key already exists and update it for (i = 0; i < db->count; i++) { if (strcmp(db->hashes[i].key, key) == 0) { - return -1; + if (db->hashes[i].type == DB_TYPE_CHAR) + { + free(db->hashes[i].value); + } + + db->hashes[i].value = value; + + return 0; } } @@ -115,8 +123,33 @@ int db_add_hash(struct db_table *db, char *key, void *value) return 0; } -int db_add_hash_char(struct db_table *db, char *key, char *value) + +int db_set_hash_char(struct db_table *db, char *key, char *value) { + // check if the key already exists and update it + int i; + + for (i = 0; i < db->count; i++) + { + if (strcmp(db->hashes[i].key, key) == 0) + { + if (db->hashes[i].type == DB_TYPE_CHAR) + { + free(db->hashes[i].value); + } + + db->hashes[i].type = DB_TYPE_CHAR; + db->hashes[i].value_len = strlen(value) + 1; + db->hashes[i].value = (char *)malloc(sizeof(char) * db->hashes[i].value_len); + + memset(db->hashes[i].value, 0, sizeof(char) * db->hashes[i].value_len); + + strlcpy(db->hashes[i].value, value, sizeof(char) * db->hashes[i].value_len); + + return 0; + } + } + db->hashes = (struct db_hash *)realloc(db->hashes, sizeof(struct db_hash) * (db->count + 1)); // zero out reallocated memory @@ -130,10 +163,10 @@ int db_add_hash_char(struct db_table *db, char *key, char *value) strlcpy(db->hashes[db->count].value, value, sizeof(char) * db->hashes[db->count].value_len); - return db_add_hash(db, key, db->hashes[db->count].value); + return db_set_hash(db, key, db->hashes[db->count].value); } -int db_add_hash_int(struct db_table *db, char *key, int value) +int db_set_hash_int(struct db_table *db, char *key, int value) { db->hashes = (struct db_hash *)realloc(db->hashes, sizeof(struct db_hash) * (db->count + 1)); @@ -146,7 +179,23 @@ int db_add_hash_int(struct db_table *db, char *key, int value) memcpy(db->hashes[db->count].value, &value, sizeof(int)); - return db_add_hash(db, key, db->hashes[db->count].value); + return db_set_hash(db, key, db->hashes[db->count].value); +} + +int db_set_hash_float(struct db_table *db, char *key, float value) +{ + db->hashes = (struct db_hash *)realloc(db->hashes, sizeof(struct db_hash) * (db->count + 1)); + + // zero out reallocated memory + memset(&db->hashes[db->count], 0, sizeof(struct db_hash)); + + db->hashes[db->count].type = DB_TYPE_FLOAT; + db->hashes[db->count].value_len = sizeof(float); + db->hashes[db->count].value = (float *)malloc(sizeof(float)); + + memcpy(db->hashes[db->count].value, &value, sizeof(float)); + + return db_set_hash(db, key, db->hashes[db->count].value); } int db_del_hash(struct db_table *db, char *key) @@ -169,7 +218,7 @@ int db_del_hash(struct db_table *db, char *key) return -1; } -void *get_hash(struct db_table *db, char *key) +void *db_get_hash(struct db_table *db, char *key) { int i; @@ -184,16 +233,40 @@ void *get_hash(struct db_table *db, char *key) return NULL; } -char *get_hash_char(struct db_table *db, char *key) +int db_get_hash_type(struct db_table *db, char *key) { - return (char *)get_hash(db, key); + int i; + + for (i = 0; i < db->count; i++) + { + if (strcmp(db->hashes[i].key, key) == 0) + { + return db->hashes[i].type; + } + } + + return -1; } -int get_hash_int(struct db_table *db, char *key) +char *db_get_hash_char(struct db_table *db, char *key) +{ + return (char *)db_get_hash(db, key); +} + +int db_get_hash_int(struct db_table *db, char *key) { int value; - memcpy(&value, get_hash(db, key), sizeof(int)); + memcpy(&value, db_get_hash(db, key), sizeof(int)); + + return value; +} + +float db_get_hash_float(struct db_table *db, char *key) +{ + float value; + + memcpy(&value, db_get_hash(db, key), sizeof(float)); return value; } diff --git a/src/main.c b/src/main.c index ba166b2..95b9a4f 100755 --- a/src/main.c +++ b/src/main.c @@ -46,30 +46,37 @@ int main() last_ping.tv_sec = time(NULL); set_bot(&bot); + init_events(); init_timers(); init_mods(); - // Read the config + bot = read_config(bot, "xbot.cfg"); // check if the db exists, if not, create it if (access(bot.db_file, F_OK) == -1) { - printf("Creating db\n"); + printf("Creating database file: %s\n", bot.db_file); bot.db = (struct db_table *)malloc(sizeof(struct db_table)); memset(bot.db, 0, sizeof(struct db_table)); + set_bot_db(bot.db); bot.db->count = 0; bot.db->hashes = NULL; - write_db(bot.db, bot.db_file); + db_write(bot.db, bot.db_file); } else { - bot.db = read_db(bot.db_file); + printf("Reading database file: %s\n", bot.db_file); + bot.db = db_read(bot.db_file); + set_bot_db(bot.db); } + // run autoload + run_autoload(&bot); + // Connect to the server printf("Connecting to %s...\n", bot.host); diff --git a/src/module.c b/src/module.c index 0696ec6..3c0e315 100755 --- a/src/module.c +++ b/src/module.c @@ -14,6 +14,7 @@ struct mods *mods; struct irc_conn *instance; +struct db_table *dbinstance; void init_mods() { @@ -315,3 +316,13 @@ void set_bot(struct irc_conn *b) { instance = b; } + +void set_bot_db(struct db_table *db) +{ + dbinstance = db; +} + +MY_API struct db_table *get_bot_db() +{ + return dbinstance; +} diff --git a/test_db.c b/test_db.c index df2d54a..3dc4f3f 100755 --- a/test_db.c +++ b/test_db.c @@ -27,8 +27,9 @@ int main() // write some data if db is empty if (db->count == 0) { - db_add_hash_char(db, "lua.scripts", "hello.lua,test.lua,youtube.lua"); - db_add_hash_int(db, "lua.scriptcount", 2); + db_set_hash_char(db, "lua.scripts", "hello.lua,test.lua,youtube.lua"); + db_set_hash_int(db, "lua.scriptcount", 2); + db_set_hash_float(db, "lua.version", 5.1); write_db(db, FNAME); return 0; @@ -40,7 +41,11 @@ int main() { printf("Key: %s, Value: %d\n", db->hashes[i].key, get_hash_int(db, db->hashes[i].key)); } - else + else if (db->hashes[i].type == DB_TYPE_FLOAT) + { + printf("Key: %s, Value: %f\n", db->hashes[i].key, get_hash_float(db, db->hashes[i].key)); + } + else if (db->hashes[i].type == DB_TYPE_CHAR) { printf("Key: %s, Value: %s\n", db->hashes[i].key, get_hash_char(db, db->hashes[i].key)); } diff --git a/testdb b/testdb index 5a58f5a5dc35d6d19908108730f0b13558fe3f23..479996cbdfd0bd57d061ae98dbc44a3181cc0cc8 100755 GIT binary patch delta 6667 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 delta 5870 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 diff --git a/xbot.db b/xbot.db old mode 100644 new mode 100755 index 7c75e0d55567e015ce9b9c2f1f8bb67800a9c802..973d31842f21bd058de3a1c47cc259eba2e2e310 GIT binary patch literal 77 zcmaFAZ|yw+1_lO3AO?XC3nN2ALm3!&fNV~%2!s%r2NB;e2SVqRCh8R@7iAWd6f=~h K7MJJ&1sDL1JQA7! literal 151 zcmaFAZ|yw+1_lNuAO?Ye>7hWtz`z4!%Y#KAgaK5X0ZN1PumCY5RLudX_yQ=MQ<|t( toLrPyP*Tj0k(!f}uLl&-DM>9Z0W&J|OG`?VQbBA6gwo{v(!3I|QvgVnB{Kj3