genocide 232__tar.gz → 233__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (120) hide show
  1. {genocide-232 → genocide-233}/PKG-INFO +5 -2
  2. {genocide-232 → genocide-233}/README.rst +3 -0
  3. genocide-233/genocide/booting.py +137 -0
  4. genocide-233/genocide/brokers.py +58 -0
  5. genocide-233/genocide/command.py +77 -0
  6. genocide-232/genocide/defines.py → genocide-233/genocide/configs.py +7 -11
  7. {genocide-232 → genocide-233}/genocide/encoder.py +21 -11
  8. {genocide-232 → genocide-233}/genocide/handler.py +71 -32
  9. genocide-233/genocide/modules/adm.py +54 -0
  10. genocide-233/genocide/modules/bsc.py +40 -0
  11. genocide-233/genocide/modules/cfg.py +49 -0
  12. genocide-232/genocide/modules/atr.py → genocide-233/genocide/modules/fie.py +7 -7
  13. {genocide-232 → genocide-233}/genocide/modules/flt.py +1 -1
  14. {genocide-232 → genocide-233}/genocide/modules/fnd.py +15 -0
  15. {genocide-232 → genocide-233}/genocide/modules/irc.py +21 -20
  16. genocide-233/genocide/modules/log.py +25 -0
  17. {genocide-232 → genocide-233}/genocide/modules/man.py +31 -20
  18. genocide-233/genocide/modules/mbx.py +90 -0
  19. {genocide-232 → genocide-233}/genocide/modules/mdl.py +12 -14
  20. {genocide-232 → genocide-233}/genocide/modules/pth.py +1 -1
  21. genocide-233/genocide/modules/pwd.py +18 -0
  22. {genocide-232 → genocide-233}/genocide/modules/req.py +2 -1
  23. {genocide-232 → genocide-233}/genocide/modules/rss.py +47 -41
  24. {genocide-232 → genocide-233}/genocide/modules/rst.py +4 -4
  25. genocide-233/genocide/modules/tbl.py +0 -0
  26. {genocide-232 → genocide-233}/genocide/modules/tdo.py +4 -14
  27. {genocide-232 → genocide-233}/genocide/modules/tmr.py +20 -39
  28. {genocide-232 → genocide-233}/genocide/modules/udp.py +10 -6
  29. {genocide-232 → genocide-233}/genocide/modules/web.py +18 -15
  30. {genocide-232 → genocide-233}/genocide/modules/wsd.py +1 -2
  31. genocide-233/genocide/network/_images/abilifynew2.png +0 -0
  32. genocide-233/genocide/network/_images/clozapinenew2.png +0 -0
  33. genocide-233/genocide/network/_images/haloperidolnew2.png +0 -0
  34. genocide-233/genocide/network/_images/zyprexanew2.png +0 -0
  35. {genocide-232 → genocide-233}/genocide/network/_static/documentation_options.js +1 -1
  36. {genocide-232 → genocide-233}/genocide/network/_static/genocide.css +2 -2
  37. {genocide-232 → genocide-233}/genocide/network/_static/opensearch.xml +4 -4
  38. genocide-233/genocide/network/_static/otpcr.css +72 -0
  39. {genocide-232 → genocide-233}/genocide/network/_static/sitemap.xml +6 -6
  40. {genocide-232 → genocide-233}/genocide/network/about.html +5 -5
  41. genocide-233/genocide/network/echa.html +68 -0
  42. {genocide-232 → genocide-233}/genocide/network/evidence.html +9 -7
  43. {genocide-232 → genocide-233}/genocide/network/genindex-all.html +2 -2
  44. {genocide-232 → genocide-233}/genocide/network/genindex.html +2 -2
  45. genocide-233/genocide/network/googlea6568bcc05c8d50b.html +1 -0
  46. {genocide-232 → genocide-233}/genocide/network/guilty.html +6 -6
  47. {genocide-232 → genocide-233}/genocide/network/index.html +9 -5
  48. {genocide-232 → genocide-233}/genocide/network/manual.html +164 -53
  49. genocide-233/genocide/network/objects.inv +6 -0
  50. {genocide-232 → genocide-233}/genocide/network/pubchem.html +9 -9
  51. {genocide-232 → genocide-233}/genocide/network/reconsider.html +6 -6
  52. {genocide-232 → genocide-233}/genocide/network/request.html +5 -6
  53. genocide-233/genocide/network/robots.txt +4 -0
  54. {genocide-232 → genocide-233}/genocide/network/search.html +2 -2
  55. genocide-233/genocide/network/searchindex.js +1 -0
  56. {genocide-232 → genocide-233}/genocide/network/writings.html +6 -6
  57. {genocide-232 → genocide-233}/genocide/objects.py +87 -64
  58. genocide-233/genocide/package.py +154 -0
  59. {genocide-232 → genocide-233}/genocide/persist.py +64 -75
  60. genocide-233/genocide/runtime.py +195 -0
  61. {genocide-232 → genocide-233}/genocide/threads.py +37 -31
  62. {genocide-232 → genocide-233}/genocide/utility.py +108 -29
  63. {genocide-232 → genocide-233}/genocide.egg-info/PKG-INFO +5 -2
  64. {genocide-232 → genocide-233}/genocide.egg-info/SOURCES.txt +15 -4
  65. genocide-233/genocide.egg-info/entry_points.txt +2 -0
  66. {genocide-232 → genocide-233}/pyproject.toml +4 -3
  67. genocide-232/genocide/brokers.py +0 -50
  68. genocide-232/genocide/command.py +0 -61
  69. genocide-232/genocide/loggers.py +0 -38
  70. genocide-232/genocide/modules/log.py +0 -35
  71. genocide-232/genocide/modules/mbx.py +0 -133
  72. genocide-232/genocide/modules/upt.py +0 -17
  73. genocide-232/genocide/network/objects.inv +0 -0
  74. genocide-232/genocide/network/robots.txt +0 -2
  75. genocide-232/genocide/network/searchindex.js +0 -1
  76. genocide-232/genocide/package.py +0 -109
  77. genocide-232/genocide/runtime.py +0 -377
  78. genocide-232/genocide.egg-info/entry_points.txt +0 -2
  79. {genocide-232 → genocide-233}/genocide/modules/__init__.py +0 -0
  80. {genocide-232 → genocide-233}/genocide/modules/sil.py +0 -0
  81. {genocide-232 → genocide-233}/genocide/modules/slg.py +0 -0
  82. {genocide-232 → genocide-233}/genocide/modules/thr.py +0 -0
  83. {genocide-232 → genocide-233}/genocide/modules/wdr.py +0 -0
  84. {genocide-232 → genocide-233}/genocide/network/_images/ECHAabilify.png +0 -0
  85. {genocide-232 → genocide-233}/genocide/network/_images/ECHAclozapine.png +0 -0
  86. {genocide-232 → genocide-233}/genocide/network/_images/ECHAhaldol.png +0 -0
  87. {genocide-232 → genocide-233}/genocide/network/_images/ECHAzyprexa.png +0 -0
  88. {genocide-232 → genocide-233}/genocide/network/_images/OTP111.png +0 -0
  89. {genocide-232 → genocide-233}/genocide/network/_images/OTP222.png +0 -0
  90. {genocide-232 → genocide-233}/genocide/network/_images/abilifypubchem.png +0 -0
  91. {genocide-232 → genocide-233}/genocide/network/_images/ack3.png +0 -0
  92. {genocide-232 → genocide-233}/genocide/network/_images/bevestigd.jpg +0 -0
  93. {genocide-232 → genocide-233}/genocide/network/_images/clozapinepubchem.png +0 -0
  94. {genocide-232 → genocide-233}/genocide/network/_images/genocide.png +0 -0
  95. {genocide-232 → genocide-233}/genocide/network/_images/haldolpubchem.png +0 -0
  96. {genocide-232 → genocide-233}/genocide/network/_images/informed.jpg +0 -0
  97. {genocide-232 → genocide-233}/genocide/network/_images/kamer2.png +0 -0
  98. {genocide-232 → genocide-233}/genocide/network/_images/skull3.png +0 -0
  99. {genocide-232 → genocide-233}/genocide/network/_images/zyprexapubchem.png +0 -0
  100. {genocide-232 → genocide-233}/genocide/network/_static/alabaster.css +0 -0
  101. {genocide-232 → genocide-233}/genocide/network/_static/basic.css +0 -0
  102. {genocide-232 → genocide-233}/genocide/network/_static/custom.css +0 -0
  103. {genocide-232 → genocide-233}/genocide/network/_static/doctools.js +0 -0
  104. {genocide-232 → genocide-233}/genocide/network/_static/file.png +0 -0
  105. {genocide-232 → genocide-233}/genocide/network/_static/language_data.js +0 -0
  106. {genocide-232 → genocide-233}/genocide/network/_static/minus.png +0 -0
  107. {genocide-232 → genocide-233}/genocide/network/_static/plus.png +0 -0
  108. {genocide-232 → genocide-233}/genocide/network/_static/pygments.css +0 -0
  109. {genocide-232 → genocide-233}/genocide/network/_static/searchtools.js +0 -0
  110. {genocide-232 → genocide-233}/genocide/network/_static/skull3.png +0 -0
  111. {genocide-232 → genocide-233}/genocide/network/_static/sphinx_highlight.js +0 -0
  112. {genocide-232 → genocide-233}/genocide/network/pdf/EM_Ack_OTP-CR-117_19.pdf +0 -0
  113. {genocide-232 → genocide-233}/genocide/network/pdf/EM_T04_OTP-CR-117_19.pdf +0 -0
  114. {genocide-232 → genocide-233}/genocide/network/pdf/EM_T07_OTP-CR-117_19_001.pdf +0 -0
  115. {genocide-232 → genocide-233}/genocide/network/pdf/Kamer.pdf +0 -0
  116. {genocide-232 → genocide-233}/genocide/network/pdf/Rome-Statute.pdf +0 -0
  117. {genocide-232 → genocide-233}/genocide/network/pdf/bevestigd.pdf +0 -0
  118. {genocide-232 → genocide-233}/genocide.egg-info/dependency_links.txt +0 -0
  119. {genocide-232 → genocide-233}/genocide.egg-info/top_level.txt +0 -0
  120. {genocide-232 → genocide-233}/setup.cfg +0 -0
