dimp 2.3.1__tar.gz → 2.3.2__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.
Files changed (52) hide show
  1. {dimp-2.3.1 → dimp-2.3.2}/PKG-INFO +1 -1
  2. {dimp-2.3.1 → dimp-2.3.2}/dimp/__init__.py +1 -1
  3. {dimp-2.3.1 → dimp-2.3.2}/dimp/crypto/keys.py +44 -20
  4. {dimp-2.3.1 → dimp-2.3.2}/dimp/crypto/pnf.py +10 -7
  5. {dimp-2.3.1 → dimp-2.3.2}/dimp/crypto/ted.py +11 -11
  6. {dimp-2.3.1 → dimp-2.3.2}/dimp/dkd/__init__.py +17 -16
  7. {dimp-2.3.1 → dimp-2.3.2}/dimp/mkm/docs.py +19 -15
  8. {dimp-2.3.1 → dimp-2.3.2}/dimp/mkm/document.py +5 -9
  9. {dimp-2.3.1 → dimp-2.3.2}/dimp/mkm/meta.py +7 -7
  10. {dimp-2.3.1 → dimp-2.3.2}/dimp/msg/base.py +2 -2
  11. {dimp-2.3.1 → dimp-2.3.2}/dimp/msg/envelope.py +17 -14
  12. {dimp-2.3.1 → dimp-2.3.2}/dimp/msg/instant.py +8 -6
  13. {dimp-2.3.1 → dimp-2.3.2}/dimp/msg/reliable.py +2 -2
  14. {dimp-2.3.1 → dimp-2.3.2}/dimp/msg/secure.py +15 -9
  15. {dimp-2.3.1 → dimp-2.3.2}/dimp/plugins/__init__.py +2 -2
  16. {dimp-2.3.1 → dimp-2.3.2}/dimp/protocol/__init__.py +8 -8
  17. {dimp-2.3.1/dimp/dkd → dimp-2.3.2/dimp/protocol}/base.py +140 -15
  18. {dimp-2.3.1/dimp/dkd → dimp-2.3.2/dimp/protocol}/commands.py +126 -30
  19. {dimp-2.3.1/dimp/dkd → dimp-2.3.2/dimp/protocol}/contents.py +166 -132
  20. {dimp-2.3.1 → dimp-2.3.2}/dimp/protocol/files.py +150 -9
  21. dimp-2.3.2/dimp/protocol/forward.py +253 -0
  22. dimp-2.3.2/dimp/protocol/groups.py +498 -0
  23. {dimp-2.3.1/dimp/dkd → dimp-2.3.2/dimp/protocol}/money.py +93 -27
  24. {dimp-2.3.1 → dimp-2.3.2}/dimp/protocol/quote.py +51 -34
  25. {dimp-2.3.1/dimp/dkd → dimp-2.3.2/dimp/protocol}/receipt.py +83 -11
  26. {dimp-2.3.1 → dimp-2.3.2}/dimp.egg-info/PKG-INFO +1 -1
  27. {dimp-2.3.1 → dimp-2.3.2}/dimp.egg-info/SOURCES.txt +2 -10
  28. dimp-2.3.2/dimp.egg-info/requires.txt +2 -0
  29. {dimp-2.3.1 → dimp-2.3.2}/setup.py +3 -3
  30. dimp-2.3.1/dimp/dkd/files.py +0 -181
  31. dimp-2.3.1/dimp/dkd/group_admins.py +0 -142
  32. dimp-2.3.1/dimp/dkd/groups.py +0 -234
  33. dimp-2.3.1/dimp/dkd/quote.py +0 -145
  34. dimp-2.3.1/dimp/plugins/cmd.py +0 -79
  35. dimp-2.3.1/dimp/protocol/commands.py +0 -247
  36. dimp-2.3.1/dimp/protocol/contents.py +0 -279
  37. dimp-2.3.1/dimp/protocol/groups.py +0 -286
  38. dimp-2.3.1/dimp/protocol/money.py +0 -124
  39. dimp-2.3.1/dimp/protocol/receipt.py +0 -130
  40. dimp-2.3.1/dimp.egg-info/requires.txt +0 -2
  41. {dimp-2.3.1 → dimp-2.3.2}/LICENSE +0 -0
  42. {dimp-2.3.1 → dimp-2.3.2}/README.md +0 -0
  43. {dimp-2.3.1 → dimp-2.3.2}/dimp/crypto/__init__.py +0 -0
  44. {dimp-2.3.1 → dimp-2.3.2}/dimp/crypto/algorithms.py +0 -0
  45. {dimp-2.3.1 → dimp-2.3.2}/dimp/mkm/__init__.py +0 -0
  46. {dimp-2.3.1 → dimp-2.3.2}/dimp/msg/__init__.py +0 -0
  47. {dimp-2.3.1 → dimp-2.3.2}/dimp/protocol/docs.py +0 -0
  48. {dimp-2.3.1 → dimp-2.3.2}/dimp/protocol/helpers.py +0 -0
  49. {dimp-2.3.1 → dimp-2.3.2}/dimp/protocol/types.py +0 -0
  50. {dimp-2.3.1 → dimp-2.3.2}/dimp.egg-info/dependency_links.txt +0 -0
  51. {dimp-2.3.1 → dimp-2.3.2}/dimp.egg-info/top_level.txt +0 -0
  52. {dimp-2.3.1 → dimp-2.3.2}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: dimp
