naeural-client 2.0.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- naeural_client/__init__.py +13 -0
- naeural_client/_ver.py +13 -0
- naeural_client/base/__init__.py +6 -0
- naeural_client/base/distributed_custom_code_presets.py +44 -0
- naeural_client/base/generic_session.py +1763 -0
- naeural_client/base/instance.py +616 -0
- naeural_client/base/payload/__init__.py +1 -0
- naeural_client/base/payload/payload.py +66 -0
- naeural_client/base/pipeline.py +1499 -0
- naeural_client/base/plugin_template.py +5209 -0
- naeural_client/base/responses.py +209 -0
- naeural_client/base/transaction.py +157 -0
- naeural_client/base_decentra_object.py +143 -0
- naeural_client/bc/__init__.py +3 -0
- naeural_client/bc/base.py +1046 -0
- naeural_client/bc/chain.py +0 -0
- naeural_client/bc/ec.py +324 -0
- naeural_client/certs/__init__.py +0 -0
- naeural_client/certs/r9092118.ala.eu-central-1.emqxsl.com.crt +22 -0
- naeural_client/code_cheker/__init__.py +1 -0
- naeural_client/code_cheker/base.py +520 -0
- naeural_client/code_cheker/checker.py +294 -0
- naeural_client/comm/__init__.py +2 -0
- naeural_client/comm/amqp_wrapper.py +338 -0
- naeural_client/comm/mqtt_wrapper.py +539 -0
- naeural_client/const/README.md +3 -0
- naeural_client/const/__init__.py +9 -0
- naeural_client/const/base.py +101 -0
- naeural_client/const/comms.py +80 -0
- naeural_client/const/environment.py +26 -0
- naeural_client/const/formatter.py +7 -0
- naeural_client/const/heartbeat.py +111 -0
- naeural_client/const/misc.py +20 -0
- naeural_client/const/payload.py +190 -0
- naeural_client/default/__init__.py +1 -0
- naeural_client/default/instance/__init__.py +4 -0
- naeural_client/default/instance/chain_dist_custom_job_01_plugin.py +54 -0
- naeural_client/default/instance/custom_web_app_01_plugin.py +118 -0
- naeural_client/default/instance/net_mon_01_plugin.py +45 -0
- naeural_client/default/instance/view_scene_01_plugin.py +28 -0
- naeural_client/default/session/mqtt_session.py +72 -0
- naeural_client/io_formatter/__init__.py +2 -0
- naeural_client/io_formatter/base/__init__.py +1 -0
- naeural_client/io_formatter/base/base_formatter.py +80 -0
- naeural_client/io_formatter/default/__init__.py +3 -0
- naeural_client/io_formatter/default/a_dummy.py +51 -0
- naeural_client/io_formatter/default/aixp1.py +113 -0
- naeural_client/io_formatter/default/default.py +22 -0
- naeural_client/io_formatter/io_formatter_manager.py +96 -0
- naeural_client/logging/__init__.py +1 -0
- naeural_client/logging/base_logger.py +2056 -0
- naeural_client/logging/logger_mixins/__init__.py +12 -0
- naeural_client/logging/logger_mixins/class_instance_mixin.py +92 -0
- naeural_client/logging/logger_mixins/computer_vision_mixin.py +443 -0
- naeural_client/logging/logger_mixins/datetime_mixin.py +344 -0
- naeural_client/logging/logger_mixins/download_mixin.py +421 -0
- naeural_client/logging/logger_mixins/general_serialization_mixin.py +242 -0
- naeural_client/logging/logger_mixins/json_serialization_mixin.py +481 -0
- naeural_client/logging/logger_mixins/pickle_serialization_mixin.py +301 -0
- naeural_client/logging/logger_mixins/process_mixin.py +63 -0
- naeural_client/logging/logger_mixins/resource_size_mixin.py +81 -0
- naeural_client/logging/logger_mixins/timers_mixin.py +501 -0
- naeural_client/logging/logger_mixins/upload_mixin.py +260 -0
- naeural_client/logging/logger_mixins/utils_mixin.py +675 -0
- naeural_client/logging/small_logger.py +93 -0
- naeural_client/logging/tzlocal/__init__.py +20 -0
- naeural_client/logging/tzlocal/unix.py +231 -0
- naeural_client/logging/tzlocal/utils.py +113 -0
- naeural_client/logging/tzlocal/win32.py +151 -0
- naeural_client/logging/tzlocal/windows_tz.py +718 -0
- naeural_client/plugins_manager_mixin.py +273 -0
- naeural_client/utils/__init__.py +2 -0
- naeural_client/utils/comm_utils.py +44 -0
- naeural_client/utils/dotenv.py +75 -0
- naeural_client-2.0.0.dist-info/METADATA +365 -0
- naeural_client-2.0.0.dist-info/RECORD +78 -0
- naeural_client-2.0.0.dist-info/WHEEL +4 -0
- naeural_client-2.0.0.dist-info/licenses/LICENSE +201 -0
@@ -0,0 +1,294 @@
|
|
1
|
+
import ast
|
2
|
+
|
3
|
+
|
4
|
+
class CheckerConstants:
|
5
|
+
"""
|
6
|
+
ASTChecker constants.
|
7
|
+
"""
|
8
|
+
type_key = 'type'
|
9
|
+
error_key = 'error'
|
10
|
+
var = 'var'
|
11
|
+
attr = 'attribute'
|
12
|
+
|
13
|
+
|
14
|
+
class ASTChecker(ast.NodeVisitor):
|
15
|
+
"""
|
16
|
+
An Abstract Syntax Tree based checker for custom code.
|
17
|
+
"""
|
18
|
+
|
19
|
+
def __init__(self, unallowed_dict: dict, safe_imports: list):
|
20
|
+
"""
|
21
|
+
Constructor for the AST checker.
|
22
|
+
|
23
|
+
Parameters
|
24
|
+
----------
|
25
|
+
unallowed_dict - a dictionary for unallowed identifiers.
|
26
|
+
The dictionary has the indentifier names as keys. The
|
27
|
+
Values are dictionaries with keys 'error' and 'type'.
|
28
|
+
The error is used for error printing while the type
|
29
|
+
specifies the context in which the identifier is not
|
30
|
+
allowed. Valid values for the type are 'var' and
|
31
|
+
'attribute':
|
32
|
+
- 'var': the identifier is not allowed to be used as
|
33
|
+
a variable
|
34
|
+
- 'attribute': the identifier is not allowed to be used
|
35
|
+
as the attribute name of an object.
|
36
|
+
safe_imports: list, a list of strings containing module names
|
37
|
+
from which we can import without producing an error.
|
38
|
+
|
39
|
+
Example:
|
40
|
+
TEST_UNALLOWED_DICT = {
|
41
|
+
'getattr': {
|
42
|
+
'error': 'Usage of `getattr()` is not allowed in plugin code ',
|
43
|
+
'type': 'var',
|
44
|
+
},
|
45
|
+
'log': {
|
46
|
+
'error': 'Logger object cannot be used directly in plugin code - please use API ',
|
47
|
+
'type': 'attribute',
|
48
|
+
}
|
49
|
+
}
|
50
|
+
safe_imports=['fiz']
|
51
|
+
checker = ASTChecker(TEST_UNALLOWED_DICT, safe_imports)
|
52
|
+
"""
|
53
|
+
self.unallowed_dict = unallowed_dict
|
54
|
+
self.errors = {}
|
55
|
+
self.safe_imports = safe_imports
|
56
|
+
if self.safe_imports is None:
|
57
|
+
self.safe_imports = []
|
58
|
+
return
|
59
|
+
|
60
|
+
def add_error(self, node, error):
|
61
|
+
"""
|
62
|
+
Add an error to the set of found errors.
|
63
|
+
|
64
|
+
Parameters
|
65
|
+
----------
|
66
|
+
node: ast.AST, the AST node for which we've found this error.
|
67
|
+
|
68
|
+
error: str, the error message to be recorded.
|
69
|
+
|
70
|
+
Returns
|
71
|
+
-------
|
72
|
+
None
|
73
|
+
"""
|
74
|
+
lst = self.errors.get(error)
|
75
|
+
if lst is None:
|
76
|
+
self.errors[error] = [node.lineno]
|
77
|
+
return
|
78
|
+
self.errors[error].append(node.lineno)
|
79
|
+
return
|
80
|
+
|
81
|
+
def _is_safe_import(self, name):
|
82
|
+
"""
|
83
|
+
Check if the import of the class with the name `name` is considered to be
|
84
|
+
safe and should not produce an error.
|
85
|
+
|
86
|
+
Parameters
|
87
|
+
----------
|
88
|
+
name: str, the name of the class being imported
|
89
|
+
|
90
|
+
Returns
|
91
|
+
-------
|
92
|
+
bool - True if the import is safe, False otherwise.
|
93
|
+
"""
|
94
|
+
for safe_name in self.safe_imports:
|
95
|
+
if name == safe_name:
|
96
|
+
return True
|
97
|
+
if name.startswith(safe_name + '.'):
|
98
|
+
return True
|
99
|
+
return False
|
100
|
+
|
101
|
+
def visit_Import(self, node):
|
102
|
+
for imp_alias in node.names:
|
103
|
+
if not self._is_safe_import(imp_alias.name):
|
104
|
+
self.add_error(node, f'Import forbidden for {imp_alias.name} ')
|
105
|
+
|
106
|
+
self.generic_visit(node)
|
107
|
+
return
|
108
|
+
|
109
|
+
def visit_ImportFrom(self, node):
|
110
|
+
if not self._is_safe_import(node.module):
|
111
|
+
self.add_error(node, f'Import forbidden for {node.module} ')
|
112
|
+
self.generic_visit(node)
|
113
|
+
return
|
114
|
+
|
115
|
+
def visit_Attribute(self, node):
|
116
|
+
handle = self.unallowed_dict.get(node.attr)
|
117
|
+
if handle is not None and handle[CheckerConstants.type_key] == CheckerConstants.attr:
|
118
|
+
self.add_error(node, handle[CheckerConstants.error_key])
|
119
|
+
self.generic_visit(node)
|
120
|
+
return
|
121
|
+
|
122
|
+
def visit_Name(self, node):
|
123
|
+
handle = self.unallowed_dict.get(node.id)
|
124
|
+
if handle is not None and handle[CheckerConstants.type_key] == CheckerConstants.var:
|
125
|
+
self.add_error(node, handle[CheckerConstants.error_key])
|
126
|
+
self.generic_visit(node)
|
127
|
+
return
|
128
|
+
|
129
|
+
def validate(self, code: str) -> str:
|
130
|
+
"""
|
131
|
+
Runs code validation on the given code.
|
132
|
+
|
133
|
+
Parameters
|
134
|
+
----------
|
135
|
+
code: str, the code to validate
|
136
|
+
|
137
|
+
Returns
|
138
|
+
-------
|
139
|
+
dict - a dictionary with the error strings as the keys and a list
|
140
|
+
of lines numbers where these occured as the values.
|
141
|
+
"""
|
142
|
+
try:
|
143
|
+
tree = ast.parse(code, type_comments=True)
|
144
|
+
self.visit(tree)
|
145
|
+
return self.errors
|
146
|
+
except Exception as e:
|
147
|
+
return {
|
148
|
+
f"Unable to parse code {e}": [0]
|
149
|
+
}
|
150
|
+
|
151
|
+
|
152
|
+
if __name__ == '__main__':
|
153
|
+
TEST_UNALLOWED_DICT = {
|
154
|
+
'globals': {
|
155
|
+
'error': 'Global vars access is not allowed in plugin code ',
|
156
|
+
'type': 'var',
|
157
|
+
},
|
158
|
+
|
159
|
+
'locals': {
|
160
|
+
'error': 'Local vars dict access is not allowed in plugin code ',
|
161
|
+
'type': 'var',
|
162
|
+
},
|
163
|
+
|
164
|
+
'memoryview': {
|
165
|
+
'error': 'Pointer handling is unsafe in plugin code ',
|
166
|
+
'type': 'var',
|
167
|
+
},
|
168
|
+
|
169
|
+
'log': {
|
170
|
+
'error': 'Logger object cannot be used directly in plugin code - please use API ',
|
171
|
+
'type': 'attribute',
|
172
|
+
},
|
173
|
+
|
174
|
+
'vars': {
|
175
|
+
'error': 'Usage of `vars(obj)` is not allowed in plugin code ',
|
176
|
+
'type': 'var',
|
177
|
+
},
|
178
|
+
|
179
|
+
'dir': {
|
180
|
+
'error': 'Usage of `dir(obj)` is not allowed in plugin code ',
|
181
|
+
'type': 'var',
|
182
|
+
},
|
183
|
+
|
184
|
+
'global_shmem': {
|
185
|
+
'error': 'Usage of `global_shmem` is not allowed in plugin code ',
|
186
|
+
'type': 'attribute',
|
187
|
+
},
|
188
|
+
|
189
|
+
'plugins_shmem': {
|
190
|
+
'error': 'Usage of `plugins_shmem` is not allowed in plugin code ',
|
191
|
+
'type': 'attribute',
|
192
|
+
},
|
193
|
+
|
194
|
+
'config_data': {
|
195
|
+
'error': 'Usage of `config_data` is not allowed in plugin code ',
|
196
|
+
'type': 'attribute',
|
197
|
+
},
|
198
|
+
|
199
|
+
'_default_config': {
|
200
|
+
'error': 'Usage of `_default_config` is not allowed in plugin code ',
|
201
|
+
'type': 'attribute',
|
202
|
+
},
|
203
|
+
|
204
|
+
'_upstream_config': {
|
205
|
+
'error': 'Usage of `_upstream_config` is not allowed in plugin code ',
|
206
|
+
'type': 'attribute',
|
207
|
+
},
|
208
|
+
|
209
|
+
'exec': {
|
210
|
+
'error': 'Usage of `exec()` is not allowed in plugin code ',
|
211
|
+
'type': 'var',
|
212
|
+
},
|
213
|
+
|
214
|
+
'eval': {
|
215
|
+
'error': 'Usage of `eval()` is not allowed in plugin code ',
|
216
|
+
'type': 'var',
|
217
|
+
},
|
218
|
+
|
219
|
+
'getattr': {
|
220
|
+
'error': 'Usage of `getattr()` is not allowed in plugin code ',
|
221
|
+
'type': 'var',
|
222
|
+
},
|
223
|
+
}
|
224
|
+
safe_imports = ['fiz', 'biz']
|
225
|
+
checker = ASTChecker(TEST_UNALLOWED_DICT, safe_imports)
|
226
|
+
|
227
|
+
code = """import ast
|
228
|
+
import foo as bar
|
229
|
+
from foo import bar as baz
|
230
|
+
|
231
|
+
import biz
|
232
|
+
|
233
|
+
print(eval('some_string'))
|
234
|
+
|
235
|
+
foo=eval
|
236
|
+
foo('another_string')
|
237
|
+
|
238
|
+
self.log.P()
|
239
|
+
__builtins__.eval()
|
240
|
+
|
241
|
+
def bar():
|
242
|
+
global x
|
243
|
+
x = x + 42
|
244
|
+
return
|
245
|
+
|
246
|
+
"""
|
247
|
+
print(checker.validate(code))
|
248
|
+
|
249
|
+
# Make sure we print sane errors when parsing fails.
|
250
|
+
code = "x &&&& y"
|
251
|
+
checker = ASTChecker(TEST_UNALLOWED_DICT, safe_imports)
|
252
|
+
print(checker.validate(code))
|
253
|
+
|
254
|
+
# Make sure we print sane errors when parsing fails.
|
255
|
+
code = """
|
256
|
+
a = x + y
|
257
|
+
"""
|
258
|
+
checker = ASTChecker(TEST_UNALLOWED_DICT, safe_imports)
|
259
|
+
print(checker.validate(code))
|
260
|
+
|
261
|
+
# Even though the following import starts with 'fiz' which is safe we should
|
262
|
+
# fail it.
|
263
|
+
code = """
|
264
|
+
import fizzy
|
265
|
+
"""
|
266
|
+
checker = ASTChecker(TEST_UNALLOWED_DICT, safe_imports)
|
267
|
+
print(checker.validate(code))
|
268
|
+
|
269
|
+
# Case when an user defines a method
|
270
|
+
code = """
|
271
|
+
def foo():
|
272
|
+
import fizzy
|
273
|
+
return
|
274
|
+
"""
|
275
|
+
checker = ASTChecker(TEST_UNALLOWED_DICT, safe_imports)
|
276
|
+
print(checker.validate(code))
|
277
|
+
|
278
|
+
# Case when the user defines a method with an empty line in body
|
279
|
+
code = """
|
280
|
+
|
281
|
+
return
|
282
|
+
"""
|
283
|
+
checker = ASTChecker(TEST_UNALLOWED_DICT, safe_imports)
|
284
|
+
print(checker.validate(code))
|
285
|
+
|
286
|
+
# Case when the user defines a method with variables not defined
|
287
|
+
code = """
|
288
|
+
def foo():
|
289
|
+
|
290
|
+
x = a + 1
|
291
|
+
return
|
292
|
+
"""
|
293
|
+
checker = ASTChecker(TEST_UNALLOWED_DICT, safe_imports)
|
294
|
+
print(checker.validate(code))
|
@@ -0,0 +1,338 @@
|
|
1
|
+
# PIKA
|
2
|
+
|
3
|
+
import uuid
|
4
|
+
from time import sleep
|
5
|
+
|
6
|
+
import pika
|
7
|
+
|
8
|
+
|
9
|
+
from ..const import COLORS, COMMS, BASE_CT, PAYLOAD_CT
|
10
|
+
|
11
|
+
|
12
|
+
class AMQPWrapper(object):
|
13
|
+
def __init__(
|
14
|
+
self,
|
15
|
+
log,
|
16
|
+
config,
|
17
|
+
recv_buff=None,
|
18
|
+
send_channel_name=None,
|
19
|
+
recv_channel_name=None,
|
20
|
+
comm_type=None,
|
21
|
+
verbosity=1,
|
22
|
+
**kwargs
|
23
|
+
):
|
24
|
+
self._config = config
|
25
|
+
self._recv_buff = recv_buff
|
26
|
+
self._send_to = None
|
27
|
+
self._comm_type = comm_type
|
28
|
+
self.__verbosity = verbosity
|
29
|
+
self.send_channel_name = send_channel_name
|
30
|
+
self.recv_channel_name = recv_channel_name
|
31
|
+
self._disconnected_log = []
|
32
|
+
|
33
|
+
if self.recv_channel_name is not None:
|
34
|
+
assert self._recv_buff is not None
|
35
|
+
|
36
|
+
self._recv_objects = {'queue': None, 'exchange': None}
|
37
|
+
self._send_objects = {'queue': None, 'exchange': None}
|
38
|
+
|
39
|
+
self._connection = None
|
40
|
+
self._channel = None
|
41
|
+
|
42
|
+
super(AMQPWrapper, self).__init__(log=log, **kwargs)
|
43
|
+
return
|
44
|
+
|
45
|
+
def P(self, s, color=None, verbosity=1, **kwargs):
|
46
|
+
if verbosity > self.__verbosity:
|
47
|
+
return
|
48
|
+
if color is None or (isinstance(color, str) and color[0] not in ['e', 'r']):
|
49
|
+
color = COLORS.COMM
|
50
|
+
super().P(s, prefix=False, color=color, **kwargs)
|
51
|
+
return
|
52
|
+
|
53
|
+
@property
|
54
|
+
def send_channel_name(self):
|
55
|
+
return self._send_channel_name
|
56
|
+
|
57
|
+
@property
|
58
|
+
def recv_channel_name(self):
|
59
|
+
return self._recv_channel_name
|
60
|
+
|
61
|
+
@send_channel_name.setter
|
62
|
+
def send_channel_name(self, x):
|
63
|
+
if isinstance(x, tuple):
|
64
|
+
self._send_channel_name, self._send_to = x
|
65
|
+
else:
|
66
|
+
self._send_channel_name = x
|
67
|
+
return
|
68
|
+
|
69
|
+
@recv_channel_name.setter
|
70
|
+
def recv_channel_name(self, x):
|
71
|
+
self._recv_channel_name = x
|
72
|
+
return
|
73
|
+
|
74
|
+
@property
|
75
|
+
def cfg_broker(self):
|
76
|
+
return self._config[COMMS.BROKER]
|
77
|
+
|
78
|
+
@property
|
79
|
+
def cfg_user(self):
|
80
|
+
return self._config[COMMS.USER]
|
81
|
+
|
82
|
+
@property
|
83
|
+
def cfg_pass(self):
|
84
|
+
return self._config[COMMS.PASS]
|
85
|
+
|
86
|
+
@property
|
87
|
+
def cfg_vhost(self):
|
88
|
+
return self._config[COMMS.VHOST]
|
89
|
+
|
90
|
+
@property
|
91
|
+
def cfg_port(self):
|
92
|
+
return self._config[COMMS.PORT]
|
93
|
+
|
94
|
+
@property
|
95
|
+
def cfg_routing_key(self):
|
96
|
+
return self._config.get(COMMS.ROUTING_KEY, "")
|
97
|
+
|
98
|
+
@property
|
99
|
+
def cfg_node_id(self):
|
100
|
+
return self._config.get(COMMS.EE_ID, self._config.get(COMMS.SB_ID, None))
|
101
|
+
|
102
|
+
@property
|
103
|
+
def send_channel_def(self):
|
104
|
+
if self.send_channel_name is None:
|
105
|
+
return
|
106
|
+
|
107
|
+
cfg = self._config[self.send_channel_name].copy()
|
108
|
+
queue = cfg.get(COMMS.QUEUE, cfg[COMMS.EXCHANGE])
|
109
|
+
if self._send_to is not None and "{}" in queue:
|
110
|
+
queue = queue.format(self._send_to)
|
111
|
+
|
112
|
+
assert "{}" not in queue
|
113
|
+
|
114
|
+
cfg[COMMS.QUEUE] = queue
|
115
|
+
return cfg
|
116
|
+
|
117
|
+
@property
|
118
|
+
def recv_channel_def(self):
|
119
|
+
if self.recv_channel_name is None:
|
120
|
+
return
|
121
|
+
|
122
|
+
cfg = self._config[self.recv_channel_name].copy()
|
123
|
+
queue = cfg.get(COMMS.QUEUE, cfg[COMMS.EXCHANGE])
|
124
|
+
cfg[COMMS.QUEUE] = queue
|
125
|
+
_queue_device_specific = cfg.pop(COMMS.QUEUE_DEVICE_SPECIFIC, True)
|
126
|
+
if _queue_device_specific:
|
127
|
+
cfg[COMMS.QUEUE] += '/{}'.format(self.cfg_node_id)
|
128
|
+
cfg[COMMS.QUEUE] += '/{}'.format(str(uuid.uuid4())[:8])
|
129
|
+
return cfg
|
130
|
+
|
131
|
+
@property
|
132
|
+
def connection(self):
|
133
|
+
return self._connection
|
134
|
+
|
135
|
+
@property
|
136
|
+
def channel(self):
|
137
|
+
return self._channel
|
138
|
+
|
139
|
+
@property
|
140
|
+
def recv_queue(self):
|
141
|
+
return self._recv_objects['queue']
|
142
|
+
|
143
|
+
@property
|
144
|
+
def recv_exchange(self):
|
145
|
+
return self._recv_objects['exchange']
|
146
|
+
|
147
|
+
@property
|
148
|
+
def send_queue(self):
|
149
|
+
return self._send_objects['queue']
|
150
|
+
|
151
|
+
@property
|
152
|
+
def send_exchange(self):
|
153
|
+
return self._send_objects['exchange']
|
154
|
+
|
155
|
+
def server_connect(self, max_retries=5):
|
156
|
+
url = 'amqp://{}:{}@{}:{}/{}'.format(self.cfg_user, self.cfg_pass, self.cfg_broker, self.cfg_port, self.cfg_vhost)
|
157
|
+
|
158
|
+
nr_retry = 1
|
159
|
+
has_connection = False
|
160
|
+
exception = None
|
161
|
+
|
162
|
+
while nr_retry <= max_retries:
|
163
|
+
try:
|
164
|
+
self._connection = pika.BlockingConnection(parameters=pika.URLParameters(url))
|
165
|
+
sleep(1)
|
166
|
+
self._channel = self._connection.channel()
|
167
|
+
has_connection = True
|
168
|
+
except Exception as e:
|
169
|
+
exception = e
|
170
|
+
# end try-except
|
171
|
+
|
172
|
+
if has_connection:
|
173
|
+
break
|
174
|
+
|
175
|
+
nr_retry += 1
|
176
|
+
# endwhile
|
177
|
+
|
178
|
+
if has_connection:
|
179
|
+
msg = 'AMQP (Pika) SERVER conn ok: {}{}'.format(self.cfg_broker, self.cfg_port)
|
180
|
+
msg_type = PAYLOAD_CT.STATUS_TYPE.STATUS_NORMAL
|
181
|
+
else:
|
182
|
+
msg = 'AMQP (Pika) SERVER connection could not be initialized after {} retries (reason:{})'.format(
|
183
|
+
max_retries, exception
|
184
|
+
)
|
185
|
+
msg_type = PAYLOAD_CT.STATUS_TYPE.STATUS_EXCEPTION
|
186
|
+
# endif
|
187
|
+
|
188
|
+
dct_ret = {
|
189
|
+
'has_connection': has_connection,
|
190
|
+
'msg': msg,
|
191
|
+
'msg_type': msg_type
|
192
|
+
}
|
193
|
+
|
194
|
+
return dct_ret
|
195
|
+
|
196
|
+
def establish_one_way_connection(self, channel_name, max_retries=5):
|
197
|
+
cfg = None
|
198
|
+
if channel_name.lower() == 'send':
|
199
|
+
cfg = self.send_channel_def
|
200
|
+
elif channel_name.lower() == 'recv':
|
201
|
+
cfg = self.recv_channel_def
|
202
|
+
# endif
|
203
|
+
|
204
|
+
if cfg is None:
|
205
|
+
return
|
206
|
+
|
207
|
+
exchange = cfg[COMMS.EXCHANGE]
|
208
|
+
queue = cfg[COMMS.QUEUE]
|
209
|
+
exchange_type = cfg.get(COMMS.EXCHANGE_TYPE, 'fanout')
|
210
|
+
queue_durable = cfg.get(COMMS.QUEUE_DURABLE, True)
|
211
|
+
queue_exclusive = cfg.get(COMMS.QUEUE_EXCLUSIVE, False)
|
212
|
+
|
213
|
+
nr_retry = 1
|
214
|
+
has_connection = False
|
215
|
+
exception = None
|
216
|
+
|
217
|
+
while nr_retry <= max_retries:
|
218
|
+
try:
|
219
|
+
self._channel.exchange_declare(
|
220
|
+
exchange=exchange,
|
221
|
+
exchange_type=exchange_type
|
222
|
+
)
|
223
|
+
self._channel.queue_declare(
|
224
|
+
queue=queue,
|
225
|
+
durable=queue_durable,
|
226
|
+
exclusive=queue_exclusive
|
227
|
+
)
|
228
|
+
self._channel.queue_bind(
|
229
|
+
queue=queue,
|
230
|
+
exchange=exchange,
|
231
|
+
routing_key=self.cfg_routing_key
|
232
|
+
)
|
233
|
+
|
234
|
+
has_connection = True
|
235
|
+
except Exception as e:
|
236
|
+
exception = e
|
237
|
+
# end try-except
|
238
|
+
|
239
|
+
if has_connection:
|
240
|
+
break
|
241
|
+
|
242
|
+
sleep(1)
|
243
|
+
nr_retry += 1
|
244
|
+
# endwhile
|
245
|
+
|
246
|
+
if has_connection:
|
247
|
+
msg = "AMQP (Pika) '{}' connection successfully established on exchange '{}', queue '{}'".format(
|
248
|
+
channel_name.lower(), exchange, queue,
|
249
|
+
)
|
250
|
+
msg_type = PAYLOAD_CT.STATUS_TYPE.STATUS_NORMAL
|
251
|
+
else:
|
252
|
+
msg = "AMQP (Pika) '{}' connection on exchange '{}', queue '{}' could not be initialized after {} retries (reason:{})".format(
|
253
|
+
channel_name.lower(), exchange, queue, max_retries, exception
|
254
|
+
)
|
255
|
+
msg_type = PAYLOAD_CT.STATUS_TYPE.STATUS_EXCEPTION
|
256
|
+
# endif
|
257
|
+
|
258
|
+
dct_objects = {'queue': queue, 'exchange': exchange}
|
259
|
+
if channel_name.lower() == 'send':
|
260
|
+
self._send_objects = dct_objects
|
261
|
+
elif channel_name.lower() == 'recv':
|
262
|
+
self._recv_objects = dct_objects
|
263
|
+
# endif
|
264
|
+
|
265
|
+
dct_ret = {
|
266
|
+
'has_connection': has_connection,
|
267
|
+
'msg': msg,
|
268
|
+
'msg_type': msg_type
|
269
|
+
}
|
270
|
+
|
271
|
+
return dct_ret
|
272
|
+
|
273
|
+
def receive(self):
|
274
|
+
method_frame, header_frame, body = self._channel.basic_get(queue=self.recv_queue)
|
275
|
+
if method_frame:
|
276
|
+
msg = body.decode('utf-8')
|
277
|
+
self._channel.basic_ack(method_frame.delivery_tag)
|
278
|
+
self._recv_buff.append(msg)
|
279
|
+
# endif
|
280
|
+
return
|
281
|
+
|
282
|
+
def send(self, message):
|
283
|
+
properties = pika.BasicProperties(content_type='application/json')
|
284
|
+
self._channel.basic_publish(
|
285
|
+
exchange=self.send_exchange,
|
286
|
+
routing_key=self.cfg_routing_key,
|
287
|
+
body=message,
|
288
|
+
properties=properties
|
289
|
+
)
|
290
|
+
|
291
|
+
####
|
292
|
+
self.D("Sent message '{}'".format(message))
|
293
|
+
####
|
294
|
+
|
295
|
+
return
|
296
|
+
|
297
|
+
def release(self):
|
298
|
+
msgs = []
|
299
|
+
|
300
|
+
if self.recv_queue is not None:
|
301
|
+
try:
|
302
|
+
self._channel.queue_unbind(
|
303
|
+
queue=self.recv_queue,
|
304
|
+
exchange=self.recv_exchange,
|
305
|
+
routing_key=self.cfg_routing_key,
|
306
|
+
)
|
307
|
+
|
308
|
+
self._channel.queue_delete(queue=self.recv_queue)
|
309
|
+
msgs.append("AMQP (Pika) deleted queue '{}'".format(self.recv_queue))
|
310
|
+
except Exception as e:
|
311
|
+
msgs.append("AMQP (Pika) exception when deleting queue '{}'".format(self.recv_queue))
|
312
|
+
# end try-except
|
313
|
+
# endif
|
314
|
+
|
315
|
+
try:
|
316
|
+
self._channel.cancel()
|
317
|
+
self._channel.close()
|
318
|
+
del self._channel
|
319
|
+
self._channel = None
|
320
|
+
msgs.append('AMQP (Pika) closed channel')
|
321
|
+
except Exception as e:
|
322
|
+
msgs.append('AMQP (Pika) exception when closing channel: `{}`'.format(str(e)))
|
323
|
+
# end try-except
|
324
|
+
|
325
|
+
try:
|
326
|
+
self._connection.close()
|
327
|
+
del self._connection
|
328
|
+
self._connection = None
|
329
|
+
msgs.append('AMQP (Pika) disconnected')
|
330
|
+
except Exception as e:
|
331
|
+
msgs.append('AMQP (Pika) exception when disconnecting: `{}`'.format(str(e)))
|
332
|
+
# end try-except
|
333
|
+
|
334
|
+
dct_ret = {
|
335
|
+
'msgs': msgs
|
336
|
+
}
|
337
|
+
|
338
|
+
return dct_ret
|