toxio.nim (2842B)
1 # toxio: turn any CLI program/script into a Tox bot 2 # deps: toxcore, nim-toxcore 3 # created by Luxferre in 2024, released into public domain 4 5 import toxcore, times, sets, osproc, streams 6 from threadpool import spawn 7 from std/os import sleep 8 from std/cmdline import paramCount, paramStr 9 10 # command line parameters 11 if paramCount() < 4: 12 echo "Usage: toxio name datafile [w|r] cmd" 13 quit(1) 14 let 15 botname = paramStr(1) 16 toxdatafile = paramStr(2) 17 writeperm: bool = (paramStr(3) == "w") 18 subcmd = paramStr(4) 19 20 # read Tox save data 21 var toxconfig = "" 22 try: 23 toxconfig = readFile(toxdatafile) 24 except IOError: 25 stderr.writeLine "Cannot read the Tox data file!" 26 quit(1) 27 28 # bootstrap constants 29 const 30 bootstrapHost = "46.101.197.175" 31 bootstrapKey = "CD133B521159541FB1D326DE9850F5E56A6C724B5B8E5EB5CD8D950408E95707".toPublicKey 32 bootstrapPort = 33445 33 34 # declare the bot type to wrap GC-safe data 35 type Bot = ref object 36 tox: Tox 37 datafile: string 38 activeFriends: HashSet[Friend] 39 sproc: Process 40 41 # input loop procedure 42 proc inputloop(bot: Bot) = 43 var gline = "" 44 while bot.sproc.outputStream.readLine(gline): 45 for f in bot.activeFriends.items: 46 bot.tox.send(f, gline, TOX_MESSAGE_TYPE_NORMAL) 47 bot.sproc.outputStream.flush() 48 49 # GC-safe bot callbacks 50 proc cbs(bot: Bot) = 51 # what do do on a new friend request (only in write-enable mode) 52 if writeperm: 53 bot.tox.onFriendRequest do (pk: PublicKey; msg: string): 54 discard bot.tox.addFriendNoRequest(pk) 55 try: 56 writeFile(bot.datafile, bot.tox.saveData) 57 except IOError: 58 stderr.writeLine "Cannot write the Tox data file!" 59 60 # what to do on a new message 61 bot.tox.onFriendMessage do (f: Friend; msg: string; kind: MessageType): 62 if msg == "/toxiostop": # temporarily unsubscribe from the output 63 bot.activeFriends.excl(f) 64 else: 65 bot.activeFriends.incl(f) # first-time activation 66 bot.sproc.inputStream.writeLine msg 67 bot.sproc.inputStream.flush() 68 69 # bot options description 70 proc botopt(opts: Options) = 71 opts.savedata_type = TOX_SAVEDATA_TYPE_TOX_SAVE 72 opts.saveData = toxconfig 73 74 # spawn the subprocess 75 var subproc:Process 76 77 try: 78 subproc = startProcess(subcmd, options={poEvalCommand,poStdErrToStdOut,poInteractive,poUsePath}) 79 stderr.writeLine "Subprocess started" 80 except: 81 stderr.writeLine "Cannot spawn the subprocess command!" 82 quit(1) 83 84 # init the bot 85 let iobot = Bot(tox:initTox(botopt)) 86 iobot.tox.name = botname 87 iobot.datafile = toxdatafile 88 iobot.cbs() 89 iobot.tox.bootstrap(bootstrapHost, bootstrapKey, bootstrapPort) 90 iobot.tox.statusMessage = "Serving " & subcmd 91 iobot.sproc = subproc 92 stderr.writeLine iobot.tox.name, " online at ", iobot.tox.address 93 94 # run the input loop 95 spawn inputloop(iobot) 96 97 # run the toxcore loop 98 while true: 99 iterate(iobot.tox) 100 sleep inMilliseconds(iobot.tox.iterationInterval)