3
- Version: 2.3.1
3
+ Version: 2.3.2
4
4
  Summary: Decentralized Instant Messaging Protocol
5
5
  Home-page: https://github.com/dimchat/core-py
6
6
  Author: Albert Moky
@@ -34,7 +34,7 @@ from mkm.crypto import *
34
34
  from mkm import *
35
35
  from dkd import *
36
36
 
37
- from .protocol.commands import CommandFactory
37
+ from .protocol.base import CommandFactory
38
38
  from .protocol import *
39
39
  from .crypto import *
40
40
  from .mkm import *
@@ -29,9 +29,9 @@
29
29
  # ==============================================================================
30
30
 
31
31
  from abc import ABC
32
- from typing import Any, Dict
32
+ from typing import Dict
33
33
 
34
- from mkm.types import Dictionary
34
+ from mkm.types import Mapper, Dictionary
35
35
  from mkm.crypto import CryptographyKey, EncryptKey, DecryptKey, SignKey, VerifyKey
36
36
  from mkm.crypto import SymmetricKey, AsymmetricKey, PublicKey, PrivateKey
37
37
  from mkm.plugins import SharedCryptoExtensions
@@ -46,7 +46,7 @@ from mkm.plugins import SharedCryptoExtensions
46
46
  # noinspection PyAbstractClass
47
47
  class BaseKey(Dictionary, CryptographyKey, ABC):
48
48
 
49
- def __init__(self, key: Dict[str, Any]):
49
+ def __init__(self, key: Dict):
50
50
  super().__init__(dictionary=key)
51
51
 
52
52
  @property # Override
@@ -58,7 +58,7 @@ class BaseKey(Dictionary, CryptographyKey, ABC):
58
58
  #
59
59
 
60
60
  @classmethod
61
- def get_key_algorithm(cls, key: Dict[str, Any]) -> str:
61
+ def get_key_algorithm(cls, key: Dict) -> str:
62
62
  ext = SharedCryptoExtensions()
63
63
  algorithm = ext.helper.get_key_algorithm(key=key, default=None)
64
64
  return '' if algorithm is None else algorithm
@@ -97,20 +97,32 @@ class BaseKey(Dictionary, CryptographyKey, ABC):
97
97
  # noinspection PyAbstractClass
98
98
  class BaseSymmetricKey(Dictionary, SymmetricKey, ABC):
99
99
 
100
- def __init__(self, key: Dict[str, Any]):
100
+ def __init__(self, key: Dict):
101
101
  super().__init__(dictionary=key)
102
102
 
103
103
  # Override
104
104
  def __eq__(self, other) -> bool:
105
- if isinstance(other, SymmetricKey):
106
- return BaseKey.symmetric_keys_equal(other, self)
105
+ if isinstance(other, Mapper):
106
+ if self is other:
107
+ # same object
108
+ return True
109
+ elif isinstance(other, SymmetricKey):
110
+ return BaseKey.symmetric_keys_equal(other, self)
111
+ # compare with inner map
112
+ other = other.dictionary
113
+ return self.dictionary.__eq__(other)
107
114
 
