A Python robot that edits Wikipedia and interacts with people over IRC https://en.wikipedia.org/wiki/User:EarwigBot
Nie możesz wybrać więcej, niż 25 tematów Tematy muszą się zaczynać od litery lub cyfry, mogą zawierać myślniki ('-') i mogą mieć do 35 znaków.

watcher.py 2.9 KiB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394
  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, we run
  6. it through rules.py's process() function, which can result in wiki bot tasks
  7. being started (located in tasks/) or messages being sent to channels on the IRC
  8. frontend.
  9. """
  10. import logging
  11. import config
  12. from classes import Connection, RC, BrokenSocketException
  13. import rules
  14. frontend_conn = None
  15. logger = logging.getLogger("watcher")
  16. def get_connection():
  17. """Return a new Connection() instance with connection information.
  18. Don't actually connect yet.
  19. """
  20. cf = config.irc["watcher"]
  21. connection = Connection(cf["host"], cf["port"], cf["nick"], cf["ident"],
  22. cf["realname"], logger)
  23. return connection
  24. def main(connection, f_conn=None):
  25. """Main loop for the Watcher IRC Bot component.
  26. get_connection() should have already been called and the connection should
  27. have been started with connection.connect(). Accept the frontend connection
  28. as well as an optional parameter in order to send messages directly to
  29. frontend IRC channels.
  30. """
  31. global frontend_conn
  32. frontend_conn = f_conn
  33. read_buffer = str()
  34. while 1:
  35. try:
  36. read_buffer = read_buffer + connection.get()
  37. except BrokenSocketException:
  38. return
  39. lines = read_buffer.split("\n")
  40. read_buffer = lines.pop()
  41. for line in lines:
  42. _process_message(connection, line)
  43. def _process_message(connection, line):
  44. """Process a single message from IRC."""
  45. line = line.strip().split()
  46. if line[1] == "PRIVMSG":
  47. chan = line[2]
  48. # Ignore messages originating from channels not in our list, to prevent
  49. # someone PMing us false data:
  50. if chan not in config.irc["watcher"]["channels"]:
  51. return
  52. msg = ' '.join(line[3:])[1:]
  53. rc = RC(msg) # new RC object to store this event's data
  54. rc.parse() # parse a message into pagenames, usernames, etc.
  55. process_rc(rc) # report to frontend channels or start tasks
  56. # If we are pinged, pong back to the server:
  57. elif line[0] == "PING":
  58. msg = " ".join(("PONG", line[1]))
  59. connection.send(msg)
  60. # When we've finished starting up, join all watcher channels:
  61. elif line[1] == "376":
  62. for chan in config.irc["watcher"]["channels"]:
  63. connection.join(chan)
  64. def process_rc(rc):
  65. """Process a recent change event from IRC (or, an RC object).
  66. The actual processing is configurable, so we don't have that hard-coded
  67. here. We simply call rules's process() function and expect a list of
  68. channels back, which we report the event data to.
  69. """
  70. chans = rules.process(rc)
  71. if chans and frontend_conn:
  72. pretty = rc.prettify()
  73. for chan in chans:
  74. frontend_conn.say(chan, pretty)