dimp 1.0.2__tar.gz → 2.0.0__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.
- {dimp-1.0.2 → dimp-2.0.0}/PKG-INFO +1 -1
- {dimp-1.0.2 → dimp-2.0.0}/dimp/barrack.py +27 -27
- {dimp-1.0.2 → dimp-2.0.0}/dimp/dkd/commands.py +12 -14
- {dimp-1.0.2 → dimp-2.0.0}/dimp/dkd/contents.py +73 -49
- {dimp-1.0.2 → dimp-2.0.0}/dimp/dkd/files.py +16 -89
- {dimp-1.0.2 → dimp-2.0.0}/dimp/dkd/groups.py +9 -2
- {dimp-1.0.2 → dimp-2.0.0}/dimp/mkm/delegate.py +2 -2
- {dimp-1.0.2 → dimp-2.0.0}/dimp/mkm/entity.py +8 -8
- {dimp-1.0.2 → dimp-2.0.0}/dimp/mkm/group.py +28 -27
- {dimp-1.0.2 → dimp-2.0.0}/dimp/mkm/user.py +38 -36
- {dimp-1.0.2 → dimp-2.0.0}/dimp/packer.py +6 -6
- {dimp-1.0.2 → dimp-2.0.0}/dimp/processor.py +5 -5
- {dimp-1.0.2 → dimp-2.0.0}/dimp/protocol/commands.py +8 -11
- {dimp-1.0.2 → dimp-2.0.0}/dimp/protocol/contents.py +63 -22
- {dimp-1.0.2 → dimp-2.0.0}/dimp/protocol/files.py +6 -6
- {dimp-1.0.2 → dimp-2.0.0}/dimp/protocol/groups.py +9 -3
- {dimp-1.0.2 → dimp-2.0.0}/dimp/transceiver.py +24 -24
- {dimp-1.0.2 → dimp-2.0.0}/dimp.egg-info/PKG-INFO +1 -1
- dimp-2.0.0/dimp.egg-info/requires.txt +2 -0
- {dimp-1.0.2 → dimp-2.0.0}/setup.py +3 -3
- dimp-1.0.2/dimp.egg-info/requires.txt +0 -2
- {dimp-1.0.2 → dimp-2.0.0}/README.md +0 -0
- {dimp-1.0.2 → dimp-2.0.0}/dimp/__init__.py +0 -0
- {dimp-1.0.2 → dimp-2.0.0}/dimp/crypto/__init__.py +0 -0
- {dimp-1.0.2 → dimp-2.0.0}/dimp/crypto/keys.py +0 -0
- {dimp-1.0.2 → dimp-2.0.0}/dimp/crypto/pnf.py +0 -0
- {dimp-1.0.2 → dimp-2.0.0}/dimp/crypto/ted.py +0 -0
- {dimp-1.0.2 → dimp-2.0.0}/dimp/dkd/__init__.py +0 -0
- {dimp-1.0.2 → dimp-2.0.0}/dimp/dkd/base.py +0 -0
- {dimp-1.0.2 → dimp-2.0.0}/dimp/dkd/customized.py +0 -0
- {dimp-1.0.2 → dimp-2.0.0}/dimp/dkd/factory.py +0 -0
- {dimp-1.0.2 → dimp-2.0.0}/dimp/dkd/group_admins.py +0 -0
- {dimp-1.0.2 → dimp-2.0.0}/dimp/dkd/money.py +0 -0
- {dimp-1.0.2 → dimp-2.0.0}/dimp/dkd/receipt.py +0 -0
- {dimp-1.0.2 → dimp-2.0.0}/dimp/mkm/__init__.py +0 -0
- {dimp-1.0.2 → dimp-2.0.0}/dimp/mkm/docs.py +0 -0
- {dimp-1.0.2 → dimp-2.0.0}/dimp/mkm/document.py +0 -0
- {dimp-1.0.2 → dimp-2.0.0}/dimp/mkm/helper.py +0 -0
- {dimp-1.0.2 → dimp-2.0.0}/dimp/mkm/meta.py +0 -0
- {dimp-1.0.2 → dimp-2.0.0}/dimp/msg/__init__.py +0 -0
- {dimp-1.0.2 → dimp-2.0.0}/dimp/msg/base.py +0 -0
- {dimp-1.0.2 → dimp-2.0.0}/dimp/msg/envelope.py +0 -0
- {dimp-1.0.2 → dimp-2.0.0}/dimp/msg/instant.py +0 -0
- {dimp-1.0.2 → dimp-2.0.0}/dimp/msg/reliable.py +0 -0
- {dimp-1.0.2 → dimp-2.0.0}/dimp/msg/secure.py +0 -0
- {dimp-1.0.2 → dimp-2.0.0}/dimp/protocol/__init__.py +0 -0
- {dimp-1.0.2 → dimp-2.0.0}/dimp/protocol/customized.py +0 -0
- {dimp-1.0.2 → dimp-2.0.0}/dimp/protocol/docs.py +0 -0
- {dimp-1.0.2 → dimp-2.0.0}/dimp/protocol/money.py +0 -0
- {dimp-1.0.2 → dimp-2.0.0}/dimp/protocol/receipt.py +0 -0
- {dimp-1.0.2 → dimp-2.0.0}/dimp.egg-info/SOURCES.txt +0 -0
- {dimp-1.0.2 → dimp-2.0.0}/dimp.egg-info/dependency_links.txt +0 -0
- {dimp-1.0.2 → dimp-2.0.0}/dimp.egg-info/top_level.txt +0 -0
- {dimp-1.0.2 → dimp-2.0.0}/setup.cfg +0 -0
|
@@ -85,7 +85,7 @@ class Barrack(EntityDelegate, UserDataSource, GroupDataSource, ABC):
|
|
|
85
85
|
return finger >> 1
|
|
86
86
|
|
|
87
87
|
@abstractmethod # protected
|
|
88
|
-
def create_user(self, identifier: ID) -> Optional[User]:
|
|
88
|
+
async def create_user(self, identifier: ID) -> Optional[User]:
|
|
89
89
|
"""
|
|
90
90
|
Create user when visa.key exists
|
|
91
91
|
|
|
@@ -95,7 +95,7 @@ class Barrack(EntityDelegate, UserDataSource, GroupDataSource, ABC):
|
|
|
95
95
|
raise NotImplemented
|
|
96
96
|
|
|
97
97
|
@abstractmethod # protected
|
|
98
|
-
def create_group(self, identifier: ID) -> Optional[Group]:
|
|
98
|
+
async def create_group(self, identifier: ID) -> Optional[Group]:
|
|
99
99
|
"""
|
|
100
100
|
Create group when members exist
|
|
101
101
|
|
|
@@ -105,25 +105,25 @@ class Barrack(EntityDelegate, UserDataSource, GroupDataSource, ABC):
|
|
|
105
105
|
raise NotImplemented
|
|
106
106
|
|
|
107
107
|
# protected
|
|
108
|
-
def
|
|
109
|
-
visa = self.
|
|
108
|
+
async def get_visa_key(self, identifier: ID) -> Optional[EncryptKey]:
|
|
109
|
+
visa = await self.get_visa(identifier=identifier)
|
|
110
110
|
if visa is not None: # and visa.valid:
|
|
111
111
|
return visa.public_key
|
|
112
112
|
|
|
113
113
|
# protected
|
|
114
|
-
def
|
|
115
|
-
meta = self.
|
|
114
|
+
async def get_meta_key(self, identifier: ID) -> Optional[VerifyKey]:
|
|
115
|
+
meta = await self.get_meta(identifier=identifier)
|
|
116
116
|
if meta is not None: # and meta.valid:
|
|
117
117
|
return meta.public_key
|
|
118
118
|
|
|
119
|
-
def
|
|
119
|
+
async def get_visa(self, identifier: ID) -> Optional[Visa]:
|
|
120
120
|
""" Get last visa document """
|
|
121
|
-
documents = self.
|
|
121
|
+
documents = await self.get_documents(identifier=identifier)
|
|
122
122
|
return DocumentHelper.last_visa(documents=documents)
|
|
123
123
|
|
|
124
|
-
def
|
|
124
|
+
async def get_bulletin(self, identifier: ID) -> Optional[Bulletin]:
|
|
125
125
|
""" get last bulletin document """
|
|
126
|
-
documents = self.
|
|
126
|
+
documents = await self.get_documents(identifier=identifier)
|
|
127
127
|
return DocumentHelper.last_bulletin(documents=documents)
|
|
128
128
|
|
|
129
129
|
#
|
|
@@ -131,23 +131,23 @@ class Barrack(EntityDelegate, UserDataSource, GroupDataSource, ABC):
|
|
|
131
131
|
#
|
|
132
132
|
|
|
133
133
|
# Override
|
|
134
|
-
def
|
|
134
|
+
async def get_user(self, identifier: ID) -> Optional[User]:
|
|
135
135
|
# 1. get from user cache
|
|
136
136
|
usr = self.__users.get(identifier)
|
|
137
137
|
if usr is None:
|
|
138
138
|
# 2. create and cache it
|
|
139
|
-
usr = self.create_user(identifier=identifier)
|
|
139
|
+
usr = await self.create_user(identifier=identifier)
|
|
140
140
|
if usr is not None:
|
|
141
141
|
self.cache_user(user=usr)
|
|
142
142
|
return usr
|
|
143
143
|
|
|
144
144
|
# Override
|
|
145
|
-
def
|
|
145
|
+
async def get_group(self, identifier: ID) -> Optional[Group]:
|
|
146
146
|
# 1. get from group cache
|
|
147
147
|
grp = self.__groups.get(identifier)
|
|
148
148
|
if grp is None:
|
|
149
149
|
# 2. create and cache it
|
|
150
|
-
grp = self.create_group(identifier=identifier)
|
|
150
|
+
grp = await self.create_group(identifier=identifier)
|
|
151
151
|
if grp is not None:
|
|
152
152
|
self.cache_group(group=grp)
|
|
153
153
|
return grp
|
|
@@ -157,30 +157,30 @@ class Barrack(EntityDelegate, UserDataSource, GroupDataSource, ABC):
|
|
|
157
157
|
#
|
|
158
158
|
|
|
159
159
|
# Override
|
|
160
|
-
def public_key_for_encryption(self, identifier: ID) -> Optional[EncryptKey]:
|
|
160
|
+
async def public_key_for_encryption(self, identifier: ID) -> Optional[EncryptKey]:
|
|
161
161
|
# 1. get key from visa
|
|
162
|
-
key = self.
|
|
162
|
+
key = await self.get_visa_key(identifier=identifier)
|
|
163
163
|
if key is not None:
|
|
164
164
|
# if visa.key exists, use it for encryption
|
|
165
165
|
return key
|
|
166
166
|
# 2. get key from meta
|
|
167
|
-
key = self.
|
|
167
|
+
key = await self.get_meta_key(identifier=identifier)
|
|
168
168
|
if isinstance(key, EncryptKey):
|
|
169
169
|
# if visa.key not exists and meta.key is encrypt key,
|
|
170
170
|
# use it for encryption
|
|
171
171
|
return key
|
|
172
172
|
|
|
173
173
|
# Override
|
|
174
|
-
def public_keys_for_verification(self, identifier: ID) -> List[VerifyKey]:
|
|
174
|
+
async def public_keys_for_verification(self, identifier: ID) -> List[VerifyKey]:
|
|
175
175
|
keys = []
|
|
176
176
|
# 1. get key from meta
|
|
177
|
-
key = self.
|
|
177
|
+
key = await self.get_meta_key(identifier=identifier)
|
|
178
178
|
if key is not None:
|
|
179
179
|
# the sender may use identity key to sign message.data,
|
|
180
180
|
# try to verify it with meta.key
|
|
181
181
|
keys.append(key)
|
|
182
182
|
# 2. get key from visa
|
|
183
|
-
key = self.
|
|
183
|
+
key = await self.get_visa_key(identifier=identifier)
|
|
184
184
|
if isinstance(key, VerifyKey):
|
|
185
185
|
# the sender may use communication key to sign message.data,
|
|
186
186
|
# so try to verify it with visa.key here
|
|
@@ -193,19 +193,19 @@ class Barrack(EntityDelegate, UserDataSource, GroupDataSource, ABC):
|
|
|
193
193
|
#
|
|
194
194
|
|
|
195
195
|
# Override
|
|
196
|
-
def
|
|
196
|
+
async def get_founder(self, identifier: ID) -> Optional[ID]:
|
|
197
197
|
# check for broadcast
|
|
198
198
|
if identifier.is_broadcast:
|
|
199
199
|
# founder of broadcast group
|
|
200
200
|
return BroadcastHelper.broadcast_founder(group=identifier)
|
|
201
201
|
# get from document
|
|
202
|
-
doc = self.
|
|
202
|
+
doc = await self.get_bulletin(identifier=identifier)
|
|
203
203
|
if doc is not None: # and doc.valid:
|
|
204
204
|
return doc.founder
|
|
205
205
|
# TODO: load founder from database
|
|
206
206
|
|
|
207
207
|
# Override
|
|
208
|
-
def
|
|
208
|
+
async def get_owner(self, identifier: ID) -> Optional[ID]:
|
|
209
209
|
# check for broadcast
|
|
210
210
|
if identifier.is_broadcast:
|
|
211
211
|
# owner of broadcast group
|
|
@@ -213,11 +213,11 @@ class Barrack(EntityDelegate, UserDataSource, GroupDataSource, ABC):
|
|
|
213
213
|
# check group type
|
|
214
214
|
if identifier.type == EntityType.GROUP:
|
|
215
215
|
# Polylogue's owner is its founder
|
|
216
|
-
return self.
|
|
216
|
+
return await self.get_founder(identifier=identifier)
|
|
217
217
|
# TODO: load owner from database
|
|
218
218
|
|
|
219
219
|
# Override
|
|
220
|
-
def
|
|
220
|
+
async def get_members(self, identifier: ID) -> List[ID]:
|
|
221
221
|
# check for broadcast
|
|
222
222
|
if identifier.is_broadcast:
|
|
223
223
|
# members of broadcast group
|
|
@@ -226,8 +226,8 @@ class Barrack(EntityDelegate, UserDataSource, GroupDataSource, ABC):
|
|
|
226
226
|
return []
|
|
227
227
|
|
|
228
228
|
# Override
|
|
229
|
-
def
|
|
230
|
-
doc = self.
|
|
229
|
+
async def get_assistants(self, identifier: ID) -> List[ID]:
|
|
230
|
+
doc = await self.get_bulletin(identifier=identifier)
|
|
231
231
|
if doc is not None: # and doc.valid:
|
|
232
232
|
bots = doc.assistants
|
|
233
233
|
if bots is not None:
|
|
@@ -38,6 +38,7 @@
|
|
|
38
38
|
|
|
39
39
|
from typing import Optional, Any, Dict
|
|
40
40
|
|
|
41
|
+
from mkm.types import DateTime
|
|
41
42
|
from mkm import ID, Meta, Document
|
|
42
43
|
|
|
43
44
|
from ..protocol import MetaCommand, DocumentCommand
|
|
@@ -123,23 +124,25 @@ class BaseDocumentCommand(BaseMetaCommand, DocumentCommand):
|
|
|
123
124
|
identifier: ID = None,
|
|
124
125
|
meta: Optional[Meta] = None,
|
|
125
126
|
document: Optional[Document] = None,
|
|
126
|
-
|
|
127
|
+
last_time: Optional[DateTime] = None):
|
|
127
128
|
if content is None:
|
|
128
129
|
# 1. new command with ID, meta, document & signature
|
|
129
130
|
if identifier is None:
|
|
130
|
-
assert document is not None, 'document command error: %s, %s' % (meta,
|
|
131
|
+
assert document is not None, 'document command error: %s, %s' % (meta, last_time)
|
|
131
132
|
identifier = document.identifier
|
|
132
|
-
assert identifier is not None, 'document command error: %s, %s, %s' % (meta, document,
|
|
133
|
+
assert identifier is not None, 'document command error: %s, %s, %s' % (meta, document, last_time)
|
|
133
134
|
cmd = Command.DOCUMENT
|
|
134
135
|
super().__init__(cmd=cmd, identifier=identifier, meta=meta)
|
|
136
|
+
# respond with document info
|
|
135
137
|
if document is not None:
|
|
136
138
|
self['document'] = document.dictionary
|
|
137
|
-
|
|
138
|
-
|
|
139
|
+
# query with last document time
|
|
140
|
+
if last_time is not None:
|
|
141
|
+
self.set_datetime(key='last_time', value=last_time)
|
|
139
142
|
else:
|
|
140
143
|
# 2. command info from network
|
|
141
|
-
assert identifier is None and meta is None and document is None and
|
|
142
|
-
'params error: %s, %s, %s, %s, %s' % (content, identifier, meta, document,
|
|
144
|
+
assert identifier is None and meta is None and document is None and last_time is None, \
|
|
145
|
+
'params error: %s, %s, %s, %s, %s' % (content, identifier, meta, document, last_time)
|
|
143
146
|
super().__init__(content)
|
|
144
147
|
# lazy load
|
|
145
148
|
self.__doc = document
|
|
@@ -154,10 +157,5 @@ class BaseDocumentCommand(BaseMetaCommand, DocumentCommand):
|
|
|
154
157
|
return self.__doc
|
|
155
158
|
|
|
156
159
|
@property # Override
|
|
157
|
-
def
|
|
158
|
-
|
|
159
|
-
signature for checking new document
|
|
160
|
-
|
|
161
|
-
:return: part of signature in current document (base64)
|
|
162
|
-
"""
|
|
163
|
-
return self.get_str(key='signature', default=None)
|
|
160
|
+
def last_time(self) -> Optional[DateTime]:
|
|
161
|
+
return self.get_datetime(key='last_time', default=None)
|
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
|
|
31
31
|
from typing import Optional, Any, Dict, List
|
|
32
32
|
|
|
33
|
-
from mkm.format import
|
|
33
|
+
from mkm.format import PortableNetworkFile
|
|
34
34
|
from mkm.types import URI
|
|
35
35
|
from mkm import ID
|
|
36
36
|
from dkd import ContentType, Content
|
|
@@ -184,44 +184,45 @@ class WebPageContent(BaseContent, PageContent):
|
|
|
184
184
|
type : 0x20,
|
|
185
185
|
sn : 123,
|
|
186
186
|
|
|
187
|
-
|
|
188
|
-
icon : "...",
|
|
189
|
-
|
|
190
|
-
|
|
187
|
+
title : "...", // Web title
|
|
188
|
+
icon : "...", // base64_encode(icon)
|
|
189
|
+
desc : "...",
|
|
190
|
+
|
|
191
|
+
URL : "https://github.com/moky/dimp",
|
|
192
|
+
|
|
193
|
+
HTML : "...", // Web content
|
|
194
|
+
mime_type : "text/html", // Content-Type
|
|
195
|
+
encoding : "utf8",
|
|
196
|
+
base : "about:blank" // Base URL
|
|
191
197
|
}
|
|
192
198
|
"""
|
|
193
199
|
|
|
194
200
|
def __init__(self, content: Dict[str, Any] = None,
|
|
195
|
-
url: URI = None, title: str = None,
|
|
196
|
-
desc: Optional[str] = None, icon: Optional[
|
|
201
|
+
url: URI = None, html: str = None, title: str = None,
|
|
202
|
+
desc: Optional[str] = None, icon: Optional[URI] = None):
|
|
197
203
|
if content is None:
|
|
198
204
|
# 1. new content with url, title, desc & icon
|
|
199
205
|
assert url is not None and title is not None, 'page info error: %s, %s, %s, %s' % (url, title, desc, icon)
|
|
200
206
|
msg_type = ContentType.PAGE.value
|
|
201
207
|
super().__init__(None, msg_type)
|
|
202
|
-
self['URL'] = url
|
|
203
|
-
self['title'] = title
|
|
204
|
-
if desc is not None:
|
|
205
|
-
self['desc'] = desc
|
|
206
|
-
if icon is not None:
|
|
207
|
-
self.set_icon(icon)
|
|
208
208
|
else:
|
|
209
209
|
# 2. content info from network
|
|
210
|
-
assert url is None and title is None and desc is None and icon is None, \
|
|
211
|
-
'params error: %s, %s, %s, %s, %s' % (content, url, title, desc, icon)
|
|
212
210
|
super().__init__(content)
|
|
213
|
-
#
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
#
|
|
219
|
-
|
|
211
|
+
# URL or HTML
|
|
212
|
+
if url is not None:
|
|
213
|
+
self.url = url
|
|
214
|
+
if html is not None:
|
|
215
|
+
self.html = html
|
|
216
|
+
# title, icon, description
|
|
217
|
+
self.title = title
|
|
218
|
+
if desc is not None:
|
|
219
|
+
self.desc = desc
|
|
220
|
+
if icon is not None:
|
|
221
|
+
self.icon = icon
|
|
220
222
|
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
self['URL'] = string
|
|
223
|
+
#
|
|
224
|
+
# Web Title
|
|
225
|
+
#
|
|
225
226
|
|
|
226
227
|
@property # Override
|
|
227
228
|
def title(self) -> str:
|
|
@@ -231,40 +232,63 @@ class WebPageContent(BaseContent, PageContent):
|
|
|
231
232
|
def title(self, string: str):
|
|
232
233
|
self['title'] = string
|
|
233
234
|
|
|
235
|
+
#
|
|
236
|
+
# Fav Icon
|
|
237
|
+
#
|
|
238
|
+
|
|
239
|
+
@property # Override
|
|
240
|
+
def icon(self) -> Optional[URI]:
|
|
241
|
+
base64 = self.get_str(key='icon', default=None)
|
|
242
|
+
# TODO: convert 'data:' URI
|
|
243
|
+
return base64
|
|
244
|
+
|
|
245
|
+
@icon.setter # Override
|
|
246
|
+
def icon(self, base64: URI):
|
|
247
|
+
self['icon'] = base64
|
|
248
|
+
|
|
249
|
+
#
|
|
250
|
+
# Description
|
|
251
|
+
#
|
|
252
|
+
|
|
234
253
|
@property # Override
|
|
235
254
|
def desc(self) -> Optional[str]:
|
|
236
255
|
return self.get_str(key='desc', default=None)
|
|
237
256
|
|
|
238
257
|
@desc.setter # Override
|
|
239
|
-
def desc(self,
|
|
240
|
-
if
|
|
258
|
+
def desc(self, text: Optional[str]):
|
|
259
|
+
if text is None:
|
|
241
260
|
self.pop('desc', None)
|
|
242
261
|
else:
|
|
243
|
-
self['desc'] =
|
|
262
|
+
self['desc'] = text
|
|
263
|
+
|
|
264
|
+
#
|
|
265
|
+
# Page URL
|
|
266
|
+
#
|
|
244
267
|
|
|
245
268
|
@property # Override
|
|
246
|
-
def
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
base64 = self.get('icon')
|
|
250
|
-
self.__icon = ted = TransportableData.parse(base64)
|
|
251
|
-
if ted is not None:
|
|
252
|
-
return ted.data
|
|
253
|
-
|
|
254
|
-
@icon.setter
|
|
255
|
-
def icon(self, image: Optional[bytes]):
|
|
256
|
-
if image is None or len(image) == 0:
|
|
257
|
-
ted = None
|
|
258
|
-
else:
|
|
259
|
-
ted = TransportableData.create(data=image)
|
|
260
|
-
self.set_icon(ted)
|
|
269
|
+
def url(self) -> URI:
|
|
270
|
+
# TODO: convert str to URI
|
|
271
|
+
return self.get_str(key='URL', default=None)
|
|
261
272
|
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
273
|
+
@url.setter # Override
|
|
274
|
+
def url(self, locator: URI):
|
|
275
|
+
# TODO: convert URI to str
|
|
276
|
+
self['URL'] = locator
|
|
277
|
+
|
|
278
|
+
#
|
|
279
|
+
# Page content
|
|
280
|
+
#
|
|
281
|
+
|
|
282
|
+
@property # Override
|
|
283
|
+
def html(self) -> Optional[str]:
|
|
284
|
+
return self.get_str(key='desc', default=None)
|
|
285
|
+
|
|
286
|
+
@html.setter # Override
|
|
287
|
+
def html(self, content: Optional[str]):
|
|
288
|
+
if content is None:
|
|
289
|
+
self.pop('HTML', None)
|
|
265
290
|
else:
|
|
266
|
-
self['
|
|
267
|
-
self.__icon = ted
|
|
291
|
+
self['HTML'] = content
|
|
268
292
|
|
|
269
293
|
|
|
270
294
|
class NameCardContent(BaseContent, NameCard):
|
|
@@ -43,19 +43,7 @@ from .contents import BaseContent
|
|
|
43
43
|
|
|
44
44
|
|
|
45
45
|
class BaseFileContent(BaseContent, FileContent):
|
|
46
|
-
"""
|
|
47
|
-
File Message Content
|
|
48
|
-
~~~~~~~~~~~~~~~~~~~~
|
|
49
|
-
|
|
50
|
-
data format: {
|
|
51
|
-
type : 0x10,
|
|
52
|
-
sn : 123,
|
|
53
|
-
|
|
54
|
-
URL : "http://", // upload to CDN
|
|
55
|
-
data : "...", // if (!URL) base64_encode(fileContent)
|
|
56
|
-
filename : "..."
|
|
57
|
-
}
|
|
58
|
-
"""
|
|
46
|
+
""" File Message Content """
|
|
59
47
|
|
|
60
48
|
def __init__(self, content: Dict[str, Any] = None,
|
|
61
49
|
msg_type: int = None,
|
|
@@ -120,64 +108,27 @@ class BaseFileContent(BaseContent, FileContent):
|
|
|
120
108
|
|
|
121
109
|
|
|
122
110
|
class ImageFileContent(BaseFileContent, ImageContent):
|
|
123
|
-
"""
|
|
124
|
-
Image Message Content
|
|
125
|
-
~~~~~~~~~~~~~~~~~~~~~
|
|
126
|
-
|
|
127
|
-
data format: {
|
|
128
|
-
type : 0x12,
|
|
129
|
-
sn : 123,
|
|
130
|
-
|
|
131
|
-
URL : "http://", // upload to CDN
|
|
132
|
-
data : "...", // if (!URL) base64_encode(image)
|
|
133
|
-
thumbnail : "...", // base64_encode(smallImage)
|
|
134
|
-
filename : "..."
|
|
135
|
-
}
|
|
136
|
-
"""
|
|
111
|
+
""" Image Message Content """
|
|
137
112
|
|
|
138
113
|
def __init__(self, content: Dict[str, Any] = None,
|
|
139
114
|
data: Optional[TransportableData] = None, filename: Optional[str] = None,
|
|
140
115
|
url: Optional[URI] = None, password: Optional[DecryptKey] = None):
|
|
141
116
|
msg_type = ContentType.IMAGE.value if content is None else None
|
|
142
117
|
super().__init__(content, msg_type, data=data, filename=filename, url=url, password=password)
|
|
143
|
-
# lazy load
|
|
144
|
-
self.__thumbnail: Optional[TransportableData] = None
|
|
145
118
|
|
|
146
119
|
@property # Override
|
|
147
|
-
def thumbnail(self) -> Optional[
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
self.__thumbnail = ted = TransportableData.parse(base64)
|
|
152
|
-
if ted is not None:
|
|
153
|
-
return ted.data
|
|
120
|
+
def thumbnail(self) -> Optional[URI]:
|
|
121
|
+
base64 = self.get_str(key='thumbnail', default=None)
|
|
122
|
+
# TODO: convert 'data:' URI
|
|
123
|
+
return base64
|
|
154
124
|
|
|
155
125
|
@thumbnail.setter # Override
|
|
156
|
-
def thumbnail(self,
|
|
157
|
-
|
|
158
|
-
self.pop('thumbnail', None)
|
|
159
|
-
ted = None
|
|
160
|
-
else:
|
|
161
|
-
ted = TransportableData.create(data=image)
|
|
162
|
-
self['thumbnail'] = ted.object
|
|
163
|
-
self.__thumbnail = ted
|
|
126
|
+
def thumbnail(self, base64: URI):
|
|
127
|
+
self['thumbnail'] = base64
|
|
164
128
|
|
|
165
129
|
|
|
166
130
|
class AudioFileContent(BaseFileContent, AudioContent):
|
|
167
|
-
"""
|
|
168
|
-
Audio Message Content
|
|
169
|
-
~~~~~~~~~~~~~~~~~~~~~
|
|
170
|
-
|
|
171
|
-
data format: {
|
|
172
|
-
type : 0x14,
|
|
173
|
-
sn : 123,
|
|
174
|
-
|
|
175
|
-
URL : "http://", // upload to CDN
|
|
176
|
-
data : "...", // if (!URL) base64_encode(audio)
|
|
177
|
-
text : "...", // Automatic Speech Recognition
|
|
178
|
-
filename : "..."
|
|
179
|
-
}
|
|
180
|
-
"""
|
|
131
|
+
""" Audio Message Content """
|
|
181
132
|
|
|
182
133
|
def __init__(self, content: Dict[str, Any] = None,
|
|
183
134
|
data: Optional[TransportableData] = None, filename: Optional[str] = None,
|
|
@@ -195,44 +146,20 @@ class AudioFileContent(BaseFileContent, AudioContent):
|
|
|
195
146
|
|
|
196
147
|
|
|
197
148
|
class VideoFileContent(BaseFileContent, VideoContent):
|
|
198
|
-
"""
|
|
199
|
-
Video Message Content
|
|
200
|
-
~~~~~~~~~~~~~~~~~~~~~
|
|
201
|
-
|
|
202
|
-
data format: {
|
|
203
|
-
type : 0x16,
|
|
204
|
-
sn : 123,
|
|
205
|
-
|
|
206
|
-
URL : "http://", // upload to CDN
|
|
207
|
-
data : "...", // if (!URL) base64_encode(video)
|
|
208
|
-
snapshot : "...", // base64_encode(smallImage)
|
|
209
|
-
filename : "..."
|
|
210
|
-
}
|
|
211
|
-
"""
|
|
149
|
+
""" Video Message Content """
|
|
212
150
|
|
|
213
151
|
def __init__(self, content: Dict[str, Any] = None,
|
|
214
152
|
data: Optional[TransportableData] = None, filename: Optional[str] = None,
|
|
215
153
|
url: Optional[URI] = None, password: Optional[DecryptKey] = None):
|
|
216
154
|
msg_type = ContentType.VIDEO.value if content is None else None
|
|
217
155
|
super().__init__(content, msg_type, data=data, filename=filename, url=url, password=password)
|
|
218
|
-
# lazy load
|
|
219
|
-
self.__snapshot: Optional[TransportableData] = None
|
|
220
156
|
|
|
221
157
|
@property # Override
|
|
222
|
-
def snapshot(self) -> Optional[
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
self.__snapshot = ted = TransportableData.parse(base64)
|
|
227
|
-
if ted is not None:
|
|
228
|
-
return ted.data
|
|
158
|
+
def snapshot(self) -> Optional[URI]:
|
|
159
|
+
base64 = self.get_str(key='thumbnail', default=None)
|
|
160
|
+
# TODO: convert 'data:' URI
|
|
161
|
+
return base64
|
|
229
162
|
|
|
230
163
|
@snapshot.setter # Override
|
|
231
|
-
def snapshot(self,
|
|
232
|
-
|
|
233
|
-
self.pop('snapshot', None)
|
|
234
|
-
ted = None
|
|
235
|
-
else:
|
|
236
|
-
ted = TransportableData.create(data=image)
|
|
237
|
-
self['snapshot'] = ted.object
|
|
238
|
-
self.__snapshot = ted
|
|
164
|
+
def snapshot(self, base64: URI):
|
|
165
|
+
self['snapshot'] = base64
|
|
@@ -39,8 +39,9 @@
|
|
|
39
39
|
|
|
40
40
|
from typing import Optional, Any, Dict, List
|
|
41
41
|
|
|
42
|
-
from
|
|
42
|
+
from mkm.types import DateTime
|
|
43
43
|
from mkm import ID
|
|
44
|
+
from dkd import ContentType
|
|
44
45
|
|
|
45
46
|
from ..protocol import HistoryCommand, GroupCommand
|
|
46
47
|
from ..protocol import InviteCommand, ExpelCommand, JoinCommand, QuitCommand, QueryCommand, ResetCommand
|
|
@@ -200,7 +201,7 @@ class QuitGroupCommand(BaseGroupCommand, QuitCommand):
|
|
|
200
201
|
|
|
201
202
|
class QueryGroupCommand(BaseGroupCommand, QueryCommand):
|
|
202
203
|
|
|
203
|
-
def __init__(self, content: Dict[str, Any] = None, group: ID = None):
|
|
204
|
+
def __init__(self, content: Dict[str, Any] = None, group: ID = None, last_time: DateTime = None):
|
|
204
205
|
"""
|
|
205
206
|
Create query group members command (not history command)
|
|
206
207
|
|
|
@@ -210,6 +211,12 @@ class QueryGroupCommand(BaseGroupCommand, QueryCommand):
|
|
|
210
211
|
"""
|
|
211
212
|
cmd = GroupCommand.QUERY if content is None else None
|
|
212
213
|
super().__init__(content, cmd=cmd, group=group)
|
|
214
|
+
if last_time is not None:
|
|
215
|
+
self.set_datetime(key='last_time', value=last_time)
|
|
216
|
+
|
|
217
|
+
@property # Override
|
|
218
|
+
def last_time(self) -> Optional[DateTime]:
|
|
219
|
+
return self.get_datetime(key='last_time', default=None)
|
|
213
220
|
|
|
214
221
|
|
|
215
222
|
class ResetGroupCommand(BaseGroupCommand, ResetCommand):
|
|
@@ -41,7 +41,7 @@ from .group import Group
|
|
|
41
41
|
class EntityDelegate(ABC):
|
|
42
42
|
|
|
43
43
|
@abstractmethod
|
|
44
|
-
def
|
|
44
|
+
async def get_user(self, identifier: ID) -> Optional[User]:
|
|
45
45
|
"""
|
|
46
46
|
Create user with ID
|
|
47
47
|
|
|
@@ -51,7 +51,7 @@ class EntityDelegate(ABC):
|
|
|
51
51
|
raise NotImplemented
|
|
52
52
|
|
|
53
53
|
@abstractmethod
|
|
54
|
-
def
|
|
54
|
+
async def get_group(self, identifier: ID) -> Optional[Group]:
|
|
55
55
|
"""
|
|
56
56
|
Create group with ID
|
|
57
57
|
|
|
@@ -48,7 +48,7 @@ class EntityDataSource(ABC):
|
|
|
48
48
|
"""
|
|
49
49
|
|
|
50
50
|
@abstractmethod
|
|
51
|
-
def
|
|
51
|
+
async def get_meta(self, identifier: ID) -> Optional[Meta]:
|
|
52
52
|
"""
|
|
53
53
|
Get meta for entity
|
|
54
54
|
|
|
@@ -58,7 +58,7 @@ class EntityDataSource(ABC):
|
|
|
58
58
|
raise NotImplemented
|
|
59
59
|
|
|
60
60
|
@abstractmethod
|
|
61
|
-
def
|
|
61
|
+
async def get_documents(self, identifier: ID) -> List[Document]:
|
|
62
62
|
"""
|
|
63
63
|
Get documents for entity ID
|
|
64
64
|
|
|
@@ -104,13 +104,13 @@ class Entity(ABC):
|
|
|
104
104
|
|
|
105
105
|
@property
|
|
106
106
|
@abstractmethod
|
|
107
|
-
def meta(self) -> Meta:
|
|
107
|
+
async def meta(self) -> Meta:
|
|
108
108
|
""" Get meta """
|
|
109
109
|
raise NotImplemented
|
|
110
110
|
|
|
111
111
|
@property
|
|
112
112
|
@abstractmethod
|
|
113
|
-
def documents(self) -> List[Document]:
|
|
113
|
+
async def documents(self) -> List[Document]:
|
|
114
114
|
""" Get documents """
|
|
115
115
|
raise NotImplemented
|
|
116
116
|
|
|
@@ -176,13 +176,13 @@ class BaseEntity(Entity):
|
|
|
176
176
|
return self.__id.type
|
|
177
177
|
|
|
178
178
|
@property # Override
|
|
179
|
-
def meta(self) -> Meta:
|
|
179
|
+
async def meta(self) -> Meta:
|
|
180
180
|
delegate = self.data_source
|
|
181
181
|
# assert delegate is not None, 'entity delegate not set yet'
|
|
182
|
-
return delegate.
|
|
182
|
+
return await delegate.get_meta(identifier=self.__id)
|
|
183
183
|
|
|
184
184
|
@property # Override
|
|
185
|
-
def documents(self) -> List[Document]:
|
|
185
|
+
async def documents(self) -> List[Document]:
|
|
186
186
|
delegate = self.data_source
|
|
187
187
|
# assert delegate is not None, 'entity delegate not set yet'
|
|
188
|
-
return delegate.
|
|
188
|
+
return await delegate.get_documents(identifier=self.__id)
|