@@ -1,7 +1,7 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: genocide
3
- Version: 232
4
- Summary: Since 4 march 2019.
3
+ Version: 233
4
+ Summary: Since 4 March 2019.
5
5
  Author-email: Bart Thate <bthate@dds.nl>
6
6
  License-Expression: Unlicense
7
7
  Project-URL: home, https://pypi.org/project/genocide
@@ -66,3 +66,6 @@ are poison at the time they voted for this law and the day the Wfz law took
66
66
  effect (1-1-2019), i ask the prosecutor to prosecute the king for making the
67
67
  commiting of the above mentioned crimes (killing, torture and impotent making)
68
68
  possible.
69
+
70
+
71
+ (*) The website of the **ECHA** <European Chemical Agency> has been updated in January 2026 and no longer shows a skull and bones when visited.
@@ -51,3 +51,6 @@ are poison at the time they voted for this law and the day the Wfz law took
51
51
  effect (1-1-2019), i ask the prosecutor to prosecute the king for making the
52
52
  commiting of the above mentioned crimes (killing, torture and impotent making)
53
53
  possible.
54
+
55
+
56
+ (*) The website of the **ECHA** <European Chemical Agency> has been updated in January 2026 and no longer shows a skull and bones when visited.
@@ -0,0 +1,137 @@
1
+ # This file is placed in the Public Domain.
2
+
3
+
4
+ "at the beginning"
5
+
6
+
7
+ import argparse
8
+
9
+
10
+ from .runtime import Runtime
11
+ from .command import Commands
12
+ from .configs import Main
13
+ from .handler import Console, Event
14
+ from .objects import Object
15
+
16
+
17
+ class Arguments:
18
+
19
+ args = None
20
+ txt = None
21
+
22
+ @classmethod
23
+ def getargs(cls):
24
+ "parse commandline arguments."
25
+ parser = argparse.ArgumentParser(prog=Main.name, description=f"{Main.name.upper()}")
26
+ parser.add_argument("-a", "--all", action="store_true", help="load all modules.")
27
+ parser.add_argument("-c", "--console", action="store_true", help="start console.")
28
+ parser.add_argument("-d", "--daemon", action="store_true", help="start background daemon.")
29
+ parser.add_argument("-i", "--ignore", default="", help='modules to ignore.')
30
+ parser.add_argument("-l", "--level", default=Main.level, help='set loglevel.')
31
+ parser.add_argument("-m", "--mods", default="", help='modules to load.')
32
+ parser.add_argument("-n", "--index", action="store", type=int, help="set index to use.")
33
+ parser.add_argument("-r", "--read", action="store_true", help="read config on start.")
34
+ parser.add_argument("-s", "--service", action="store_true", help="start service.")
35
+ parser.add_argument("-v", "--verbose", action='store_true', help='enable verbose.')
36
+ parser.add_argument("-w", "--wait", action='store_true', help='wait for services to start.')
37
+ parser.add_argument("-u", "--user", action="store_true", help="use local mods directory.")
38
+ parser.add_argument("-x", "--admin", action="store_true", help="enable admin mode.")
39
+ parser.add_argument("--wdr", help='set working directory.')
40
+ parser.add_argument("--nochdir", action="store_true", help='set working directory.')
41
+ parser.add_argument("--noignore", action="store_true", help="disable ignore")
42
+ cls.args, arguments = parser.parse_known_args()
43
+ cls.txt = " ".join(arguments)
44
+ Object.merge(Main, cls.args)
45
+
46
+
47
+ class Line(Console):
48
+
49
+ def raw(self, text):
50
+ "write to console."
51
+ print(text.encode('utf-8', 'replace').decode("utf-8"))
52
+
53
+
54
+ class CSL(Line):
55
+
56
+ def poll(self):
57
+ "poll for an event."
58
+ evt = Event()
59
+ evt.orig = repr(self)
60
+ evt.text = input("> ")
61
+ evt.kind = "command"
62
+ return evt
63
+
64
+
65
+ class Scripts:
66
+
67
+ @staticmethod
68
+ def background():
69
+ "background script."
70
+ Runtime.daemon(Main.verbose, Main.nochdir)
71
+ Runtime.privileges()
72
+ Runtime.configure(Main)
73
+ Runtime.pidfile(Main.name)
74
+ Runtime.scan(Main)
75
+ Runtime.init(Main)
76
+ Runtime.forever()
77
+
78
+ @staticmethod
79
+ def cmd(text):
80
+ cli = Line()
81
+ for txt in text.split(" ! "):
82
+ evt = Event()
83
+ evt.kind = "command"
84
+ evt.orig = repr(cli)
85
+ evt.text = txt
86
+ Commands.command(evt)
87
+ evt.wait()
88
+
89
+ @staticmethod
90
+ def console():
91
+ "console script."
92
+ import readline
93
+ readline.redisplay()
94
+ Runtime.configure(Main)
95
+ if Main.verbose:
96
+ Runtime.banner()
97
+ Runtime.scan(Main)
98
+ Runtime.init(Main)
99
+ csl = CSL()
100
+ csl.start()
101
+ Runtime.forever()
102
+
103
+ @staticmethod
104
+ def control():
105
+ "cli script."
106
+ if not Arguments.txt:
107
+ return
108
+ Main.all = True
109
+ Runtime.configure(Main)
110
+ Runtime.scan(Main)
111
+ Scripts.cmd(Arguments.txt)
112
+
113
+ @staticmethod
114
+ def service():
115
+ "service script."
116
+ Runtime.privileges()
117
+ Runtime.configure(Main)
118
+ Runtime.scan(Main)
119
+ Runtime.banner()
120
+ Runtime.pidfile(Main.name)
121
+ Runtime.init(Main)
122
+ Runtime.forever()
123
+
124
+
125
+ def main():
126
+ "main"
127
+ Arguments.getargs()
128
+ Main.all = True
129
+ Main.ignore = "mbx,rst,udp,web,wsd"
130
+ if Main.daemon:
131
+ Runtime.wrap(Scripts.background)
132
+ elif Main.console:
133
+ Runtime.wrap(Scripts.console)
134
+ elif Main.service:
135
+ Runtime.wrap(Scripts.service)
136
+ else:
137
+ Runtime.wrap(Scripts.control)
@@ -0,0 +1,58 @@
1
+ # This file is placed in the Public Domain.
2
+
3
+
4
+ "brokers"
5
+
6
+
7
+ class Broker:
8
+
9
+ objects = {}
10
+
11
+ @classmethod
12
+ def add(cls, obj):
13
+ "add object to the broker, key is repr(obj)."
14
+ cls.objects[repr(obj)] = obj
15
+
16
+ @classmethod
17
+ def announce(cls, txt):
18
+ "announce text on all objects with an announce method."
19
+ for obj in cls.objs("announce"):
20
+ obj.announce(txt)
21
+
22
+ @classmethod
23
+ def get(cls, origin):
24
+ "object by repr(obj)."
25
+ return cls.objects.get(origin)
26
+
27
+ @classmethod
28
+ def has(cls, obj):
29
+ "whether the Broker has object."
30
+ return repr(obj) in cls.objects
31
+
32
+ @classmethod
33
+ def like(cls, txt):
34
+ "all keys with a substring in their key."
35
+ for orig in cls.objects:
36
+ if txt in orig.split()[0]:
37
+ yield orig, cls.get(orig)
38
+
39
+ @classmethod
40
+ def objs(cls, attr):
41
+ "objects with a certain attribute."
42
+ for obj in cls.objects.values():
43
+ if attr in dir(obj):
44
+ yield obj
45
+
46
+ @classmethod
47
+ def stop(cls):
48
+ "announce text on all objects with an announce method."
49
+ for obj in cls.objs("stop"):
50
+ if "wait" in dir(obj):
51
+ obj.wait()
52
+ obj.stop()
53
+
54
+
55
+ def __dir__():
56
+ return (
57
+ 'Broker',
58
+ )
@@ -0,0 +1,77 @@
1
+ # This file is placed in the Public Domain.
2
+
3
+
4
+ "write your own commands"
5
+
6
+
7
+ import inspect
8
+
9
+
10
+ from .objects import Methods
11
+ from .package import Mods
12
+
13
+
14
+ class Commands:
15
+
16
+ cmds = {}
17
+ names = {}
18
+
19
+ @classmethod
20
+ def add(cls, *args):
21
+ "add functions to commands."
22
+ for func in args:
23
+ name = func.__name__
24
+ cls.cmds[name] = func
25
+ modname = func.__module__.split(".")[-1]
26
+ if "__" in modname:
27
+ continue
28
+ cls.names[name] = modname
29
+
30
+ @classmethod
31
+ def command(cls, evt):
32
+ "command callback."
33
+ Methods.parse(evt, evt.text)
34
+ func = cls.get(evt.cmd)
35
+ if not func:
36
+ name = cls.names.get(evt.cmd)
37
+ mod = None
38
+ if name:
39
+ mod = Mods.get(name)
40
+ if mod:
41
+ cls.scan(mod)
42
+ func = cls.get(evt.cmd)
43
+ if func:
44
+ func(evt)
45
+ evt.display()
46
+ evt.ready()
47
+
48
+ @classmethod
49
+ def commands(cls, orig):
50
+ "list cpmmands available."
51
+ return cls.names.keys()
52
+
53
+ @classmethod
54
+ def get(cls, cmd):
55
+ "get function for command."
56
+ return cls.cmds.get(cmd, None)
57
+
58
+ @classmethod
59
+ def scan(cls, module):
60
+ "scan a module for functions with event as argument."
61
+ for key, cmdz in inspect.getmembers(module, inspect.isfunction):
62
+ if 'event' in inspect.signature(cmdz).parameters:
63
+ cls.add(cmdz)
64
+
65
+ @classmethod
66
+ def table(cls):
67
+ "load names from table."
68
+ mod = Mods.get("tbl")
69
+ names = getattr(mod, "NAMES", None)
70
+ if names:
71
+ cls.names.update(names)
72
+
73
+
74
+ def __dir__():
75
+ return (
76
+ 'Commands',
77
+ )
@@ -4,18 +4,13 @@
4
4
  "configurations"
