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.

125 lines
4.7 KiB

  1. # -*- coding: utf-8 -*-
  2. # Manage wiki tasks from IRC, and check on thread status.
  3. import threading
  4. import re
  5. from irc.base_command import BaseCommand
  6. from irc.data import *
  7. from wiki import task_manager
  8. from core import config
  9. class Tasks(BaseCommand):
  10. def get_hooks(self):
  11. return ["msg"]
  12. def get_help(self, command):
  13. return "Manage wiki tasks from IRC, and check on thread status."
  14. def check(self, data):
  15. if data.is_command and data.command in ["tasks", "threads", "tasklist"]:
  16. return True
  17. return False
  18. def process(self, data):
  19. self.data = data
  20. if data.host not in config.irc.permissions["owners"]:
  21. self.connection.reply(data, "at this time, you must be a bot owner to use this command.")
  22. return
  23. if not data.args:
  24. if data.command == "tasklist":
  25. self.do_list()
  26. else:
  27. self.connection.reply(data, "no arguments provided. Maybe you wanted '!{cmnd} list', '!{cmnd} start', or '!{cmnd} listall'?".format(cmnd=data.command))
  28. return
  29. if data.args[0] == "list":
  30. self.do_list()
  31. elif data.args[0] == "start":
  32. self.do_start()
  33. elif data.args[0] in ["listall", "all"]:
  34. self.do_listall()
  35. else: # they asked us to do something we don't know
  36. self.connection.reply(data, "unknown argument: \x0303{}\x0301.".format(data.args[0]))
  37. def do_list(self):
  38. threads = threading.enumerate()
  39. normal_threads = []
  40. task_threads = []
  41. for thread in threads:
  42. tname = thread.name
  43. if tname == "MainThread":
  44. tname = self.get_main_thread_name()
  45. normal_threads.append("\x0302{}\x0301 (as main thread, id {})".format(tname, thread.ident))
  46. elif tname in ["irc-frontend", "irc-watcher", "wiki-scheduler"]:
  47. normal_threads.append("\x0302{}\x0301 (id {})".format(tname, thread.ident))
  48. else:
  49. tname, start_time = re.findall("^(.*?) \((.*?)\)$", tname)[0]
  50. task_threads.append("\x0302{}\x0301 (id {}, since {})".format(tname, thread.ident, start_time))
  51. if task_threads:
  52. msg = "\x02{}\x0F threads active: {}, and \x02{}\x0F task threads: {}.".format(len(threads), ', '.join(normal_threads), len(task_threads), ', '.join(task_threads))
  53. else:
  54. msg = "\x02{}\x0F threads active: {}, and \x020\x0F task threads.".format(len(threads), ', '.join(normal_threads))
  55. self.connection.reply(self.data, msg)
  56. def do_listall(self):
  57. tasks = task_manager.task_list.keys()
  58. threads = threading.enumerate()
  59. tasklist = []
  60. tasks.sort()
  61. for task in tasks:
  62. threads_running_task = [t for t in threads if t.name.startswith(task)]
  63. ids = map(lambda t: str(t.ident), threads_running_task)
  64. if not ids:
  65. tasklist.append("\x0302{}\x0301 (idle)".format(task))
  66. elif len(ids) == 1:
  67. tasklist.append("\x0302{}\x0301 (\x02active\x0F as id {})".format(task, ids[0]))
  68. else:
  69. tasklist.append("\x0302{}\x0301 (\x02active\x0F as ids {})".format(task, ', '.join(ids)))
  70. tasklist = ", ".join(tasklist)
  71. msg = "{} tasks loaded: {}.".format(len(tasks), tasklist)
  72. self.connection.reply(self.data, msg)
  73. def do_start(self):
  74. data = self.data
  75. try:
  76. task_name = data.args[1]
  77. except IndexError: # no task name given
  78. self.connection.reply(data, "what task do you want me to start?")
  79. return
  80. try:
  81. data.parse_kwargs()
  82. except KwargParseException, arg:
  83. self.connection.reply(data, "error parsing argument: \x0303{}\x0301.".format(arg))
  84. return
  85. if task_name not in task_manager.task_list.keys(): # this task does not exist or hasn't been loaded
  86. self.connection.reply(data, "task could not be found; either wiki/tasks/{}.py doesn't exist, or it wasn't loaded correctly.".format(task_name))
  87. return
  88. task_manager.start_task(task_name, **data.kwargs)
  89. self.connection.reply(data, "task \x0302{}\x0301 started.".format(task_name))
  90. def get_main_thread_name(self):
  91. """Return the "proper" name of the MainThread; e.g. "irc-frontend" or "irc-watcher"."""
  92. if config.components["irc_frontend"]:
  93. return "irc-frontend"
  94. elif config.components["wiki_schedule"]:
  95. return "wiki-scheduler"
  96. else:
  97. return "irc-watcher"