1
- from enum import Enum
2
1
import json
3
- from ovos_utils .json_helper import merge_dict
2
+ from enum import Enum
3
+
4
4
from ovos_bus_client import Message
5
+ from ovos_utils .json_helper import merge_dict
6
+ from typing import Union , List , Optional
5
7
6
8
7
9
class HiveMessageType (str , Enum ):
8
10
HANDSHAKE = "shake" # negotiate initial connection
9
11
BUS = "bus" # request meant for internal mycroft-bus in master
10
12
SHARED_BUS = "shared_bus" # passive sharing of message
11
- # from mycroft-bus in slave
13
+ # from mycroft-bus in slave
14
+
15
+ INTERCOM = "intercom" # from satellite to satellite
16
+
12
17
BROADCAST = "broadcast" # forward message to all slaves
13
18
PROPAGATE = "propagate" # forward message to all slaves and masters
14
19
ESCALATE = "escalate" # forward message up the authority chain to all
15
- # masters
20
+ # masters
16
21
HELLO = "hello" # like escalate, used to announce the device
17
22
QUERY = "query" # like escalate, but stops once one of the nodes can
18
- # send a response
23
+ # send a response
19
24
CASCADE = "cascade" # like propagate, but expects a response back from
20
- # all nodes in the hive (responses optional)
25
+ # all nodes in the hive (responses optional)
21
26
PING = "ping" # like cascade, but used to map the network
22
27
RENDEZVOUS = "rendezvous" # reserved for rendezvous-nodes
23
28
THIRDPRTY = "3rdparty" # user land message, do whatever you want
24
29
BINARY = "bin" # binary data container, payload for something else
25
30
26
31
27
32
class HiveMessage :
28
- def __init__ (self , msg_type , payload = None , node = None , source_peer = None ,
29
- route = None , target_peers = None , meta = None , target_site_id = None ):
33
+ def __init__ (self , msg_type : Union [HiveMessageType , str ],
34
+ payload : Optional [Union [Message , 'HiveMessage' , str , dict ]] = None ,
35
+ node : Optional [str ]= None ,
36
+ source_peer : Optional [str ]= None ,
37
+ route : Optional [List [str ]]= None ,
38
+ target_peers : Optional [List [str ]]= None ,
39
+ target_site_id : Optional [str ] = None ,
40
+ target_pubkey : Optional [str ] = None ):
30
41
# except for the hivemind node classes receiving the message and
31
42
# creating the object nothing should be able to change these values
32
43
# node classes might change them a runtime by the private attribute
33
44
# but end-users should consider them read_only
45
+
46
+
34
47
if msg_type not in [m .value for m in HiveMessageType ]:
35
48
raise ValueError ("Unknown HiveMessage.msg_type" )
36
-
37
49
self ._msg_type = msg_type
50
+
38
51
# the payload is more or less a free for all
39
52
# the msg_type determines what happens to the message, but the
40
53
# payload can simply be ignored by the receiving module
41
-
42
- # some msg_types might return HiveMessage, others (mycroft) Message
43
- # we should support the dict/json format, json is used at the
44
- # transport layer before converting into any of these formats
54
+ # we store things in dict/json format, json is always used at the
55
+ # transport layer before converting into any of the other formats
45
56
if isinstance (payload , Message ):
46
57
payload = {"type" : payload .msg_type ,
47
58
"data" : payload .data ,
@@ -51,40 +62,44 @@ def __init__(self, msg_type, payload=None, node=None, source_peer=None,
51
62
self ._payload = payload or {}
52
63
53
64
self ._site_id = target_site_id
65
+ self ._target_pubkey = target_pubkey
54
66
self ._node = node # node semi-unique identifier
55
67
self ._source_peer = source_peer # peer_id
56
68
self ._route = route or [] # where did this message come from
57
69
self ._targets = target_peers or [] # where will it be sent
58
- self ._meta = meta or {}
59
70
60
71
@property
61
- def target_site_id (self ):
72
+ def target_site_id (self ) -> str :
62
73
return self ._site_id
63
74
64
75
@property
65
- def msg_type (self ):
76
+ def target_public_key (self ) -> str :
77
+ return self ._target_pubkey
78
+
79
+ @property
80
+ def msg_type (self ) -> str :
66
81
return self ._msg_type
67
82
68
83
@property
69
- def node_id (self ):
84
+ def node_id (self ) -> str :
70
85
return self ._node
71
86
72
87
@property
73
- def source_peer (self ):
88
+ def source_peer (self ) -> str :
74
89
return self ._source_peer
75
90
76
91
@property
77
- def target_peers (self ):
92
+ def target_peers (self ) -> List [ str ] :
78
93
if self .source_peer :
79
94
return self ._targets or [self ._source_peer ]
80
95
return self ._targets
81
96
82
97
@property
83
- def route (self ):
98
+ def route (self ) -> List [ str ] :
84
99
return [r for r in self ._route if r .get ("targets" ) and r .get ("source" )]
85
100
86
101
@property
87
- def payload (self ):
102
+ def payload (self ) -> Union [ 'HiveMessage' , Message , dict ] :
88
103
if self .msg_type in [HiveMessageType .BUS , HiveMessageType .SHARED_BUS ]:
89
104
return Message (self ._payload ["type" ],
90
105
data = self ._payload .get ("data" ),
@@ -97,37 +112,42 @@ def payload(self):
97
112
return self ._payload
98
113
99
114
@property
100
- def as_dict (self ):
115
+ def as_dict (self ) -> dict :
101
116
pload = self ._payload
102
117
if isinstance (pload , HiveMessage ):
103
- pload = pload .as_json
118
+ pload = pload .as_dict
104
119
elif isinstance (pload , Message ):
105
120
pload = pload .serialize ()
106
121
if isinstance (pload , str ):
107
122
pload = json .loads (pload )
123
+
124
+ assert isinstance (pload , dict )
125
+
108
126
return {"msg_type" : self .msg_type ,
109
127
"payload" : pload ,
110
128
"route" : self .route ,
111
129
"node" : self .node_id ,
112
130
"target_site_id" : self .target_site_id ,
131
+ "target_pubkey" : self .target_public_key ,
113
132
"source_peer" : self .source_peer }
114
133
115
134
@property
116
- def as_json (self ):
135
+ def as_json (self ) -> str :
117
136
return json .dumps (self .as_dict )
118
137
119
- def serialize (self ):
138
+ def serialize (self ) -> str :
120
139
return self .as_json
121
140
122
141
@staticmethod
123
- def deserialize (payload ) :
142
+ def deserialize (payload : Union [ str , dict ]) -> 'HiveMessage' :
124
143
if isinstance (payload , str ):
125
144
payload = json .loads (payload )
126
145
127
146
if "msg_type" in payload :
128
147
try :
129
148
return HiveMessage (payload ["msg_type" ], payload ["payload" ],
130
- target_site_id = payload .get ("target_site_id" ))
149
+ target_site_id = payload .get ("target_site_id" ),
150
+ target_pubkey = payload .get ("target_pubkey" ))
131
151
except :
132
152
pass # not a hivemind message
133
153
@@ -136,12 +156,14 @@ def deserialize(payload):
136
156
# NOTE: technically could also be SHARED_BUS or THIRDPRTY
137
157
return HiveMessage (HiveMessageType .BUS ,
138
158
Message .deserialize (payload ),
139
- target_site_id = payload .get ("target_site_id" ))
159
+ target_site_id = payload .get ("target_site_id" ),
160
+ target_pubkey = payload .get ("target_pubkey" ))
140
161
except :
141
162
pass # not a mycroft message
142
163
143
164
return HiveMessage (HiveMessageType .THIRDPRTY , payload ,
144
- target_site_id = payload .get ("target_site_id" ))
165
+ target_site_id = payload .get ("target_site_id" ),
166
+ target_pubkey = payload .get ("target_pubkey" ))
145
167
146
168
def __getitem__ (self , item ):
147
169
return self ._payload .get (item )
0 commit comments