5
5
 
6
6
 
7
- from .objects import Data, Dict, Methods
7
+ from .objects import Base, Object
8
8
  from .utility import Utils
9
9
 
10
10
 
11
- class Configuration(Data):
11
+ class Configuration(Base):
12
12
 
13
- def __init__(self, *args, **kwargs):
14
- super().__init__()
15
- if args:
16
- Dict.update(self, args[0])
17
- if kwargs:
18
- Dict.update(self, kwargs)
13
+ pass
19
14
 
20
15
 
21
16
  class MainConfig(type):
@@ -26,13 +21,14 @@ class MainConfig(type):
26
21
  return cls.__getattribute__(key)
27
22
 
28
23
  def __str__(cls):
29
- return str(Methods.skip(cls.__dict__))
24
+ return str(Object.skip(cls.__dict__))
30
25
 
31
26
 
32
27
  class Main(metaclass=MainConfig):
33
28
 
34
- name = Utils.pkgname(Configuration)
35
- wdr = f".{name}"
29
+ level = "info"
30
+ name = Utils.pkgname(MainConfig)
31
+ wdr = ""
36
32
 
37
33
 
38
34
  def __dir__():
@@ -5,25 +5,35 @@
5
5
 
6
6
 
7
7
  import json
8
+ import threading
8
9
  import types
