Parsee/src/Main.c
LDA 3ceae7b053 I honestly don't know what to call it.
It's not a 0.2 release, btw.
2024-09-26 19:07:46 +02:00

290 lines
8.3 KiB
C

#include <Cytoplasm/HttpServer.h>
#include <Cytoplasm/Cytoplasm.h>
#include <Cytoplasm/Memory.h>
#include <Cytoplasm/Util.h>
#include <Cytoplasm/Cron.h>
#include <Cytoplasm/Args.h>
#include <Cytoplasm/Log.h>
#include <Cytoplasm/Str.h>
#include <pthread.h>
#include <string.h>
#include <signal.h>
#include <stdlib.h>
#include <Unistring.h>
#include <Parsee.h>
#include <XMPP.h>
#include <AS.h>
static HttpServer *server = NULL;
static pthread_t xmpp_thr;
static XMPPComponent *jabber = NULL;
static volatile uint64_t start;
uint64_t
ParseeUptime(void)
{
return UtilTsMillis() - start;
}
static const Argument arguments[] =
{
#define Arg(c, req, vdesc, desc) \
{ \
.end = false, \
.argument = c, .value_req = req, \
.value_descr = vdesc, \
.description = desc \
},
#define EndOfArgs { .end = true }
Arg('H', true, "number(=8)", "Sets the number of HTTP threads")
Arg('J', true, "number(=8)", "Sets the number of XMPP threads")
Arg('C', true, "file(='parsee.json')", "Sets the JSON config to use")
Arg('g', false, NULL,
"Generates a parsee.yaml AS file before exiting")
Arg('v', false, NULL,
"Forces Parsee to print in a more verbose fashion "
"(-vvv prints stanzas to stderr)")
Arg('h', false, NULL,
"Generates an help screen(this one!)")
EndOfArgs
#undef EndOfArgs
#undef Argument
};
int
Main(Array *args, HashMap *env)
{
HttpServerConfig conf;
const ParseeConfig *parsee_conf;
Stream *yaml;
Cron *cron = NULL;
char *configuration = "parsee.json";
int xmpp = 8;
int http = 8;
int verbose = 0;
start = UtilTsMillis();
memset(&conf, 0, sizeof(conf));
Log(LOG_INFO,
"%s - v%s[%s] (Cytoplasm %s)",
NAME, VERSION, CODE, CytoplasmGetVersionStr()
);
ParseePrintASCII();
Log(LOG_INFO, "=======================");
Log(LOG_INFO, "(C)opyright 2023 LDA");
Log(LOG_INFO, "(This program is free software, see LICENSE.)");
LogConfigIndent(LogConfigGlobal());
{
ArgParseState state;
char *opts = ParseeGenerateGetopt(arguments);
int flag;
ArgParseStateInit(&state);
while ((flag = ArgParse(&state, args, opts)) != -1)
{
switch (flag)
{
case 'h':
ParseeGenerateHelp(arguments);
Free(opts);
goto end;
case 'H':
http = strtol(state.optArg, NULL, 10);
break;
case 'J':
xmpp = strtol(state.optArg, NULL, 10);
break;
case 'g':
/* Write out the config file to a YAML document */
Log(LOG_INFO, "Generating YAML...");
yaml = StreamOpen("parsee.yaml", "w");
ParseeExportConfigYAML(yaml);
StreamClose(yaml);
Free(opts);
goto end;
case 'v':
switch (++verbose)
{
case PARSEE_VERBOSE_LOG:
LogConfigLevelSet(LogConfigGlobal(), LOG_DEBUG);
break;
case PARSEE_VERBOSE_TIMINGS:
Log(LOG_DEBUG, "Logging bench information.");
break;
case PARSEE_VERBOSE_STANZA:
Log(LOG_DEBUG, "Enabling stanza printing.");
break;
case PARSEE_VERBOSE_COMICAL:
Log(LOG_DEBUG, "What?");
Log(LOG_DEBUG, "No, but like, what do you except?");
Log(LOG_DEBUG, "Like do you want to log _every_ instruction?");
Log(LOG_DEBUG, "Like just every single thing %s does?", NAME);
Log(LOG_DEBUG, " ( why??? )");
Log(LOG_DEBUG, ".....................................");
Log(LOG_DEBUG, "Argh.");
Log(LOG_DEBUG, "Alright. I'll do my best.");
Log(LOG_DEBUG, "Get what you paid for.");
break;
}
break;
case 'C':
if (!UtilLastModified(state.optArg))
{
Log(LOG_ERR, "Invalid config: %s", state.optArg);
Log(LOG_ERR, "Ignoring.");
break;
}
configuration = state.optArg;
break;
case '?':
Log(LOG_ERR, "INVALID ARGUMENT GIVEN");
Free(opts);
goto end;
}
}
Free(opts);
ParseeSetThreads(xmpp, http);
}
if (verbose >= PARSEE_VERBOSE_COMICAL)
{
Log(LOG_DEBUG, "Loading configuration...");
}
ParseeConfigLoad(configuration);
ParseeConfigInit();
parsee_conf = ParseeConfigGet();
if (!parsee_conf)
{
goto end;
}
Log(LOG_NOTICE, "Connecting to XMPP...");
jabber = XMPPInitialiseCompStream(
parsee_conf->component_host,
parsee_conf->component_port
);
if (!XMPPAuthenticateCompStream(
jabber,
parsee_conf->shared_comp_secret
))
{
Log(LOG_ERR, "Could not connect to XMPP...");
if (verbose >= PARSEE_VERBOSE_COMICAL)
{
Log(LOG_DEBUG, "Destroying component...");
}
XMPPEndCompStream(jabber);
goto end;
}
Log(LOG_NOTICE, "Creating volatile tables...");
if (verbose >= PARSEE_VERBOSE_COMICAL)
{
Log(LOG_DEBUG, "Initialising JID table");
}
ParseeInitialiseJIDTable();
if (verbose >= PARSEE_VERBOSE_COMICAL)
{
Log(LOG_DEBUG, "Initialising OID table");
}
ParseeInitialiseOIDTable();
if (verbose >= PARSEE_VERBOSE_COMICAL)
{
Log(LOG_DEBUG, "Initialising head table");
}
ParseeInitialiseHeadTable();
if (verbose >= PARSEE_VERBOSE_COMICAL)
{
Log(LOG_DEBUG, "Initialising nick table");
}
ParseeInitialiseNickTable();
conf.port = parsee_conf->port;
conf.threads = parsee_conf->http_threads;
conf.maxConnections = conf.threads << 2;
conf.handlerArgs = ParseeInitData(jabber);
conf.handler = ParseeRequest;
if (!conf.handlerArgs)
{
goto end;
}
Log(LOG_DEBUG, "Verbosity level: %d", verbose);
((ParseeData *) conf.handlerArgs)->verbosity = verbose;
Log(LOG_NOTICE, "Setting up local Matrix user...");
if (ASRegisterUser(parsee_conf, parsee_conf->sender_localpart))
{
char *parsee = ParseeMXID(conf.handlerArgs);
/* TODO: An hardcoded avatar like this sucks. */
ASSetAvatar(parsee_conf,
parsee,
"mxc://tedomum.net/"
"7e228734ec8e792960bb5633e43f0cb845f709f61825130490034651136"
);
ASSetName(parsee_conf, parsee, "Parsee bridge");
Free(parsee);
}
Log(LOG_NOTICE, "Starting up local cronjobs...");
cron = CronCreate(10 SECONDS);
CronEvery(cron, 5 MINUTES, ParseeCleanup, conf.handlerArgs);
ParseeCleanup(conf.handlerArgs);
CronStart(cron);
Log(LOG_NOTICE, "Creating XMPP listener thread...");
if (pthread_create(&xmpp_thr, NULL, ParseeXMPPThread, conf.handlerArgs))
{
Log(LOG_ERR, "Couldn't start XMPP listener thread.");
goto end;
}
server = HttpServerCreate(&conf);
if (!ParseeInitialiseSignals(server, xmpp_thr, jabber))
{
goto end;
}
HttpServerStart(server);
Log(LOG_NOTICE, "Listening to MUCs...");
LogConfigIndent(LogConfigGlobal());
ParseeSendPresence(conf.handlerArgs);
LogConfigUnindent(LogConfigGlobal());
LogConfigUnindent(LogConfigGlobal());
Log(LOG_INFO, "=======================");
HttpServerJoin(server);
end:
Log(LOG_INFO, "Exiting...");
HttpServerFree(server);
ParseeConfigFree();
CronStop(cron);
CronFree(cron);
ParseeFreeData(conf.handlerArgs);
ParseeDestroyNickTable();
ParseeDestroyOIDTable();
ParseeDestroyHeadTable();
ParseeDestroyJIDTable();
(void) env;
return 0;
}