108
115
  # Override
109
116
  def __ne__(self, other) -> bool:
110
- if isinstance(other, SymmetricKey):
111
- return not BaseKey.symmetric_keys_equal(other, self)
112
- else:
113
- return True
117
+ if isinstance(other, Mapper):
118
+ if self is other:
119
+ # same object
120
+ return False
121
+ elif isinstance(other, SymmetricKey):
122
+ return not BaseKey.symmetric_keys_equal(other, self)
123
+ # compare with inner map
124
+ other = other.dictionary
125
+ return self.dictionary.__ne__(other)
114
126
 
115
127
  @property # Override
116
128
  def algorithm(self) -> str:
@@ -124,7 +136,7 @@ class BaseSymmetricKey(Dictionary, SymmetricKey, ABC):
124
136
  # noinspection PyAbstractClass
125
137
  class BaseAsymmetricKey(Dictionary, AsymmetricKey, ABC):
126
138
 
127
- def __init__(self, key: Dict[str, Any]):
139
+ def __init__(self, key: Dict):
128
140
  super().__init__(dictionary=key)
129
141
 
130
142
  @property # Override
@@ -135,7 +147,7 @@ class BaseAsymmetricKey(Dictionary, AsymmetricKey, ABC):
135
147
  # noinspection PyAbstractClass
136
148
  class BasePublicKey(Dictionary, PublicKey, ABC):
137
149
 
138
- def __init__(self, key: Dict[str, Any]):
150
+ def __init__(self, key: Dict):
139
151
  super().__init__(dictionary=key)
140
152
 
141
153
  @property # Override
@@ -150,20 +162,32 @@ class BasePublicKey(Dictionary, PublicKey, ABC):
150
162
  # noinspection PyAbstractClass
151
163
  class BasePrivateKey(Dictionary, PrivateKey, ABC):
152
164
 
153
- def __init__(self, key: Dict[str, Any]):
165
+ def __init__(self, key: Dict):
154
166
  super().__init__(dictionary=key)
155
167
 
156
168
  # Override
157
169
  def __eq__(self, other) -> bool:
158
- if isinstance(other, PrivateKey):
159
- return BaseKey.private_keys_equal(other, self)
170
+ if isinstance(other, Mapper):
171
+ if self is other:
172
+ # same object
173
+ return True
174
+ elif isinstance(other, PrivateKey):
175
+ return BaseKey.private_keys_equal(other, self)
176
+ # compare with inner map
177
+ other = other.dictionary
178
+ return self.dictionary.__eq__(other)
160
179
 
161
180
  # Override
162
181
  def __ne__(self, other) -> bool:
163
- if isinstance(other, PrivateKey):
164
- return not BaseKey.private_keys_equal(other, self)
165
- else:
166
- return True
182
+ if isinstance(other, Mapper):
183
+ if self is other:
184
+ # same object
185
+ return False
186
+ elif isinstance(other, PrivateKey):
187
+ return not BaseKey.private_keys_equal(other, self)
188
+ # compare with inner map
189
+ other = other.dictionary
190
+ return self.dictionary.__ne__(other)
167
191
 
168
192
  @property # Override
169
193
  def algorithm(self) -> str:
@@ -28,7 +28,7 @@
28
28
  # SOFTWARE.
29
29
  # ==============================================================================
30
30
 
31
- from typing import Optional, Any, Dict
31
+ from typing import Optional, Dict
32
32
 
33
33
  from mkm.format import TransportableData
34
34
  from mkm.types import URI
@@ -55,7 +55,7 @@ class BaseFileWrapper(Dictionary):
55
55
  }
