A Python robot that edits Wikipedia and interacts with people over IRC https://en.wikipedia.org/wiki/User:EarwigBot
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

frontend.py 3.9 KiB

13 years ago
13 years ago
13 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117
  1. # -*- coding: utf-8 -*-
  2. """
  3. EarwigBot's IRC Frontend Component
  4. The IRC frontend runs on a normal IRC server and expects users to interact with
  5. it and give it commands. Commands are stored as "command classes", subclasses
  6. of BaseCommand in irc/base_command.py. All command classes are automatically
  7. imported by irc/command_handler.py if they are in irc/commands.
  8. """
  9. import logging
  10. import re
  11. import config
  12. import commands
  13. from classes import Connection, Data, BrokenSocketException
  14. __all__ = ["get_connection", "startup", "main"]
  15. connection = None
  16. logger = logging.getLogger("frontend")
  17. sender_regex = re.compile(":(.*?)!(.*?)@(.*?)\Z")
  18. def get_connection():
  19. """Return a new Connection() instance with information about our server
  20. connection, but don't actually connect yet."""
  21. cf = config.irc["frontend"]
  22. connection = Connection(cf["host"], cf["port"], cf["nick"], cf["ident"],
  23. cf["realname"], logger)
  24. return connection
  25. def startup(conn):
  26. """Accept a single arg, a Connection() object, and set our global variable
  27. 'connection' to it. Load all command classes in irc/commands with
  28. command_handler, and then establish a connection with the IRC server."""
  29. global connection
  30. connection = conn
  31. commands.load(connection)
  32. connection.connect()
  33. def main():
  34. """Main loop for the frontend component.
  35. get_connection() and startup() should have already been called before this.
  36. """
  37. read_buffer = str()
  38. while 1:
  39. try:
  40. read_buffer = read_buffer + connection.get()
  41. except BrokenSocketException:
  42. logger.warn("Socket has broken on front-end; restarting bot")
  43. return
  44. lines = read_buffer.split("\n")
  45. read_buffer = lines.pop()
  46. for line in lines:
  47. ret = _process_message(line)
  48. if ret:
  49. return
  50. def _process_message(line):
  51. """Process a single message from IRC."""
  52. line = line.strip().split()
  53. data = Data(line) # new Data instance to store info about this line
  54. if line[1] == "JOIN":
  55. data.nick, data.ident, data.host = sender_regex.findall(line[0])[0]
  56. data.chan = line[2]
  57. # Check for 'join' hooks in our commands:
  58. commands.check("join", data)
  59. elif line[1] == "PRIVMSG":
  60. data.nick, data.ident, data.host = sender_regex.findall(line[0])[0]
  61. data.msg = ' '.join(line[3:])[1:]
  62. data.chan = line[2]
  63. if data.chan == config.irc["frontend"]["nick"]:
  64. # This is a privmsg to us, so set 'chan' as the nick of the, sender
  65. # then check for private-only command hooks:
  66. data.chan = data.nick
  67. commands.check("msg_private", data)
  68. else:
  69. # Check for public-only command hooks:
  70. commands.check("msg_public", data)
  71. # Check for command hooks that apply to all messages:
  72. commands.check("msg", data)
  73. # Hardcode the !restart command (we can't restart from within an
  74. # ordinary command):
  75. if data.msg in ["!restart", ".restart"]:
  76. if data.host in config.irc["permissions"]["owners"]:
  77. logger.info("Restarting bot per owner request")
  78. return True
  79. # If we are pinged, pong back:
  80. elif line[0] == "PING":
  81. msg = " ".join(("PONG", line[1]))
  82. connection.send(msg)
  83. # On successful connection to the server:
  84. elif line[1] == "376":
  85. # If we're supposed to auth to NickServ, do that:
  86. try:
  87. username = config.irc["frontend"]["nickservUsername"]
  88. password = config.irc["frontend"]["nickservPassword"]
  89. except KeyError:
  90. pass
  91. else:
  92. msg = " ".join(("IDENTIFY", username, password))
  93. connection.say("NickServ", msg)
  94. # Join all of our startup channels:
  95. for chan in config.irc["frontend"]["channels"]:
  96. connection.join(chan)