9
10
 
10
11
 
12
+ from .objects import Object
13
+
14
+
11
15
  class Encoder(json.JSONEncoder):
12
16
 
17
+ lock = threading.RLock()
18
+
13
19
  def default(self, o):
14
- if isinstance(o, dict):
15
- return o.items()
16
- if isinstance(o, list):
17
- return iter(o)
18
- if isinstance(o, types.MappingProxyType):
19
- return dict(o)
20
- try:
21
- return json.JSONEncoder.default(self, o)
22
- except TypeError:
20
+ "generate serializable versions."
21
+ with Encoder.lock:
22
+ if isinstance(o, type):
23
+ return Object.skip(o)
24
+ if isinstance(o, dict):
25
+ return o.items()
26
+ if isinstance(o, list):
27
+ return iter(o)
28
+ if isinstance(o, types.MappingProxyType):
29
+ return dict(o)
23
30
  try:
24
- return vars(o)
31
+ return json.JSONEncoder.default(self, o)
25
32
  except TypeError:
26
- return repr(o)
33
+ try:
34
+ return vars(o)
35
+ except TypeError:
36
+ return repr(o)
27
37
 
28
38
 
29
39
  class Json:
@@ -4,32 +4,44 @@
4
4
  "callback engine"
5
5
 
6
6
 