56
56
  """
57
57
 
58
- def __init__(self, dictionary: Dict[str, Any]):
58
+ def __init__(self, dictionary: Dict):
59
59
  super().__init__(dictionary=dictionary)
60
60
  # file data (not encrypted)
61
61
  self.__attachment: Optional[TransportableData] = None
@@ -115,11 +115,12 @@ class BaseFileWrapper(Dictionary):
115
115
 
116
116
  @property
117
117
  def url(self) -> Optional[URI]:
118
- if self.__url is None:
118
+ remote = self.__url
119
+ if remote is None:
119
120
  remote = self.get_str(key='URL', default=None)
120
121
  # TODO: convert str to URI
121
122
  self.__url = remote
122
- return self.__url
123
+ return remote
123
124
 
124
125
  @url.setter
125
126
  def url(self, remote: Optional[URI]):
@@ -136,10 +137,12 @@ class BaseFileWrapper(Dictionary):
136
137
 
137
138
  @property
138
139
  def password(self) -> Optional[DecryptKey]:
139
- if self.__password is None:
140
+ key = self.__password
141
+ if key is None:
140
142
  info = self.get('key')
141
- self.__password = SymmetricKey.parse(key=info)
142
- return self.__password
143
+ key = SymmetricKey.parse(key=info)
144
+ self.__password = key
145
+ return key
143
146
 
144
147
  @password.setter
145
148
  def password(self, key: Optional[DecryptKey]):
@@ -28,7 +28,7 @@
28
28
  # SOFTWARE.
29
29
  # ==============================================================================
30
30
 
31
- from typing import Optional, Any, Dict
31
+ from typing import Optional, Dict
32
32
 
33
33
  from mkm.format import base64_encode, base64_decode
34
34
  from mkm.format import base58_encode, base58_decode
@@ -54,18 +54,18 @@ class BaseDataWrapper(Dictionary):
54
54
  2. "data:image/png;base64,{BASE64_ENCODE}"
55
55
  """
56
56
 
57
- def __init__(self, dictionary: Dict[str, Any]):
57
+ def __init__(self, dictionary: Dict):
58
58
  super().__init__(dictionary=dictionary)
59
59
  # binary data
60
60
  self.__data: Optional[bytes] = None
61
61
 
62
- # Override
63
- def __len__(self) -> int:
64
- """ return len(self) """
65
- # if super().__len__() == 0:
66
- # return 0
67
- data = self.data
68
- return 0 if data is None else len(data)
62
+ # # Override
63
+ # def __len__(self) -> int:
64
+ # """ return len(self) """
65
+ # if super().__len__() == 0:
66
+ # return 0
67
+ # data = self.data
68
+ # return 0 if data is None else len(data)
69
69
 
70
70
  # Override
71
71
  def __str__(self) -> str:
@@ -120,8 +120,8 @@ class BaseDataWrapper(Dictionary):
120
120
  if binary is None:
121
121
  text = self.get_str(key='data', default=None)
122
122
  if text is None or len(text) == 0:
123
- assert False, 'TED data empty: %s' % self.dictionary
124
- # return None
123
+ # assert False, 'TED data empty: %s' % self.dictionary
124
+ return None
125
125
  else:
126
126
  alg = self.algorithm
127
127
  if alg == EncodeAlgorithms.BASE_64:
@@ -31,22 +31,23 @@
31
31
  from dkd import *
32
32
  from ..protocol import *
33
33
 
34
- from .base import BaseContent, BaseCommand
35
- from .contents import BaseTextContent, ListContent, SecretContent
36
- from .contents import WebPageContent, NameCardContent
37
- from .files import BaseFileContent, ImageFileContent, AudioFileContent, VideoFileContent
38
- from .money import BaseMoneyContent, TransferMoneyContent
39
- from .quote import BaseQuoteContent, CombineForwardContent
40
-
41
- from .commands import BaseMetaCommand, BaseDocumentCommand
42
- from .receipt import BaseReceiptCommand
43
-
44
- from .groups import BaseHistoryCommand, BaseGroupCommand
45
- from .groups import InviteGroupCommand, ExpelGroupCommand, JoinGroupCommand
46
- from .groups import QuitGroupCommand, QueryGroupCommand, ResetGroupCommand
47
- from .group_admins import HireGroupCommand, FireGroupCommand, ResignGroupCommand
48
-
49
- # from ..protocol.commands import CommandHelper
34
+ from ..protocol.base import BaseContent
35
+ from ..protocol.contents import BaseTextContent, WebPageContent, NameCardContent
36
+ from ..protocol.forward import SecretContent, CombineForwardContent, ListContent
37
+ from ..protocol.files import BaseFileContent, ImageFileContent, AudioFileContent, VideoFileContent
38
+ from ..protocol.money import BaseMoneyContent, TransferMoneyContent
39
+ from ..protocol.quote import BaseQuoteContent
40
+
41
+ from ..protocol.base import BaseCommand
42
+ from ..protocol.commands import BaseMetaCommand, BaseDocumentCommand
43
+ from ..protocol.receipt import BaseReceiptCommand
44
+
45
+ from ..protocol.groups import BaseHistoryCommand, BaseGroupCommand
46
+ from ..protocol.groups import InviteGroupCommand, ExpelGroupCommand, JoinGroupCommand
47
+ from ..protocol.groups import QuitGroupCommand, QueryGroupCommand, ResetGroupCommand
48
+ from ..protocol.groups import HireGroupCommand, FireGroupCommand, ResignGroupCommand
49
+
50
+ # from ..protocol.base import CommandHelper
50
51
  # from ..protocol.helpers import CommandExtensions
