stinger-ipc 0.0.9__tar.gz → 0.0.25__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 (81) hide show
  1. {stinger_ipc-0.0.9/stinger_ipc.egg-info → stinger_ipc-0.0.25}/PKG-INFO +3 -2
  2. {stinger_ipc-0.0.9 → stinger_ipc-0.0.25}/pyproject.toml +5 -3
  3. {stinger_ipc-0.0.9 → stinger_ipc-0.0.25/stinger_ipc.egg-info}/PKG-INFO +3 -2
  4. {stinger_ipc-0.0.9 → stinger_ipc-0.0.25}/stinger_ipc.egg-info/SOURCES.txt +7 -1
  5. {stinger_ipc-0.0.9 → stinger_ipc-0.0.25}/stinger_ipc.egg-info/requires.txt +2 -1
  6. {stinger_ipc-0.0.9 → stinger_ipc-0.0.25}/stingeripc/asyncapi.py +3 -0
  7. {stinger_ipc-0.0.9 → stinger_ipc-0.0.25}/stingeripc/components.py +61 -10
  8. stinger_ipc-0.0.25/stingeripc/schema/schema.yaml +240 -0
  9. {stinger_ipc-0.0.9 → stinger_ipc-0.0.25}/stingeripc/templates/cpp/examples/client_main.cpp.jinja2 +18 -0
  10. {stinger_ipc-0.0.9 → stinger_ipc-0.0.25}/stingeripc/templates/cpp/include/broker.hpp.jinja2 +18 -10
  11. stinger_ipc-0.0.25/stingeripc/templates/cpp/include/client.hpp.jinja2 +130 -0
  12. {stinger_ipc-0.0.9 → stinger_ipc-0.0.25}/stingeripc/templates/cpp/include/ibrokerconnection.hpp.jinja2 +24 -4
  13. stinger_ipc-0.0.25/stingeripc/templates/cpp/include/property_structs.hpp.jinja2 +48 -0
  14. {stinger_ipc-0.0.9 → stinger_ipc-0.0.25}/stingeripc/templates/cpp/include/server.hpp.jinja2 +5 -1
  15. {stinger_ipc-0.0.9 → stinger_ipc-0.0.25}/stingeripc/templates/cpp/include/structs.hpp.jinja2 +2 -0
  16. stinger_ipc-0.0.25/stingeripc/templates/cpp/partials/args.jinja2 +11 -0
  17. stinger_ipc-0.0.25/stingeripc/templates/cpp/partials/deserialize.jinja2 +42 -0
  18. stinger_ipc-0.0.25/stingeripc/templates/cpp/partials/serialize.jinja2 +18 -0
  19. {stinger_ipc-0.0.9 → stinger_ipc-0.0.25}/stingeripc/templates/cpp/src/broker.cpp.jinja2 +46 -24
  20. {stinger_ipc-0.0.9 → stinger_ipc-0.0.25}/stingeripc/templates/cpp/src/client.cpp.jinja2 +109 -36
  21. stinger_ipc-0.0.25/stingeripc/templates/cpp/src/property_structs.cpp.jinja2 +25 -0
  22. {stinger_ipc-0.0.9 → stinger_ipc-0.0.25}/stingeripc/templates/cpp/src/server.cpp.jinja2 +17 -25
  23. stinger_ipc-0.0.25/stingeripc/templates/cpp/src/structs.cpp.jinja2 +13 -0
  24. stinger_ipc-0.0.25/stingeripc/templates/html/app.js.jinja2 +226 -0
  25. stinger_ipc-0.0.25/stingeripc/templates/html/index.html.jinja2 +131 -0
  26. stinger_ipc-0.0.25/stingeripc/templates/html/styles.css.jinja2 +322 -0
  27. stinger_ipc-0.0.25/stingeripc/templates/markdown/index.md.jinja2 +356 -0
  28. {stinger_ipc-0.0.9 → stinger_ipc-0.0.25}/stingeripc/templates/rust/client/src/lib.rs.jinja2 +24 -5
  29. {stinger_ipc-0.0.9 → stinger_ipc-0.0.25}/stingeripc/templates/rust/server/examples/server.rs.jinja2 +59 -23
  30. {stinger_ipc-0.0.9 → stinger_ipc-0.0.25}/stingeripc/templates/rust/server/src/lib.rs.jinja2 +78 -55
  31. {stinger_ipc-0.0.9 → stinger_ipc-0.0.25}/stingeripc/tools/cli.py +33 -7
  32. stinger_ipc-0.0.25/stingeripc/tools/cpp_generator.py +90 -0
  33. {stinger_ipc-0.0.9 → stinger_ipc-0.0.25}/stingeripc/tools/rust_generator.py +1 -1
  34. stinger_ipc-0.0.9/stingeripc/templates/cpp/include/client.hpp.jinja2 +0 -61
  35. stinger_ipc-0.0.9/stingeripc/templates/cpp/include/property_structs.hpp.jinja2 +0 -10
  36. stinger_ipc-0.0.9/stingeripc/templates/html/app.js.jinja2 +0 -125
  37. stinger_ipc-0.0.9/stingeripc/templates/html/index.html.jinja2 +0 -43
  38. stinger_ipc-0.0.9/stingeripc/templates/html/styles.css.jinja2 +0 -187
  39. stinger_ipc-0.0.9/stingeripc/templates/markdown/index.md.jinja2 +0 -215
  40. stinger_ipc-0.0.9/stingeripc/templates/rust/payloads/src/handler.rs.jinja2 +0 -0
  41. {stinger_ipc-0.0.9 → stinger_ipc-0.0.25}/LICENSE +0 -0
  42. {stinger_ipc-0.0.9 → stinger_ipc-0.0.25}/README.md +0 -0
  43. {stinger_ipc-0.0.9 → stinger_ipc-0.0.25}/setup.cfg +0 -0
  44. {stinger_ipc-0.0.9 → stinger_ipc-0.0.25}/stinger_ipc.egg-info/dependency_links.txt +0 -0
  45. {stinger_ipc-0.0.9 → stinger_ipc-0.0.25}/stinger_ipc.egg-info/entry_points.txt +0 -0
  46. {stinger_ipc-0.0.9 → stinger_ipc-0.0.25}/stinger_ipc.egg-info/top_level.txt +0 -0
  47. {stinger_ipc-0.0.9 → stinger_ipc-0.0.25}/stingeripc/__init__.py +0 -0
  48. {stinger_ipc-0.0.9 → stinger_ipc-0.0.25}/stingeripc/args.py +0 -0
  49. {stinger_ipc-0.0.9 → stinger_ipc-0.0.25}/stingeripc/connection.py +0 -0
  50. {stinger_ipc-0.0.9 → stinger_ipc-0.0.25}/stingeripc/exceptions.py +0 -0
  51. {stinger_ipc-0.0.9 → stinger_ipc-0.0.25}/stingeripc/interface.py +0 -0
  52. {stinger_ipc-0.0.9 → stinger_ipc-0.0.25}/stingeripc/lang_symb.py +0 -0
  53. {stinger_ipc-0.0.9 → stinger_ipc-0.0.25}/stingeripc/templates/cpp/CMakeLists.txt.jinja2 +0 -0
  54. {stinger_ipc-0.0.9 → stinger_ipc-0.0.25}/stingeripc/templates/cpp/examples/server_main.cpp.jinja2 +0 -0
  55. {stinger_ipc-0.0.9 → stinger_ipc-0.0.25}/stingeripc/templates/cpp/include/enums.hpp.jinja2 +0 -0
  56. {stinger_ipc-0.0.9 → stinger_ipc-0.0.25}/stingeripc/templates/cpp/include/return_types.hpp.jinja2 +0 -0
  57. {stinger_ipc-0.0.9 → stinger_ipc-0.0.25}/stingeripc/templates/python/__init__.py.jinja2 +0 -0
  58. {stinger_ipc-0.0.9 → stinger_ipc-0.0.25}/stingeripc/templates/python/client.py.jinja2 +0 -0
  59. {stinger_ipc-0.0.9 → stinger_ipc-0.0.25}/stingeripc/templates/python/connection.py.jinja2 +0 -0
  60. {stinger_ipc-0.0.9 → stinger_ipc-0.0.25}/stingeripc/templates/python/interface_types.py.jinja2 +0 -0
  61. {stinger_ipc-0.0.9 → stinger_ipc-0.0.25}/stingeripc/templates/python/method_codes.py.jinja2 +0 -0
  62. {stinger_ipc-0.0.9 → stinger_ipc-0.0.25}/stingeripc/templates/python/pyproject.toml.jinja2 +0 -0
  63. {stinger_ipc-0.0.9 → stinger_ipc-0.0.25}/stingeripc/templates/python/server.py.jinja2 +0 -0
  64. {stinger_ipc-0.0.9 → stinger_ipc-0.0.25}/stingeripc/templates/rust/Cargo.toml.jinja2 +0 -0
  65. {stinger_ipc-0.0.9 → stinger_ipc-0.0.25}/stingeripc/templates/rust/client/Cargo.toml.jinja2 +0 -0
  66. {stinger_ipc-0.0.9 → stinger_ipc-0.0.25}/stingeripc/templates/rust/client/examples/client.rs.jinja2 +0 -0
  67. {stinger_ipc-0.0.9 → stinger_ipc-0.0.25}/stingeripc/templates/rust/payloads/Cargo.toml.jinja2 +0 -0
  68. {stinger_ipc-0.0.9 → stinger_ipc-0.0.25}/stingeripc/templates/rust/payloads/examples/pub_and_recv.rs.jinja2 +0 -0
  69. {stinger_ipc-0.0.9 → stinger_ipc-0.0.25}/stingeripc/templates/rust/payloads/src/lib.rs.jinja2 +0 -0
  70. {stinger_ipc-0.0.9 → stinger_ipc-0.0.25}/stingeripc/templates/rust/payloads/src/payloads.rs.jinja2 +0 -0
  71. {stinger_ipc-0.0.9 → stinger_ipc-0.0.25}/stingeripc/templates/rust/server/Cargo.toml.jinja2 +0 -0
  72. {stinger_ipc-0.0.9 → stinger_ipc-0.0.25}/stingeripc/tools/__init__.py +0 -0
  73. {stinger_ipc-0.0.9 → stinger_ipc-0.0.25}/stingeripc/tools/markdown_generator.py +0 -0
  74. {stinger_ipc-0.0.9 → stinger_ipc-0.0.25}/stingeripc/tools/python_generator.py +0 -0
  75. {stinger_ipc-0.0.9 → stinger_ipc-0.0.25}/stingeripc/topic.py +0 -0
  76. {stinger_ipc-0.0.9 → stinger_ipc-0.0.25}/tests/test_args.py +0 -0
  77. {stinger_ipc-0.0.9 → stinger_ipc-0.0.25}/tests/test_enum.py +0 -0
  78. {stinger_ipc-0.0.9 → stinger_ipc-0.0.25}/tests/test_examples.py +0 -0
  79. {stinger_ipc-0.0.9 → stinger_ipc-0.0.25}/tests/test_interface.py +0 -0
  80. {stinger_ipc-0.0.9 → stinger_ipc-0.0.25}/tests/test_signal.py +0 -0
  81. {stinger_ipc-0.0.9 → stinger_ipc-0.0.25}/tests/test_topics.py +0 -0