7
+ import collections
7
8
  import logging
8
9
  import queue
9
10
  import threading
10
- import time
11
11
  import _thread
12
12
 
13
13
 
14
14
  from .brokers import Broker
15
+ from .command import Commands
16
+ from .objects import Base
15
17
  from .threads import Thread
16
18
 
17
19
 
18
- class Event:
20
+ class Event(Base):
19
21
 
20
22
  def __init__(self):
23
+ Base.__init__(self)
21
24
  self._ready = threading.Event()
22
25
  self._thr = None
23
- self.result = {}
24
26
  self.args = []
27
+ self.channel = ""
25
28
  self.index = 0
26
29
  self.kind = "event"
27
-
28
- def __getattr__(self, key):
29
- return self.__dict__.get(key, "")
30
-
31
- def __str__(self):
32
- return str(self.__dict__)
30
+ self.orig = ""
31
+ self.result = collections.deque()
32
+ self.text = ""
33
+
34
+ def display(self):
35
+ "print results."
36
+ bot = Broker.get(self.orig)
37
+ if bot:
38
+ bot.display(self)
39
+
40
+ def ok(self, txt=""):
41
+ "print ok response."
42
+ if not txt:
43
+ txt = self.text
44
+ self.reply(f"ok {txt}".strip())
33
45
 
