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.

105 lines
4.1 KiB

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