# toxio: turn any CLI program/script into a Tox bot # deps: toxcore, nim-toxcore # created by Luxferre in 2024, released into public domain import toxcore, times, sets, osproc, streams from threadpool import spawn from std/os import sleep from std/cmdline import paramCount, paramStr # command line parameters if paramCount() < 4: echo "Usage: toxio name datafile [w|r] cmd" quit(1) let botname = paramStr(1) toxdatafile = paramStr(2) writeperm: bool = (paramStr(3) == "w") subcmd = paramStr(4) # read Tox save data var toxconfig = "" try: toxconfig = readFile(toxdatafile) except IOError: stderr.writeLine "Cannot read the Tox data file!" quit(1) # bootstrap constants const bootstrapHost = "46.101.197.175" bootstrapKey = "CD133B521159541FB1D326DE9850F5E56A6C724B5B8E5EB5CD8D950408E95707".toPublicKey bootstrapPort = 33445 # declare the bot type to wrap GC-safe data type Bot = ref object tox: Tox datafile: string activeFriends: HashSet[Friend] sproc: Process # input loop procedure proc inputloop(bot: Bot) = var gline = "" while bot.sproc.outputStream.readLine(gline): for f in bot.activeFriends.items: bot.tox.send(f, gline, TOX_MESSAGE_TYPE_NORMAL) bot.sproc.outputStream.flush() # GC-safe bot callbacks proc cbs(bot: Bot) = # what do do on a new friend request (only in write-enable mode) if writeperm: bot.tox.onFriendRequest do (pk: PublicKey; msg: string): discard bot.tox.addFriendNoRequest(pk) try: writeFile(bot.datafile, bot.tox.saveData) except IOError: stderr.writeLine "Cannot write the Tox data file!" # what to do on a new message bot.tox.onFriendMessage do (f: Friend; msg: string; kind: MessageType): if msg == "/toxiostop": # temporarily unsubscribe from the output bot.activeFriends.excl(f) else: bot.activeFriends.incl(f) # first-time activation bot.sproc.inputStream.writeLine msg bot.sproc.inputStream.flush() # bot options description proc botopt(opts: Options) = opts.savedata_type = TOX_SAVEDATA_TYPE_TOX_SAVE opts.saveData = toxconfig # spawn the subprocess var subproc:Process try: subproc = startProcess(subcmd, options={poEvalCommand,poStdErrToStdOut,poInteractive,poUsePath}) stderr.writeLine "Subprocess started" except: stderr.writeLine "Cannot spawn the subprocess command!" quit(1) # init the bot let iobot = Bot(tox:initTox(botopt)) iobot.tox.name = botname iobot.datafile = toxdatafile iobot.cbs() iobot.tox.bootstrap(bootstrapHost, bootstrapKey, bootstrapPort) iobot.tox.statusMessage = "Serving " & subcmd iobot.sproc = subproc stderr.writeLine iobot.tox.name, " online at ", iobot.tox.address # run the input loop spawn inputloop(iobot) # run the toxcore loop while true: iterate(iobot.tox) sleep inMilliseconds(iobot.tox.iterationInterval)