1
1
import uwsgi
2
2
import traceback
3
3
import oxenmq
4
+ from oxenc import bt_deserialize
5
+ import time
4
6
from datetime import timedelta
7
+ import functools
5
8
6
9
from .web import app
7
- from .signal import Signal
8
10
from . import cleanup
9
11
from . import config
10
12
from . import crypto
13
+ from .omq import omq
11
14
12
15
# This is the uwsgi "mule" that handles things not related to serving HTTP requests:
13
16
# - it holds the oxenmq instance (with its own interface into sogs)
14
17
# - it handles cleanup jobs (e.g. periodic deletions)
15
18
16
- omq = None
17
-
18
19
19
20
def run ():
20
- if uwsgi .mule_id () != 1 :
21
- app .logger .critical (
22
- "Error: sogs.mule must be the first uwsgi mule (mule1), not mule{}" .format (
23
- uwsgi .mule_id ()
24
- )
25
- )
26
- raise RuntimeError ("Invalid uwsgi configuration" )
27
-
28
21
try :
29
- setup_omq ( )
22
+ app . logger . info ( "OxenMQ mule started." )
30
23
31
- run_loop ()
32
- except :
24
+ while True :
25
+ time .sleep (1 )
26
+
27
+ except Exception :
33
28
app .logger .error ("mule died via exception:\n {}" .format (traceback .format_exc ()))
34
29
35
30
@@ -38,13 +33,18 @@ def allow_conn(addr, pk, sn):
38
33
return oxenmq .AuthLevel .basic
39
34
40
35
36
+ def admin_conn (addr , pk , sn ):
37
+ return oxenmq .AuthLevel .admin
38
+
39
+
40
+ def inproc_fail (connid , reason ):
41
+ raise RuntimeError (f"Couldn't connect mule to itself: { reason } " )
42
+
43
+
41
44
def setup_omq ():
42
- global omq
43
- omq = oxenmq .OxenMQ (
44
- privkey = crypto ._privkey .encode (),
45
- pubkey = crypto .server_pubkey .encode (),
46
- log_level = oxenmq .LogLevel .fatal ,
47
- )
45
+ global omq , mule_conn
46
+
47
+ app .logger .debug ("Mule setting up omq" )
48
48
if isinstance (config .OMQ_LISTEN , list ):
49
49
listen = config .OMQ_LISTEN
50
50
elif config .OMQ_LISTEN is None :
@@ -54,41 +54,52 @@ def setup_omq():
54
54
for addr in listen :
55
55
omq .listen (addr , curve = True , allow_connection = allow_conn )
56
56
app .logger .info (f"OxenMQ listening on { addr } " )
57
+
58
+ # Internal socket for workers to talk to us:
59
+ omq .listen (config .OMQ_INTERNAL , curve = False , allow_connection = admin_conn )
60
+
61
+ # Periodic database cleanup timer:
57
62
omq .add_timer (cleanup .cleanup , timedelta (seconds = cleanup .INTERVAL ))
58
- omq .start ()
59
63
64
+ # Commands other workers can send to us, e.g. for notifications of activity for us to know about
65
+ worker = omq .add_category ("worker" , access_level = oxenmq .AuthLevel .admin )
66
+ worker .add_command ("message_posted" , message_posted )
67
+ worker .add_command ("messages_deleted" , messages_deleted )
68
+ worker .add_command ("message_edited" , message_edited )
60
69
61
- def run_loop ():
62
- app . logger . info ( "mule started!" )
70
+ app . logger . debug ( "Mule starting omq" )
71
+ omq . start ( )
63
72
64
- callbacks = {Signal .MESSAGE_POSTED : message_posted , Signal .MESSAGE_DELETED : message_deleted }
73
+ # Connect mule to itself so that if something the mule does wants to send something to the mule
74
+ # it will work. (And so be careful not to recurse!)
75
+ app .logger .debug ("Mule connecting to self" )
76
+ mule_conn = omq .connect_inproc (on_success = None , on_failure = inproc_fail )
65
77
66
- app .logger .info ("mule started 2!" )
67
- while True :
68
- app .logger .info ("mule started looping" )
69
- msg = uwsgi .mule_get_msg ()
70
- app .logger .info ("mule ax {}" .format (msg ))
78
+
79
+ def log_exceptions (f ):
80
+ @functools .wraps (f )
81
+ def wrapper (* args , ** kwargs ):
71
82
try :
72
- sig = Signal (int (msg .decode ()))
73
- except ValueError :
74
- app .logger .error (f"mule received unregistered uwsgi mule message { msg } " )
75
- continue
83
+ return f (* args , ** kwargs )
84
+ except Exception as e :
85
+ app .logger .error (f"{ f .__name__ } raised exception: { e } " )
86
+ raise
87
+
88
+ return wrapper
89
+
76
90
77
- if sig in callbacks :
78
- try :
79
- callbacks [sig ]()
80
- except Exception as e :
81
- app .logger .error (
82
- f"An exception occured while mule was processing uwsgi signal { sig } :\n { e } "
83
- )
84
- else :
85
- app .logger .error (f"mule received uwsgi signal { sig } but that signal has no handler!" )
86
- app .logger .info ("mule done" )
91
+ @log_exceptions
92
+ def message_posted (m : oxenmq .Message ):
93
+ id = bt_deserialize (m .data ()[0 ])
94
+ app .logger .warning (f"FIXME: mule -- message posted stub, id={ id } " )
87
95
88
96
89
- def message_posted ():
90
- app .logger .warning ("FIXME: mule -- message posted stub" )
97
+ @log_exceptions
98
+ def messages_deleted (m : oxenmq .Message ):
99
+ ids = bt_deserialize (m .data ()[0 ])
100
+ app .logger .warning (f"FIXME: mule -- message delete stub, deleted messages: { ids } " )
91
101
92
102
93
- def message_deleted ():
94
- app .logger .warning ("FIXME: mule -- message delete stub" )
103
+ @log_exceptions
104
+ def message_edited (m : oxenmq .Message ):
105
+ app .logger .warning ("FIXME: mule -- message edited stub" )
0 commit comments