imbot-sdk-python 0.1.0__py3-none-any.whl
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.
- imbot_sdk/__init__.py +57 -0
- imbot_sdk/client.py +1155 -0
- imbot_sdk/consts.py +36 -0
- imbot_sdk/data_accessor.py +35 -0
- imbot_sdk/listeners.py +67 -0
- imbot_sdk/messages/__init__.py +93 -0
- imbot_sdk/messages/base.py +54 -0
- imbot_sdk/messages/contents.py +463 -0
- imbot_sdk/models.py +99 -0
- imbot_sdk/pb/__init__.py +0 -0
- imbot_sdk/pb/appmessages_pb2.py +433 -0
- imbot_sdk/pb/chatroom_pb2.py +98 -0
- imbot_sdk/pb/connect_pb2.py +55 -0
- imbot_sdk/pb/rtcroom_pb2.py +82 -0
- imbot_sdk/py.typed +0 -0
- imbot_sdk_python-0.1.0.dist-info/METADATA +296 -0
- imbot_sdk_python-0.1.0.dist-info/RECORD +20 -0
- imbot_sdk_python-0.1.0.dist-info/WHEEL +5 -0
- imbot_sdk_python-0.1.0.dist-info/licenses/LICENSE +201 -0
- imbot_sdk_python-0.1.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,463 @@
|
|
|
1
|
+
"""Concrete message content models.
|
|
2
|
+
|
|
3
|
+
Each class serializes to a stable JSON shape, so messages sent from this SDK
|
|
4
|
+
are interchangeable with the other JuggleIM client SDKs.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import json
|
|
8
|
+
from typing import Dict, List, Optional
|
|
9
|
+
|
|
10
|
+
from ..models import (
|
|
11
|
+
Conversation,
|
|
12
|
+
UserInfo,
|
|
13
|
+
DEFAULT_MESSAGE_FLAGS,
|
|
14
|
+
MESSAGE_CONTENT_TYPE_UNKNOWN,
|
|
15
|
+
)
|
|
16
|
+
from .base import (
|
|
17
|
+
MessageContent,
|
|
18
|
+
_json_bytes,
|
|
19
|
+
MESSAGE_CONTENT_TYPE_TEXT,
|
|
20
|
+
MESSAGE_CONTENT_TYPE_IMAGE,
|
|
21
|
+
MESSAGE_CONTENT_TYPE_FILE,
|
|
22
|
+
MESSAGE_CONTENT_TYPE_VIDEO,
|
|
23
|
+
MESSAGE_CONTENT_TYPE_VOICE,
|
|
24
|
+
MESSAGE_CONTENT_TYPE_STREAM_TEXT,
|
|
25
|
+
MESSAGE_CONTENT_TYPE_RECALL_INFO,
|
|
26
|
+
MESSAGE_CONTENT_TYPE_MERGE,
|
|
27
|
+
MESSAGE_CONTENT_TYPE_THUMBNAIL_PACKED_IMAGE,
|
|
28
|
+
MESSAGE_CONTENT_TYPE_SNAPSHOT_PACKED_VIDEO,
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class TextMessage(MessageContent):
|
|
33
|
+
CONTENT_TYPE = MESSAGE_CONTENT_TYPE_TEXT
|
|
34
|
+
|
|
35
|
+
def __init__(self, content: str = "", extra: str = "") -> None:
|
|
36
|
+
self.content = content
|
|
37
|
+
self.extra = extra
|
|
38
|
+
|
|
39
|
+
def encode(self) -> bytes:
|
|
40
|
+
obj = {}
|
|
41
|
+
if self.content:
|
|
42
|
+
obj["content"] = self.content
|
|
43
|
+
if self.extra:
|
|
44
|
+
obj["extra"] = self.extra
|
|
45
|
+
return _json_bytes(obj)
|
|
46
|
+
|
|
47
|
+
def decode(self, data: bytes) -> None:
|
|
48
|
+
obj = json.loads(data or b"{}")
|
|
49
|
+
self.content = obj.get("content", "")
|
|
50
|
+
self.extra = obj.get("extra", "")
|
|
51
|
+
|
|
52
|
+
def conversation_digest(self) -> str:
|
|
53
|
+
return self.content
|
|
54
|
+
|
|
55
|
+
def get_search_content(self) -> str:
|
|
56
|
+
return self.content
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
class ImageMessage(MessageContent):
|
|
60
|
+
CONTENT_TYPE = MESSAGE_CONTENT_TYPE_IMAGE
|
|
61
|
+
|
|
62
|
+
def __init__(self) -> None:
|
|
63
|
+
self.url = ""
|
|
64
|
+
self.local_path = ""
|
|
65
|
+
self.thumbnail_url = ""
|
|
66
|
+
self.thumbnail_local_path = ""
|
|
67
|
+
self.height = 0
|
|
68
|
+
self.width = 0
|
|
69
|
+
self.extra = ""
|
|
70
|
+
self.size = 0
|
|
71
|
+
|
|
72
|
+
def encode(self) -> bytes:
|
|
73
|
+
obj = {"height": self.height, "width": self.width, "size": self.size}
|
|
74
|
+
if self.url:
|
|
75
|
+
obj["url"] = self.url
|
|
76
|
+
if self.local_path:
|
|
77
|
+
obj["local"] = self.local_path
|
|
78
|
+
if self.thumbnail_url:
|
|
79
|
+
obj["thumbnail"] = self.thumbnail_url
|
|
80
|
+
if self.thumbnail_local_path:
|
|
81
|
+
obj["thumbnailLocalPath"] = self.thumbnail_local_path
|
|
82
|
+
if self.extra:
|
|
83
|
+
obj["extra"] = self.extra
|
|
84
|
+
return _json_bytes(obj)
|
|
85
|
+
|
|
86
|
+
def decode(self, data: bytes) -> None:
|
|
87
|
+
obj = json.loads(data or b"{}")
|
|
88
|
+
self.url = obj.get("url", "")
|
|
89
|
+
self.local_path = obj.get("local", "")
|
|
90
|
+
self.thumbnail_url = obj.get("thumbnail", "")
|
|
91
|
+
self.thumbnail_local_path = obj.get("thumbnailLocalPath", "")
|
|
92
|
+
self.height = obj.get("height", 0)
|
|
93
|
+
self.width = obj.get("width", 0)
|
|
94
|
+
self.extra = obj.get("extra", "")
|
|
95
|
+
self.size = obj.get("size", 0)
|
|
96
|
+
|
|
97
|
+
def conversation_digest(self) -> str:
|
|
98
|
+
return "[Image]"
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
class FileMessage(MessageContent):
|
|
102
|
+
CONTENT_TYPE = MESSAGE_CONTENT_TYPE_FILE
|
|
103
|
+
|
|
104
|
+
def __init__(self) -> None:
|
|
105
|
+
self.name = ""
|
|
106
|
+
self.url = ""
|
|
107
|
+
self.local_path = ""
|
|
108
|
+
self.size = 0
|
|
109
|
+
self.type = ""
|
|
110
|
+
self.extra = ""
|
|
111
|
+
|
|
112
|
+
def encode(self) -> bytes:
|
|
113
|
+
obj = {"size": self.size}
|
|
114
|
+
if self.name:
|
|
115
|
+
obj["name"] = self.name
|
|
116
|
+
if self.url:
|
|
117
|
+
obj["url"] = self.url
|
|
118
|
+
if self.local_path:
|
|
119
|
+
obj["local"] = self.local_path
|
|
120
|
+
if self.type:
|
|
121
|
+
obj["type"] = self.type
|
|
122
|
+
if self.extra:
|
|
123
|
+
obj["extra"] = self.extra
|
|
124
|
+
return _json_bytes(obj)
|
|
125
|
+
|
|
126
|
+
def decode(self, data: bytes) -> None:
|
|
127
|
+
obj = json.loads(data or b"{}")
|
|
128
|
+
self.name = obj.get("name", "")
|
|
129
|
+
self.url = obj.get("url", "")
|
|
130
|
+
self.local_path = obj.get("local", "")
|
|
131
|
+
self.size = obj.get("size", 0)
|
|
132
|
+
self.type = obj.get("type", "")
|
|
133
|
+
self.extra = obj.get("extra", "")
|
|
134
|
+
|
|
135
|
+
def conversation_digest(self) -> str:
|
|
136
|
+
return "[File]"
|
|
137
|
+
|
|
138
|
+
def get_search_content(self) -> str:
|
|
139
|
+
return self.name
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
class VideoMessage(MessageContent):
|
|
143
|
+
CONTENT_TYPE = MESSAGE_CONTENT_TYPE_VIDEO
|
|
144
|
+
|
|
145
|
+
def __init__(self) -> None:
|
|
146
|
+
self.url = ""
|
|
147
|
+
self.local_path = ""
|
|
148
|
+
self.snapshot_url = ""
|
|
149
|
+
self.snapshot_local_path = ""
|
|
150
|
+
self.height = 0
|
|
151
|
+
self.width = 0
|
|
152
|
+
self.size = 0
|
|
153
|
+
self.duration = 0
|
|
154
|
+
self.extra = ""
|
|
155
|
+
|
|
156
|
+
def encode(self) -> bytes:
|
|
157
|
+
obj = {
|
|
158
|
+
"height": self.height,
|
|
159
|
+
"width": self.width,
|
|
160
|
+
"size": self.size,
|
|
161
|
+
"duration": self.duration,
|
|
162
|
+
}
|
|
163
|
+
if self.url:
|
|
164
|
+
obj["url"] = self.url
|
|
165
|
+
if self.local_path:
|
|
166
|
+
obj["local"] = self.local_path
|
|
167
|
+
if self.snapshot_url:
|
|
168
|
+
obj["poster"] = self.snapshot_url
|
|
169
|
+
if self.snapshot_local_path:
|
|
170
|
+
obj["snapshotLocalPath"] = self.snapshot_local_path
|
|
171
|
+
if self.extra:
|
|
172
|
+
obj["extra"] = self.extra
|
|
173
|
+
return _json_bytes(obj)
|
|
174
|
+
|
|
175
|
+
def decode(self, data: bytes) -> None:
|
|
176
|
+
obj = json.loads(data or b"{}")
|
|
177
|
+
self.url = obj.get("url", "")
|
|
178
|
+
self.local_path = obj.get("local", "")
|
|
179
|
+
self.snapshot_url = obj.get("poster", "")
|
|
180
|
+
self.snapshot_local_path = obj.get("snapshotLocalPath", "")
|
|
181
|
+
self.height = obj.get("height", 0)
|
|
182
|
+
self.width = obj.get("width", 0)
|
|
183
|
+
self.size = obj.get("size", 0)
|
|
184
|
+
self.duration = obj.get("duration", 0)
|
|
185
|
+
self.extra = obj.get("extra", "")
|
|
186
|
+
|
|
187
|
+
def conversation_digest(self) -> str:
|
|
188
|
+
return "[Video]"
|
|
189
|
+
|
|
190
|
+
|
|
191
|
+
class VoiceMessage(MessageContent):
|
|
192
|
+
CONTENT_TYPE = MESSAGE_CONTENT_TYPE_VOICE
|
|
193
|
+
|
|
194
|
+
def __init__(self) -> None:
|
|
195
|
+
self.url = ""
|
|
196
|
+
self.local_path = ""
|
|
197
|
+
self.duration = 0
|
|
198
|
+
self.extra = ""
|
|
199
|
+
|
|
200
|
+
def encode(self) -> bytes:
|
|
201
|
+
obj = {"duration": self.duration}
|
|
202
|
+
if self.url:
|
|
203
|
+
obj["url"] = self.url
|
|
204
|
+
if self.local_path:
|
|
205
|
+
obj["local"] = self.local_path
|
|
206
|
+
if self.extra:
|
|
207
|
+
obj["extra"] = self.extra
|
|
208
|
+
return _json_bytes(obj)
|
|
209
|
+
|
|
210
|
+
def decode(self, data: bytes) -> None:
|
|
211
|
+
obj = json.loads(data or b"{}")
|
|
212
|
+
self.url = obj.get("url", "")
|
|
213
|
+
self.local_path = obj.get("local", "")
|
|
214
|
+
self.duration = obj.get("duration", 0)
|
|
215
|
+
self.extra = obj.get("extra", "")
|
|
216
|
+
|
|
217
|
+
def conversation_digest(self) -> str:
|
|
218
|
+
return "[Voice]"
|
|
219
|
+
|
|
220
|
+
|
|
221
|
+
class StreamTextMessage(MessageContent):
|
|
222
|
+
CONTENT_TYPE = MESSAGE_CONTENT_TYPE_STREAM_TEXT
|
|
223
|
+
|
|
224
|
+
def __init__(self) -> None:
|
|
225
|
+
self.content = ""
|
|
226
|
+
self.is_finished = False
|
|
227
|
+
self.seq = 0
|
|
228
|
+
|
|
229
|
+
def encode(self) -> bytes:
|
|
230
|
+
obj = {"is_finished": self.is_finished, "seq": self.seq}
|
|
231
|
+
if self.content:
|
|
232
|
+
obj["content"] = self.content
|
|
233
|
+
return _json_bytes(obj)
|
|
234
|
+
|
|
235
|
+
def decode(self, data: bytes) -> None:
|
|
236
|
+
obj = json.loads(data or b"{}")
|
|
237
|
+
self.content = obj.get("content", "")
|
|
238
|
+
self.is_finished = obj.get("is_finished", False)
|
|
239
|
+
self.seq = obj.get("seq", 0)
|
|
240
|
+
|
|
241
|
+
def conversation_digest(self) -> str:
|
|
242
|
+
return self.content
|
|
243
|
+
|
|
244
|
+
def get_search_content(self) -> str:
|
|
245
|
+
return self.content
|
|
246
|
+
|
|
247
|
+
|
|
248
|
+
class RecallInfoMessage(MessageContent):
|
|
249
|
+
CONTENT_TYPE = MESSAGE_CONTENT_TYPE_RECALL_INFO
|
|
250
|
+
|
|
251
|
+
def __init__(self) -> None:
|
|
252
|
+
self.extra: Dict[str, str] = {}
|
|
253
|
+
|
|
254
|
+
def encode(self) -> bytes:
|
|
255
|
+
obj = {}
|
|
256
|
+
if self.extra:
|
|
257
|
+
obj["exts"] = self.extra
|
|
258
|
+
return _json_bytes(obj)
|
|
259
|
+
|
|
260
|
+
def decode(self, data: bytes) -> None:
|
|
261
|
+
obj = json.loads(data or b"{}")
|
|
262
|
+
self.extra = obj.get("exts", {}) or {}
|
|
263
|
+
|
|
264
|
+
|
|
265
|
+
class MergeMessagePreviewUnit:
|
|
266
|
+
def __init__(self, preview_content: str = "", sender: Optional[UserInfo] = None) -> None:
|
|
267
|
+
self.preview_content = preview_content
|
|
268
|
+
self.sender = sender
|
|
269
|
+
|
|
270
|
+
|
|
271
|
+
class MergeMessage(MessageContent):
|
|
272
|
+
CONTENT_TYPE = MESSAGE_CONTENT_TYPE_MERGE
|
|
273
|
+
|
|
274
|
+
def __init__(
|
|
275
|
+
self,
|
|
276
|
+
title: str = "",
|
|
277
|
+
conversation: Optional[Conversation] = None,
|
|
278
|
+
message_id_list: Optional[List[str]] = None,
|
|
279
|
+
preview_list: Optional[List[MergeMessagePreviewUnit]] = None,
|
|
280
|
+
) -> None:
|
|
281
|
+
message_id_list = list(message_id_list or [])
|
|
282
|
+
preview_list = list(preview_list or [])
|
|
283
|
+
if len(message_id_list) > 100:
|
|
284
|
+
message_id_list = message_id_list[:100]
|
|
285
|
+
if len(preview_list) > 10:
|
|
286
|
+
preview_list = preview_list[:10]
|
|
287
|
+
self.title = title
|
|
288
|
+
self.container_msg_id = ""
|
|
289
|
+
self.conversation = conversation
|
|
290
|
+
self.message_id_list = message_id_list
|
|
291
|
+
self.preview_list = preview_list
|
|
292
|
+
self.extra = ""
|
|
293
|
+
|
|
294
|
+
def encode(self) -> bytes:
|
|
295
|
+
dto: Dict[str, object] = {}
|
|
296
|
+
if self.title:
|
|
297
|
+
dto["title"] = self.title
|
|
298
|
+
if self.container_msg_id:
|
|
299
|
+
dto["containerMsgId"] = self.container_msg_id
|
|
300
|
+
if self.conversation is not None:
|
|
301
|
+
if self.conversation.conversation:
|
|
302
|
+
dto["conversationId"] = self.conversation.conversation
|
|
303
|
+
if self.conversation.conversation_type:
|
|
304
|
+
dto["conversationType"] = int(self.conversation.conversation_type)
|
|
305
|
+
if self.conversation.sub_channel:
|
|
306
|
+
dto["sub_channel"] = self.conversation.sub_channel
|
|
307
|
+
if self.message_id_list:
|
|
308
|
+
dto["messageIdList"] = self.message_id_list
|
|
309
|
+
previews = []
|
|
310
|
+
for preview in self.preview_list:
|
|
311
|
+
unit: Dict[str, str] = {}
|
|
312
|
+
if preview.preview_content:
|
|
313
|
+
unit["content"] = preview.preview_content
|
|
314
|
+
if preview.sender is not None:
|
|
315
|
+
if preview.sender.user_id:
|
|
316
|
+
unit["userId"] = preview.sender.user_id
|
|
317
|
+
if preview.sender.user_name:
|
|
318
|
+
unit["userName"] = preview.sender.user_name
|
|
319
|
+
if preview.sender.user_portrait:
|
|
320
|
+
unit["portrait"] = preview.sender.user_portrait
|
|
321
|
+
previews.append(unit)
|
|
322
|
+
if previews:
|
|
323
|
+
dto["previewList"] = previews
|
|
324
|
+
if self.extra:
|
|
325
|
+
dto["extra"] = self.extra
|
|
326
|
+
return _json_bytes(dto)
|
|
327
|
+
|
|
328
|
+
def decode(self, data: bytes) -> None:
|
|
329
|
+
dto = json.loads(data or b"{}")
|
|
330
|
+
self.title = dto.get("title", "")
|
|
331
|
+
self.container_msg_id = dto.get("containerMsgId", "")
|
|
332
|
+
self.message_id_list = dto.get("messageIdList", []) or []
|
|
333
|
+
self.extra = dto.get("extra", "")
|
|
334
|
+
conv_id = dto.get("conversationId", "")
|
|
335
|
+
if conv_id:
|
|
336
|
+
self.conversation = Conversation(
|
|
337
|
+
conversation=conv_id,
|
|
338
|
+
conversation_type=dto.get("conversationType", 0),
|
|
339
|
+
sub_channel=dto.get("sub_channel", ""),
|
|
340
|
+
)
|
|
341
|
+
self.preview_list = []
|
|
342
|
+
for unit in dto.get("previewList", []) or []:
|
|
343
|
+
self.preview_list.append(
|
|
344
|
+
MergeMessagePreviewUnit(
|
|
345
|
+
preview_content=unit.get("content", ""),
|
|
346
|
+
sender=UserInfo(
|
|
347
|
+
user_id=unit.get("userId", ""),
|
|
348
|
+
user_name=unit.get("userName", ""),
|
|
349
|
+
user_portrait=unit.get("portrait", ""),
|
|
350
|
+
),
|
|
351
|
+
)
|
|
352
|
+
)
|
|
353
|
+
|
|
354
|
+
def conversation_digest(self) -> str:
|
|
355
|
+
return "[Merge]"
|
|
356
|
+
|
|
357
|
+
|
|
358
|
+
class ThumbnailPackedImageMessage(MessageContent):
|
|
359
|
+
CONTENT_TYPE = MESSAGE_CONTENT_TYPE_THUMBNAIL_PACKED_IMAGE
|
|
360
|
+
|
|
361
|
+
def __init__(self) -> None:
|
|
362
|
+
self.image_uri = ""
|
|
363
|
+
self.local_path = ""
|
|
364
|
+
self.content = ""
|
|
365
|
+
self.height = 0
|
|
366
|
+
self.width = 0
|
|
367
|
+
self.extra = ""
|
|
368
|
+
self.size = 0
|
|
369
|
+
|
|
370
|
+
def encode(self) -> bytes:
|
|
371
|
+
obj = {"height": self.height, "width": self.width, "size": self.size}
|
|
372
|
+
if self.image_uri:
|
|
373
|
+
obj["imageUri"] = self.image_uri
|
|
374
|
+
if self.local_path:
|
|
375
|
+
obj["local"] = self.local_path
|
|
376
|
+
if self.content:
|
|
377
|
+
obj["content"] = self.content
|
|
378
|
+
if self.extra:
|
|
379
|
+
obj["extra"] = self.extra
|
|
380
|
+
return _json_bytes(obj)
|
|
381
|
+
|
|
382
|
+
def decode(self, data: bytes) -> None:
|
|
383
|
+
obj = json.loads(data or b"{}")
|
|
384
|
+
self.image_uri = obj.get("imageUri", "")
|
|
385
|
+
self.local_path = obj.get("local", "")
|
|
386
|
+
self.content = obj.get("content", "")
|
|
387
|
+
self.height = obj.get("height", 0)
|
|
388
|
+
self.width = obj.get("width", 0)
|
|
389
|
+
self.extra = obj.get("extra", "")
|
|
390
|
+
self.size = obj.get("size", 0)
|
|
391
|
+
|
|
392
|
+
def conversation_digest(self) -> str:
|
|
393
|
+
return "[Image]"
|
|
394
|
+
|
|
395
|
+
|
|
396
|
+
class SnapshotPackedVideoMessage(MessageContent):
|
|
397
|
+
CONTENT_TYPE = MESSAGE_CONTENT_TYPE_SNAPSHOT_PACKED_VIDEO
|
|
398
|
+
|
|
399
|
+
def __init__(self) -> None:
|
|
400
|
+
self.sight_url = ""
|
|
401
|
+
self.local_path = ""
|
|
402
|
+
self.content = ""
|
|
403
|
+
self.height = 0
|
|
404
|
+
self.width = 0
|
|
405
|
+
self.size = 0
|
|
406
|
+
self.duration = 0
|
|
407
|
+
self.name = ""
|
|
408
|
+
self.extra = ""
|
|
409
|
+
|
|
410
|
+
def encode(self) -> bytes:
|
|
411
|
+
obj = {
|
|
412
|
+
"height": self.height,
|
|
413
|
+
"width": self.width,
|
|
414
|
+
"size": self.size,
|
|
415
|
+
"duration": self.duration,
|
|
416
|
+
}
|
|
417
|
+
if self.sight_url:
|
|
418
|
+
obj["sightUrl"] = self.sight_url
|
|
419
|
+
if self.local_path:
|
|
420
|
+
obj["local"] = self.local_path
|
|
421
|
+
if self.content:
|
|
422
|
+
obj["content"] = self.content
|
|
423
|
+
if self.name:
|
|
424
|
+
obj["name"] = self.name
|
|
425
|
+
if self.extra:
|
|
426
|
+
obj["extra"] = self.extra
|
|
427
|
+
return _json_bytes(obj)
|
|
428
|
+
|
|
429
|
+
def decode(self, data: bytes) -> None:
|
|
430
|
+
obj = json.loads(data or b"{}")
|
|
431
|
+
self.sight_url = obj.get("sightUrl", "")
|
|
432
|
+
self.local_path = obj.get("local", "")
|
|
433
|
+
self.content = obj.get("content", "")
|
|
434
|
+
self.height = obj.get("height", 0)
|
|
435
|
+
self.width = obj.get("width", 0)
|
|
436
|
+
self.size = obj.get("size", 0)
|
|
437
|
+
self.duration = obj.get("duration", 0)
|
|
438
|
+
self.name = obj.get("name", "")
|
|
439
|
+
self.extra = obj.get("extra", "")
|
|
440
|
+
|
|
441
|
+
def conversation_digest(self) -> str:
|
|
442
|
+
return "[Video]"
|
|
443
|
+
|
|
444
|
+
|
|
445
|
+
class UnknownMessage(MessageContent):
|
|
446
|
+
"""Fallback for content types the SDK does not model."""
|
|
447
|
+
|
|
448
|
+
def __init__(self, message_type: str = "") -> None:
|
|
449
|
+
self.message_type = message_type
|
|
450
|
+
self.content = ""
|
|
451
|
+
self.flags = 0
|
|
452
|
+
|
|
453
|
+
def encode(self) -> bytes:
|
|
454
|
+
return self.content.encode("utf-8") if isinstance(self.content, str) else bytes(self.content)
|
|
455
|
+
|
|
456
|
+
def decode(self, data: bytes) -> None:
|
|
457
|
+
self.content = data.decode("utf-8", errors="replace") if isinstance(data, (bytes, bytearray)) else str(data)
|
|
458
|
+
|
|
459
|
+
def get_content_type(self) -> str:
|
|
460
|
+
return self.message_type or MESSAGE_CONTENT_TYPE_UNKNOWN
|
|
461
|
+
|
|
462
|
+
def get_flags(self) -> int:
|
|
463
|
+
return self.flags
|
imbot_sdk/models.py
ADDED
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
"""High-level domain models exposed to SDK users.
|
|
2
|
+
|
|
3
|
+
:class:`Conversation`, :class:`Message`, :class:`ConversationInfo`,
|
|
4
|
+
:class:`UserInfo` and friends — plain data holders decoupled from the protobuf
|
|
5
|
+
wire types.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from dataclasses import dataclass, field
|
|
9
|
+
from typing import Dict, List, Optional
|
|
10
|
+
|
|
11
|
+
from .pb import appmessages_pb2 as pb
|
|
12
|
+
|
|
13
|
+
# Message flag bits
|
|
14
|
+
MESSAGE_FLAG_NONE = 0
|
|
15
|
+
MESSAGE_FLAG_IS_CMD = 1
|
|
16
|
+
MESSAGE_FLAG_IS_COUNTABLE = 2
|
|
17
|
+
MESSAGE_FLAG_IS_STATUS = 4
|
|
18
|
+
MESSAGE_FLAG_IS_SAVE = 8
|
|
19
|
+
MESSAGE_FLAG_IS_MODIFIED = 16
|
|
20
|
+
MESSAGE_FLAG_IS_MERGED = 32
|
|
21
|
+
MESSAGE_FLAG_IS_MUTE = 64
|
|
22
|
+
MESSAGE_FLAG_IS_BROADCAST = 128
|
|
23
|
+
|
|
24
|
+
DEFAULT_MESSAGE_FLAGS = MESSAGE_FLAG_IS_COUNTABLE | MESSAGE_FLAG_IS_SAVE
|
|
25
|
+
|
|
26
|
+
MESSAGE_CONTENT_TYPE_UNKNOWN = "jg:unknown"
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
@dataclass
|
|
30
|
+
class UserInfo:
|
|
31
|
+
user_id: str = ""
|
|
32
|
+
user_name: str = ""
|
|
33
|
+
user_portrait: str = ""
|
|
34
|
+
extras: Dict[str, str] = field(default_factory=dict)
|
|
35
|
+
updated_time: int = 0
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
@dataclass
|
|
39
|
+
class Conversation:
|
|
40
|
+
"""Target conversation + channel type."""
|
|
41
|
+
|
|
42
|
+
conversation: str = ""
|
|
43
|
+
sub_channel: str = ""
|
|
44
|
+
conversation_type: int = pb.Unknown # ChannelType enum value
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
@dataclass
|
|
48
|
+
class MessageMentionInfo:
|
|
49
|
+
mention_type: int = pb.MentionDefault
|
|
50
|
+
target_user_ids: List[str] = field(default_factory=list)
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
@dataclass
|
|
54
|
+
class Message:
|
|
55
|
+
conversation: Optional[Conversation] = None
|
|
56
|
+
msg_id: str = ""
|
|
57
|
+
has_read: bool = False
|
|
58
|
+
msg_time: int = 0
|
|
59
|
+
sender_id: str = ""
|
|
60
|
+
msg_type: str = ""
|
|
61
|
+
msg_content: object = None # a messages.MessageContent subclass
|
|
62
|
+
group_id: str = ""
|
|
63
|
+
refered_message: Optional["Message"] = None
|
|
64
|
+
mention_info: Optional[MessageMentionInfo] = None
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
@dataclass
|
|
68
|
+
class ConversationMentionInfo:
|
|
69
|
+
sender_id: str = ""
|
|
70
|
+
msg_id: str = ""
|
|
71
|
+
msg_time: int = 0
|
|
72
|
+
mention_type: int = pb.MentionDefault
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
@dataclass
|
|
76
|
+
class ConversationInfo:
|
|
77
|
+
conversation: Optional[Conversation] = None
|
|
78
|
+
latest_message: Optional[Message] = None
|
|
79
|
+
unread_count: int = 0
|
|
80
|
+
sort_time: int = 0
|
|
81
|
+
is_top: bool = False
|
|
82
|
+
mute: bool = False
|
|
83
|
+
draft: str = ""
|
|
84
|
+
mention_info: Optional[ConversationMentionInfo] = None
|
|
85
|
+
display_name: str = ""
|
|
86
|
+
alias: str = ""
|
|
87
|
+
portrait: str = ""
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
@dataclass
|
|
91
|
+
class MessageReactionItem:
|
|
92
|
+
reaction_id: str = ""
|
|
93
|
+
user_info_list: List[UserInfo] = field(default_factory=list)
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
@dataclass
|
|
97
|
+
class MessageReaction:
|
|
98
|
+
message_id: str = ""
|
|
99
|
+
item_list: List[MessageReactionItem] = field(default_factory=list)
|
imbot_sdk/pb/__init__.py
ADDED
|
File without changes
|