dimp 2.3.2__tar.gz → 2.3.4__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 (43) hide show
  1. {dimp-2.3.2 → dimp-2.3.4}/PKG-INFO +71 -96
  2. {dimp-2.3.2 → dimp-2.3.4}/README.md +70 -95
  3. {dimp-2.3.2 → dimp-2.3.4}/dimp/__init__.py +16 -16
  4. {dimp-2.3.2 → dimp-2.3.4}/dimp/crypto/__init__.py +4 -4
  5. {dimp-2.3.2 → dimp-2.3.4}/dimp/crypto/keys.py +12 -12
  6. {dimp-2.3.2 → dimp-2.3.4}/dimp/crypto/pnf.py +3 -3
  7. {dimp-2.3.2 → dimp-2.3.4}/dimp/crypto/ted.py +5 -5
  8. {dimp-2.3.2 → dimp-2.3.4}/dimp/dkd/__init__.py +15 -12
  9. {dimp-2.3.2/dimp/plugins → dimp-2.3.4/dimp/ext}/__init__.py +2 -2
  10. {dimp-2.3.2 → dimp-2.3.4}/dimp/mkm/document.py +3 -3
  11. {dimp-2.3.2 → dimp-2.3.4}/dimp/mkm/meta.py +1 -1
  12. {dimp-2.3.2 → dimp-2.3.4}/dimp/msg/envelope.py +6 -6
  13. {dimp-2.3.2 → dimp-2.3.4}/dimp/protocol/__init__.py +5 -3
  14. dimp-2.3.4/dimp/protocol/app.py +135 -0
  15. {dimp-2.3.2 → dimp-2.3.4}/dimp/protocol/base.py +2 -2
  16. {dimp-2.3.2 → dimp-2.3.4}/dimp/protocol/commands.py +2 -5
  17. {dimp-2.3.2 → dimp-2.3.4}/dimp/protocol/contents.py +5 -8
  18. {dimp-2.3.2 → dimp-2.3.4}/dimp/protocol/files.py +3 -3
  19. {dimp-2.3.2 → dimp-2.3.4}/dimp/protocol/groups.py +3 -35
  20. {dimp-2.3.2 → dimp-2.3.4}/dimp.egg-info/PKG-INFO +71 -96
  21. {dimp-2.3.2 → dimp-2.3.4}/dimp.egg-info/SOURCES.txt +3 -2
  22. dimp-2.3.4/dimp.egg-info/requires.txt +2 -0
  23. {dimp-2.3.2 → dimp-2.3.4}/setup.py +3 -3
  24. dimp-2.3.2/dimp.egg-info/requires.txt +0 -2
  25. {dimp-2.3.2 → dimp-2.3.4}/LICENSE +0 -0
  26. {dimp-2.3.2 → dimp-2.3.4}/dimp/crypto/algorithms.py +0 -0
  27. {dimp-2.3.2 → dimp-2.3.4}/dimp/mkm/__init__.py +0 -0
  28. {dimp-2.3.2 → dimp-2.3.4}/dimp/mkm/docs.py +0 -0
  29. {dimp-2.3.2 → dimp-2.3.4}/dimp/msg/__init__.py +0 -0
  30. {dimp-2.3.2 → dimp-2.3.4}/dimp/msg/base.py +0 -0
  31. {dimp-2.3.2 → dimp-2.3.4}/dimp/msg/instant.py +0 -0
  32. {dimp-2.3.2 → dimp-2.3.4}/dimp/msg/reliable.py +0 -0
  33. {dimp-2.3.2 → dimp-2.3.4}/dimp/msg/secure.py +0 -0
  34. /dimp-2.3.2/dimp/protocol/money.py → /dimp-2.3.4/dimp/protocol/assets.py +0 -0
  35. {dimp-2.3.2 → dimp-2.3.4}/dimp/protocol/docs.py +0 -0
  36. {dimp-2.3.2 → dimp-2.3.4}/dimp/protocol/forward.py +0 -0
  37. {dimp-2.3.2 → dimp-2.3.4}/dimp/protocol/helpers.py +0 -0
  38. {dimp-2.3.2 → dimp-2.3.4}/dimp/protocol/quote.py +0 -0
  39. {dimp-2.3.2 → dimp-2.3.4}/dimp/protocol/receipt.py +0 -0
  40. {dimp-2.3.2 → dimp-2.3.4}/dimp/protocol/types.py +0 -0
  41. {dimp-2.3.2 → dimp-2.3.4}/dimp.egg-info/dependency_links.txt +0 -0
  42. {dimp-2.3.2 → dimp-2.3.4}/dimp.egg-info/top_level.txt +0 -0
  43. {dimp-2.3.2 → dimp-2.3.4}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: dimp
