11import json
2- from enum import Enum
2+ from enum import Enum , IntEnum
33
44from ovos_bus_client import Message
55from ovos_utils .json_helper import merge_dict
@@ -29,31 +29,45 @@ class HiveMessageType(str, Enum):
2929 BINARY = "bin" # binary data container, payload for something else
3030
3131
32+ class HiveMindBinaryPayloadType (IntEnum ):
33+ """ Pseudo extension type for binary payloads
34+ it doesnt describe the payload but rather provides instruction to hivemind about how to handle it"""
35+ UNDEFINED = 0 # no info provided about binary contents
36+ RAW_AUDIO = 1 # binary content is raw audio (TODO spec exactly what "raw audio" means)
37+ NUMPY_IMAGE = 2 # binary content is an image as a numpy array, eg. webcam picture
38+ FILE = 3 # binary is a file to be saved, additional metadata provided elsewhere
39+
40+
3241class HiveMessage :
3342 def __init__ (self , msg_type : Union [HiveMessageType , str ],
34- payload : Optional [Union [Message , 'HiveMessage' , str , dict ]] = None ,
43+ payload : Optional [Union [Message , 'HiveMessage' , str , dict , bytes ]] = None ,
3544 node : Optional [str ]= None ,
3645 source_peer : Optional [str ]= None ,
3746 route : Optional [List [str ]]= None ,
3847 target_peers : Optional [List [str ]]= None ,
3948 target_site_id : Optional [str ] = None ,
40- target_pubkey : Optional [str ] = None ):
49+ target_pubkey : Optional [str ] = None ,
50+ bin_type : HiveMindBinaryPayloadType = HiveMindBinaryPayloadType .UNDEFINED ):
4151 # except for the hivemind node classes receiving the message and
4252 # creating the object nothing should be able to change these values
4353 # node classes might change them a runtime by the private attribute
4454 # but end-users should consider them read_only
45-
46-
4755 if msg_type not in [m .value for m in HiveMessageType ]:
4856 raise ValueError ("Unknown HiveMessage.msg_type" )
57+ if msg_type != HiveMessageType .BINARY and bin_type != HiveMindBinaryPayloadType .UNDEFINED :
58+ raise ValueError ("bin_type can only be set for BINARY message type" )
59+
4960 self ._msg_type = msg_type
61+ self ._bin_type = bin_type
5062
5163 # the payload is more or less a free for all
5264 # the msg_type determines what happens to the message, but the
5365 # payload can simply be ignored by the receiving module
5466 # we store things in dict/json format, json is always used at the
5567 # transport layer before converting into any of the other formats
56- if isinstance (payload , Message ):
68+ if not isinstance (payload , bytes ) and msg_type == HiveMessageType .BINARY :
69+ raise ValueError (f"expected 'bytes' payload for HiveMessageType.BINARY, got { type (payload )} " )
70+ elif isinstance (payload , Message ):
5771 payload = {"type" : payload .msg_type ,
5872 "data" : payload .data ,
5973 "context" : payload .context }
@@ -99,7 +113,7 @@ def route(self) -> List[str]:
99113 return [r for r in self ._route if r .get ("targets" ) and r .get ("source" )]
100114
101115 @property
102- def payload (self ) -> Union ['HiveMessage' , Message , dict ]:
116+ def payload (self ) -> Union ['HiveMessage' , Message , dict , bytes ]:
103117 if self .msg_type in [HiveMessageType .BUS , HiveMessageType .SHARED_BUS ]:
104118 return Message (self ._payload ["type" ],
105119 data = self ._payload .get ("data" ),
@@ -111,9 +125,15 @@ def payload(self) -> Union['HiveMessage', Message, dict]:
111125 return HiveMessage (** self ._payload )
112126 return self ._payload
113127
128+ @property
129+ def bin_type (self ) -> HiveMindBinaryPayloadType :
130+ return self ._bin_type
131+
114132 @property
115133 def as_dict (self ) -> dict :
116134 pload = self ._payload
135+ if self .msg_type == HiveMessageType .BINARY :
136+ raise ValueError ("messages with type HiveMessageType.BINARY can not be cast to dict" )
117137 if isinstance (pload , HiveMessage ):
118138 pload = pload .as_dict
119139 elif isinstance (pload , Message ):
@@ -166,12 +186,19 @@ def deserialize(payload: Union[str, dict]) -> 'HiveMessage':
166186 target_pubkey = payload .get ("target_pubkey" ))
167187
168188 def __getitem__ (self , item ):
189+ if not isinstance (self ._payload , dict ):
190+ raise TypeError (f"Item access not supported for payload type { type (self ._payload )} " )
169191 return self ._payload .get (item )
170192
171193 def __setitem__ (self , key , value ):
172- self ._payload [key ] = value
194+ if isinstance (self ._payload , dict ):
195+ self ._payload [key ] = value
196+ else :
197+ raise TypeError (f"Item assignment not supported for payload type { type (self ._payload )} " )
173198
174199 def __str__ (self ):
200+ if self .msg_type == HiveMessageType .BINARY :
201+ return f"HiveMessage(BINARY:{ len (self ._payload )} ])"
175202 return self .as_json
176203
177204 def update_hop_data (self , data = None , ** kwargs ):
0 commit comments