@@ -1,11 +1,12 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: stinger-ipc
3
- Version: 0.0.9
3
+ Version: 0.0.25
4
4
  Summary: Tools to create code to do IPC over MQTT
5
5
  Requires-Python: >=3.12
6
6
  Description-Content-Type: text/markdown
7
7
  License-File: LICENSE
8
- Requires-Dist: jacobs-jinja-too>=0.2.4
8
+ Requires-Dist: jacobs-jinja-too>=0.2.5
9
+ Requires-Dist: jacobs-json-schema>=0.4.2
9
10
  Requires-Dist: packaging>=25.0
10
11
  Requires-Dist: pydantic>=2.11.7
11
12
  Requires-Dist: pyyaml>=6.0.2
@@ -1,11 +1,12 @@
1
1
  [project]
2
2
  name = "stinger-ipc"
3
- version = "0.0.9"
3
+ version = "0.0.25"
4
4
  description = "Tools to create code to do IPC over MQTT"
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.12"
7
7
  dependencies = [
8
- "jacobs-jinja-too>=0.2.4",
8
+ "jacobs-jinja-too>=0.2.5",
9
+ "jacobs-json-schema>=0.4.2",
9
10
  "packaging>=25.0",
10
11
  "pydantic>=2.11.7",
11
12
  "pyyaml>=6.0.2",
@@ -38,7 +39,8 @@ packages = ["stingeripc", "stingeripc.tools"]
38
39
 
39
40
  [tool.setuptools.package-data]
40
41
  stingeripc = [
41
- "templates/**/*.jinja2"
42
+ "templates/**/*.jinja2",
43
+ "schema/schema.yaml",
42
44
  ]
43
45
 
44
46
  [project.scripts]
@@ -1,11 +1,12 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: stinger-ipc
3
- Version: 0.0.9
3
+ Version: 0.0.25
4
4
  Summary: Tools to create code to do IPC over MQTT
5
5
  Requires-Python: >=3.12
6
6
  Description-Content-Type: text/markdown
7
7
  License-File: LICENSE
8
- Requires-Dist: jacobs-jinja-too>=0.2.4
8
+ Requires-Dist: jacobs-jinja-too>=0.2.5
9
+ Requires-Dist: jacobs-json-schema>=0.4.2
9
10
  Requires-Dist: packaging>=25.0
10
11
  Requires-Dist: pydantic>=2.11.7
11
12
  Requires-Dist: pyyaml>=6.0.2
@@ -16,6 +16,7 @@ stingeripc/exceptions.py
16
16
  stingeripc/interface.py
17
17
  stingeripc/lang_symb.py
18
18
  stingeripc/topic.py
19
+ stingeripc/schema/schema.yaml
19
20
  stingeripc/templates/cpp/CMakeLists.txt.jinja2
20
21
  stingeripc/templates/cpp/examples/client_main.cpp.jinja2
21
22
  stingeripc/templates/cpp/examples/server_main.cpp.jinja2
@@ -27,9 +28,14 @@ stingeripc/templates/cpp/include/property_structs.hpp.jinja2
27
28
  stingeripc/templates/cpp/include/return_types.hpp.jinja2
28
29
  stingeripc/templates/cpp/include/server.hpp.jinja2
29
30
  stingeripc/templates/cpp/include/structs.hpp.jinja2
31
+ stingeripc/templates/cpp/partials/args.jinja2
32
+ stingeripc/templates/cpp/partials/deserialize.jinja2
33
+ stingeripc/templates/cpp/partials/serialize.jinja2
30
34
  stingeripc/templates/cpp/src/broker.cpp.jinja2
31
35
  stingeripc/templates/cpp/src/client.cpp.jinja2
36
+ stingeripc/templates/cpp/src/property_structs.cpp.jinja2
32
37
  stingeripc/templates/cpp/src/server.cpp.jinja2
38
+ stingeripc/templates/cpp/src/structs.cpp.jinja2
33
39
  stingeripc/templates/html/app.js.jinja2
34
40
  stingeripc/templates/html/index.html.jinja2
35
41
  stingeripc/templates/html/styles.css.jinja2
@@ -47,7 +53,6 @@ stingeripc/templates/rust/client/examples/client.rs.jinja2
47
53
  stingeripc/templates/rust/client/src/lib.rs.jinja2
48
54
  stingeripc/templates/rust/payloads/Cargo.toml.jinja2
49
55
  stingeripc/templates/rust/payloads/examples/pub_and_recv.rs.jinja2
50
- stingeripc/templates/rust/payloads/src/handler.rs.jinja2
51
56
  stingeripc/templates/rust/payloads/src/lib.rs.jinja2
52
57
  stingeripc/templates/rust/payloads/src/payloads.rs.jinja2
53
58
  stingeripc/templates/rust/server/Cargo.toml.jinja2
@@ -55,6 +60,7 @@ stingeripc/templates/rust/server/examples/server.rs.jinja2
55
60
  stingeripc/templates/rust/server/src/lib.rs.jinja2
56
61
  stingeripc/tools/__init__.py
57
62
  stingeripc/tools/cli.py
63
+ stingeripc/tools/cpp_generator.py
58
64
  stingeripc/tools/markdown_generator.py
59
65
  stingeripc/tools/python_generator.py
60
66
  stingeripc/tools/rust_generator.py
@@ -1,4 +1,5 @@
1
- jacobs-jinja-too>=0.2.4
1
+ jacobs-jinja-too>=0.2.5
2
+ jacobs-json-schema>=0.4.2
2
3
  packaging>=25.0
3
4
  pydantic>=2.11.7
4
5
  pyyaml>=6.0.2
@@ -571,6 +571,9 @@ class StingerToAsyncApi:
571
571
  add_arg(arg_spec)
572
572
  resp_msg_schema.add_value_dependency(arg_spec.name, "result", 0)
573
573
  elif method_spec.return_value is not None:
574
+ assert isinstance(
575
+ method_spec.return_value, Arg
576
+ ), "Method return value must be a primitive or enum"
574
577
  add_arg(method_spec.return_value)
575
578
  resp_msg_schema.add_value_dependency(
576
579
  method_spec.return_value_name, "result", 0
@@ -79,6 +79,10 @@ class Arg:
79
79
  def rust_local_type(self) -> str:
80
80
  return self.rust_type
81
81
 
82
+ @property
83
+ def cpp_type(self) -> str:
84
+ return stringmanip.upper_camel_case(self.name)
85
+
82
86
  @classmethod
83
87
  def new_arg_from_stinger(
84
88
  cls, arg_spec: YamlArg, stinger_spec: StingerSpec | None = None
@@ -107,32 +111,40 @@ class Arg:
107
111
  if arg_spec["type"] == "enum":
108
112
  if "enumName" not in arg_spec:
109
113
  raise InvalidStingerStructure(f"Enum args need a 'enumName'")
114
+ if not isinstance(arg_spec["enumName"], str):
115
+ raise InvalidStingerStructure("'enumName' in arg structure must be a string")
110
116
  if arg_spec["enumName"] not in stinger_spec.enums:
111
117
  raise InvalidStingerStructure(
112
118
  f"Enum arg '{arg_spec['enumName']}' was not found in the list of stinger spec enums"
113
119
  )
114
- arg = ArgEnum(
120
+ enum_arg = ArgEnum(
115
121
  arg_spec["name"], stinger_spec.get_interface_enum(arg_spec["enumName"])
116
122
  )
117
123
  if opt := arg_spec.get("optional", False):
118
- arg.optional = opt
119
- arg.try_set_description_from_spec(arg_spec)
120
- return arg
124
+ if not isinstance(opt, bool):
125
+ raise InvalidStingerStructure("'optional' in arg structure must be a boolean")
126
+ enum_arg.optional = opt
127
+ enum_arg.try_set_description_from_spec(arg_spec)
128
+ return enum_arg
121
129
 
122
130
  if arg_spec["type"] == "struct":
123
131
  if "structName" not in arg_spec:
124
132
  raise InvalidStingerStructure("Struct args need a 'structName'")
133
+ if not isinstance(arg_spec["structName"], str):
134
+ raise InvalidStingerStructure("'structName' in arg structure must be a string")
125
135
  if arg_spec["structName"] not in stinger_spec.structs:
126
136
  raise InvalidStingerStructure(
127
137
  f"Struct arg '{arg_spec["structName"]}' was not found in the list of stinger spec structs"
128
138
  )
129
- arg = ArgStruct(
139
+ st_arg = ArgStruct(
130
140
  arg_spec["name"], stinger_spec.structs[arg_spec["structName"]]
131
141
  )
132
142
  if opt := arg_spec.get("optional", False):
133
- arg.optional = opt
134
- arg.try_set_description_from_spec(arg_spec)
135
- return arg
143
+ if not isinstance(opt, bool):
144
+ raise InvalidStingerStructure("'optional' in arg structure must be a boolean")
145
+ st_arg.optional = opt
146
+ st_arg.try_set_description_from_spec(arg_spec)
147
+ return st_arg
136
148
  raise RuntimeError(f"unknown arg type: {arg_spec['type']}")
137
149
 
138
150
  @abstractmethod
@@ -240,6 +252,8 @@ class ArgPrimitive(Arg):
240
252
  @property
241
253
  def cpp_temp_type(self) -> str:
242
254
  if self._arg_type == ArgPrimitiveType.STRING:
255
+ if self.optional:
256
+ return "boost::optional<std::string>"
243
257
  return "std::string"
244
258
  else:
245
259
  return self.cpp_type
@@ -288,6 +302,10 @@ class ArgPrimitive(Arg):
288
302
  raise InvalidStingerStructure("No 'type' in arg structure")
289
303
  if "name" not in arg_spec:
290
304
  raise InvalidStingerStructure("No 'name' in arg structure")
305
+ if not isinstance(arg_spec["type"], str):
306
+ raise InvalidStingerStructure("'type' in arg structure must be a string")
307
+ if not isinstance(arg_spec["name"], str):
308
+ raise InvalidStingerStructure("'name' in arg structure must be a string")
291
309
 
292
310
  arg_primitive_type = ArgPrimitiveType.from_string(arg_spec["type"])
293
311
  arg: ArgPrimitive = cls(name=arg_spec["name"], arg_type=arg_primitive_type)
@@ -333,6 +351,10 @@ class ArgStruct(Arg):
333
351
  def markdown_type(self) -> str:
334
352
  return f"[Struct {self._interface_struct.class_name}](#enum-{self._interface_struct.class_name})"
335
353
 
354
+ @property
355
+ def cpp_rapidjson_type(self) -> str:
356
+ return "Object"
357
+
336
358
  def get_random_example_value(self, lang="python", seed: int = 2) -> str | None:
337
359
  example_list: dict[str, str] = {
338
360
  a.name: str(a.get_random_example_value(lang, seed=seed))
@@ -688,6 +710,8 @@ class Property(InterfaceComponent):
688
710
  prop_obj.add_arg(new_arg)
689
711
 
690
712
  if r_o := prop_spec.get("readOnly", False):
713
+ if not isinstance(r_o, bool):
714
+ raise InvalidStingerStructure("'readOnly' in property structure must be a boolean")
691
715
  prop_obj._read_only = r_o
692
716
 
693
717
  prop_obj.try_set_documentation_from_spec(prop_spec)
@@ -749,6 +773,11 @@ class InterfaceEnum:
749
773
  @property
750
774
  def values(self):
751
775
  return self._values
776
+
777
+ def value_description(self, index: int) -> str | None:
778
+ if index < 0 or index >= len(self._value_descriptions):
779
+ return None
780
+ return self._value_descriptions[index]
752
781
 
753
782
  @classmethod
754
783
  def new_enum_from_stinger(cls, name, enum_spec: YamlIfaceEnum) -> InterfaceEnum:
@@ -756,7 +785,12 @@ class InterfaceEnum:
756
785
  for enum_obj in enum_spec.get("values", []):
757
786
  assert isinstance(enum_obj, dict), f"Enum values must be a dicts."
758
787
  if "name" in enum_obj and isinstance(enum_obj["name"], str):
759
- ie.add_value(enum_obj["name"], enum_obj.get("description", None))
788
+ value_description = enum_obj.get("description", None)
789
+ if value_description is not None and not isinstance(value_description, str):
790
+ raise InvalidStingerStructure(
791
+ f"InterfaceEnum '{name}' item descriptions must be strings."
792
+ )
793
+ ie.add_value(enum_obj["name"], description=value_description)
760
794
  else:
761
795
  raise InvalidStingerStructure(
762
796
  f"InterfaceEnum '{name}' items must have string names."
@@ -834,9 +868,14 @@ class InterfaceStruct:
834
868
  ) -> InterfaceStruct:
835
869
  istruct = cls(name)
836
870
  for memb in spec.get("members", []):
871
+ if not isinstance(memb, dict):
872
+ raise InvalidStingerStructure("Struct members must be dicts")
837
873
  arg = Arg.new_arg_from_stinger(memb, stinger_spec=stinger_spec)
838
874
  istruct.add_member(arg)
839
- istruct._description = spec.get("description", None)
875
+ description = spec.get("description", None)
876
+ if description is not None and not isinstance(description, str):
877
+ raise InvalidStingerStructure("Struct description must be a string")
878
+ istruct._description = description
840
879
  return istruct
841
880
 
842
881
  def __str__(self) -> str:
@@ -948,6 +987,18 @@ class StingerSpec:
948
987
  }
949
988
  return (self._topic_creator.interface_info_topic(), info)
950
989
 
990
+ @property
991
+ def summary(self) -> str:
992
+ return self._summary or ""
993
+
994
+ @property
995
+ def title(self) -> str:
996
+ return self._title or self._name or ""
997
+
998
+ @property
999
+ def documentation(self) -> str:
1000
+ return self._documentation or ""
1001
+
951
1002
  def add_broker(self, broker: Broker):
952
1003
  assert broker is not None
953
1004
  self._brokers[broker.name] = broker
@@ -0,0 +1,240 @@
1
+ $id: "https://stingeripc.peargrove.com/stingeripc.schema.yaml"
2
+ $schema: "http://json-schema.org/draft-07/schema#"
3
+ description: |
4
+ This schema is used to validate StingerIPC stinger files.
5
+ type: object
6
+
7
+ properties:
8
+
9
+ stingeripc:
10
+ type: object
11
+ properties:
12
+ version:
13
+ type: string
14
+ const: "0.0.7"
15
+ required:
16
+ - version
17
+
18
+ interface:
19
+ type: object
20
+ parameters:
21
+ name:
22
+ type: string
23
+ pattern: "[a-zA-Z0-9_]+"
24
+ maxLength: 32
25
+ description: "A short token that will be used to create class names, folder names, filenames, etc."
26
+ title:
27
+ type: string
28
+ maxLength: 64
29
+ description: "A few words that are the title for the API. Used at the top of documentation, etc. The interface name is used if not provided."
30
+ summary:
31
+ type: string
32
+ description: "A one sentence description of the service."
33
+ maxLength: 128
34
+ version:
35
+ type: string
36
+ maxLength: 32
37
+ documentation:
38
+ $ref: "#/$defs/documentation"
39
+ required:
40
+ - name
41
+ - version
42
+
43
+ brokers:
44
+ type: object
45
+ additionalProperties:
46
+ type: object
47
+ properties:
48
+ host:
49
+ type: string
50
+ port:
51
+ type: integer
52
+ protocol:
53
+ type: string
54
+ enum:
55
+ - tcp
56
+ - websockets
57
+ default: tcp
58
+ secure:
59
+ type: boolean
60
+ default: false
61
+ description:
62
+ type: string
63
+
64
+ dependentRequired:
65
+ host: ["port"]
66
+
67
+ enums:
68
+ type: object
69
+ additionalProperties:
70
+ type: object
71
+ properties:
72
+ values:
73
+ type: array
74
+ uniqueItems: true
75
+ items:
76
+ type: object
77
+ properties:
78
+ name:
79
+ type: string
80
+ required:
81
+ - name
82
+ documentation:
83
+ $ref: "#/$defs/documentation"
84
+ required:
85
+ - values
86
+
87
+ structures:
88
+ type: object
89
+ additionalProperties:
90
+ type: object
91
+ properties:
92
+ members:
93
+ $ref: "#/$defs/payload"
94
+ documentation:
95
+ $ref: "#/$defs/documentation"
96
+ required:
97
+ - members
98
+
99
+ signals:
100
+ type: object
101
+ additionalProperties:
102
+ $ref: "#/$defs/signal"
103
+
104
+ properties:
105
+ type: object
106
+ additionalProperties:
107
+ $ref: "#/$defs/property"
108
+
109
+ methods:
110
+ type: object
111
+ additionalProperties:
112
+ $ref: "#/$defs/method"
113
+
114
+ required:
115
+ - stingeripc
116
+ - interface
117
+
118
+ $defs:
119
+
120
+ documentation:
121
+ type: string
122
+
123
+ payload:
124
+ type: array
125
+ uniqueItems: true
126
+ items:
127
+ $ref: "#/$defs/arg"
128
+
129
+ genericArg:
130
+ type: object
131
+ required:
132
+ - "type"
133
+ - "name"
134
+ properties:
135
+ name:
136
+ type: string
137
+ optional:
138
+ type: boolean
139
+ default: false
140
+ description:
141
+ type: string
142
+ schema:
143
+ type: object
144
+ description: A JSON schema which further constrains the value.
145
+
146
+ primitiveArg:
147
+ properties:
148
+ type:
149
+ type: string
150
+ enum:
151
+ - float
152
+ - string
153
+ - integer
154
+ - boolean
155
+ - date
156
+ - time
157
+ - datetime
158
+ - duration
159
+ - binary
160
+
161
+ enumArg:
162
+ properties:
163
+ type:
164
+ type: string
165
+ const: "enum"
166
+ enumName:
167
+ type: string
168
+ required:
169
+ - enumName
170
+
171
+ structArg:
172
+ properties:
173
+ type:
174
+ type: string
175
+ const: "struct"
176
+ structName:
177
+ type: string
178
+ required:
179
+ - structName
180
+
181
+ listArg:
182
+ properties:
183
+ type:
184
+ type: string
185
+ const: "list"
186
+ itemType:
187
+ oneOf:
188
+ - $ref: "#/$defs/primitiveArg"
189
+ - $ref: "#/$defs/enumArg"
190
+ - $ref: "#/$defs/structArg"
191
+ required:
192
+ - itemType
193
+
194
+ arg:
195
+ oneOf:
196
+ - allOf:
197
+ - $ref: "#/$defs/genericArg"
198
+ - $ref: "#/$defs/primitiveArg"
199
+ - allOf:
200
+ - $ref: "#/$defs/genericArg"
201
+ - $ref: "#/$defs/enumArg"
202
+ - allOf:
203
+ - $ref: "#/$defs/genericArg"
204
+ - $ref: "#/$defs/structArg"
205
+ - allOf:
206
+ - $ref: "#/$defs/genericArg"
207
+ - $ref: "#/$defs/listArg"
208
+
209
+ signal:
210
+ type: object
211
+ properties:
212
+ documentation:
213
+ $ref: "#/$defs/documentation"
214
+ payload:
215
+ $ref: "#/$defs/payload"
216
+
217
+ property:
218
+ type: object
219
+ properties:
220
+ documentation:
221
+ $ref: "#/$defs/documentation"
222
+ values:
223
+ $ref: "#/$defs/payload"
224
+ readOnly:
225
+ type: boolean
226
+ default: false
227
+ required:
228
+ - values
229
+
230
+ method:
231
+ type: object
232
+ properties:
233
+ documentation:
234
+ $ref: "#/$defs/documentation"
235
+ arguments:
236
+ $ref: "#/$defs/payload"
237
+ returnValues:
238
+ $ref: "#/$defs/payload"
239
+ required:
240
+ - arguments
@@ -1,3 +1,4 @@
1
+ {% import 'partials/args.jinja2' as ar %}
1
2
 
2
3
  #include <iostream>
3
4
  #include <boost/chrono/chrono.hpp>
@@ -16,6 +17,23 @@ int main(int argc, char** argv) {
16
17
  });
17
18
  {%-endfor%}
18
19
 
20
+ {%- for prop_name, prop in stinger.properties.items() %}
21
+ client.register{{prop_name | UpperCamelCase}}PropertyCallback([]({{ar.methodParams(prop.arg_list)}}) {
22
+ std::cout << "Received update for {{prop_name}} property: " << {# #}
23
+ {%-for arg in prop.arg_list-%}
24
+ "{{arg.name}}=" << {%if arg.optional%} "None"{%else%}
25
+ {%-if arg.arg_type.name.lower() == 'enum'%}
26
+ {{arg.enum.name | camelCase }}Strings[static_cast<int>({{arg.name}})]
27
+ {%elif arg.arg_type.name.lower() == 'struct'-%}
28
+ "[{{arg.cpp_type}} object]"
29
+ {%-else%}{{arg.name}}{%endif%}
30
+ {%-endif%} <<
31
+ {%-if not loop.last %} " | " << {%endif%}
32
+ {%-endfor-%}
33
+ std::endl;
34
+ });
35
+ {%endfor%}
36
+
19
37
  {%-for method_name, method in stinger.methods.items() %}
20
38
  std::cout << "Calling {{method_name}}" << std::endl;
21
39
  auto {{method_name|camelCase}}ResultFuture = client.{{method_name | camelCase}}({%for arg in method.arg_list%}{{arg.get_random_example_value('c++')}}{%if not loop.last%}, {%endif%}{%endfor%});
@@ -51,21 +51,24 @@ public:
51
51
  const std::string& payload,
52
52
  unsigned qos,
53
53
  bool retain,
54
- boost::optional<std::string> optCorrelationId,
55
- boost::optional<std::string> optResponseTopic,
56
- boost::optional<MethodResultCode> optResultCode);
54
+ const MqttProperties& properties);
57
55
 
58
56
  /*! Subscribe to a topic.
59
57
  * \param topic the subscription topic.
60
58
  * \param qos an MQTT quality of service value between 0 and 2 inclusive.
59
+ * \return the MQTT subscription ID.
61
60
  */
62
- virtual void Subscribe(const std::string& topic, int qos);
61
+ virtual int Subscribe(const std::string& topic, int qos);
63
62
 
64
63
  /*! Add a function that is called on the receipt of a message.
65
64
  * Many callbacks can be added, and each will be called in the order in which the callbacks were added.
66
65
  * \param cb the callback function.
67
66
  */
68
- virtual void AddMessageCallback(const std::function<void(const std::string&, const std::string&, const boost::optional<std::string>, const boost::optional<std::string>, const boost::optional<MethodResultCode>)>& cb);
67
+ virtual void AddMessageCallback(const std::function<void(
68
+ const std::string&,
69
+ const std::string&,
70
+ const MqttProperties&
71
+ )>& cb);
69
72
 
70
73
  /*! Determines if a topic string matches a subscription topic.
71
74
  * \param topic a topic to match against a subscription.
@@ -99,20 +102,25 @@ private:
99
102
 
100
103
  struct MqttSubscription
101
104
  {
102
- MqttSubscription(const std::string& topic, int qos) : _topic(topic), _qos(qos) {}
105
+ MqttSubscription(const std::string& topic, int qos, int subscriptionId) : topic(topic), qos(qos), subscriptionId(subscriptionId) {}
103
106
  ~MqttSubscription() = default;
104
- std::string _topic;
105
- int _qos;
106
- int subscription_id;
107
+ std::string topic;
108
+ int qos;
109
+ int subscriptionId;
107
110
  };
108
111
 
109
112
  mosquitto *_mosq;
110
113
  std::string _host;
111
114
  int _port;
112
115
  std::string _clientId;
116
+ int _nextSubscriptionId = 1;
113
117
  std::queue<MqttSubscription> _subscriptions;
114
118
  boost::mutex _mutex;
115
- std::vector<std::function<void(const std::string&, const std::string&, const boost::optional<std::string>, const boost::optional<std::string>, const boost::optional<MethodResultCode>)>> _messageCallbacks;
119
+ std::vector<std::function<void(
120
+ const std::string&,
121
+ const std::string&,
122
+ const MqttProperties&
123
+ )>> _messageCallbacks;
116
124
  std::queue<MqttMessage> _msgQueue;
117
125
  std::map<int, std::shared_ptr<boost::promise<bool>>> _sendMessages;
118
126
  };