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.8 KiB

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