brenns10 / cbot Goto Github PK
View Code? Open in Web Editor NEWIRC chatbot written in C.
License: BSD 3-Clause "New" or "Revised" License
IRC chatbot written in C.
License: BSD 3-Clause "New" or "Revised" License
Currently, plugins consist of a single function loaded from a shared object. This function registers all handlers. The bot itself doesn't know which handlers belong to which plugin, or how to safely unload the plugin. The bot also can't query the plugin for information such as help text, etc. A better system would be for a plugin to (optionally) populate a struct of function pointers at registration time. Further, a plugin should receive a pointer to some sort of bookkeeping struct (e.g. struct cbot_plugin
) which it can use to store a pointer to private data.
High level goals:
Once #9 is implemented, we should make the karma plugin store data in sqlite. This may actually be easier since it will handle a lot of the logic of sorting and updating for us. Plus, it will mean that karma can survive a cbot restart, which would be a momentous achievement.
Darwin IRC server reboots a lot to try new features and builds. It would be ideal if cbot could reconnect on server shutdown. This could be achieved in a bash while loop, but it would be nice to have some exponential backoff or something (which could still be done in bash, or C).
none of this "two space indentation" garbage
Plugins will likely want to tokenize messages into a sequence of command arguments separated by whitespace. Create a common system to simplify plugins:
struct cbot_tok {
char *original; // the original copied string, modified to tokenize
char **tokens; // pointers into original for each token
int ntok; // count of tokens in array
int cap; // capacity of the token array
};
/**
* Tokenize `msg` (copy it first) and fill `*result` with the tokens.
* Return count of tokens (also stored in ntok) on success, negative on fail.
*/
int cbot_tokenize(const char *msg, struct cbot_tok *result);
/**
* Frees resources held by `tokens`. Does not free the actual tokens struct.
*/
void cbot_tok_destroy(struct cbot_tok *tokens);
The tokenizing system would be defined as follows:
"
, the token will be delimited by the next whitespace character (\t
or space
) or NUL. The next token will begin with the next non-whitespace character (if this token was not delimited by NUL)."
, then the token will continue until the first matching double quote is found. The matching double quote MUST be followed by either a whitespace character or NUL, which will delimit the token. The token will contain all the text except the opening and closing double quote.Some examples (input string enclosed in brackets for simplicity, assume no brackets occur in the input strings):
INPUT: [arg1 arg2]
[0]: arg1
[1]: arg2
INPUT: ["hello world" 2]
[0]: hello world
[1]: 2
INPUT: [""]
[0]: (empty string)
INPUT: []
No tokens found, zero length array.
INPUT: ["hello ]
Error, rule 5.
INPUT: [hello" world]
[0]: hello"
[1]: world
INPUT: ["hello"world]
Error, rule 4.
INPUT: ["he said ""hello"" to me"]
[0]: he said "hello" to me
Reasons for using this method:
using meson build in the cbot directory eventually gives me this error:
meson.build:52:0: ERROR: C shared or static library 'dl' not found
Any solutions? things i am forgetting?
Get weather reports, probably from wttr.in or something similar and simple.
Simply writes timestamp, username, and message to CHANNEL-DATE.txt
whenever it receives a message. No buffering or anything like that. RIP Hard Drive.
This would be a good flex for my sc-lwt async powers.
Multiple plugins have the ability to schedule a callback, and they usually do it by a month, day of month, weekday, etc. All cron stuff. I wonder if an API could be provided like:
void *cbot_callback_cron(plugin, callback, char *schedule);
Which would trigger the callback at the next matching time. The callback would need to re-register itself with the same expression to trigger it again.
Air quality by zip code or similar
The hashchain thing was neat but maybe not terribly practical. I do think that here still needs to be a good way to ask "is a user trusted to execute some privileged command?". I think this should be modular and specified in the config. Some implementations:
./sample.cfg:10: syntax error (cbot config op read)lab@lab:~/git/cbot$
cbot: remind me to [x] {in,at} [time]
My IRC "client/bouncer/whatever" of choice is thelounge. It doesn't have per-channel notification settings, which is a bit of a drag because there are a few channels where I would like to be pinged for most messages, but for most channels I would not like notifications. Add a plugin which allows you to register to be DM'd whenever there is a message which satisfies some conditions:
Upon a message satisfying these conditions (stored in persistent db #9 ?), the plugin should DM the requestor to notify them.
Suggested command interface:
cbot notify add CHANNEL [inactive-for:[[HH:]MM:]SS] [regex:pattern] [from:nick]
-> NICK: added rule NUMBER
cbot notify list
-> NICK: rule NUMBER: <rule string using same syntax above>
cbot notify remove NUMBER
-> NICK: removed rule NUMBER
cbot notify update NUMBER <rule string using same syntax above>
This would depend on #9 for storing rules across restarts, and #10 for parsing commands in a foolproof way.
This is a problem associated with the separation of HEAR and MSG events. They're not fundamentally different, and yet I separate them.
I think the resolution will be to get rid of the distinction and make sure regex matching is nice.
If two cbot instances, cbot and cbotdev are in a channel and a user says "hello cbot", both will reply. This is because their regex matches, but there is still more message after the end of the cbotdev match.
In regex matching, we should verify that the regex match length is length of the entire string.
There are several plugins whose entire purpose is to reply to some message with another message, possibly including a captured regex field, or an attribute such as the sender's nickname. As nice as it is to write some good old fashioned C code to achieve such tasks, we probably don't need that. Let's build a generic reply plugin, which loads its triggers and responses from the configuration file. Depends on #15 and #16 for configuration and improved plugin support.
cbot rona
/ cbot covid
- ask questions about the latest covid data
Currently we provide all bot configuration on the command line. I've begun creating launcher scripts which contain all the options, so functionally we're abusing bash scripts as configuration files.
This actually isn't awful; it has worked for a while. But we've reached the point where plugins should be able to have configuration of their own, and this can't be achieved with command line arguments.
Integrate with libconfig
(or an INI parser) to allow cbot to accept a configuration file.
A while back I had fun implementing userspace threads. I'd like to wrap that into a library which implements threads and supports a poll-based event loop. The library would need to do the following:
O_NONBLOCK
, and if they get EWOULDBLOCK, they block until their file descriptor becomes available. I say maybe, because I don't actually need file operations, and this would be considerable work.This would be enough from the library features.
The current cbot operation would be mostly unchanged. The cbot operations which occur in my code are mostly non blocking. The entire main bot would run on one thread. Plugins would get an API to create a thread (but there would be no way to retrieve its return value, or join it) so they can do I/O, but the I/O must be non-blocking (e.g. libcurl has a mode for this). Plugins could also use threads to run asynchronous operations by a timer.
cbot weather aoeu will return a weather report, but like, that's not a place!
See what wttr.in is doing and see whether I could detect an error and give a real error message.
In #16 I listed out several things to improve the plugin mechanism. The big ticket items were done, but one thing not fully realized was the ability to load multiple instances of the same plugin from the same shared object.
This ticket is to ensure that this is supported. Update the configuration file syntax (hopefully in a backward compatible way) so that you can specify a plugin filename, thus multiple config entries mapping to the same .so file would be allowed. Then, ensure that all plugins are correct about not misusing global data/variables. Test out loading multiple instances with different configurations.
I've begun using unity for unit testing. I could expand that quite a bit, but some functionality needs integration testing. A fake backend would be good for that. I'd probably use Python to write the tests, and I'd want flexibility in the integration testing system for:
Meson is configurable enough, we should be able to specify which backends and plugins we want to build support for. We could get rid of libircclient when we don't need it, among other things.
It would also be interesting to see if we could have built-in plugins to eliminate the runtime dlopen(). I used dlopen() mostly for learning back in the day, but it serves no practical purpose, as we have no stable ABI for plugins.
Since the introduction of sc-lwt the event loop will continue running if there is at least one thread active. Unfortunately, there are multiple threads active now with the curl integration, so an IRC shutdown or EOF on stdin will not result in a graceful shutdown.
Need to implement a shutdown hook which backends call when they end their main loop, which can terminate all other threads (hopefully gracefully) and shut things down.
bot->privDb
is a memory-only sqlite connection for tracking usernames and channel memberships, and other transient data. Create a sqlite database file and connection, and CLI argument to specify its location. Then, provide this database to the plugin API to allow plugins to have persistent state.
As discovered in darwin: cbot currently loads sadness even if it's not addressed; according to @brenns10, CBOT_MESSAGE
should be CBOT_ADDRESSED
In #16 I listed out several things to improve the plugin mechanism. The big ticket items were done, but one thing not fully realized was a help system.
Build a help command which reads the description field of each plugin's ops struct, and gives a list of those as output. Remove the old help plugin. Be sure to add descriptions to all plugins.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.