3
- Version: 2.3.2
3
+ Version: 2.3.4
4
4
  Summary: Decentralized Instant Messaging Protocol
5
5
  Home-page: https://github.com/dimchat/core-py
6
6
  Author: Albert Moky
@@ -18,7 +18,7 @@ License-File: LICENSE
18
18
  [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)](https://github.com/dimchat/core-py/pulls)
19
19
  [![Platform](https://img.shields.io/badge/Platform-Python%203-brightgreen.svg)](https://github.com/dimchat/core-py/wiki)
20
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)
21
+ [![Repo Size](https://img.shields.io/github/repo-size/dimchat/core-py)](https://github.com/dimchat/core-py/archive/refs/heads/master.zip)
22
22
  [![Tags](https://img.shields.io/github/tag/dimchat/core-py)](https://github.com/dimchat/core-py/tags)
23
23
  [![Version](https://img.shields.io/pypi/v/dimp)](https://pypi.org/project/dimp)
24
24
 
@@ -36,7 +36,7 @@ License-File: LICENSE
36
36
 
37
37
  ## Examples
38
38
 
39
- ### extends Command
39
+ ### Extends Command
40
40
 
41
41
  * _Handshake Command Protocol_
42
42
  0. (C-S) handshake start
@@ -45,8 +45,9 @@ License-File: LICENSE
45
45
  3. (S-C) handshake success
46
46
 
47
47
  ```python
48
+ from abc import ABC, abstractmethod
48
49
  from enum import IntEnum
49
- from typing import Optional, Any, Dict
50
+ from typing import Optional, Dict
50
51
 
51
52
  from dimp import Command, BaseCommand
52
53
 
@@ -58,7 +59,20 @@ class HandshakeState(IntEnum):
58
59
  Success = 3 # S -> C, handshake accepted
59
60
 
60
61
 
61
- class HandshakeCommand(BaseCommand):
62
+ def handshake_state(title: str, session: str = None) -> HandshakeState:
63
+ # Server -> Client
64
+ if title == 'DIM!': # or title == 'OK!':
65
+ return HandshakeState.Success
66
+ if title == 'DIM?':
67
+ return HandshakeState.Again
68
+ # Client -> Server: "Hello world!"
69
+ if session is None or len(session) == 0:
70
+ return HandshakeState.Start
71
+ else:
72
+ return HandshakeState.Restart
73
+
74
+
75
+ class HandshakeCommand(Command, ABC):
62
76
  """
63
77
  Handshake Command
64
78
  ~~~~~~~~~~~~~~~~~
@@ -74,37 +88,24 @@ class HandshakeCommand(BaseCommand):
74
88
  """
75
89
  HANDSHAKE = 'handshake'
76
90
 
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
91
  @property
92
+ @abstractmethod
93
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
94
+ raise NotImplemented
100
95
 
101
96
  @property
97
+ @abstractmethod
102
98
  def session(self) -> Optional[str]:
103
- return self.get_str(key='session', default=None)
99
+ raise NotImplemented
104
100
 
105
101
  @property
102
+ @abstractmethod
106
103
  def state(self) -> HandshakeState:
107
- return handshake_state(title=self.title, session=self.session)
104
+ raise NotImplemented
105
+
106
+ #
107
+ # Factories
108
+ #
108
109
 
109
110
  @classmethod
110
111
  def offer(cls, session: str = None) -> Command:
@@ -114,7 +115,7 @@ class HandshakeCommand(BaseCommand):
114
115
  :param session: Old session key
115
116
  :return: HandshakeCommand object
116
117
  """
117
- return HandshakeCommand(title='Hello world!', session=session)
118
+ return BaseHandshakeCommand(title='Hello world!', session=session)
118
119
 
119
120
  @classmethod
120
121
  def ask(cls, session: str) -> Command:
@@ -124,7 +125,7 @@ class HandshakeCommand(BaseCommand):
124
125
  :param session: New session key
125
126
  :return: HandshakeCommand object
126
127
  """
127
- return HandshakeCommand(title='DIM?', session=session)
128
+ return BaseHandshakeCommand(title='DIM?', session=session)
128
129
 
129
130
  @classmethod
130
131
  def accepted(cls, session: str = None) -> Command:
@@ -133,7 +134,7 @@ class HandshakeCommand(BaseCommand):
133
134
 
134
135
  :return: HandshakeCommand object
135
136
  """
136
- return HandshakeCommand(title='DIM!', session=session)
137
+ return BaseHandshakeCommand(title='DIM!', session=session)
137
138
 
138
139
  start = offer # (1. C->S) first handshake, without session
139
140
  again = ask # (2. S->C) ask client to handshake with new session key
@@ -141,108 +142,82 @@ class HandshakeCommand(BaseCommand):
141
142
  success = accepted # (4. S->C) notice the client that handshake accepted
142
143
 
143
144
 
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
145
+ class BaseHandshakeCommand(BaseCommand, HandshakeCommand):
146
+
147
+ def __init__(self, content: Dict = None, title: str = None, session: str = None):
148
+ if content is None:
149
+ # 1. new command with title & session key
150
+ assert title is not None, 'handshake command error: %s' % session
151
+ cmd = self.HANDSHAKE
152
+ super().__init__(cmd=cmd)
153
+ self['title'] = title
154
+ self['message'] = title # TODO: remove after all clients upgraded
155
+ if session is not None:
156
+ self['session'] = session
157
+ else:
158
+ # 2. command info from network
159
+ assert title is None and session is None, 'params error: %s, %s, %s' % (content, title, session)
160
+ super().__init__(content)
161
+
162
+ @property
163
+ def title(self) -> str:
164
+ return self.get_str(key='title', default='')
165
+
166
+ @property
167
+ def session(self) -> Optional[str]:
168
+ return self.get_str(key='session')
169
+
170
+ @property
171
+ def state(self) -> HandshakeState:
172
+ return handshake_state(title=self.title, session=self.session)
155
173
  ```
156
174
 
157
- ### extends Content
175
+ ### Extends Content
158
176
 
159
177
  ```python
160
- from abc import ABC, abstractmethod
161
178
  from typing import Any, Dict
162
179
 
163
- from dimp import ContentType
164
- from dimp import Content
165
- from dimp import BaseContent
180
+ from dimp import *
166
181
 
167
182
 
168
- class CustomizedContent(Content, ABC):
183
+ class ApplicationContent(BaseContent, AppContent):
169
184
  """
170
185
  Application Customized message
171
186
  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
172
187
 
173
188
  data format: {
174
- type : 0xCC,
189
+ type : i2s(0xA0),
175
190
  sn : 123,
176
191
 
177
192
  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
193
  extra : info // action parameters
181
194
  }
182
195
  """
183
196
 
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
197
  def __init__(self, content: Dict[str, Any] = None,
210
- msg_type: int = None,
211
- app: str = None, mod: str = None, act: str = None):
198
+ msg_type: str = None, app: str = None):
212
199
  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)
200
+ # 1. new content with type, app_id
201
+ assert app is not None, 'customized content error: %s, %s' % (msg_type, app)
216
202
  if msg_type is None:
217
- msg_type = ContentType.CUSTOMIZED.value
203
+ msg_type = ContentType.APPLICATION
218
204
  super().__init__(None, msg_type)
219
205
  self['app'] = app
220
- self['mod'] = mod
221
- self['act'] = act
222
206
  else:
223
207
  # 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)
208
+ assert msg_type is None and app is None, 'params error: %s, %s, %s' % (content, msg_type, app)
226
209
  super().__init__(content)
227
210
 
228
211
  @property # Override
229
212
  def application(self) -> str:
230
213
  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
214
  ```
240
215
 
241
- ### extends ID Address
216
+ ### Extends ID Address
242
217
 
243
218
  * Examples in [dim plugins](https://pypi.org/project/dimplugins)
244
219
 
245
220
  ----
246
221
 
247
- Copyright © 2018 Albert Moky
222
+ Copyright © 2018-2025 Albert Moky
248
223
  [![Followers](https://img.shields.io/github/followers/moky)](https://github.com/moky?tab=followers)
@@ -4,7 +4,7 @@
4
4
  [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)](https://github.com/dimchat/core-py/pulls)
5
5
  [![Platform](https://img.shields.io/badge/Platform-Python%203-brightgreen.svg)](https://github.com/dimchat/core-py/wiki)
6
6
  [![Issues](https://img.shields.io/github/issues/dimchat/core-py)](https://github.com/dimchat/core-py/issues)
7
- [![Repo Size](https://img.shields.io/github/repo-size/dimchat/core-py)](https://github.com/dimchat/core-py/archive/refs/heads/main.zip)
7
+ [![Repo Size](https://img.shields.io/github/repo-size/dimchat/core-py)](https://github.com/dimchat/core-py/archive/refs/heads/master.zip)
8
8
  [![Tags](https://img.shields.io/github/tag/dimchat/core-py)](https://github.com/dimchat/core-py/tags)
9
9
  [![Version](https://img.shields.io/pypi/v/dimp)](https://pypi.org/project/dimp)
10
10
 
@@ -22,7 +22,7 @@
22
22
 
23
23
  ## Examples
24
24
 
25
- ### extends Command
25
+ ### Extends Command
26
26
 
27
27
  * _Handshake Command Protocol_
28
28
  0. (C-S) handshake start
@@ -31,8 +31,9 @@
31
31
  3. (S-C) handshake success
32
32
 
33
33
  ```python
34
+ from abc import ABC, abstractmethod
34
35
  from enum import IntEnum
35
- from typing import Optional, Any, Dict
36
+ from typing import Optional, Dict
36
37
 
37
38
  from dimp import Command, BaseCommand
38
39
 
@@ -44,7 +45,20 @@ class HandshakeState(IntEnum):
44
45
  Success = 3 # S -> C, handshake accepted
45
46
 
46
47
 
47
- class HandshakeCommand(BaseCommand):
48
+ def handshake_state(title: str, session: str = None) -> HandshakeState:
49
+ # Server -> Client
50
+ if title == 'DIM!': # or title == 'OK!':
51
+ return HandshakeState.Success
52
+ if title == 'DIM?':
53
+ return HandshakeState.Again
54
+ # Client -> Server: "Hello world!"
55
+ if session is None or len(session) == 0:
56
+ return HandshakeState.Start
57
+ else:
58
+ return HandshakeState.Restart
59
+
60
+
61
+ class HandshakeCommand(Command, ABC):
48
62
  """
49
63
  Handshake Command
50
64
  ~~~~~~~~~~~~~~~~~
@@ -60,37 +74,24 @@ class HandshakeCommand(BaseCommand):
60
74
  """
61
75
  HANDSHAKE = 'handshake'
62
76
 
63
- def __init__(self, content: Dict[str, Any] = None, title: str = None, session: str = None):
64
- if content is None:
65
- # 1. new command with title & session key
66
- assert title is not None, 'handshake command error: %s' % session
67
- cmd = self.HANDSHAKE
68
- super().__init__(cmd=cmd)
69
- self['title'] = title
70
- self['message'] = title # TODO: remove after all clients upgraded
71
- if session is not None:
72
- self['session'] = session
73
- else:
74
- # 2. command info from network
75
- assert title is None and session is None, 'params error: %s, %s, %s' % (content, title, session)
76
- super().__init__(content)
77
-
78
77
  @property
78
+ @abstractmethod
79
79
  def title(self) -> str:
80
- # TODO: modify after all clients upgraded
81
- text = self.get_str(key='title', default=None)
82
- if text is None:
83
- # compatible with v1.0
84
- text = self.get_str(key='message', default='')
85
- return text
80
+ raise NotImplemented
86
81
 
87
82
  @property
83
+ @abstractmethod
88
84
  def session(self) -> Optional[str]:
89
- return self.get_str(key='session', default=None)
85
+ raise NotImplemented
90
86
 
91
87
  @property
88
+ @abstractmethod
92
89
  def state(self) -> HandshakeState:
93
- return handshake_state(title=self.title, session=self.session)
90
+ raise NotImplemented
91
+
92
+ #
93
+ # Factories
94
+ #
94
95
 
95
96
  @classmethod
96
97
  def offer(cls, session: str = None) -> Command:
@@ -100,7 +101,7 @@ class HandshakeCommand(BaseCommand):
100
101
  :param session: Old session key
101
102
  :return: HandshakeCommand object
102
103
  """
103
- return HandshakeCommand(title='Hello world!', session=session)
104
+ return BaseHandshakeCommand(title='Hello world!', session=session)
104
105
 
105
106
  @classmethod
106
107
  def ask(cls, session: str) -> Command:
@@ -110,7 +111,7 @@ class HandshakeCommand(BaseCommand):
110
111
  :param session: New session key
111
112
  :return: HandshakeCommand object
112
113
  """
113
- return HandshakeCommand(title='DIM?', session=session)
114
+ return BaseHandshakeCommand(title='DIM?', session=session)
114
115
 
115
116
  @classmethod
116
117
  def accepted(cls, session: str = None) -> Command:
@@ -119,7 +120,7 @@ class HandshakeCommand(BaseCommand):
119
120
 
120
121
  :return: HandshakeCommand object
121
122
  """
122
- return HandshakeCommand(title='DIM!', session=session)
123
+ return BaseHandshakeCommand(title='DIM!', session=session)
123
124
 
124
125
  start = offer # (1. C->S) first handshake, without session
125
126
  again = ask # (2. S->C) ask client to handshake with new session key
@@ -127,108 +128,82 @@ class HandshakeCommand(BaseCommand):
127
128
  success = accepted # (4. S->C) notice the client that handshake accepted
128
129
 
129
130
 
130
- def handshake_state(title: str, session: str = None) -> HandshakeState:
131
- # Server -> Client
132
- if title == 'DIM!': # or title == 'OK!':
133
- return HandshakeState.Success
134
- if title == 'DIM?':
135
- return HandshakeState.Again
136
- # Client -> Server: "Hello world!"
137
- if session is None or len(session) == 0:
138
- return HandshakeState.Start
139
- else:
140
- return HandshakeState.Restart
131
+ class BaseHandshakeCommand(BaseCommand, HandshakeCommand):
132
+
133
+ def __init__(self, content: Dict = None, title: str = None, session: str = None):
134
+ if content is None:
135
+ # 1. new command with title & session key
136
+ assert title is not None, 'handshake command error: %s' % session
137
+ cmd = self.HANDSHAKE
138
+ super().__init__(cmd=cmd)
139
+ self['title'] = title
140
+ self['message'] = title # TODO: remove after all clients upgraded
141
+ if session is not None:
142
+ self['session'] = session
143
+ else:
144
+ # 2. command info from network
145
+ assert title is None and session is None, 'params error: %s, %s, %s' % (content, title, session)
146
+ super().__init__(content)
147
+
148
+ @property
149
+ def title(self) -> str:
150
+ return self.get_str(key='title', default='')
151
+
152
+ @property
153
+ def session(self) -> Optional[str]:
154
+ return self.get_str(key='session')
155
+
156
+ @property
157
+ def state(self) -> HandshakeState:
158
+ return handshake_state(title=self.title, session=self.session)
141
159
  ```
142
160
 
143
- ### extends Content
161
+ ### Extends Content
144
162
 
145
163
  ```python
146
- from abc import ABC, abstractmethod
147
164
  from typing import Any, Dict
148
165
 
149
- from dimp import ContentType
150
- from dimp import Content
151
- from dimp import BaseContent
166
+ from dimp import *
152
167
 
153
168
 
154
- class CustomizedContent(Content, ABC):
169
+ class ApplicationContent(BaseContent, AppContent):
155
170
  """
156
171
  Application Customized message
157
172
  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
158
173
 
159
174
  data format: {
160
- type : 0xCC,
175
+ type : i2s(0xA0),
161
176
  sn : 123,
162
177
 
163
178
  app : "{APP_ID}", // application (e.g.: "chat.dim.sechat")
164
- mod : "{MODULE}", // module name (e.g.: "drift_bottle")
165
- act : "{ACTION}", // action name (e.g.: "throw")
166
179
  extra : info // action parameters
167
180
  }
168
181
  """
169
182
 
170
- @property
171
- @abstractmethod
172
- def application(self) -> str:
173
- """ App ID """
174
- raise NotImplemented
175
-
176
- @property
177
- @abstractmethod
178
- def module(self) -> str:
179
- """ Module Name """
180
- raise NotImplemented
181
-
182
- @property
183
- @abstractmethod
184
- def action(self) -> str:
185
- """ Action Name """
186
- raise NotImplemented
187
-
188
- @classmethod
189
- def create(cls, app: str, mod: str, act: str):
190
- return AppCustomizedContent(app=app, mod=mod, act=act)
191
-
192
-
193
- class AppCustomizedContent(BaseContent, CustomizedContent):
194
-
195
183
  def __init__(self, content: Dict[str, Any] = None,
196
- msg_type: int = None,
197
- app: str = None, mod: str = None, act: str = None):
184
+ msg_type: str = None, app: str = None):
198
185
  if content is None:
199
- # 1. new content with type, application, module & action
200
- assert app is not None and mod is not None and act is not None, \
201
- 'customized content error: %s, %s, %s, %s' % (msg_type, app, mod, act)
186
+ # 1. new content with type, app_id
187
+ assert app is not None, 'customized content error: %s, %s' % (msg_type, app)
202
188
  if msg_type is None:
203
- msg_type = ContentType.CUSTOMIZED.value
189
+ msg_type = ContentType.APPLICATION
204
190
  super().__init__(None, msg_type)
205
191
  self['app'] = app
206
- self['mod'] = mod
207
- self['act'] = act
208
192
  else:
209
193
  # 2. content info from network
210
- assert msg_type is None and app is None and mod is None and act is None, \
211
- 'params error: %s, %s, %s, %s, %s' % (content, msg_type, app, mod, act)
194
+ assert msg_type is None and app is None, 'params error: %s, %s, %s' % (content, msg_type, app)
212
195
  super().__init__(content)
213
196
 
214
197
  @property # Override
215
198
  def application(self) -> str:
216
199
  return self.get_str(key='app', default='')
217
-
218
- @property # Override
219
- def module(self) -> str:
220
- return self.get_str(key='mod', default='')
221
-
222
- @property # Override
223
- def action(self) -> str:
224
- return self.get_str(key='act', default='')
225
200
  ```
226
201
 
227
- ### extends ID Address
202
+ ### Extends ID Address
228
203
 
229
204
  * Examples in [dim plugins](https://pypi.org/project/dimplugins)
230
205
 
231
206
  ----
232
207
 
233
- Copyright © 2018 Albert Moky
208
+ Copyright © 2018-2025 Albert Moky
234
209
  [![Followers](https://img.shields.io/github/followers/moky)](https://github.com/moky?tab=followers)
@@ -65,7 +65,6 @@ __all__ = [
65
65
  'DataCoder', 'Hex', 'Base58', 'Base64',
66
66
  'ObjectCoder', 'JSON',
67
67
  'MapCoder', 'JSONMap',
68
- 'ListCoder', 'JSONList',
69
68
  'StringCoder', 'UTF8',
70
69
 
71
70
  'hex_encode', 'hex_decode',
@@ -81,10 +80,9 @@ __all__ = [
81
80
  # Digest
82
81
  #
83
82
 
84
- 'DataDigester',
85
- 'MD5', 'SHA1', 'SHA256', 'KECCAK256', 'RIPEMD160',
86
-
87
- 'md5', 'sha1', 'sha256', 'keccak256', 'ripemd160',
83
+ 'MessageDigester',
84
+ 'SHA256', 'KECCAK256', 'RIPEMD160',
85
+ 'sha256', 'keccak256', 'ripemd160',
88
86
 
89
87
  #
90
88
  # Crypto
@@ -119,6 +117,8 @@ __all__ = [
119
117
  'Meta',
120
118
  'Document', 'Visa', 'Bulletin',
121
119
 
120
+ 'MetaType', 'DocumentType',
121
+
122
122
  'AddressFactory',
123
123
  'IDFactory',
124
124
  'MetaFactory',
@@ -132,8 +132,6 @@ __all__ = [
132
132
  'BaseMeta',
133
133
  'BaseDocument', 'BaseVisa', 'BaseBulletin',
134
134
 
135
- 'MetaType', 'DocumentType',
136
-
137
135
  #
138
136
  # DaoKeDao
139
137
  #
@@ -145,11 +143,12 @@ __all__ = [
145
143
  'InstantMessage', 'SecureMessage', 'ReliableMessage',
146
144
 
147
145
  # contents
148
- 'TextContent', 'ArrayContent', 'ForwardContent',
149
- 'PageContent', 'NameCard',
146
+ 'TextContent', 'PageContent', 'NameCard',
147
+ 'ForwardContent', 'CombineContent', 'ArrayContent',
150
148
  'FileContent', 'ImageContent', 'AudioContent', 'VideoContent',
151
149
  'MoneyContent', 'TransferContent',
152
- 'QuoteContent', 'CombineContent',
150
+ 'QuoteContent',
151
+ 'CustomizedContent',
153
152
 
154
153
  # commands
155
154
  'Command',
@@ -158,16 +157,17 @@ __all__ = [
158
157
 
159
158
  # group history
160
159
  'HistoryCommand', 'GroupCommand',
161
- 'InviteCommand', 'ExpelCommand', 'JoinCommand', 'QuitCommand', 'QueryCommand', 'ResetCommand',
160
+ 'InviteCommand', 'ExpelCommand', 'JoinCommand', 'QuitCommand', 'ResetCommand',
162
161
  'HireCommand', 'FireCommand', 'ResignCommand',
163
162
 
164
163
  # extend contents
165
164
  'BaseContent',
166
- 'BaseTextContent', 'ListContent', 'SecretContent',
167
- 'WebPageContent', 'NameCardContent',
165
+ 'BaseTextContent', 'WebPageContent', 'NameCardContent',
166
+ 'SecretContent', 'CombineForwardContent', 'ListContent',
168
167
  'BaseFileContent', 'ImageFileContent', 'AudioFileContent', 'VideoFileContent',
169
168
  'BaseMoneyContent', 'TransferMoneyContent',
170
- 'BaseQuoteContent', 'CombineForwardContent',
169
+ 'BaseQuoteContent',
170
+ 'AppCustomizedContent',
171
171
 
172
172
  # extend commands
173
173
  'BaseCommand',
@@ -176,8 +176,8 @@ __all__ = [
176
176
 
177
177
  # extend group history
178
178
  'BaseHistoryCommand', 'BaseGroupCommand',
179
- 'InviteGroupCommand', 'ExpelGroupCommand', 'JoinGroupCommand',
180
- 'QuitGroupCommand', 'QueryGroupCommand', 'ResetGroupCommand',
179
+ 'InviteGroupCommand', 'ExpelGroupCommand',
180
+ 'JoinGroupCommand', 'QuitGroupCommand', 'ResetGroupCommand',
181
181
  'HireGroupCommand', 'FireGroupCommand', 'ResignGroupCommand',
182
182
 
183
183
  #
@@ -42,12 +42,12 @@ from .pnf import BaseFileWrapper
42
42
  __all__ = [
43
43
 
44
44
  #
45
- # Data Digest
45
+ # Digest
46
46
  #
47
47
 
48
- 'DataDigester',
49
- 'MD5', 'SHA1', 'SHA256', 'KECCAK256', 'RIPEMD160',
50
- 'md5', 'sha1', 'sha256', 'keccak256', 'ripemd160',
48
+ 'MessageDigester',
49
+ 'SHA256', 'KECCAK256', 'RIPEMD160',
50
+ 'sha256', 'keccak256', 'ripemd160',
51
51
 
52
52
  #
53
53
  # Crypto