34
46
  def ready(self):
35
47
  "flag message as ready."
@@ -37,13 +49,13 @@ class Event:
37
49
 
38
50
  def reply(self, text):
39
51
  "add text to result."
40
- self.result[time.time()] = text
52
+ self.result.append(text)
41
53
 
42
54
  def wait(self, timeout=0.0):
43
55
  "wait for completion."
44
- self._ready.wait(timeout or None)
45
56
  if self._thr:
46
57
  self._thr.join(timeout or None)
58
+ self._ready.wait(timeout or None)
47
59
 
48
60
 
49
61
  class Handler:
@@ -66,7 +78,7 @@ class Handler:
66
78
  "event loop."
67
79
  while self.running.is_set():
68
80
  event = self.queue.get()
69
- if not event:
81
+ if event is None:
70
82
  break
71
83
  event.orig = repr(self)
72
84
  self.callback(event)
@@ -79,16 +91,19 @@ class Handler:
79
91
  "register callback."
80
92
  self.cbs[kind] = callback
81
93
 
82
- def start(self):
94
+ def start(self, daemon=True):
83
95
  "start event handler loop."
84
96
  self.running.set()
85
- Thread.launch(self.loop)
97
+ Thread.launch(self.loop, daemon=daemon)
86
98
 
87
99
  def stop(self):
