dimp 2.2.2__tar.gz → 2.3.1__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/LICENSE +21 -0
  2. dimp-2.3.1/PKG-INFO +248 -0
  3. {dimp-2.2.2 → dimp-2.3.1}/dimp/__init__.py +10 -1
  4. {dimp-2.2.2 → dimp-2.3.1}/dimp/crypto/__init__.py +9 -0
  5. dimp-2.3.1/dimp/crypto/algorithms.py +57 -0
  6. {dimp-2.2.2 → dimp-2.3.1}/dimp/crypto/keys.py +4 -3
  7. {dimp-2.2.2 → dimp-2.3.1}/dimp/crypto/ted.py +27 -22
  8. {dimp-2.2.2 → dimp-2.3.1}/dimp/dkd/base.py +9 -8
  9. {dimp-2.2.2 → dimp-2.3.1}/dimp/dkd/commands.py +24 -25
  10. {dimp-2.2.2 → dimp-2.3.1}/dimp/dkd/contents.py +34 -31
  11. {dimp-2.2.2 → dimp-2.3.1}/dimp/dkd/files.py +6 -7
  12. {dimp-2.2.2 → dimp-2.3.1}/dimp/dkd/group_admins.py +48 -12
  13. {dimp-2.2.2 → dimp-2.3.1}/dimp/dkd/groups.py +7 -7
  14. {dimp-2.2.2 → dimp-2.3.1}/dimp/dkd/money.py +15 -7
  15. {dimp-2.2.2 → dimp-2.3.1}/dimp/dkd/quote.py +13 -8
  16. {dimp-2.2.2 → dimp-2.3.1}/dimp/dkd/receipt.py +1 -1
  17. {dimp-2.2.2 → dimp-2.3.1}/dimp/mkm/__init__.py +3 -0
  18. {dimp-2.2.2 → dimp-2.3.1}/dimp/mkm/docs.py +5 -5
  19. {dimp-2.2.2 → dimp-2.3.1}/dimp/mkm/document.py +3 -13
  20. {dimp-2.2.2 → dimp-2.3.1}/dimp/mkm/meta.py +8 -9
  21. {dimp-2.2.2 → dimp-2.3.1}/dimp/msg/base.py +1 -1
  22. {dimp-2.2.2 → dimp-2.3.1}/dimp/msg/envelope.py +3 -3
  23. {dimp-2.2.2 → dimp-2.3.1}/dimp/msg/instant.py +6 -6
  24. {dimp-2.2.2 → dimp-2.3.1}/dimp/protocol/__init__.py +3 -0
  25. {dimp-2.2.2 → dimp-2.3.1}/dimp/protocol/commands.py +15 -15
  26. {dimp-2.2.2 → dimp-2.3.1}/dimp/protocol/contents.py +8 -44
  27. {dimp-2.2.2 → dimp-2.3.1}/dimp/protocol/files.py +11 -10
  28. {dimp-2.2.2 → dimp-2.3.1}/dimp/protocol/groups.py +28 -10
  29. {dimp-2.2.2 → dimp-2.3.1}/dimp/protocol/money.py +6 -5
  30. {dimp-2.2.2 → dimp-2.3.1}/dimp/protocol/quote.py +3 -21
  31. {dimp-2.2.2 → dimp-2.3.1}/dimp/protocol/receipt.py +1 -1
  32. dimp-2.3.1/dimp/protocol/types.py +177 -0
  33. dimp-2.3.1/dimp.egg-info/PKG-INFO +248 -0
  34. {dimp-2.2.2 → dimp-2.3.1}/dimp.egg-info/SOURCES.txt +4 -1
  35. dimp-2.3.1/dimp.egg-info/requires.txt +2 -0
  36. {dimp-2.2.2 → dimp-2.3.1}/setup.py +3 -3
  37. dimp-2.2.2/PKG-INFO +0 -248
  38. dimp-2.2.2/dimp.egg-info/PKG-INFO +0 -248
  39. dimp-2.2.2/dimp.egg-info/requires.txt +0 -2
  40. {dimp-2.2.2 → dimp-2.3.1}/README.md +0 -0
  41. {dimp-2.2.2 → dimp-2.3.1}/dimp/crypto/pnf.py +0 -0
  42. {dimp-2.2.2 → dimp-2.3.1}/dimp/dkd/__init__.py +0 -0
  43. {dimp-2.2.2 → dimp-2.3.1}/dimp/msg/__init__.py +0 -0
  44. {dimp-2.2.2 → dimp-2.3.1}/dimp/msg/reliable.py +0 -0
  45. {dimp-2.2.2 → dimp-2.3.1}/dimp/msg/secure.py +0 -0
  46. {dimp-2.2.2 → dimp-2.3.1}/dimp/plugins/__init__.py +0 -0
  47. {dimp-2.2.2 → dimp-2.3.1}/dimp/plugins/cmd.py +0 -0
  48. {dimp-2.2.2 → dimp-2.3.1}/dimp/protocol/docs.py +0 -0
  49. {dimp-2.2.2 → dimp-2.3.1}/dimp/protocol/helpers.py +0 -0
  50. {dimp-2.2.2 → dimp-2.3.1}/dimp.egg-info/dependency_links.txt +0 -0
  51. {dimp-2.2.2 → dimp-2.3.1}/dimp.egg-info/top_level.txt +0 -0
  52. {dimp-2.2.2 → dimp-2.3.1}/setup.cfg +0 -0
