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.

watcher.py 2.9 KiB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778
  1. # -*- coding: utf-8 -*-
  2. """
  3. EarwigBot's IRC Watcher Component
  4. The IRC watcher runs on a wiki recent-changes server and listens for edits.
  5. Users cannot interact with this part of the bot. When an event occurs, run it
  6. through irc/watcher_logic.py's process() function, which can result in either
  7. wiki bot tasks being started (listed in wiki/tasks/) or messages being sent to
  8. channels in the IRC frontend.
  9. """
  10. from core import config
  11. from irc.classes import Connection, RC, BrokenSocketException
  12. from irc import watcher_logic
  13. frontend_conn = 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["watcher"]
  18. connection = Connection(cf["host"], cf["port"], cf["nick"], cf["ident"],
  19. cf["realname"])
  20. return connection
  21. def main(connection, f_conn=None):
  22. """Main loop for the Watcher IRC Bot component. get_connection() should
  23. have already been called and the connection should have been started with
  24. connection.connect(). Accept the frontend connection as well as an optional
  25. parameter in order to send messages directly to frontend IRC channels."""
  26. global frontend_conn
  27. frontend_conn = f_conn
  28. read_buffer = str()
  29. while 1:
  30. try:
  31. read_buffer = read_buffer + connection.get()
  32. except BrokenSocketException:
  33. return
  34. lines = read_buffer.split("\n")
  35. read_buffer = lines.pop()
  36. for line in lines:
  37. line = line.strip().split()
  38. if line[1] == "PRIVMSG":
  39. chan = line[2]
  40. # ignore messages originating from channels not in our list, to
  41. # prevent someone PMing us false data
  42. if chan not in config.irc["watcher"]["channels"]:
  43. continue
  44. msg = ' '.join(line[3:])[1:]
  45. rc = RC(msg) # new RC object to store this event's data
  46. rc.parse() # parse a message into pagenames, usernames, etc.
  47. process(rc) # report to frontend channels or start tasks
  48. if line[0] == "PING": # if we are pinged, pong back to the server
  49. connection.send("PONG %s" % line[1])
  50. # when we've finished starting up, join all watcher channels
  51. if line[1] == "376":
  52. for chan in config.irc["watcher"]["channels"]:
  53. connection.join(chan)
  54. def process(rc):
  55. """Process a message from IRC (technically, an RC object). The actual
  56. processing is configurable, so we don't have that hard-coded here. We
  57. simply call irc/watcher_logic.py's process() function and expect a list of
  58. channels back, which we report the event data to."""
  59. chans = watcher_logic.process(rc)
  60. if chans and frontend_conn:
  61. pretty = rc.get_pretty()
  62. for chan in chans:
  63. frontend_conn.say(chan, pretty)