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.

пре 13 година
пре 13 година
пре 10 година
пре 13 година
пре 10 година
пре 10 година
пре 10 година
пре 13 година
пре 10 година
пре 13 година
пре 13 година
пре 13 година
пре 13 година
пре 13 година
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150
  1. # -*- coding: utf-8 -*-
  2. #
  3. # Copyright (C) 2009-2014 Ben Kurtovic <ben.kurtovic@gmail.com>
  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. import threading
  23. import re
  24. from earwigbot.commands import Command
  25. class Threads(Command):
  26. """Manage wiki tasks from IRC, and check on thread status."""
  27. name = "threads"
  28. commands = ["tasks", "task", "threads", "tasklist"]
  29. def process(self, data):
  30. self.data = data
  31. if not self.config.irc["permissions"].is_owner(data):
  32. msg = "You must be a bot owner to use this command."
  33. self.reply(data, msg)
  34. return
  35. if not data.args:
  36. if data.command == "tasklist":
  37. self.do_list()
  38. else:
  39. msg = "No arguments provided. Maybe you wanted '!{0} list', '!{0} start', or '!{0} listall'?"
  40. self.reply(data, msg.format(data.command))
  41. return
  42. if data.args[0] == "list":
  43. self.do_list()
  44. elif data.args[0] == "start":
  45. self.do_start()
  46. elif data.args[0] in ["listall", "all"]:
  47. self.do_listall()
  48. else: # They asked us to do something we don't know
  49. msg = "Unknown argument: \x0303{0}\x0F.".format(data.args[0])
  50. self.reply(data, msg)
  51. def do_list(self):
  52. """With !tasks list (or abbreviation !tasklist), list all running
  53. threads. This includes the main threads, like the irc frontend and the
  54. watcher, and task threads."""
  55. threads = threading.enumerate()
  56. normal_threads = []
  57. daemon_threads = []
  58. for thread in threads:
  59. tname = thread.name
  60. ident = thread.ident % 10000
  61. if tname == "MainThread":
  62. t = "\x0302MainThread\x0F (id {0})"
  63. normal_threads.append(t.format(ident))
  64. elif tname in self.config.components:
  65. t = "\x0302{0}\x0F (id {1})"
  66. normal_threads.append(t.format(tname, ident))
  67. elif tname.startswith("remind-"):
  68. t = "\x0302reminder\x0F (id {0})"
  69. daemon_threads.append(t.format(tname[len("remind-"):]))
  70. elif tname.startswith("cvworker-"):
  71. t = "\x0302copyvio worker\x0F (site {0})"
  72. daemon_threads.append(t.format(tname[len("cvworker-"):]))
  73. else:
  74. match = re.findall("^(.*?) \((.*?)\)$", tname)
  75. if match:
  76. t = "\x0302{0}\x0F (id {1}, since {2})"
  77. thread_info = t.format(match[0][0], ident, match[0][1])
  78. daemon_threads.append(thread_info)
  79. else:
  80. t = "\x0302{0}\x0F (id {1})"
  81. daemon_threads.append(t.format(tname, ident))
  82. if daemon_threads:
  83. if len(daemon_threads) > 1:
  84. msg = "\x02{0}\x0F threads active: {1}, and \x02{2}\x0F command/task threads: {3}."
  85. else:
  86. msg = "\x02{0}\x0F threads active: {1}, and \x02{2}\x0F command/task thread: {3}."
  87. msg = msg.format(len(threads), ', '.join(normal_threads),
  88. len(daemon_threads), ', '.join(daemon_threads))
  89. else:
  90. msg = "\x02{0}\x0F threads active: {1}, and \x020\x0F command/task threads."
  91. msg = msg.format(len(threads), ', '.join(normal_threads))
  92. self.reply(self.data, msg)
  93. def do_listall(self):
  94. """With !tasks listall or !tasks all, list all loaded tasks, and report
  95. whether they are currently running or idle."""
  96. threads = threading.enumerate()
  97. tasklist = []
  98. for task in sorted([task.name for task in self.bot.tasks]):
  99. threadlist = [t for t in threads if t.name.startswith(task)]
  100. ids = [str(t.ident) for t in threadlist]
  101. if not ids:
  102. tasklist.append("\x0302{0}\x0F (idle)".format(task))
  103. elif len(ids) == 1:
  104. t = "\x0302{0}\x0F (\x02active\x0F as id {1})"
  105. tasklist.append(t.format(task, ids[0]))
  106. else:
  107. t = "\x0302{0}\x0F (\x02active\x0F as ids {1})"
  108. tasklist.append(t.format(task, ', '.join(ids)))
  109. tasks = ", ".join(tasklist)
  110. msg = "\x02{0}\x0F tasks loaded: {1}.".format(len(tasklist), tasks)
  111. self.reply(self.data, msg)
  112. def do_start(self):
  113. """With !tasks start, start any loaded task by name with or without
  114. kwargs."""
  115. data = self.data
  116. try:
  117. task_name = data.args[1]
  118. except IndexError: # No task name given
  119. self.reply(data, "What task do you want me to start?")
  120. return
  121. if task_name not in [task.name for task in self.bot.tasks]:
  122. # This task does not exist or hasn't been loaded:
  123. msg = "Task could not be found; either it doesn't exist, or it wasn't loaded correctly."
  124. self.reply(data, msg.format(task_name))
  125. return
  126. data.kwargs["fromIRC"] = True
  127. self.bot.tasks.start(task_name, **data.kwargs)
  128. msg = "Task \x0302{0}\x0F started.".format(task_name)
  129. self.reply(data, msg)