dimp-2.3.1/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2019 Albert Moky
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
dimp-2.3.1/PKG-INFO ADDED
@@ -0,0 +1,248 @@
1
+ Metadata-Version: 2.1
2
+ Name: dimp
3
+ Version: 2.3.1
4
+ Summary: Decentralized Instant Messaging Protocol
5
+ Home-page: https://github.com/dimchat/core-py
6
+ Author: Albert Moky
7
+ Author-email: albert.moky@gmail.com
8
+ License: MIT
9
+ Classifier: Programming Language :: Python :: 3
10
+ Classifier: License :: OSI Approved :: MIT License
11
+ Classifier: Operating System :: OS Independent
12
+ Description-Content-Type: text/markdown
13
+ License-File: LICENSE
14
+
15
+ # Decentralized Instant Messaging Protocol (Python)
16
+
17
+ [![License](https://img.shields.io/github/license/dimchat/core-py)](https://github.com/dimchat/core-py/blob/master/LICENSE)
18
+ [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)](https://github.com/dimchat/core-py/pulls)
19
+ [![Platform](https://img.shields.io/badge/Platform-Python%203-brightgreen.svg)](https://github.com/dimchat/core-py/wiki)
20
+ [![Issues](https://img.shields.io/github/issues/dimchat/core-py)](https://github.com/dimchat/core-py/issues)
21
+ [![Repo Size](https://img.shields.io/github/repo-size/dimchat/core-py)](https://github.com/dimchat/core-py/archive/refs/heads/main.zip)
22
+ [![Tags](https://img.shields.io/github/tag/dimchat/core-py)](https://github.com/dimchat/core-py/tags)
23
+ [![Version](https://img.shields.io/pypi/v/dimp)](https://pypi.org/project/dimp)
24
+
25
+ [![Watchers](https://img.shields.io/github/watchers/dimchat/core-py)](https://github.com/dimchat/core-py/watchers)
26
+ [![Forks](https://img.shields.io/github/forks/dimchat/core-py)](https://github.com/dimchat/core-py/forks)
27
+ [![Stars](https://img.shields.io/github/stars/dimchat/core-py)](https://github.com/dimchat/core-py/stargazers)
28
+ [![Followers](https://img.shields.io/github/followers/dimchat)](https://github.com/orgs/dimchat/followers)
29
+
30
+ ## Dependencies
31
+
32
+ | Name | Version | Description |
33
+ |------|---------|-------------|
34
+ | [Ming Ke Ming (名可名)](https://github.com/dimchat/mkm-py) | [![Version](https://img.shields.io/pypi/v/mkm)](https://pypi.org/project/mkm) | Decentralized User Identity Authentication |
35
+ | [Dao Ke Dao (道可道)](https://github.com/dimchat/dkd-py) | [![Version](https://img.shields.io/pypi/v/dkd)](https://pypi.org/project/dkd) | Universal Message Module |
36
+
37
+ ## Examples
38
+
39
+ ### extends Command
40
+
41
+ * _Handshake Command Protocol_
42
+ 0. (C-S) handshake start
43
+ 1. (S-C) handshake again with new session
44
+ 2. (C-S) handshake restart with new session
45
+ 3. (S-C) handshake success
46
+
47
+ ```python
48
+ from enum import IntEnum
49
+ from typing import Optional, Any, Dict
50
+
51
+ from dimp import Command, BaseCommand
52
+
53
+
54
+ class HandshakeState(IntEnum):
55
+ Start = 0 # C -> S, without session key(or session expired)
56
+ Again = 1 # S -> C, with new session key
57
+ Restart = 2 # C -> S, with new session key
58
+ Success = 3 # S -> C, handshake accepted
59
+
60
+
61
+ class HandshakeCommand(BaseCommand):
62
+ """
63
+ Handshake Command
64
+ ~~~~~~~~~~~~~~~~~
65
+
66
+ data format: {
67
+ type : 0x88,
68
+ sn : 123,
69
+
70
+ command : "handshake", // command name
71
+ title : "Hello world!", // "DIM?", "DIM!"
72
+ session : "{SESSION_ID}", // session key
73
+ }
74
+ """
75
+ HANDSHAKE = 'handshake'
76
+
77
+ def __init__(self, content: Dict[str, Any] = None, title: str = None, session: str = None):
78
+ if content is None:
79
+ # 1. new command with title & session key
80
+ assert title is not None, 'handshake command error: %s' % session
81
+ cmd = self.HANDSHAKE
82
+ super().__init__(cmd=cmd)
83
+ self['title'] = title
84
+ self['message'] = title # TODO: remove after all clients upgraded
85
+ if session is not None:
86
+ self['session'] = session
87
+ else:
88
+ # 2. command info from network
89
+ assert title is None and session is None, 'params error: %s, %s, %s' % (content, title, session)
90
+ super().__init__(content)
91
+
92
+ @property
93
+ def title(self) -> str:
94
+ # TODO: modify after all clients upgraded
95
+ text = self.get_str(key='title', default=None)
96
+ if text is None:
97
+ # compatible with v1.0
98
+ text = self.get_str(key='message', default='')
99
+ return text
100
+
101
+ @property
102
+ def session(self) -> Optional[str]:
103
+ return self.get_str(key='session', default=None)
104
+
105
+ @property
106
+ def state(self) -> HandshakeState:
107
+ return handshake_state(title=self.title, session=self.session)
108
+
109
+ @classmethod
110
+ def offer(cls, session: str = None) -> Command:
111
+ """
112
+ Create client-station handshake offer
113
+
114
+ :param session: Old session key
115
+ :return: HandshakeCommand object
116
+ """
117
+ return HandshakeCommand(title='Hello world!', session=session)
118
+
119
+ @classmethod
120
+ def ask(cls, session: str) -> Command:
121
+ """
122
+ Create station-client handshake again with new session
123
+
124
+ :param session: New session key
125
+ :return: HandshakeCommand object
126
+ """
127
+ return HandshakeCommand(title='DIM?', session=session)
128
+
129
+ @classmethod
130
+ def accepted(cls, session: str = None) -> Command:
131
+ """
132
+ Create station-client handshake success notice
133
+
134
+ :return: HandshakeCommand object
135
+ """
136
+ return HandshakeCommand(title='DIM!', session=session)
137
+
138
+ start = offer # (1. C->S) first handshake, without session
139
+ again = ask # (2. S->C) ask client to handshake with new session key
140
+ restart = offer # (3. C->S) handshake with new session key
141
+ success = accepted # (4. S->C) notice the client that handshake accepted
142
+
143
+
144
+ def handshake_state(title: str, session: str = None) -> HandshakeState:
145
+ # Server -> Client
146
+ if title == 'DIM!': # or title == 'OK!':
147
+ return HandshakeState.Success
148
+ if title == 'DIM?':
149
+ return HandshakeState.Again
150
+ # Client -> Server: "Hello world!"
151
+ if session is None or len(session) == 0:
152
+ return HandshakeState.Start
153
+ else:
154
+ return HandshakeState.Restart
155
+ ```
156
+
157
+ ### extends Content
158
+
159
+ ```python
160
+ from abc import ABC, abstractmethod
161
+ from typing import Any, Dict
162
+
163
+ from dimp import ContentType
164
+ from dimp import Content
165
+ from dimp import BaseContent
166
+
167
+
168
+ class CustomizedContent(Content, ABC):
169
+ """
170
+ Application Customized message
171
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
172
+
173
+ data format: {
174
+ type : 0xCC,
175
+ sn : 123,
176
+
177
+ app : "{APP_ID}", // application (e.g.: "chat.dim.sechat")
178
+ mod : "{MODULE}", // module name (e.g.: "drift_bottle")
179
+ act : "{ACTION}", // action name (e.g.: "throw")
180
+ extra : info // action parameters
181
+ }
182
+ """
183
+
184
+ @property
185
+ @abstractmethod
186
+ def application(self) -> str:
187
+ """ App ID """
188
+ raise NotImplemented
189
+
190
+ @property
191
+ @abstractmethod
192
+ def module(self) -> str:
193
+ """ Module Name """
194
+ raise NotImplemented
195
+
196
+ @property
197
+ @abstractmethod
198
+ def action(self) -> str:
199
+ """ Action Name """
200
+ raise NotImplemented
201
+
202
+ @classmethod
203
+ def create(cls, app: str, mod: str, act: str):
204
+ return AppCustomizedContent(app=app, mod=mod, act=act)
205
+
206
+
207
+ class AppCustomizedContent(BaseContent, CustomizedContent):
208
+
209
+ def __init__(self, content: Dict[str, Any] = None,
210
+ msg_type: int = None,
211
+ app: str = None, mod: str = None, act: str = None):
212
+ if content is None:
213
+ # 1. new content with type, application, module & action
214
+ assert app is not None and mod is not None and act is not None, \
215
+ 'customized content error: %s, %s, %s, %s' % (msg_type, app, mod, act)
216
+ if msg_type is None:
217
+ msg_type = ContentType.CUSTOMIZED.value
218
+ super().__init__(None, msg_type)
219
+ self['app'] = app
220
+ self['mod'] = mod
221
+ self['act'] = act
222
+ else:
223
+ # 2. content info from network
224
+ assert msg_type is None and app is None and mod is None and act is None, \
225
+ 'params error: %s, %s, %s, %s, %s' % (content, msg_type, app, mod, act)
226
+ super().__init__(content)
227
+
228
+ @property # Override
229
+ def application(self) -> str:
230
+ return self.get_str(key='app', default='')
231
+
232
+ @property # Override
233
+ def module(self) -> str:
234
+ return self.get_str(key='mod', default='')
235
+
236
+ @property # Override
237
+ def action(self) -> str:
238
+ return self.get_str(key='act', default='')
239
+ ```
240
+
241
+ ### extends ID Address
242
+
243
+ * Examples in [dim plugins](https://pypi.org/project/dimplugins)
244
+
245
+ ----
246
+
247
+ Copyright © 2018 Albert Moky
248
+ [![Followers](https://img.shields.io/github/followers/moky)](https://github.com/moky?tab=followers)
@@ -52,7 +52,8 @@ __all__ = [
52
52
 
53
53
  'URI', 'DateTime',
54
54
 
55
- 'Converter', 'Copier',
55
+ 'Converter', 'DataConverter', 'BaseConverter',
56
+ 'Copier',
56
57
  'Wrapper', 'Stringer', 'Mapper',
57
58
  'ConstantString', # 'String',
58
59
  'Dictionary',
@@ -102,6 +103,12 @@ __all__ = [
102
103
  'BaseDataWrapper',
103
104
  'BaseFileWrapper',
104
105
 
106
+ #
107
+ # Algorithm
108
+ #
109
+ 'AsymmetricAlgorithms', 'SymmetricAlgorithms',
110
+ 'EncodeAlgorithms',
111
+
105
112
  #
106
113
  # MingKeMing
107
114
  #
@@ -125,6 +132,8 @@ __all__ = [
125
132
  'BaseMeta',
126
133
  'BaseDocument', 'BaseVisa', 'BaseBulletin',
127
134
 
135
+ 'MetaType', 'DocumentType',
136
+
128
137
  #
129
138
  # DaoKeDao
130
139
  #
@@ -30,6 +30,9 @@
30
30
 
31
31
  from mkm.crypto import *
32
32
 
33
+ from .algorithms import AsymmetricAlgorithms, SymmetricAlgorithms
34
+ from .algorithms import EncodeAlgorithms
35
+
33
36
  from .keys import BaseKey, BaseSymmetricKey
34
37
  from .keys import BaseAsymmetricKey, BasePublicKey, BasePrivateKey
35
38
 
@@ -57,6 +60,12 @@ __all__ = [
57
60
 
58
61
  'SymmetricKeyFactory', 'PrivateKeyFactory', 'PublicKeyFactory',
59
62
 
63
+ #
64
+ # Algorithm
65
+ #
66
+ 'AsymmetricAlgorithms', 'SymmetricAlgorithms',
67
+ 'EncodeAlgorithms',
68
+
60
69
  #
61
70
  # Base Keys
62
71
  #
@@ -0,0 +1,57 @@
1
+ # -*- coding: utf-8 -*-
2
+ #
3
+ # DIMP : Decentralized Instant Messaging Protocol
4
+ #
5
+ # Written in 2025 by Moky <albert.moky@gmail.com>
6
+ #
7
+ # ==============================================================================
8
+ # MIT License
9
+ #
10
+ # Copyright (c) 2025 Albert Moky
11
+ #
12
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
13
+ # of this software and associated documentation files (the "Software"), to deal
14
+ # in the Software without restriction, including without limitation the rights
15
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
16
+ # copies of the Software, and to permit persons to whom the Software is
17
+ # furnished to do so, subject to the following conditions:
18
+ #
19
+ # The above copyright notice and this permission notice shall be included in all
20
+ # copies or substantial portions of the Software.
21
+ #
22
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
25
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
27
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
28
+ # SOFTWARE.
29
+ # ==============================================================================
30
+
31
+
32
+ class AsymmetricAlgorithms:
33
+ """ Algorithms for Asymmetric Key """
34
+
35
+ RSA = 'RSA' # -- "RSA/ECB/PKCS1Padding", "SHA256withRSA"
36
+ ECC = 'ECC'
37
+
38
+
39
+ class SymmetricAlgorithms:
40
+ """ Algorithms for Symmetric Key """
41
+
42
+ AES = 'AES' # -- "AES/CBC/PKCS7Padding"
43
+ DES = 'DES'
44
+
45
+ # Symmetric key algorithm for broadcast message,
46
+ # which will do nothing when en/decoding message data
47
+ PLAIN = 'PLAIN'
48
+
49
+
50
+ class EncodeAlgorithms:
51
+ """ Algorithms for Encoding Data """
52
+
53
+ DEFAULT = 'base64'
54
+
55
+ BASE_64 = 'base64'
56
+ BASE_58 = 'base58'
57
+ HEX = 'hex'
@@ -29,7 +29,7 @@
29
29
  # ==============================================================================
30
30
 
31
31
  from abc import ABC
32
- from typing import Optional, Any, Dict
32
+ from typing import Any, Dict
33
33
 
34
34
  from mkm.types import Dictionary
35
35
  from mkm.crypto import CryptographyKey, EncryptKey, DecryptKey, SignKey, VerifyKey
@@ -58,9 +58,10 @@ class BaseKey(Dictionary, CryptographyKey, ABC):
58
58
  #
59
59
 
60
60
  @classmethod
61
- def get_key_algorithm(cls, key: Dict[str, Any]) -> Optional[str]:
61
+ def get_key_algorithm(cls, key: Dict[str, Any]) -> str:
62
62
  ext = SharedCryptoExtensions()
63
- return ext.helper.get_key_algorithm(key=key, default='')
63
+ algorithm = ext.helper.get_key_algorithm(key=key, default=None)
64
+ return '' if algorithm is None else algorithm
64
65
 
65
66
  @classmethod
66
67
  def match_encrypt_key(cls, encrypt_key: EncryptKey, decrypt_key: DecryptKey) -> bool:
@@ -33,9 +33,10 @@ from typing import Optional, Any, Dict
33
33
  from mkm.format import base64_encode, base64_decode
34
34
  from mkm.format import base58_encode, base58_decode
35
35
  from mkm.format import hex_encode, hex_decode
36
- from mkm.format import TransportableData
37
36
  from mkm.types import Dictionary
38
37
 
38
+ from .algorithms import EncodeAlgorithms
39
+
39
40
 
40
41
  class BaseDataWrapper(Dictionary):
41
42
  """
@@ -68,11 +69,11 @@ class BaseDataWrapper(Dictionary):
68
69
 
69
70
  # Override
70
71
  def __str__(self) -> str:
71
- text = self.get_str(key='data', default='')
72
- if len(text) == 0:
73
- return text
74
- alg = self.get_str(key='algorithm', default='')
75
- if alg == TransportableData.DEFAULT:
72
+ text = self.get_str(key='data', default=None)
73
+ if text is None: # or len(text) == 0:
74
+ return ''
75
+ alg = self.get_str(key='algorithm', default=None)
76
+ if alg is None or alg == EncodeAlgorithms.DEFAULT:
76
77
  alg = ''
77
78
  if len(alg) == 0:
78
79
  # 0. "{BASE64_ENCODE}"
@@ -84,9 +85,9 @@ class BaseDataWrapper(Dictionary):
84
85
  def encode(self, mime_type: str) -> str:
85
86
  """ toString(mimeType) """
86
87
  # get encoded data
87
- text = self.get_str(key='data', default='')
88
- if len(text) == 0:
89
- return text
88
+ text = self.get_str(key='data', default=None)
89
+ if text is None: # or len(text) == 0:
90
+ return ''
90
91
  alg = self.algorithm
91
92
  # 2. "data:image/png;base64,{BASE64_ENCODE}"
92
93
  return 'data:%s;%s,%s' % (mime_type, alg, text)
@@ -97,14 +98,14 @@ class BaseDataWrapper(Dictionary):
97
98
 
98
99
  @property
99
100
  def algorithm(self) -> str:
100
- alg = self.get_str(key='algorithm', default='')
101
- if len(alg) == 0:
102
- alg = TransportableData.DEFAULT
101
+ alg = self.get_str(key='algorithm', default=None)
102
+ if alg is None or len(alg) == 0:
103
+ alg = EncodeAlgorithms.DEFAULT
103
104
  return alg
104
105
 
105
106
  @algorithm.setter
106
107
  def algorithm(self, name: str):
107
- if name is None: # or name == TransportableData.DEFAULT:
108
+ if name is None: # or name == EncodeAlgorithms.DEFAULT:
108
109
  self.pop('algorithm', None)
109
110
  else:
110
111
  self['algorithm'] = name
@@ -117,14 +118,17 @@ class BaseDataWrapper(Dictionary):
117
118
  def data(self) -> Optional[bytes]:
118
119
  binary = self.__data
119
120
  if binary is None:
120
- text = self.get_str(key='data', default='')
121
- if len(text) > 0:
121
+ text = self.get_str(key='data', default=None)
122
+ if text is None or len(text) == 0:
123
+ assert False, 'TED data empty: %s' % self.dictionary
124
+ # return None
125
+ else:
122
126
  alg = self.algorithm
123
- if alg == TransportableData.BASE_64:
127
+ if alg == EncodeAlgorithms.BASE_64:
124
128
  binary = base64_decode(string=text)
125
- elif alg == TransportableData.BASE_58:
129
+ elif alg == EncodeAlgorithms.BASE_58:
126
130
  binary = base58_decode(string=text)
127
- elif alg == TransportableData.HEX:
131
+ elif alg == EncodeAlgorithms.HEX:
128
132
  binary = hex_decode(string=text)
129
133
  else:
130
134
  assert False, 'data algorithm not support: %s' % alg
@@ -137,13 +141,14 @@ class BaseDataWrapper(Dictionary):
137
141
  self.pop('data', None)
138
142
  else:
139
143
  alg = self.algorithm
140
- if alg == TransportableData.BASE_64:
144
+ if alg == EncodeAlgorithms.BASE_64:
141
145
  text = base64_encode(data=binary)
142
- elif alg == TransportableData.BASE_58:
146
+ elif alg == EncodeAlgorithms.BASE_58:
143
147
  text = base58_encode(data=binary)
144
- elif alg == TransportableData.HEX:
148
+ elif alg == EncodeAlgorithms.HEX:
145
149
  text = hex_encode(data=binary)
146
150
  else:
147
- assert False, 'data algorithm not support: %s' % alg
151
+ raise ArithmeticError('data algorithm not support: %s' % alg)
152
+ # assert False, 'data algorithm not support: %s' % alg
148
153
  self['data'] = text
149
154
  self.__data = binary
@@ -33,10 +33,11 @@ from typing import Optional, Any, Dict
33
33
  from mkm.types import DateTime
34
34
  from mkm.types import Dictionary
35
35
  from mkm import ID
36
- from dkd import ContentType, Content
36
+ from dkd import Content
37
37
  from dkd import InstantMessage
38
38
  from dkd.plugins import SharedMessageExtensions
39
39
 
40
+ from ..protocol import ContentType
40
41
  from ..protocol import Command
41
42
 
42
43
  from ..plugins import SharedCommandExtensions
@@ -52,11 +53,11 @@ from ..plugins import SharedCommandExtensions
52
53
 
53
54
  class BaseContent(Dictionary, Content):
54
55
 
55
- def __init__(self, content: Dict[str, Any] = None, msg_type: int = None):
56
+ def __init__(self, content: Dict[str, Any] = None, msg_type: str = None):
56
57
  # check parameters
57
58
  if content is None:
58
59
  # 1. new content with type
59
- assert msg_type is not None and msg_type > 0, 'content type error: %s' % msg_type
60
+ assert msg_type is not None and len(msg_type) > 0, 'content type error: %s' % msg_type
60
61
  time = DateTime.now()
61
62
  sn = InstantMessage.generate_serial_number(msg_type, time)
62
63
  content = {
@@ -77,11 +78,11 @@ class BaseContent(Dictionary, Content):
77
78
  self.__time = time
78
79
 
79
80
  @property # Override
80
- def type(self) -> int:
81
+ def type(self) -> str:
81
82
  """ message content type: text, image, ... """
82
83
  if self.__type is None:
83
84
  ext = SharedMessageExtensions()
84
- self.__type = ext.helper.get_content_type(content=self.dictionary, default=0)
85
+ self.__type = ext.helper.get_content_type(content=self.dictionary, default='')
85
86
  # self.__type = self.get_int(key='type', default=0)
86
87
  return self.__type
87
88
 
@@ -114,18 +115,18 @@ class BaseContent(Dictionary, Content):
114
115
 
115
116
  class BaseCommand(BaseContent, Command):
116
117
 
117
- def __init__(self, content: Dict[str, Any] = None, msg_type: int = None, cmd: str = None):
118
+ def __init__(self, content: Dict[str, Any] = None, msg_type: str = None, cmd: str = None):
118
119
  # check parameters
119
120
  if content is None:
120
121
  # 1. new command with type & name
121
122
  if msg_type is None:
122
- msg_type = ContentType.COMMAND.value
123
+ msg_type = ContentType.COMMAND
123
124
  assert cmd is not None and len(cmd) > 0, 'command name should not empty'
124
125
  super().__init__(None, msg_type)
125
126
  self['command'] = cmd
126
127
  else:
127
128
  # 2. command info from network
128
- assert msg_type is None and cmd is None, 'params error: %d, %s' % (msg_type, cmd)
129
+ assert msg_type is None and cmd is None, 'params error: %s, %s' % (msg_type, cmd)
129
130
  super().__init__(content)
130
131
 
131
132
  @property # Override