A Python robot that edits Wikipedia and interacts with people over IRC https://en.wikipedia.org/wiki/User:EarwigBot
選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。

115 行
4.1 KiB

  1. # -*- coding: utf-8 -*-
  2. #
  3. # Copyright (C) 2009-2012 by Ben Kurtovic <ben.kurtovic@verizon.net>
  4. #
  5. # Permission is hereby granted, free of charge, to any person obtaining a copy
  6. # of this software and associated documentation files (the "Software"), to deal
  7. # in the Software without restriction, including without limitation the rights
  8. # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  9. # copies of the Software, and to permit persons to whom the Software is
  10. # furnished to do so, subject to the following conditions:
  11. #
  12. # The above copyright notice and this permission notice shall be included in
  13. # all copies or substantial portions of the Software.
  14. #
  15. # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  16. # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  17. # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  18. # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  19. # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  20. # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  21. # SOFTWARE.
  22. """
  23. EarwigBot's IRC Watcher Component
  24. The IRC watcher runs on a wiki recent-changes server and listens for edits.
  25. Users cannot interact with this part of the bot. When an event occurs, we run
  26. it through rules.py's process() function, which can result in wiki bot tasks
  27. being started (located in tasks/) or messages being sent to channels on the IRC
  28. frontend.
  29. """
  30. import logging
  31. from earwigbot import rules
  32. from earwigbot.classes import Connection, RC, BrokenSocketException
  33. from earwigbot.config import config
  34. frontend_conn = None
  35. logger = logging.getLogger("earwigbot.watcher")
  36. def get_connection():
  37. """Return a new Connection() instance with connection information.
  38. Don't actually connect yet.
  39. """
  40. cf = config.irc["watcher"]
  41. connection = Connection(cf["host"], cf["port"], cf["nick"], cf["ident"],
  42. cf["realname"], logger)
  43. return connection
  44. def main(connection, f_conn=None):
  45. """Main loop for the Watcher IRC Bot component.
  46. get_connection() should have already been called and the connection should
  47. have been started with connection.connect(). Accept the frontend connection
  48. as well as an optional parameter in order to send messages directly to
  49. frontend IRC channels.
  50. """
  51. global frontend_conn
  52. frontend_conn = f_conn
  53. read_buffer = str()
  54. while 1:
  55. try:
  56. read_buffer = read_buffer + connection.get()
  57. except BrokenSocketException:
  58. return
  59. lines = read_buffer.split("\n")
  60. read_buffer = lines.pop()
  61. for line in lines:
  62. _process_message(connection, line)
  63. def _process_message(connection, line):
  64. """Process a single message from IRC."""
  65. line = line.strip().split()
  66. if line[1] == "PRIVMSG":
  67. chan = line[2]
  68. # Ignore messages originating from channels not in our list, to prevent
  69. # someone PMing us false data:
  70. if chan not in config.irc["watcher"]["channels"]:
  71. return
  72. msg = ' '.join(line[3:])[1:]
  73. rc = RC(msg) # new RC object to store this event's data
  74. rc.parse() # parse a message into pagenames, usernames, etc.
  75. process_rc(rc) # report to frontend channels or start tasks
  76. # If we are pinged, pong back to the server:
  77. elif line[0] == "PING":
  78. msg = " ".join(("PONG", line[1]))
  79. connection.send(msg)
  80. # When we've finished starting up, join all watcher channels:
  81. elif line[1] == "376":
  82. for chan in config.irc["watcher"]["channels"]:
  83. connection.join(chan)
  84. def process_rc(rc):
  85. """Process a recent change event from IRC (or, an RC object).
  86. The actual processing is configurable, so we don't have that hard-coded
  87. here. We simply call rules's process() function and expect a list of
  88. channels back, which we report the event data to.
  89. """
  90. chans = rules.process(rc)
  91. if chans and frontend_conn:
  92. pretty = rc.prettify()
  93. for chan in chans:
  94. frontend_conn.say(chan, pretty)