aboutsummaryrefslogtreecommitdiffstats
path: root/control.py
diff options
context:
space:
mode:
authorTim Schmidt <tim.schmidt@ewe.net>2018-12-03 17:22:53 +0100
committerTim Schmidt <tim.schmidt@ewe.net>2018-12-03 17:22:53 +0100
commitfbbd202a0416fbf5cfac8a8d2b4e43e86e15762b (patch)
tree40cd7c5be1c6b102fbb0f23ea7a2b82c234c0427 /control.py
downloadhchat-tg-bridge-fbbd202a0416fbf5cfac8a8d2b4e43e86e15762b.tar.gz
hchat-tg-bridge-fbbd202a0416fbf5cfac8a8d2b4e43e86e15762b.zip
initial commit
Diffstat (limited to 'control.py')
-rwxr-xr-xcontrol.py207
1 files changed, 207 insertions, 0 deletions
diff --git a/control.py b/control.py
new file mode 100755
index 0000000..075656b
--- /dev/null
+++ b/control.py
@@ -0,0 +1,207 @@
+#!/bin/python
+
+import datetime
+import sys
+import time
+import threading
+import traceback
+import signal
+import logging
+
+# Custom scripts
+import hackchatcustom as hackchat
+import telegrambot
+
+# Config
+import config
+
+# Constants
+CONFIG_FILE = "config.py"
+
+# Global variables holding both bots
+hcBot = None
+tgBot = None
+
+### General
+def log(s, suppress_console=True):
+ """Writes a message to the channel's logfile.
+ Will also output to the console if suppress_console is False."""
+ # Write to logfile
+ with open(config.LOG_FILENAME, "a") as f:
+ f.write("%s %s\n" % (datetime.datetime.now().isoformat(), s))
+ # Send via TG-Bot
+ if not suppress_console:
+ print(s)
+
+def mdescape(s):
+ """Hacky escapes for Telegrams Markdown parser.
+ Should really replace this with HTML."""
+ special = '*[`_'
+ for x in special:
+ s = s.replace(x, "\\" + x)
+ return s
+
+### HV-Bot
+def getUser(update):
+ """Convenience function that extracts a nick and tripcode (if any) from
+ an update object and returns the nickname in the following format:
+ If there is not tripcode: nick
+ If there is a tripcode: nick#tripcode"""
+ nick = update["nick"]
+ trip = 'null'
+ if "trip" in update:
+ trip = update["trip"]
+
+ if trip == 'null':
+ return nick
+ else:
+ return "%s#%s" % (nick, trip)
+
+def onMessage(chat, update):
+ """Callback function handling users submitting messages to the channel."""
+ message = update["text"]
+ nick = update["nick"]
+ trip = 'null'
+ if "trip" in update:
+ trip = update["trip"]
+ sender = getUser(update)
+
+ log("[%s] %s" % (sender, message))
+ if nick != config.USER:
+ if trip == 'null':
+ toTG("\\[*%s*] %s" % (mdescape(nick), mdescape(message)))
+ else:
+ toTG("\\[*%s*#%s] %s" % (mdescape(nick), trip, mdescape(message)))
+
+def onJoin(chat, update):
+ """Callback function handling users joining the channel."""
+ user = getUser(update)
+ log("# %s joined" % user)
+ toTG("# %s joined" % mdescape(user))
+
+def onLeave(chat, update):
+ """Callback function handling users leaving the channel."""
+ user = getUser(update)
+ log("# %s left" % user)
+ toTG("# %s left" % mdescape(user))
+
+def startHCBot():
+ """Starts the HC bot."""
+ global hcBot
+ bot = hackchat.HackChat(config.USER_AND_PASS, config.CHANNEL)
+ bot.on_message += [onMessage]
+ bot.on_join += [onJoin]
+ bot.on_leave += [onLeave]
+ hcBot = bot
+ bot.run()
+
+def botCrashed(signum, frame):
+ """Recovery routine that restarts the HC bot upon crash.
+ This is run automatically when a SIGALRT is received
+ (tested on Linux only) and thus relies on the HC bot
+ catching any relevant exception and sending a SIGALRT."""
+ hcBot.stop()
+
+ log("=!= Bot crashed / lost connection. Retrying in %i seconds..."\
+ % config.RECONNECT_DELAY, suppress_console=False)
+ toTG("=!= Bot crashed / lost connection. Retrying in %i seconds..."\
+ % config.RECONNECT_DELAY)
+ time.sleep(config.RECONNECT_DELAY)
+ log("Reconnecting...", suppress_console=False)
+ toTG("Reconnecting...")
+ startHCBot()
+ log("Reconnected!", suppress_console=False)
+ toTG("Reconnected!")
+
+def kill():
+ """Debug command to test reconnect functionality"""
+ hcBot.ws.close()
+
+### TG-Bot Config
+def onTGMessage(text):
+ """Handles receiving messages from the Telegram bot.
+ Currently, they are simple forwarded to the HC bot
+ which will then send them"""
+ hcBot.send_message(text)
+
+def toTG(s):
+ """Handles sending messages to the Telegram bot.
+ Currently, the TG bot will simply send
+ the message with Markdown parsing enabled."""
+ tgBot.send(s)
+
+def startTGBot():
+ """Starts the Telegram bot and sets the global
+ tgBot variable."""
+ global tgBot
+ tgBot = telegrambot.TGBot()
+ tgBot.texthandlers += [onTGMessage]
+ tgBot.addCommand("active", cmdActive)
+ tgBot.addCommand("online", cmdOnline)
+ tgBot.run()
+
+def cmdActive(bot, update):
+ """TG command: /active
+ Checks wether the HC bot has been stopped.
+ This might not work correctly if the HC bot crashed."""
+ if not hcBot.stopped:
+ tgBot.send("+++ ACTIVE")
+ else:
+ tgBot.send("--- _not_ active")
+
+def cmdOnline(bot, update):
+ """TG command: /online
+ Returns the list of users that are in the HC channel.
+ Users are listed without their tripcode."""
+ users = list(hcBot.online_users)
+ users.sort()
+ tgBot.send("Users online:\n%s" %
+ mdescape(", ".join(users)))
+
+
+### Common
+def quit():
+ """Gracefully shuts down both bots"""
+ global should_quit
+ hcBot.stop()
+ tgBot.stop()
+ should_quit = True
+
+### Main
+if __name__ == "__main__":
+ logging.basicConfig(level=logging.DEBUG,
+ format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
+
+ COMMANDS_CLI = {
+ "kill": kill,
+ "quit": quit
+ #"online" : cmdOnline
+ }
+
+ should_quit = False
+
+ # Interpret SIGALRM as bot crash
+ signal.signal(signal.SIGALRM, botCrashed)
+
+ try:
+ startTGBot()
+ startHCBot()
+ while not should_quit:
+ cmd = input("> ")
+ if not cmd in COMMANDS_CLI:
+ print("Unknown command!")
+ else:
+ COMMANDS_CLI[cmd]()
+
+ except (KeyboardInterrupt, EOFError) as e:
+ print("Interrupt received. Shutting down...")
+ quit()
+
+ except:
+ print("====================")
+ print("Main thread crashed!")
+ print("====================")
+ print()
+ traceback.print_exc()
+
+