88
100
  "stop event handler loop."
89
101
  self.running.clear()
90
102
  self.queue.put(None)
91
103
 
104
+ def wait(self):
105
+ pass
106
+
92
107
 
93
108
  class Client(Handler):
94
109
 
@@ -108,8 +123,8 @@ class Client(Handler):
108
123
  def display(self, event):
109
124
  "display event results."
110
125
  with self.olock:
111
- for tme in event.result:
112
- self.dosay(event.channel, event.result.get(tme))
126
+ for txt in event.result:
127
+ self.dosay(event.channel, txt)
113
128
 
114
129
  def dosay(self, channel, text):
115
130
  "say called by display."
@@ -117,18 +132,15 @@ class Client(Handler):
117
132
 
118
133
  def loop(self):
119
134
  "input loop."
120
- while True:
121
- event = self.poll()
122
- if not event or self.stopped.is_set():
135
+ while self.running.is_set():
136
+ event = self.iqueue.get()
137
+ if not event:
123
138
  break
124
139
  event.orig = repr(self)
125
140
  self.callback(event)
126
141
 
127
- def poll(self):
128
- "return event."
129
- return self.iqueue.get()
130
-
131
142
  def put(self, event):
143
+ "put event into queue."
132
144
  self.iqueue.put(event)
133
145
 
134
146
  def raw(self, text):
@@ -138,25 +150,52 @@ class Client(Handler):
138
150
  "say text in channel."
139
151
  self.raw(text)
140
152
 
153
+ def stop(self):
154
+ "stop client."
155
+ self.running.clear()
156
+ self.iqueue.put(None)
141
157
 
142
- class Console(Client):
158
+
159
+ class Polled(Client):
143
160
 
144
161
  def loop(self):
145
- "input loop."
146
- while True:
162
+ "polling loop."
163
+ while self.running.is_set():
147
164
  event = self.poll()
148
- if not event or self.stopped.is_set():
165
+ if event is None:
149
166
  break
167
+ if not event.text:
168
+ event.ready()
169
+ continue
150
170
  event.orig = repr(self)
151
171
  self.callback(event)
152
- event.wait()
153
172
 
154
173
  def poll(self):
155
174
  "return event."
156
175
  return self.iqueue.get()
157
176
 
158
177
 
159
- class Output(Client):
178
+ class Console(Polled):
179
+
180
+ def __init__(self):
181
+ super().__init__()
182
+ self.register("command", Commands.command)
183
+
184
+ def loop(self):
185
+ "input loop."
186
+ while self.running.is_set():
187
+ event = self.poll()
188
+ if event is None:
189
+ break
190
+ if not event.text:
191
+ event.ready()
192
+ continue
193
+ event.orig = repr(self)
194
+ self.callback(event)
195
+ event.wait()
196
+
197
+
198
+ class Output(Polled):
160
199
 