51
52
 
52
53
  __all__ = [
@@ -28,7 +28,7 @@
28
28
  # SOFTWARE.
29
29
  # ==============================================================================
30
30
 
31
- from typing import Optional, Any, Dict, List
31
+ from typing import Optional, Dict, List
32
32
 
33
33
  from mkm.crypto import PublicKey, EncryptKey
34
34
  from mkm.format import TransportableData
@@ -43,7 +43,7 @@ from .document import BaseDocument
43
43
 
44
44
  class BaseVisa(BaseDocument, Visa):
45
45
 
46
- def __init__(self, document: Optional[Dict[str, Any]] = None,
46
+ def __init__(self, document: Optional[Dict] = None,
47
47
  identifier: ID = None, data: Optional[str] = None, signature: Optional[TransportableData] = None):
48
48
  if document is None:
49
49
  # 1. document from local
@@ -68,15 +68,17 @@ class BaseVisa(BaseDocument, Visa):
68
68
 
69
69
  @property # Override
70
70
  def public_key(self) -> Optional[EncryptKey]:
71
- if self.__key is None:
71
+ visa_key = self.__key
72
+ if visa_key is None:
72
73
  info = self.get_property(name='key')
73
74
  # assert info is not None, 'visa key not found: %s' % self.dictionary
74
75
  pub = PublicKey.parse(key=info)
75
76
  if isinstance(pub, EncryptKey):
76
- self.__key = pub
77
+ visa_key = pub
78
+ self.__key = visa_key
77
79
  else:
78
80
  assert info is None, 'visa key error: %s' % info
79
- return self.__key
81
+ return visa_key
80
82
 
81
83
  @public_key.setter # Override
82
84
  def public_key(self, key: EncryptKey):
@@ -91,25 +93,27 @@ class BaseVisa(BaseDocument, Visa):
91
93
 
92
94
  @property # Override
93
95
  def avatar(self) -> Optional[PortableNetworkFile]:
94
- if self.__avatar is None:
96
+ img = self.__avatar
97
+ if img is None:
95
98
  url = self.get_property(name='avatar')
96
99
  if isinstance(url, str) and len(url) == 0:
97
100
  # ignore empty URL
98
101
  pass
99
102
  else:
100
- self.__avatar = PortableNetworkFile.parse(url)
101
- return self.__avatar
103
+ img = PortableNetworkFile.parse(url)
104
+ self.__avatar = img
105
+ return img
102
106
 
103
107
  @avatar.setter # Override
104
- def avatar(self, url: PortableNetworkFile):
105
- info = None if url is None else url.object
108
+ def avatar(self, img: PortableNetworkFile):
109
+ info = None if img is None else img.object
106
110
  self.set_property(name='avatar', value=info)
107
- self.__avatar = url
111
+ self.__avatar = img
108
112
 
109
113
 
110
114
  class BaseBulletin(BaseDocument, Bulletin):
111
115
 
112
- def __init__(self, document: Optional[Dict[str, Any]] = None,
116
+ def __init__(self, document: Optional[Dict] = None,
113
117
  identifier: ID = None,
114
118
  data: Optional[str] = None, signature: Optional[TransportableData] = None):
115
119
  if document is None:
@@ -134,13 +138,13 @@ class BaseBulletin(BaseDocument, Bulletin):
134
138
  def assistants(self) -> Optional[List[ID]]:
135
139
  if self.__bots is None:
136
140
  bots = self.get_property(name='assistants')
137
- if bots is None:
141
+ if isinstance(bots, List):
142
+ self.__bots = ID.convert(array=bots)
143
+ else:
138
144
  # get from 'assistant'
139
145
  single = self.get_property(name='assistant')
140
146
  single = ID.parse(identifier=single)
141
147
  self.__bots = [] if single is None else [single]
142
- else:
143
- self.__bots = ID.convert(array=bots)
144
148
  return self.__bots
145
149
 
146
150
  @assistants.setter # Override
@@ -48,7 +48,7 @@ from mkm import ID, Document
48
48
 
49
49
  class BaseDocument(Dictionary, Document):
50
50
 
51
- def __init__(self, document: Dict[str, Any] = None,
51
+ def __init__(self, document: Dict = None,
52
52
  doc_type: str = None, identifier: ID = None,
53
53
  data: Optional[str] = None, signature: Optional[TransportableData] = None):
54
54
  # check parameters
@@ -189,16 +189,12 @@ class BaseDocument(Dictionary, Document):
189
189
  # 2. encode & sign
190
190
  info = self.properties
191
191
  if info is None:
192
- # assert False, 'should not happen'
192
+ # assert False, 'document invalid: %s' % self.dictionary
193
193
  return None
194
194
  data = json_encode(info)
195
- if len(data) == 0:
196
- # properties error
197
- return None
195
+ assert len(data) > 0, 'should not happen: %s' % info
198
196
  signature = private_key.sign(data=utf8_encode(string=data))
199
- if len(signature) == 0:
200
- # assert False, 'should not happen'
201
- return None
197
+ assert len(signature) > 0, 'should not happen: %s' % info
202
198
  ted = TransportableData.create(data=signature)
203
199
  # 3. update 'data' & 'signature' fields
204
200
  self['data'] = data # JsON string
@@ -214,7 +210,7 @@ class BaseDocument(Dictionary, Document):
214
210
  #
215
211
 
216
212
  @property # Override
217
- def properties(self) -> Optional[Dict[str, Any]]:
213
+ def properties(self) -> Optional[Dict]:
218
214
  """ Load properties from data """
219
215
  if self.__status < 0:
220
216
  # invalid
@@ -29,7 +29,7 @@
29
29
  # ==============================================================================
30
30
 
31
31
  from abc import ABC, abstractmethod
32
- from typing import Optional, Any, Dict
32
+ from typing import Optional, Dict
33
33
 
34
34
  from mkm.format import utf8_encode
35
35
  from mkm.format import TransportableData
@@ -45,10 +45,10 @@ from mkm import Meta
45
45
  This class is used to generate entity ID
46
46
 
47
47
  data format: {
48
- type : 1, // meta version
49
- seed : "moKy", // user/group name
50
- key : "{public key}", // PK = secp256k1(SK);
51
- fingerprint: "..." // CT = sign(seed, SK);
48
+ type : 1, // meta version
49
+ key : "{public key}", // PK = secp256k1(SK);
50
+ seed : "moKy", // user/group name
51
+ fingerprint : "..." // CT = sign(seed, SK);
52
52
  }
53
53
 
54
54
  algorithm:
@@ -61,7 +61,7 @@ from mkm import Meta
61
61
 
62
62
  class BaseMeta(Dictionary, Meta, ABC):
63
63
 
64
- def __init__(self, meta: Dict[str, Any] = None,
64
+ def __init__(self, meta: Dict = None,
65
65
  version: str = None, public_key: VerifyKey = None,
66
66
  seed: Optional[str] = None, fingerprint: Optional[TransportableData] = None):
67
67
  # check parameters
@@ -142,7 +142,7 @@ class BaseMeta(Dictionary, Meta, ABC):
142
142
  ted = self.__fingerprint
143
143
  if ted is None and self.has_seed:
144
144
  base64 = self.get('fingerprint')
145
- assert base64 is not None, 'meta.fingerprint should not be empty: %s' % self
145
+ assert base64 is not None, 'meta.fingerprint should not be empty: %s' % self.dictionary
146
146
  self.__fingerprint = ted = TransportableData.parse(base64)
147
147
  assert ted is not None, 'meta.fingerprint error: %s' % base64
148
148
  if ted is not None:
@@ -50,7 +50,7 @@
50
50
  """
51
51
 
52
52
 
53
- from typing import Optional, Any, Dict
53
+ from typing import Optional, Dict
54
54
 
55
55
  from mkm.types import DateTime
56
56
  from mkm.types import Dictionary
@@ -61,7 +61,7 @@ from dkd import Envelope, Message
61
61
 
62
62
  class BaseMessage(Dictionary, Message):
63
63
 
64
- def __init__(self, msg: Dict[str, Any] = None, head: Envelope = None):
64
+ def __init__(self, msg: Dict = None, head: Envelope = None):
65
65
  if msg is None:
66
66
  # 1. new message with envelope
67
67
  assert head is not None, 'message envelope should not be empty'
@@ -28,7 +28,7 @@
28
28
  # SOFTWARE.
29
29
  # ==============================================================================
30
30
 
31
- from typing import Optional, Any, Dict
31
+ from typing import Optional, Dict
32
32
 
33
33
  from mkm.types import DateTime
34
34
  from mkm.types import Dictionary
@@ -53,7 +53,7 @@ from dkd import Envelope
53
53
 
54
54
  class MessageEnvelope(Dictionary, Envelope):
55
55
 
56
- def __init__(self, envelope: Dict[str, Any] = None,
56
+ def __init__(self, envelope: Dict = None,
57
57
  sender: ID = None, receiver: Optional[ID] = None, time: Optional[DateTime] = None):
58
58
  if envelope is None:
59
59
  # 1. new envelope with sender, receiver & time
@@ -80,21 +80,24 @@ class MessageEnvelope(Dictionary, Envelope):
80
80
 
81
81
  @property # Override
82
82
  def sender(self) -> ID:
83
- if self.__sender is None:
84
- identifier = self.get('sender')
85
- self.__sender = ID.parse(identifier=identifier)
86
- return self.__sender
83
+ did = self.__sender
84
+ if did is None:
85
+ did = self.get('sender')
86
+ did = ID.parse(identifier=did)
87
+ assert did is not None, 'message sender error: %s' % self.dictionary
88
+ self.__sender = did
89
+ return did
87
90
 
88
91
  @property # Override
89
92
  def receiver(self) -> ID:
90
- if self.__receiver is None:
91
- identifier = self.get('receiver')
92
- identifier = ID.parse(identifier=identifier)
93
- if identifier is None:
94
- self.__receiver = ANYONE
95
- else:
96
- self.__receiver = identifier
97
- return self.__receiver
93
+ did = self.__receiver
94
+ if did is None:
95
+ did = self.get('receiver')
96
+ did = ID.parse(identifier=did)
97
+ if did is None:
98
+ did = ANYONE
99
+ self.__receiver = did
100
+ return did
98
101
 
99
102
  @property # Override
100
103
  def time(self) -> Optional[DateTime]:
@@ -28,7 +28,7 @@
28
28
  # SOFTWARE.
29
29
  # ==============================================================================
30
30
 
31
- from typing import Optional, Any, Dict
31
+ from typing import Optional, Dict
32
32
 
33
33
  from mkm.types import DateTime
34
34
  from mkm import ID
@@ -57,7 +57,7 @@ from .base import BaseMessage
57
57
 
58
58
  class PlainMessage(BaseMessage, InstantMessage):
59
59
 
60
- def __init__(self, msg: Dict[str, Any] = None,
60
+ def __init__(self, msg: Dict = None,
61
61
  head: Envelope = None, body: Content = None):
62
62
  if msg is None:
63
63
  # 1. new instant message with envelope & content
@@ -73,11 +73,13 @@ class PlainMessage(BaseMessage, InstantMessage):
73
73
 
74
74
  @property # Override
75
75
  def content(self) -> Content:
76
- if self.__content is None:
76
+ body = self.__content
77
+ if body is None:
77
78
  info = self.get('content')
78
- self.__content = Content.parse(content=info)
79
- assert self.__content is not None, 'content error: %s' % info
80
- return self.__content
79
+ body = Content.parse(content=info)
80
+ assert body is not None, 'message content error: %s' % self.dictionary
81
+ self.__content = body
82
+ return body
81
83
 
82
84
  @content.setter # protected
83
85
  def content(self, value: Content):
@@ -28,7 +28,7 @@
28
28
  # SOFTWARE.
29
29
  # ==============================================================================
30
30
 
31
- from typing import Optional, Any, Dict
31
+ from typing import Optional, Dict
32
32
 
33
33
  from mkm.format import TransportableData
34
34
 
@@ -62,7 +62,7 @@ from .secure import EncryptedMessage
62
62
 
63
63
  class NetworkMessage(EncryptedMessage, ReliableMessage):
64
64
 
65
- def __init__(self, msg: Dict[str, Any]):
65
+ def __init__(self, msg: Dict):
66
66
  super().__init__(msg=msg)
67
67
  # lazy
68
68
  self.__signature: Optional[TransportableData] = None
@@ -28,7 +28,7 @@
28
28
  # SOFTWARE.
29
29
  # ==============================================================================
30
30
 
31
- from typing import Optional, Any, Dict
31
+ from typing import Optional, Dict
32
32
 
33
33
  from mkm.format import utf8_encode
34
34
  from mkm.format import TransportableData
@@ -60,7 +60,7 @@ from .base import BaseMessage
60
60
 
61
61
  class EncryptedMessage(BaseMessage, SecureMessage):
62
62
 
63
- def __init__(self, msg: Dict[str, Any]):
63
+ def __init__(self, msg: Dict):
64
64
  super().__init__(msg=msg)
65
65
  # lazy
66
66
  self.__data: Optional[bytes] = None
@@ -69,21 +69,23 @@ class EncryptedMessage(BaseMessage, SecureMessage):
69
69
 
70
70
  @property # Override
71
71
  def data(self) -> bytes:
72
- if self.__data is None:
72
+ binary = self.__data
73
+ if binary is None:
73
74
  text = self.get('data')
74
75
  if text is None:
75
- assert False, 'message data cannot be empty: %s' % self
76
+ assert False, 'message data not found: %s' % self.dictionary
76
77
  elif not BaseMessage.is_broadcast(msg=self):
77
78
  # message content had been encrypted by a symmetric key,
78
79
  # so the data should be encoded here (with algorithm 'base64' as default).
79
- self.__data = TransportableData.decode(text)
80
+ binary = TransportableData.decode(text)
80
81
  elif isinstance(text, str):
81
82
  # broadcast message content will not be encrypted (just encoded to JsON),
82
83
  # so return the string data directly
83
- self.__data = utf8_encode(string=text) # JsON
84
+ binary = utf8_encode(string=text) # JsON
84
85
  else:
85
86
  assert False, 'content data error: %s' % text
86
- return self.__data
87
+ self.__data = binary
88
+ return binary
87
89
 
88
90
  @property # Override
89
91
  def encrypted_key(self) -> Optional[bytes]:
@@ -102,7 +104,11 @@ class EncryptedMessage(BaseMessage, SecureMessage):
102
104
  return ted.data
103
105
 
104
106
  @property # Override
105
- def encrypted_keys(self) -> Optional[Dict[str, Any]]:
107
+ def encrypted_keys(self) -> Optional[Dict]:
106
108
  if self.__keys is None:
107
- self.__keys = self.get('keys')
109
+ keys = self.get('keys')
110
+ if isinstance(keys, Dict):
111
+ self.__keys = keys
112
+ else:
113
+ assert keys is None, 'message keys error: %s' % keys
108
114
  return self.__keys
@@ -31,10 +31,10 @@
31
31
  from mkm.plugins import *
32
32
  from dkd.plugins import *
33
33
 
34
- from ..protocol.commands import CommandHelper
34
+ from ..protocol.base import CommandHelper
35
35
  # from ..protocol.helpers import CommandExtensions
36
36
 
37
- from .cmd import GeneralCommandHelper, SharedCommandExtensions
37
+ from ..protocol.base import GeneralCommandHelper, SharedCommandExtensions
38
38
 
39
39
  __all__ = [
40
40