stinger-ipc 0.0.1__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.
- stinger_ipc-0.0.1.dist-info/METADATA +170 -0
- stinger_ipc-0.0.1.dist-info/RECORD +13 -0
- stinger_ipc-0.0.1.dist-info/WHEEL +5 -0
- stinger_ipc-0.0.1.dist-info/licenses/LICENSE +504 -0
- stinger_ipc-0.0.1.dist-info/top_level.txt +1 -0
- stingeripc/__init__.py +4 -0
- stingeripc/args.py +116 -0
- stingeripc/asyncapi.py +501 -0
- stingeripc/components.py +964 -0
- stingeripc/connection.py +7 -0
- stingeripc/exceptions.py +3 -0
- stingeripc/interface.py +38 -0
- stingeripc/topic.py +67 -0
stingeripc/asyncapi.py
ADDED
@@ -0,0 +1,501 @@
|
|
1
|
+
"""
|
2
|
+
Provides the functionality needed to create an AsyncAPI service specification from a Stinger file.
|
3
|
+
"""
|
4
|
+
|
5
|
+
|
6
|
+
import sys
|
7
|
+
from jacobsjinjatoo import templator as jj2
|
8
|
+
from jacobsjinjatoo import stringmanip
|
9
|
+
import os.path
|
10
|
+
from enum import Enum
|
11
|
+
from typing import Any
|
12
|
+
from collections import OrderedDict
|
13
|
+
from .components import StingerSpec, Arg, ArgPrimitive, ArgEnum, ArgStruct
|
14
|
+
from .args import ArgType, ArgPrimitiveType
|
15
|
+
|
16
|
+
class Direction(Enum):
|
17
|
+
SERVER_PUBLISHES = 1
|
18
|
+
SERVER_SUBSCRIBES = 2
|
19
|
+
|
20
|
+
|
21
|
+
class SpecType(Enum):
|
22
|
+
SERVER = 1
|
23
|
+
CLIENT = 2
|
24
|
+
LIB = 3
|
25
|
+
|
26
|
+
|
27
|
+
class ObjectSchema:
|
28
|
+
|
29
|
+
def __init__(self):
|
30
|
+
self._properties: dict[str, Any] = dict()
|
31
|
+
self._required = set()
|
32
|
+
self._dependent_schemas = {}
|
33
|
+
|
34
|
+
def add_value_property(self, name: str, arg_primitive_type: ArgPrimitiveType, required=True):
|
35
|
+
schema = {
|
36
|
+
"type": ArgPrimitiveType.to_json_type(arg_primitive_type)
|
37
|
+
}
|
38
|
+
self._properties[name] = schema
|
39
|
+
if required:
|
40
|
+
self._required.add(name)
|
41
|
+
|
42
|
+
def add_value_dependency(self, name: str, required_on_name: str, required_on_value):
|
43
|
+
self._dependent_schemas[name] = {
|
44
|
+
"properties": {
|
45
|
+
required_on_name: {
|
46
|
+
"const": required_on_value
|
47
|
+
}
|
48
|
+
}
|
49
|
+
}
|
50
|
+
|
51
|
+
def add_const_value_property(self, name: str, arg_type: ArgPrimitiveType, const_value, required=True):
|
52
|
+
self.add_value_property(name, arg_type, required)
|
53
|
+
self._properties[name]['const'] = const_value
|
54
|
+
|
55
|
+
def add_enum_value_property(self, name: str, arg_type: ArgPrimitiveType, possible_values, required=True):
|
56
|
+
self.add_value_property(name, arg_type, required)
|
57
|
+
self._properties[name]['enum'] = possible_values
|
58
|
+
|
59
|
+
def add_reference_property(self, name: str, dollar_ref: str, required=True):
|
60
|
+
schema = {
|
61
|
+
"$ref": dollar_ref
|
62
|
+
}
|
63
|
+
self._properties[name] = schema
|
64
|
+
if required:
|
65
|
+
self._required.add(name)
|
66
|
+
|
67
|
+
|
68
|
+
def to_schema(self) -> dict[str, str|dict[str, Any]|list[str]]:
|
69
|
+
props: dict[str, Any] = dict()
|
70
|
+
schema: dict[str, str|dict[str, Any]|list[str]] = {
|
71
|
+
"type": "object",
|
72
|
+
"properties": props,
|
73
|
+
"required": sorted(list(self._required)),
|
74
|
+
}
|
75
|
+
for prop_name, prop_schema in self._properties.items():
|
76
|
+
props[prop_name] = prop_schema
|
77
|
+
return schema
|
78
|
+
|
79
|
+
class Message(object):
|
80
|
+
"""The information needed to create an AsyncAPI Message structure."""
|
81
|
+
|
82
|
+
def __init__(self, message_name: str, schema: str|None = None):
|
83
|
+
self.name = message_name
|
84
|
+
self.schema = schema or {"type": "null"}
|
85
|
+
self._traits: list[dict[str, Any]] = list()
|
86
|
+
self._headers: dict[str, tuple[bool, Any]] = dict()
|
87
|
+
|
88
|
+
def set_schema(self, schema: dict[str, Any]):
|
89
|
+
self.schema = schema
|
90
|
+
return self
|
91
|
+
|
92
|
+
def set_reference(self, reference):
|
93
|
+
return self.set_schema({"$ref": reference})
|
94
|
+
|
95
|
+
def add_trait(self, trait):
|
96
|
+
self._traits.append(trait)
|
97
|
+
|
98
|
+
def add_header(self, name: str, schema: dict[str, Any], required: bool=False):
|
99
|
+
self._headers[name] = (required, schema)
|
100
|
+
|
101
|
+
def get_message(self) -> dict[str, Any]:
|
102
|
+
msg: dict[str, Any] = {
|
103
|
+
"name": self.name,
|
104
|
+
"payload": self.schema,
|
105
|
+
}
|
106
|
+
if len(self._traits) > 0:
|
107
|
+
msg["traits"] = self._traits
|
108
|
+
if len(self._headers) > 0:
|
109
|
+
msg["headers"] = OrderedDict({
|
110
|
+
"properties": OrderedDict(),
|
111
|
+
"required": list(),
|
112
|
+
})
|
113
|
+
for header_name, (required, schema) in self._headers.items():
|
114
|
+
msg["headers"]["properties"][header_name] = schema
|
115
|
+
if required:
|
116
|
+
msg["headers"]["required"].append(header_name)
|
117
|
+
return msg
|
118
|
+
|
119
|
+
|
120
|
+
class Channel(object):
|
121
|
+
"""The data needed to create an AsyncAPI Channel structure."""
|
122
|
+
|
123
|
+
def __init__(
|
124
|
+
self,
|
125
|
+
topic: str,
|
126
|
+
name: str,
|
127
|
+
direction: Direction,
|
128
|
+
message_name: str|None = None,
|
129
|
+
):
|
130
|
+
self.topic = topic
|
131
|
+
self.name = name
|
132
|
+
self.direction = direction
|
133
|
+
self.message_name = message_name or name
|
134
|
+
self.mqtt = {"qos": 1, "retain": False}
|
135
|
+
self.description: str|None = None
|
136
|
+
self.parameters: dict[str, str] = dict()
|
137
|
+
self._operation_traits: list[dict[str, Any]] = list()
|
138
|
+
|
139
|
+
def set_mqtt(self, qos: int, retain: bool):
|
140
|
+
self.mqtt = {"qos": qos, "retain": retain}
|
141
|
+
return self
|
142
|
+
|
143
|
+
def set_description(self, description: str):
|
144
|
+
self.description = description
|
145
|
+
return self
|
146
|
+
|
147
|
+
def add_topic_parameters(self, name: str, json_schema_type: str):
|
148
|
+
self.parameters[name] = json_schema_type
|
149
|
+
return self
|
150
|
+
|
151
|
+
def add_operation_trait(self, trait: dict[str, Any]):
|
152
|
+
self._operation_traits.append(trait)
|
153
|
+
return self
|
154
|
+
|
155
|
+
def get_operation(self, client_type: SpecType, use_common=False) -> dict[str, dict[str, Any]]:
|
156
|
+
channel_item: dict[str, dict[str, Any]] = dict()
|
157
|
+
op_item: OrderedDict[str, Any] = OrderedDict({
|
158
|
+
"operationId": self.name,
|
159
|
+
"message": {
|
160
|
+
"$ref": f"{use_common or ''}#/components/messages/{self.message_name}"
|
161
|
+
}
|
162
|
+
})
|
163
|
+
if use_common is not False:
|
164
|
+
op_item["traits"] = [
|
165
|
+
{"$ref": f"{use_common}#/components/operationTraits/{self.name}"}
|
166
|
+
]
|
167
|
+
elif len(self._operation_traits) > 0:
|
168
|
+
op_item.update(OrderedDict({
|
169
|
+
"traits": self._operation_traits,
|
170
|
+
}))
|
171
|
+
if (
|
172
|
+
client_type == SpecType.SERVER
|
173
|
+
and self.direction == Direction.SERVER_PUBLISHES
|
174
|
+
) or (
|
175
|
+
client_type == SpecType.CLIENT
|
176
|
+
and self.direction == Direction.SERVER_SUBSCRIBES
|
177
|
+
):
|
178
|
+
channel_item.update({"publish": op_item})
|
179
|
+
else:
|
180
|
+
channel_item.update({"subscribe": op_item})
|
181
|
+
if len(self.parameters) > 0:
|
182
|
+
params_obj = dict()
|
183
|
+
for param_name, param_type in self.parameters.items():
|
184
|
+
params_obj[param_name] = {
|
185
|
+
"schema": {
|
186
|
+
"type": param_type
|
187
|
+
}
|
188
|
+
}
|
189
|
+
channel_item.update({"parameters": params_obj})
|
190
|
+
return channel_item
|
191
|
+
|
192
|
+
|
193
|
+
class Server(object):
|
194
|
+
def __init__(self, name: str):
|
195
|
+
self.name = name
|
196
|
+
self._protocol = "mqtt"
|
197
|
+
self._host: str|None = None
|
198
|
+
self._port: int|None = None
|
199
|
+
self._lwt_topic: str|None = None
|
200
|
+
|
201
|
+
def set_host(self, host: str, port: int):
|
202
|
+
self._host = host
|
203
|
+
self._port = port
|
204
|
+
return self
|
205
|
+
|
206
|
+
def set_lwt_topic(self, topic: str):
|
207
|
+
self._lwt_topic = topic
|
208
|
+
return self
|
209
|
+
|
210
|
+
@property
|
211
|
+
def url(self) -> str:
|
212
|
+
return "{}:{}".format(
|
213
|
+
self._host or "{hostname}",
|
214
|
+
self._port or "{port}"
|
215
|
+
)
|
216
|
+
|
217
|
+
def get_server(self) -> dict[str, Any]:
|
218
|
+
spec: dict[str, Any] = {
|
219
|
+
"protocol": self._protocol,
|
220
|
+
"protocolVersion": "5",
|
221
|
+
"url": self.url,
|
222
|
+
}
|
223
|
+
if self._lwt_topic is not None:
|
224
|
+
spec['bindings'] = OrderedDict({
|
225
|
+
"mqtt": OrderedDict({
|
226
|
+
"lastWill": OrderedDict({
|
227
|
+
"retain": False,
|
228
|
+
"message": None,
|
229
|
+
"qos": 1,
|
230
|
+
"topic": self._lwt_topic,
|
231
|
+
})
|
232
|
+
})
|
233
|
+
})
|
234
|
+
if self._host is None or self._port is None:
|
235
|
+
spec['variables'] = {}
|
236
|
+
if self._host is None:
|
237
|
+
spec['variables']['hostname'] = {
|
238
|
+
"description": "The hosthame or IP address of the MQTT broker."
|
239
|
+
}
|
240
|
+
if self._port is None:
|
241
|
+
spec['variables']['port'] = {
|
242
|
+
"description": "The port for the MQTT server"
|
243
|
+
}
|
244
|
+
return spec
|
245
|
+
|
246
|
+
class AsyncApiCreator(object):
|
247
|
+
"""A class to create a AsyncAPI specification from several AsyncAPI structures.
|
248
|
+
|
249
|
+
It also accepts a Stinger spec for creating all the structures.
|
250
|
+
"""
|
251
|
+
|
252
|
+
def __init__(self):
|
253
|
+
self.info = dict()
|
254
|
+
self.asyncapi: OrderedDict[str, Any] = OrderedDict({
|
255
|
+
"asyncapi": "2.4.0",
|
256
|
+
"id": "",
|
257
|
+
"info": OrderedDict(),
|
258
|
+
"channels": OrderedDict(),
|
259
|
+
"components": OrderedDict({
|
260
|
+
"operationTraits": OrderedDict({
|
261
|
+
"methodCall": OrderedDict({
|
262
|
+
"bindings": OrderedDict({
|
263
|
+
"mqtt": OrderedDict({
|
264
|
+
"bindingVersion": "0.2.0",
|
265
|
+
"qos": 2,
|
266
|
+
"retain": False,
|
267
|
+
}),
|
268
|
+
}),
|
269
|
+
}),
|
270
|
+
"methodCallback": OrderedDict({
|
271
|
+
"bindings": OrderedDict({
|
272
|
+
"mqtt": OrderedDict({
|
273
|
+
"bindingVersion": "0.2.0",
|
274
|
+
"qos": 1,
|
275
|
+
"retain": False,
|
276
|
+
}),
|
277
|
+
}),
|
278
|
+
}),
|
279
|
+
"signal": OrderedDict({
|
280
|
+
"bindings": OrderedDict({
|
281
|
+
"mqtt": OrderedDict({
|
282
|
+
"bindingVersion": "0.2.0",
|
283
|
+
"qos": 2,
|
284
|
+
"retain": False,
|
285
|
+
}),
|
286
|
+
}),
|
287
|
+
}),
|
288
|
+
}),
|
289
|
+
"messageTraits": OrderedDict({
|
290
|
+
"methodJsonArguments": OrderedDict({
|
291
|
+
"bindings": OrderedDict({
|
292
|
+
"mqtt": OrderedDict({
|
293
|
+
"bindingVersion": "0.2.0",
|
294
|
+
"contentType": "application/json",
|
295
|
+
"correlationData": OrderedDict({
|
296
|
+
"type": "string",
|
297
|
+
"format": "uuid",
|
298
|
+
}),
|
299
|
+
}),
|
300
|
+
}),
|
301
|
+
}),
|
302
|
+
"methodJsonResponse": OrderedDict({
|
303
|
+
"bindings": OrderedDict({
|
304
|
+
"mqtt": OrderedDict({
|
305
|
+
"bindingVersion": "0.2.0",
|
306
|
+
"contentType": "application/json",
|
307
|
+
"correlationData": OrderedDict({
|
308
|
+
"type": "string",
|
309
|
+
"format": "uuid",
|
310
|
+
}),
|
311
|
+
"responseTopic": {
|
312
|
+
"type": "string",
|
313
|
+
}
|
314
|
+
}),
|
315
|
+
}),
|
316
|
+
}),
|
317
|
+
"signalJson": OrderedDict({
|
318
|
+
"bindings": OrderedDict({
|
319
|
+
"mqtt": OrderedDict({
|
320
|
+
"bindingVersion": "0.2.0",
|
321
|
+
"contentType": "application/json",
|
322
|
+
}),
|
323
|
+
}),
|
324
|
+
}),
|
325
|
+
}),
|
326
|
+
"messages": OrderedDict(),
|
327
|
+
"schemas": OrderedDict(),
|
328
|
+
}),
|
329
|
+
})
|
330
|
+
self.channels = []
|
331
|
+
self.messages = []
|
332
|
+
self.servers = []
|
333
|
+
self.name = "interface"
|
334
|
+
|
335
|
+
def add_schema(self, schema_name: str, schema_spec: dict[str, Any]):
|
336
|
+
schema_dict: dict[str, Any] = self.asyncapi['components']['schemas']
|
337
|
+
schema_dict[schema_name] = schema_spec
|
338
|
+
|
339
|
+
def add_channel(self, channel: Channel):
|
340
|
+
self.channels.append(channel)
|
341
|
+
|
342
|
+
def add_message(self, message: Message):
|
343
|
+
self.messages.append(message)
|
344
|
+
|
345
|
+
def add_server(self, server: Server):
|
346
|
+
self.servers.append(server)
|
347
|
+
|
348
|
+
def set_interface_name(self, name):
|
349
|
+
self.name = name
|
350
|
+
self.asyncapi["id"] = f"urn:stingeripc:{name}"
|
351
|
+
|
352
|
+
def add_to_info(self, key, value):
|
353
|
+
self.asyncapi["info"][key] = value
|
354
|
+
|
355
|
+
def get_asyncapi(self, client_type: SpecType, use_common=None):
|
356
|
+
spec = self.asyncapi.copy()
|
357
|
+
if len(self.servers) > 0:
|
358
|
+
spec['servers'] = {}
|
359
|
+
for svr in self.servers:
|
360
|
+
spec['servers'][svr.name] = svr.get_server()
|
361
|
+
for ch in self.channels:
|
362
|
+
spec["channels"][ch.topic] = ch.get_operation(
|
363
|
+
client_type, use_common or False
|
364
|
+
)
|
365
|
+
if use_common is None:
|
366
|
+
for msg in self.messages:
|
367
|
+
spec["components"]["messages"][msg.name] = msg.get_message()
|
368
|
+
return spec
|
369
|
+
|
370
|
+
|
371
|
+
class StingerToAsyncApi:
|
372
|
+
|
373
|
+
def __init__(self, stinger: StingerSpec):
|
374
|
+
self._asyncapi: AsyncApiCreator = AsyncApiCreator()
|
375
|
+
self._stinger: StingerSpec = stinger
|
376
|
+
self._convert()
|
377
|
+
|
378
|
+
def _convert(self):
|
379
|
+
self._asyncapi.set_interface_name(self._stinger.name)
|
380
|
+
self._add_interface_info()
|
381
|
+
self._add_servers()
|
382
|
+
self._add_enums()
|
383
|
+
self._add_signals()
|
384
|
+
self._add_methods()
|
385
|
+
if len(self._stinger.methods) > 0:
|
386
|
+
schema_name = f"stinger_method_return_codes"
|
387
|
+
description = [
|
388
|
+
f"The stinger_method_return_codes enum has the following values:"
|
389
|
+
]
|
390
|
+
accepted_values = []
|
391
|
+
for i, enum_value in self._stinger.method_return_codes.items():
|
392
|
+
description.append(f"{i} - {enum_value}")
|
393
|
+
accepted_values.append(i)
|
394
|
+
json_schema = {
|
395
|
+
"type": "integer",
|
396
|
+
"description": "\n ".join(description),
|
397
|
+
"enum": accepted_values
|
398
|
+
}
|
399
|
+
self._asyncapi.add_schema(schema_name, json_schema)
|
400
|
+
return self
|
401
|
+
|
402
|
+
def _add_interface_info(self):
|
403
|
+
topic, info = self._stinger.interface_info
|
404
|
+
self._asyncapi.add_to_info("version", info['version'])
|
405
|
+
self._asyncapi.add_to_info("title", info['title'])
|
406
|
+
ch = Channel(topic, "interfaceInfo", Direction.SERVER_PUBLISHES)
|
407
|
+
ch.set_mqtt(qos=1, retain=True)
|
408
|
+
self._asyncapi.add_channel(ch)
|
409
|
+
msg = Message("interfaceInfo")
|
410
|
+
schema = ObjectSchema()
|
411
|
+
for k,v in info.items():
|
412
|
+
schema.add_const_value_property(k, ArgPrimitiveType.STRING, v)
|
413
|
+
msg.set_schema(schema.to_schema())
|
414
|
+
self._asyncapi.add_message(msg)
|
415
|
+
|
416
|
+
def _add_servers(self):
|
417
|
+
info_topic, _ = self._stinger.interface_info
|
418
|
+
for broker_name, broker_spec in self._stinger.brokers.items():
|
419
|
+
svr = Server(broker_name)
|
420
|
+
if broker_spec.hostname is not None and broker_spec.port is not None:
|
421
|
+
svr.set_host(broker_spec.hostname, broker_spec.port)
|
422
|
+
svr.set_lwt_topic(info_topic)
|
423
|
+
self._asyncapi.add_server(svr)
|
424
|
+
|
425
|
+
def _add_enums(self):
|
426
|
+
for enum_name, enum_spec in self._stinger.enums.items():
|
427
|
+
schema_name = f"enum_{enum_name}"
|
428
|
+
description = [
|
429
|
+
f"The {enum_name} enum has the following values:"
|
430
|
+
]
|
431
|
+
accepted_values = []
|
432
|
+
for i, enum_value in enumerate(enum_spec.values):
|
433
|
+
description.append(f"{i} - {enum_value}")
|
434
|
+
accepted_values.append(i)
|
435
|
+
json_schema = {
|
436
|
+
"type": "integer",
|
437
|
+
"description": "\n ".join(description),
|
438
|
+
"enum": accepted_values
|
439
|
+
}
|
440
|
+
self._asyncapi.add_schema(schema_name, json_schema)
|
441
|
+
|
442
|
+
def _add_signals(self):
|
443
|
+
for sig_name, sig_spec in self._stinger.signals.items():
|
444
|
+
ch = Channel(sig_spec.topic, sig_name, Direction.SERVER_PUBLISHES)
|
445
|
+
ch.add_operation_trait({"$ref": "#/components/operationTraits/signal"})
|
446
|
+
self._asyncapi.add_channel(ch)
|
447
|
+
msg = Message(sig_name)
|
448
|
+
msg.add_trait({"$ref": "#/components/messageTraits/signalJson"})
|
449
|
+
schema = ObjectSchema()
|
450
|
+
for arg_spec in sig_spec.arg_list:
|
451
|
+
if isinstance(arg_spec, ArgPrimitive):
|
452
|
+
schema.add_value_property(arg_spec.name, arg_spec.type)
|
453
|
+
elif isinstance(arg_spec, ArgEnum):
|
454
|
+
schema.add_reference_property(arg_spec.name, f"#/components/schemas/enum_{arg_spec.enum.name}")
|
455
|
+
msg.set_schema(schema.to_schema())
|
456
|
+
self._asyncapi.add_message(msg)
|
457
|
+
|
458
|
+
def _add_methods(self):
|
459
|
+
for method_name, method_spec in self._stinger.methods.items():
|
460
|
+
call_ch = Channel(method_spec.topic, method_name, Direction.SERVER_SUBSCRIBES)
|
461
|
+
call_ch.add_operation_trait({"$ref": "#/components/operationTraits/methodCall"})
|
462
|
+
self._asyncapi.add_channel(call_ch)
|
463
|
+
call_msg = Message(method_name)
|
464
|
+
call_msg.add_trait({"$ref": "#/components/messageTraits/methodJsonArguments"})
|
465
|
+
call_msg_schema = ObjectSchema()
|
466
|
+
for arg_spec in method_spec.arg_list:
|
467
|
+
if isinstance(arg_spec, ArgPrimitive):
|
468
|
+
call_msg_schema.add_value_property(arg_spec.name, arg_spec.type)
|
469
|
+
elif isinstance(arg_spec, ArgEnum):
|
470
|
+
call_msg_schema.add_reference_property(arg_spec.name, f"#/components/schemas/enum_{arg_spec.name}")
|
471
|
+
call_msg.set_schema(call_msg_schema.to_schema())
|
472
|
+
self._asyncapi.add_message(call_msg)
|
473
|
+
|
474
|
+
resp_ch = Channel(method_spec.response_topic("{client_id}"), f"{method_name}Response", Direction.SERVER_PUBLISHES)
|
475
|
+
resp_ch.add_operation_trait({"$ref": "#/components/operationTraits/methodCall"})
|
476
|
+
self._asyncapi.add_channel(resp_ch)
|
477
|
+
resp_msg = Message(f"{method_name}Response")
|
478
|
+
resp_msg.add_trait({"$ref": "#/components/messageTraits/methodJsonArguments"})
|
479
|
+
resp_msg.add_header("result", {"$ref": "#/components/schemas/stinger_method_return_codes"}, required=True)
|
480
|
+
resp_msg.add_header("debug", {"type": "string"}, required=False)
|
481
|
+
resp_msg_schema = ObjectSchema()
|
482
|
+
|
483
|
+
def add_arg(arg: Arg):
|
484
|
+
if isinstance(arg, ArgPrimitive):
|
485
|
+
resp_msg_schema.add_value_property(arg.name, arg.type, required=True)
|
486
|
+
elif isinstance(arg, ArgEnum):
|
487
|
+
resp_msg_schema.add_reference_property(arg.name, f"#/components/schemas/enum_{arg.enum.name}", required=True)
|
488
|
+
|
489
|
+
if isinstance(method_spec.return_value, ArgStruct):
|
490
|
+
for arg_spec in method_spec.return_value.members:
|
491
|
+
add_arg(arg_spec)
|
492
|
+
resp_msg_schema.add_value_dependency(arg_spec.name, "result", 0)
|
493
|
+
elif method_spec.return_value is not None:
|
494
|
+
add_arg(method_spec.return_value)
|
495
|
+
resp_msg_schema.add_value_dependency(method_spec.return_value_name, "result", 0)
|
496
|
+
|
497
|
+
resp_msg.set_schema(resp_msg_schema.to_schema())
|
498
|
+
self._asyncapi.add_message(resp_msg)
|
499
|
+
|
500
|
+
def get_asyncapi(self):
|
501
|
+
return self._asyncapi.get_asyncapi(SpecType.CLIENT)
|