161
200
  def __init__(self):
162
201
  super().__init__()
@@ -164,7 +203,7 @@ class Output(Client):
164
203
 
165
204
  def output(self):
166
205
  "output loop."
167
- while True:
206
+ while self.running.is_set():
168
207
  event = self.oqueue.get()
169
208
  if event is None:
170
209
  self.oqueue.task_done()
@@ -172,10 +211,10 @@ class Output(Client):
172
211
  self.display(event)
173
212
  self.oqueue.task_done()
174
213
 
175
- def start(self):
214
+ def start(self, daemon=True):
176
215
  "start output loop."
177
216
  super().start()
178
- Thread.launch(self.output)
217
+ Thread.launch(self.output, daemon=daemon)
179
218
 
180
219
  def stop(self):
181
220
  "stop output loop."
@@ -0,0 +1,54 @@
1
+ # This file is placed in the Public Domain.
2
+
3
+
4
+ "administrator"
5
+
6
+
7
+ from genocide.command import Commands
8
+ from genocide.configs import Main
9
+ from genocide.encoder import Json
10
+ from genocide.package import Mods
11
+ from genocide.persist import Workdir
12
+ from genocide.runtime import Runtime
13
+
14
+
15
+ def srv(event):
16
+ "generate systemd service file."
17
+ import getpass
18
+ name = getpass.getuser()
19
+ event.reply(SYSTEMD % (Main.name.upper(), name, name, name, Main.name))
20
+
21
+
22
+ def tbl(event):
23
+ "create table."
24
+ Runtime.md5s = {}
25
+ Commands.names = {}
26
+ Mods.md5s = {}
27
+ for name, module in Mods.all():
28
+ Commands.scan(module)
29
+ Runtime.setmd5s()
30
+ Mods.setmd5s()
31
+ event.reply("# This file is placed in the Pubic Domain.\n\n")
32
+ event.reply('"tables"\n\n')
33
+ event.reply(f"CORE = {Json.dumps(Runtime.md5s, indent=4, sort_keys=True)}\n\n")
34
+ event.reply(f"NAMES = {Json.dumps(Commands.names, indent=4, sort_keys=True)}\n\n")
35
+ event.reply(f"MD5 = {Json.dumps(Mods.md5s, indent=4, sort_keys=True)}")
36
+
37
+
38
+ def wdr(event):
39
+ "show working directory."
40
+ event.reply(Workdir.workdir())
41
+
42
+
43
+ SYSTEMD = """[Unit]
44
+ Description=%s
45
+ After=multi-user.target
46
+
47
+ [Service]
48
+ Type=simple
49
+ User=%s
50
+ Group=%s
51
+ ExecStart=/home/%s/.local/bin/%s -s
52
+
53
+ [Install]
54
+ WantedBy=multi-user.target"""
@@ -0,0 +1,40 @@
1
+ # This file is placed in the Public Domain.
2
+
3
+
4
+ "administrator"
5
+
6
+
7
+ import time
8
+
9
+
10
+ from genocide.command import Commands
11
+ from genocide.configs import Main
12
+ from genocide.package import Mods
13
+ from genocide.utility import Time, Utils
14
+
15
+
16
+ STARTTIME = time.time()
17
+
18
+
19
+ def cmd(event):
20
+ "list available commands."
21
+ event.reply(",".join(sorted(Commands.commands(event.orig))))
22
+
23
+
24
+ def mod(event):
25
+ "list available modules."
26
+ mods = Mods.list()
27
+ if not mods:
28
+ event.reply("no modules available")
29
+ return
30
+ event.reply(mods)
31
+
32
+
33
+ def upt(event):
34
+ "show uptiome."
35
+ event.reply(Time.elapsed(time.time()-STARTTIME))
36
+
37
+
38
+ def ver(event):
39
+ "show verson."
40
+ event.reply(f"{Main.name.upper()} {Utils.md5sum(Mods.path('tbl') or '')[:7]}")