rsmp 0.47.0 → 0.48.0

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 (426) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/copilot-setup-steps.yml +1 -1
  3. data/.github/workflows/rubocop.yaml +1 -1
  4. data/.github/workflows/sus.yaml +1 -1
  5. data/CHANGELOG.md +10 -0
  6. data/Gemfile.lock +5 -5
  7. data/README.md +3 -1
  8. data/documentation/cli.md +225 -0
  9. data/documentation/configuration.md +57 -0
  10. data/lib/rsmp/cli/configuration.rb +30 -0
  11. data/lib/rsmp/cli.rb +18 -45
  12. data/lib/rsmp/collect/command_matcher.rb +13 -4
  13. data/lib/rsmp/collect/status_matcher.rb +14 -4
  14. data/lib/rsmp/command_list.rb +1 -1
  15. data/lib/rsmp/convert/export/json_schema/index.rb +64 -0
  16. data/lib/rsmp/convert/export/json_schema/items.rb +9 -1
  17. data/lib/rsmp/convert/export/json_schema/outputs.rb +65 -25
  18. data/lib/rsmp/convert/export/json_schema/values.rb +40 -11
  19. data/lib/rsmp/convert/export/json_schema.rb +3 -1
  20. data/lib/rsmp/message/sxl_codec.rb +194 -0
  21. data/lib/rsmp/message.rb +2 -0
  22. data/lib/rsmp/node/site/connections.rb +80 -0
  23. data/lib/rsmp/node/site/site.rb +21 -35
  24. data/lib/rsmp/node/supervisor/supervisor.rb +42 -0
  25. data/lib/rsmp/options/schemas/site.json +3 -0
  26. data/lib/rsmp/options/schemas/supervisor.json +1 -0
  27. data/lib/rsmp/options/site_options.rb +30 -21
  28. data/lib/rsmp/options/supervisor_options.rb +1 -0
  29. data/lib/rsmp/proxy/modules/receive.rb +3 -1
  30. data/lib/rsmp/proxy/modules/send.rb +26 -14
  31. data/lib/rsmp/proxy/proxy.rb +17 -0
  32. data/lib/rsmp/proxy/site/connection.rb +79 -0
  33. data/lib/rsmp/proxy/site/modules/commands.rb +24 -1
  34. data/lib/rsmp/proxy/site/site_proxy.rb +6 -15
  35. data/lib/rsmp/proxy/supervisor/modules/commands.rb +55 -0
  36. data/lib/rsmp/proxy/supervisor/modules/status.rb +13 -104
  37. data/lib/rsmp/proxy/supervisor/modules/status_updates.rb +148 -0
  38. data/lib/rsmp/proxy/supervisor/supervisor_proxy.rb +19 -0
  39. data/lib/rsmp/schema.rb +38 -1
  40. data/lib/rsmp/tlc/detector_logic.rb +2 -2
  41. data/lib/rsmp/tlc/modules/helpers.rb +0 -22
  42. data/lib/rsmp/tlc/modules/inputs.rb +4 -3
  43. data/lib/rsmp/tlc/modules/modes.rb +2 -2
  44. data/lib/rsmp/tlc/modules/plans.rb +7 -3
  45. data/lib/rsmp/tlc/modules/system.rb +1 -1
  46. data/lib/rsmp/tlc/proxy/control.rb +19 -19
  47. data/lib/rsmp/tlc/proxy/detectors.rb +3 -3
  48. data/lib/rsmp/tlc/proxy/io.rb +15 -12
  49. data/lib/rsmp/tlc/proxy/plans.rb +14 -14
  50. data/lib/rsmp/tlc/proxy/status.rb +9 -5
  51. data/lib/rsmp/tlc/proxy/system.rb +12 -6
  52. data/lib/rsmp/tlc/signal_group.rb +2 -2
  53. data/lib/rsmp/tlc/supervisor_interface.rb +42 -0
  54. data/lib/rsmp/tlc/traffic_controller_site.rb +1 -18
  55. data/lib/rsmp/version.rb +1 -1
  56. data/lib/rsmp.rb +4 -0
  57. data/schemas/core/3.1.4/command_response.json +11 -0
  58. data/schemas/core/3.1.5/command_response.json +11 -0
  59. data/schemas/core/3.2.0/command_response.json +11 -0
  60. data/schemas/core/3.2.1/command_response.json +11 -0
  61. data/schemas/core/3.2.2/command_response.json +11 -0
  62. data/schemas/core/3.3.0/command_response.json +11 -0
  63. data/schemas/tlc/1.0.10/alarms/A0008.json +21 -15
  64. data/schemas/tlc/1.0.10/alarms/A0201.json +26 -20
  65. data/schemas/tlc/1.0.10/alarms/A0202.json +26 -20
  66. data/schemas/tlc/1.0.10/alarms/A0301.json +69 -63
  67. data/schemas/tlc/1.0.10/alarms/A0302.json +87 -81
  68. data/schemas/tlc/1.0.10/commands/M0001.json +66 -60
  69. data/schemas/tlc/1.0.10/commands/M0002.json +48 -42
  70. data/schemas/tlc/1.0.10/commands/M0003.json +48 -42
  71. data/schemas/tlc/1.0.10/commands/M0004.json +35 -29
  72. data/schemas/tlc/1.0.10/commands/M0005.json +48 -42
  73. data/schemas/tlc/1.0.10/commands/M0006.json +48 -42
  74. data/schemas/tlc/1.0.10/commands/M0007.json +35 -29
  75. data/schemas/tlc/1.0.10/commands/M0008.json +48 -42
  76. data/schemas/tlc/1.0.10/commands/M0010.json +35 -29
  77. data/schemas/tlc/1.0.10/commands/M0011.json +35 -29
  78. data/schemas/tlc/1.0.10/commands/M0012.json +35 -29
  79. data/schemas/tlc/1.0.10/commands/M0013.json +35 -29
  80. data/schemas/tlc/1.0.10/commands/M0019.json +61 -55
  81. data/schemas/tlc/1.0.10/commands/M0103.json +51 -45
  82. data/schemas/tlc/1.0.10/commands/M0104.json +100 -94
  83. data/schemas/tlc/1.0.10/commands/command_requests.json +995 -1
  84. data/schemas/tlc/1.0.10/defs/guards.json +19 -0
  85. data/schemas/tlc/1.0.10/sxl.yaml +56 -56
  86. data/schemas/tlc/1.0.10/sxl_index.json +226 -244
  87. data/schemas/tlc/1.0.13/alarms/A0008.json +21 -15
  88. data/schemas/tlc/1.0.13/alarms/A0201.json +26 -20
  89. data/schemas/tlc/1.0.13/alarms/A0202.json +26 -20
  90. data/schemas/tlc/1.0.13/alarms/A0301.json +69 -63
  91. data/schemas/tlc/1.0.13/alarms/A0302.json +87 -81
  92. data/schemas/tlc/1.0.13/commands/M0001.json +66 -60
  93. data/schemas/tlc/1.0.13/commands/M0002.json +48 -42
  94. data/schemas/tlc/1.0.13/commands/M0003.json +48 -42
  95. data/schemas/tlc/1.0.13/commands/M0004.json +35 -29
  96. data/schemas/tlc/1.0.13/commands/M0005.json +48 -42
  97. data/schemas/tlc/1.0.13/commands/M0006.json +48 -42
  98. data/schemas/tlc/1.0.13/commands/M0007.json +35 -29
  99. data/schemas/tlc/1.0.13/commands/M0008.json +48 -42
  100. data/schemas/tlc/1.0.13/commands/M0010.json +35 -29
  101. data/schemas/tlc/1.0.13/commands/M0011.json +35 -29
  102. data/schemas/tlc/1.0.13/commands/M0012.json +35 -29
  103. data/schemas/tlc/1.0.13/commands/M0013.json +35 -29
  104. data/schemas/tlc/1.0.13/commands/M0014.json +48 -42
  105. data/schemas/tlc/1.0.13/commands/M0015.json +48 -42
  106. data/schemas/tlc/1.0.13/commands/M0016.json +35 -29
  107. data/schemas/tlc/1.0.13/commands/M0017.json +35 -29
  108. data/schemas/tlc/1.0.13/commands/M0018.json +48 -42
  109. data/schemas/tlc/1.0.13/commands/M0019.json +61 -55
  110. data/schemas/tlc/1.0.13/commands/M0103.json +51 -45
  111. data/schemas/tlc/1.0.13/commands/M0104.json +100 -94
  112. data/schemas/tlc/1.0.13/commands/command_requests.json +1293 -1
  113. data/schemas/tlc/1.0.13/defs/guards.json +19 -0
  114. data/schemas/tlc/1.0.13/sxl.yaml +63 -63
  115. data/schemas/tlc/1.0.13/sxl_index.json +280 -298
  116. data/schemas/tlc/1.0.14/alarms/A0008.json +21 -15
  117. data/schemas/tlc/1.0.14/alarms/A0201.json +26 -20
  118. data/schemas/tlc/1.0.14/alarms/A0202.json +26 -20
  119. data/schemas/tlc/1.0.14/alarms/A0301.json +69 -63
  120. data/schemas/tlc/1.0.14/alarms/A0302.json +87 -81
  121. data/schemas/tlc/1.0.14/commands/M0001.json +66 -60
  122. data/schemas/tlc/1.0.14/commands/M0002.json +48 -42
  123. data/schemas/tlc/1.0.14/commands/M0003.json +48 -42
  124. data/schemas/tlc/1.0.14/commands/M0004.json +35 -29
  125. data/schemas/tlc/1.0.14/commands/M0005.json +48 -42
  126. data/schemas/tlc/1.0.14/commands/M0006.json +48 -42
  127. data/schemas/tlc/1.0.14/commands/M0007.json +35 -29
  128. data/schemas/tlc/1.0.14/commands/M0008.json +48 -42
  129. data/schemas/tlc/1.0.14/commands/M0010.json +35 -29
  130. data/schemas/tlc/1.0.14/commands/M0011.json +35 -29
  131. data/schemas/tlc/1.0.14/commands/M0012.json +35 -29
  132. data/schemas/tlc/1.0.14/commands/M0013.json +35 -29
  133. data/schemas/tlc/1.0.14/commands/M0014.json +48 -42
  134. data/schemas/tlc/1.0.14/commands/M0015.json +48 -42
  135. data/schemas/tlc/1.0.14/commands/M0016.json +35 -29
  136. data/schemas/tlc/1.0.14/commands/M0017.json +35 -29
  137. data/schemas/tlc/1.0.14/commands/M0018.json +48 -42
  138. data/schemas/tlc/1.0.14/commands/M0019.json +61 -55
  139. data/schemas/tlc/1.0.14/commands/M0103.json +51 -45
  140. data/schemas/tlc/1.0.14/commands/M0104.json +100 -94
  141. data/schemas/tlc/1.0.14/commands/command_requests.json +1293 -1
  142. data/schemas/tlc/1.0.14/defs/guards.json +19 -0
  143. data/schemas/tlc/1.0.14/sxl.yaml +63 -63
  144. data/schemas/tlc/1.0.14/sxl_index.json +304 -322
  145. data/schemas/tlc/1.0.15/alarms/A0008.json +21 -15
  146. data/schemas/tlc/1.0.15/alarms/A0201.json +26 -20
  147. data/schemas/tlc/1.0.15/alarms/A0202.json +26 -20
  148. data/schemas/tlc/1.0.15/alarms/A0301.json +69 -63
  149. data/schemas/tlc/1.0.15/alarms/A0302.json +87 -81
  150. data/schemas/tlc/1.0.15/commands/M0001.json +66 -60
  151. data/schemas/tlc/1.0.15/commands/M0002.json +48 -42
  152. data/schemas/tlc/1.0.15/commands/M0003.json +48 -42
  153. data/schemas/tlc/1.0.15/commands/M0004.json +35 -29
  154. data/schemas/tlc/1.0.15/commands/M0005.json +48 -42
  155. data/schemas/tlc/1.0.15/commands/M0006.json +48 -42
  156. data/schemas/tlc/1.0.15/commands/M0007.json +35 -29
  157. data/schemas/tlc/1.0.15/commands/M0008.json +48 -42
  158. data/schemas/tlc/1.0.15/commands/M0010.json +35 -29
  159. data/schemas/tlc/1.0.15/commands/M0011.json +35 -29
  160. data/schemas/tlc/1.0.15/commands/M0012.json +35 -29
  161. data/schemas/tlc/1.0.15/commands/M0013.json +35 -29
  162. data/schemas/tlc/1.0.15/commands/M0014.json +48 -42
  163. data/schemas/tlc/1.0.15/commands/M0015.json +48 -42
  164. data/schemas/tlc/1.0.15/commands/M0016.json +35 -29
  165. data/schemas/tlc/1.0.15/commands/M0017.json +35 -29
  166. data/schemas/tlc/1.0.15/commands/M0018.json +48 -42
  167. data/schemas/tlc/1.0.15/commands/M0019.json +61 -55
  168. data/schemas/tlc/1.0.15/commands/M0020.json +61 -55
  169. data/schemas/tlc/1.0.15/commands/M0021.json +35 -29
  170. data/schemas/tlc/1.0.15/commands/M0103.json +51 -45
  171. data/schemas/tlc/1.0.15/commands/M0104.json +100 -94
  172. data/schemas/tlc/1.0.15/commands/command_requests.json +1425 -1
  173. data/schemas/tlc/1.0.15/defs/guards.json +19 -0
  174. data/schemas/tlc/1.0.15/sxl.yaml +66 -66
  175. data/schemas/tlc/1.0.15/sxl_index.json +330 -350
  176. data/schemas/tlc/1.0.7/alarms/A0008.json +21 -15
  177. data/schemas/tlc/1.0.7/alarms/A0201.json +26 -20
  178. data/schemas/tlc/1.0.7/alarms/A0202.json +26 -20
  179. data/schemas/tlc/1.0.7/alarms/A0301.json +69 -63
  180. data/schemas/tlc/1.0.7/alarms/A0302.json +87 -81
  181. data/schemas/tlc/1.0.7/commands/M0001.json +66 -60
  182. data/schemas/tlc/1.0.7/commands/M0002.json +48 -42
  183. data/schemas/tlc/1.0.7/commands/M0003.json +48 -42
  184. data/schemas/tlc/1.0.7/commands/M0004.json +35 -29
  185. data/schemas/tlc/1.0.7/commands/M0005.json +48 -42
  186. data/schemas/tlc/1.0.7/commands/M0006.json +48 -42
  187. data/schemas/tlc/1.0.7/commands/M0007.json +35 -29
  188. data/schemas/tlc/1.0.7/commands/M0008.json +48 -42
  189. data/schemas/tlc/1.0.7/commands/M0010.json +35 -29
  190. data/schemas/tlc/1.0.7/commands/M0011.json +35 -29
  191. data/schemas/tlc/1.0.7/commands/M0019.json +61 -55
  192. data/schemas/tlc/1.0.7/commands/M0103.json +51 -45
  193. data/schemas/tlc/1.0.7/commands/M0104.json +100 -94
  194. data/schemas/tlc/1.0.7/commands/command_requests.json +895 -1
  195. data/schemas/tlc/1.0.7/defs/guards.json +19 -0
  196. data/schemas/tlc/1.0.7/sxl.yaml +58 -58
  197. data/schemas/tlc/1.0.7/sxl_index.json +228 -246
  198. data/schemas/tlc/1.0.8/alarms/A0008.json +21 -15
  199. data/schemas/tlc/1.0.8/alarms/A0201.json +26 -20
  200. data/schemas/tlc/1.0.8/alarms/A0202.json +26 -20
  201. data/schemas/tlc/1.0.8/alarms/A0301.json +69 -63
  202. data/schemas/tlc/1.0.8/alarms/A0302.json +87 -81
  203. data/schemas/tlc/1.0.8/commands/M0001.json +66 -60
  204. data/schemas/tlc/1.0.8/commands/M0002.json +48 -42
  205. data/schemas/tlc/1.0.8/commands/M0003.json +48 -42
  206. data/schemas/tlc/1.0.8/commands/M0004.json +35 -29
  207. data/schemas/tlc/1.0.8/commands/M0005.json +48 -42
  208. data/schemas/tlc/1.0.8/commands/M0006.json +48 -42
  209. data/schemas/tlc/1.0.8/commands/M0007.json +35 -29
  210. data/schemas/tlc/1.0.8/commands/M0008.json +48 -42
  211. data/schemas/tlc/1.0.8/commands/M0010.json +35 -29
  212. data/schemas/tlc/1.0.8/commands/M0011.json +35 -29
  213. data/schemas/tlc/1.0.8/commands/M0012.json +35 -29
  214. data/schemas/tlc/1.0.8/commands/M0013.json +35 -29
  215. data/schemas/tlc/1.0.8/commands/M0019.json +61 -55
  216. data/schemas/tlc/1.0.8/commands/M0103.json +51 -45
  217. data/schemas/tlc/1.0.8/commands/M0104.json +100 -94
  218. data/schemas/tlc/1.0.8/commands/command_requests.json +995 -1
  219. data/schemas/tlc/1.0.8/defs/guards.json +19 -0
  220. data/schemas/tlc/1.0.8/sxl.yaml +56 -56
  221. data/schemas/tlc/1.0.8/sxl_index.json +226 -244
  222. data/schemas/tlc/1.0.9/alarms/A0008.json +21 -15
  223. data/schemas/tlc/1.0.9/alarms/A0201.json +26 -20
  224. data/schemas/tlc/1.0.9/alarms/A0202.json +26 -20
  225. data/schemas/tlc/1.0.9/alarms/A0301.json +69 -63
  226. data/schemas/tlc/1.0.9/alarms/A0302.json +87 -81
  227. data/schemas/tlc/1.0.9/commands/M0001.json +66 -60
  228. data/schemas/tlc/1.0.9/commands/M0002.json +48 -42
  229. data/schemas/tlc/1.0.9/commands/M0003.json +48 -42
  230. data/schemas/tlc/1.0.9/commands/M0004.json +35 -29
  231. data/schemas/tlc/1.0.9/commands/M0005.json +48 -42
  232. data/schemas/tlc/1.0.9/commands/M0006.json +48 -42
  233. data/schemas/tlc/1.0.9/commands/M0007.json +35 -29
  234. data/schemas/tlc/1.0.9/commands/M0008.json +48 -42
  235. data/schemas/tlc/1.0.9/commands/M0010.json +35 -29
  236. data/schemas/tlc/1.0.9/commands/M0011.json +35 -29
  237. data/schemas/tlc/1.0.9/commands/M0012.json +35 -29
  238. data/schemas/tlc/1.0.9/commands/M0013.json +35 -29
  239. data/schemas/tlc/1.0.9/commands/M0019.json +61 -55
  240. data/schemas/tlc/1.0.9/commands/M0103.json +51 -45
  241. data/schemas/tlc/1.0.9/commands/M0104.json +100 -94
  242. data/schemas/tlc/1.0.9/commands/command_requests.json +995 -1
  243. data/schemas/tlc/1.0.9/defs/guards.json +19 -0
  244. data/schemas/tlc/1.0.9/sxl.yaml +56 -56
  245. data/schemas/tlc/1.0.9/sxl_index.json +226 -244
  246. data/schemas/tlc/1.1.0/alarms/A0007.json +25 -19
  247. data/schemas/tlc/1.1.0/alarms/A0008.json +21 -15
  248. data/schemas/tlc/1.1.0/alarms/A0201.json +26 -20
  249. data/schemas/tlc/1.1.0/alarms/A0202.json +26 -20
  250. data/schemas/tlc/1.1.0/alarms/A0301.json +69 -63
  251. data/schemas/tlc/1.1.0/alarms/A0302.json +87 -81
  252. data/schemas/tlc/1.1.0/alarms/A0303.json +69 -63
  253. data/schemas/tlc/1.1.0/alarms/A0304.json +87 -81
  254. data/schemas/tlc/1.1.0/commands/M0001.json +66 -60
  255. data/schemas/tlc/1.1.0/commands/M0002.json +48 -42
  256. data/schemas/tlc/1.1.0/commands/M0003.json +48 -42
  257. data/schemas/tlc/1.1.0/commands/M0004.json +35 -29
  258. data/schemas/tlc/1.1.0/commands/M0005.json +48 -42
  259. data/schemas/tlc/1.1.0/commands/M0006.json +48 -42
  260. data/schemas/tlc/1.1.0/commands/M0007.json +35 -29
  261. data/schemas/tlc/1.1.0/commands/M0008.json +48 -42
  262. data/schemas/tlc/1.1.0/commands/M0010.json +35 -29
  263. data/schemas/tlc/1.1.0/commands/M0011.json +35 -29
  264. data/schemas/tlc/1.1.0/commands/M0012.json +35 -29
  265. data/schemas/tlc/1.1.0/commands/M0013.json +35 -29
  266. data/schemas/tlc/1.1.0/commands/M0014.json +48 -42
  267. data/schemas/tlc/1.1.0/commands/M0015.json +48 -42
  268. data/schemas/tlc/1.1.0/commands/M0016.json +35 -29
  269. data/schemas/tlc/1.1.0/commands/M0017.json +35 -29
  270. data/schemas/tlc/1.1.0/commands/M0018.json +48 -42
  271. data/schemas/tlc/1.1.0/commands/M0019.json +61 -55
  272. data/schemas/tlc/1.1.0/commands/M0020.json +61 -55
  273. data/schemas/tlc/1.1.0/commands/M0021.json +35 -29
  274. data/schemas/tlc/1.1.0/commands/M0022.json +194 -188
  275. data/schemas/tlc/1.1.0/commands/M0023.json +35 -29
  276. data/schemas/tlc/1.1.0/commands/M0103.json +51 -45
  277. data/schemas/tlc/1.1.0/commands/M0104.json +100 -94
  278. data/schemas/tlc/1.1.0/commands/command_requests.json +1525 -1
  279. data/schemas/tlc/1.1.0/defs/guards.json +19 -0
  280. data/schemas/tlc/1.1.0/statuses/S0033.json +2 -2
  281. data/schemas/tlc/1.1.0/sxl.yaml +75 -74
  282. data/schemas/tlc/1.1.0/sxl_index.json +391 -398
  283. data/schemas/tlc/1.2.0/alarms/A0007.json +25 -19
  284. data/schemas/tlc/1.2.0/alarms/A0008.json +21 -15
  285. data/schemas/tlc/1.2.0/alarms/A0201.json +26 -20
  286. data/schemas/tlc/1.2.0/alarms/A0202.json +26 -20
  287. data/schemas/tlc/1.2.0/alarms/A0301.json +69 -63
  288. data/schemas/tlc/1.2.0/alarms/A0302.json +87 -81
  289. data/schemas/tlc/1.2.0/alarms/A0303.json +69 -63
  290. data/schemas/tlc/1.2.0/alarms/A0304.json +87 -81
  291. data/schemas/tlc/1.2.0/commands/M0001.json +66 -60
  292. data/schemas/tlc/1.2.0/commands/M0002.json +48 -42
  293. data/schemas/tlc/1.2.0/commands/M0003.json +48 -42
  294. data/schemas/tlc/1.2.0/commands/M0004.json +35 -29
  295. data/schemas/tlc/1.2.0/commands/M0005.json +48 -42
  296. data/schemas/tlc/1.2.0/commands/M0006.json +48 -42
  297. data/schemas/tlc/1.2.0/commands/M0007.json +35 -29
  298. data/schemas/tlc/1.2.0/commands/M0008.json +48 -42
  299. data/schemas/tlc/1.2.0/commands/M0010.json +35 -29
  300. data/schemas/tlc/1.2.0/commands/M0011.json +35 -29
  301. data/schemas/tlc/1.2.0/commands/M0012.json +35 -29
  302. data/schemas/tlc/1.2.0/commands/M0013.json +35 -29
  303. data/schemas/tlc/1.2.0/commands/M0014.json +48 -42
  304. data/schemas/tlc/1.2.0/commands/M0015.json +48 -42
  305. data/schemas/tlc/1.2.0/commands/M0016.json +35 -29
  306. data/schemas/tlc/1.2.0/commands/M0017.json +35 -29
  307. data/schemas/tlc/1.2.0/commands/M0018.json +48 -42
  308. data/schemas/tlc/1.2.0/commands/M0019.json +61 -55
  309. data/schemas/tlc/1.2.0/commands/M0020.json +61 -55
  310. data/schemas/tlc/1.2.0/commands/M0021.json +35 -29
  311. data/schemas/tlc/1.2.0/commands/M0022.json +194 -188
  312. data/schemas/tlc/1.2.0/commands/M0023.json +35 -29
  313. data/schemas/tlc/1.2.0/commands/M0103.json +51 -45
  314. data/schemas/tlc/1.2.0/commands/M0104.json +100 -94
  315. data/schemas/tlc/1.2.0/commands/command_requests.json +1525 -1
  316. data/schemas/tlc/1.2.0/defs/guards.json +19 -0
  317. data/schemas/tlc/1.2.0/statuses/S0033.json +2 -2
  318. data/schemas/tlc/1.2.0/sxl.yaml +77 -76
  319. data/schemas/tlc/1.2.0/sxl_index.json +401 -397
  320. data/schemas/tlc/1.2.1/alarms/A0007.json +25 -19
  321. data/schemas/tlc/1.2.1/alarms/A0008.json +21 -15
  322. data/schemas/tlc/1.2.1/alarms/A0201.json +26 -20
  323. data/schemas/tlc/1.2.1/alarms/A0202.json +26 -20
  324. data/schemas/tlc/1.2.1/alarms/A0301.json +69 -63
  325. data/schemas/tlc/1.2.1/alarms/A0302.json +87 -81
  326. data/schemas/tlc/1.2.1/alarms/A0303.json +69 -63
  327. data/schemas/tlc/1.2.1/alarms/A0304.json +87 -81
  328. data/schemas/tlc/1.2.1/commands/M0001.json +66 -60
  329. data/schemas/tlc/1.2.1/commands/M0002.json +48 -42
  330. data/schemas/tlc/1.2.1/commands/M0003.json +48 -42
  331. data/schemas/tlc/1.2.1/commands/M0004.json +35 -29
  332. data/schemas/tlc/1.2.1/commands/M0005.json +48 -42
  333. data/schemas/tlc/1.2.1/commands/M0006.json +48 -42
  334. data/schemas/tlc/1.2.1/commands/M0007.json +35 -29
  335. data/schemas/tlc/1.2.1/commands/M0008.json +48 -42
  336. data/schemas/tlc/1.2.1/commands/M0010.json +35 -29
  337. data/schemas/tlc/1.2.1/commands/M0011.json +35 -29
  338. data/schemas/tlc/1.2.1/commands/M0012.json +35 -29
  339. data/schemas/tlc/1.2.1/commands/M0013.json +35 -29
  340. data/schemas/tlc/1.2.1/commands/M0014.json +48 -42
  341. data/schemas/tlc/1.2.1/commands/M0015.json +48 -42
  342. data/schemas/tlc/1.2.1/commands/M0016.json +35 -29
  343. data/schemas/tlc/1.2.1/commands/M0017.json +35 -29
  344. data/schemas/tlc/1.2.1/commands/M0018.json +48 -42
  345. data/schemas/tlc/1.2.1/commands/M0019.json +61 -55
  346. data/schemas/tlc/1.2.1/commands/M0020.json +61 -55
  347. data/schemas/tlc/1.2.1/commands/M0021.json +35 -29
  348. data/schemas/tlc/1.2.1/commands/M0022.json +194 -188
  349. data/schemas/tlc/1.2.1/commands/M0023.json +35 -29
  350. data/schemas/tlc/1.2.1/commands/M0103.json +51 -45
  351. data/schemas/tlc/1.2.1/commands/M0104.json +100 -94
  352. data/schemas/tlc/1.2.1/commands/command_requests.json +1525 -1
  353. data/schemas/tlc/1.2.1/defs/guards.json +19 -0
  354. data/schemas/tlc/1.2.1/statuses/S0033.json +2 -2
  355. data/schemas/tlc/1.2.1/sxl.yaml +77 -76
  356. data/schemas/tlc/1.2.1/sxl_index.json +401 -397
  357. data/schemas/tlc/1.3.0/alarms/A0007.json +25 -19
  358. data/schemas/tlc/1.3.0/alarms/A0008.json +21 -15
  359. data/schemas/tlc/1.3.0/alarms/A0201.json +26 -20
  360. data/schemas/tlc/1.3.0/alarms/A0202.json +26 -20
  361. data/schemas/tlc/1.3.0/alarms/A0301.json +69 -63
  362. data/schemas/tlc/1.3.0/alarms/A0302.json +87 -81
  363. data/schemas/tlc/1.3.0/alarms/A0303.json +70 -64
  364. data/schemas/tlc/1.3.0/alarms/A0304.json +88 -82
  365. data/schemas/tlc/1.3.0/commands/M0001.json +66 -60
  366. data/schemas/tlc/1.3.0/commands/M0002.json +48 -42
  367. data/schemas/tlc/1.3.0/commands/M0003.json +48 -42
  368. data/schemas/tlc/1.3.0/commands/M0004.json +35 -29
  369. data/schemas/tlc/1.3.0/commands/M0005.json +48 -42
  370. data/schemas/tlc/1.3.0/commands/M0006.json +48 -42
  371. data/schemas/tlc/1.3.0/commands/M0007.json +35 -29
  372. data/schemas/tlc/1.3.0/commands/M0008.json +61 -55
  373. data/schemas/tlc/1.3.0/commands/M0010.json +35 -29
  374. data/schemas/tlc/1.3.0/commands/M0011.json +35 -29
  375. data/schemas/tlc/1.3.0/commands/M0012.json +35 -29
  376. data/schemas/tlc/1.3.0/commands/M0013.json +36 -30
  377. data/schemas/tlc/1.3.0/commands/M0014.json +48 -42
  378. data/schemas/tlc/1.3.0/commands/M0015.json +48 -42
  379. data/schemas/tlc/1.3.0/commands/M0016.json +35 -29
  380. data/schemas/tlc/1.3.0/commands/M0017.json +35 -29
  381. data/schemas/tlc/1.3.0/commands/M0018.json +48 -42
  382. data/schemas/tlc/1.3.0/commands/M0019.json +61 -55
  383. data/schemas/tlc/1.3.0/commands/M0020.json +61 -55
  384. data/schemas/tlc/1.3.0/commands/M0021.json +35 -29
  385. data/schemas/tlc/1.3.0/commands/M0022.json +195 -189
  386. data/schemas/tlc/1.3.0/commands/M0023.json +35 -29
  387. data/schemas/tlc/1.3.0/commands/M0024.json +21 -15
  388. data/schemas/tlc/1.3.0/commands/M0103.json +51 -45
  389. data/schemas/tlc/1.3.0/commands/M0104.json +100 -94
  390. data/schemas/tlc/1.3.0/commands/command_requests.json +1559 -1
  391. data/schemas/tlc/1.3.0/defs/guards.json +19 -0
  392. data/schemas/tlc/1.3.0/statuses/S0001.json +4 -4
  393. data/schemas/tlc/1.3.0/statuses/S0005.json +3 -3
  394. data/schemas/tlc/1.3.0/statuses/S0006.json +2 -2
  395. data/schemas/tlc/1.3.0/statuses/S0007.json +1 -1
  396. data/schemas/tlc/1.3.0/statuses/S0008.json +1 -1
  397. data/schemas/tlc/1.3.0/statuses/S0009.json +1 -1
  398. data/schemas/tlc/1.3.0/statuses/S0010.json +1 -1
  399. data/schemas/tlc/1.3.0/statuses/S0011.json +1 -1
  400. data/schemas/tlc/1.3.0/statuses/S0012.json +1 -1
  401. data/schemas/tlc/1.3.0/statuses/S0013.json +1 -1
  402. data/schemas/tlc/1.3.0/statuses/S0014.json +1 -1
  403. data/schemas/tlc/1.3.0/statuses/S0015.json +1 -1
  404. data/schemas/tlc/1.3.0/statuses/S0016.json +1 -1
  405. data/schemas/tlc/1.3.0/statuses/S0017.json +1 -1
  406. data/schemas/tlc/1.3.0/statuses/S0019.json +1 -1
  407. data/schemas/tlc/1.3.0/statuses/S0020.json +1 -1
  408. data/schemas/tlc/1.3.0/statuses/S0025.json +2 -2
  409. data/schemas/tlc/1.3.0/statuses/S0027.json +1 -1
  410. data/schemas/tlc/1.3.0/statuses/S0032.json +2 -2
  411. data/schemas/tlc/1.3.0/statuses/S0033.json +5 -5
  412. data/schemas/tlc/1.3.0/statuses/S0034.json +1 -1
  413. data/schemas/tlc/1.3.0/statuses/S0035.json +1 -1
  414. data/schemas/tlc/1.3.0/statuses/S0091.json +1 -1
  415. data/schemas/tlc/1.3.0/statuses/S0092.json +1 -1
  416. data/schemas/tlc/1.3.0/statuses/S0096.json +6 -6
  417. data/schemas/tlc/1.3.0/statuses/S0201.json +1 -1
  418. data/schemas/tlc/1.3.0/statuses/S0202.json +1 -1
  419. data/schemas/tlc/1.3.0/statuses/S0203.json +1 -1
  420. data/schemas/tlc/1.3.0/statuses/S0204.json +9 -9
  421. data/schemas/tlc/1.3.0/statuses/S0205.json +1 -1
  422. data/schemas/tlc/1.3.0/statuses/S0206.json +1 -1
  423. data/schemas/tlc/1.3.0/statuses/S0207.json +1 -1
  424. data/schemas/tlc/1.3.0/statuses/S0208.json +9 -9
  425. data/schemas/tlc/1.3.0/sxl_index.json +408 -402
  426. metadata +8 -1
@@ -0,0 +1,64 @@
1
+ module RSMP
2
+ module Convert
3
+ module Export
4
+ # Converts SXL definitions to JSON Schema files.
5
+ module JSONSchema
6
+ def self.output_sxl_index(out, sxl)
7
+ out['sxl_index.json'] = output_json({
8
+ 'meta' => sxl[:meta],
9
+ 'statuses' => index_items(sxl[:statuses]),
10
+ 'commands' => index_items(sxl[:commands]),
11
+ 'alarms' => index_items(sxl[:alarms])
12
+ })
13
+ end
14
+
15
+ def self.index_items(items)
16
+ items.keys.sort.to_h do |key|
17
+ [key, index_item(items[key])]
18
+ end
19
+ end
20
+
21
+ def self.index_item(item)
22
+ arguments = item['arguments'] || {}
23
+ entry = {}
24
+ required = typed_arguments(arguments.reject { |_name, argument| argument['optional'] == true })
25
+ optional = typed_arguments(arguments.select { |_name, argument| argument['optional'] == true })
26
+ entry['required'] = required unless required.empty?
27
+ entry['optional'] = optional unless optional.empty?
28
+ entry
29
+ end
30
+
31
+ def self.typed_arguments(arguments)
32
+ arguments.keys.sort.to_h do |name|
33
+ [name, argument_type_descriptor(arguments[name])]
34
+ end
35
+ end
36
+
37
+ def self.argument_type_descriptor(argument)
38
+ type = argument['type']
39
+ case type
40
+ when 'array'
41
+ argument_array_descriptor(argument)
42
+ when 'object'
43
+ argument_object_descriptor(argument)
44
+ else
45
+ type
46
+ end
47
+ end
48
+
49
+ def self.argument_array_descriptor(argument)
50
+ descriptor = { 'type' => argument['type'] }
51
+ descriptor['items'] = typed_arguments(argument['items']) if argument['items'].is_a?(Hash)
52
+ descriptor
53
+ end
54
+
55
+ def self.argument_object_descriptor(argument)
56
+ descriptor = { 'type' => argument['type'] }
57
+ properties = argument['properties'] || argument['items']
58
+ descriptor['properties'] = typed_arguments(properties) if properties.is_a?(Hash)
59
+ descriptor
60
+ end
61
+ end
62
+ end
63
+ end
64
+ end
@@ -42,12 +42,20 @@ module RSMP
42
42
  'then' => { 'properties' => { property_key => build_value(argument) } }
43
43
  }
44
44
  end
45
- {
45
+ schema = {
46
46
  '$schema' => 'https://json-schema.org/draft/2020-12/schema',
47
47
  'description' => item['description'],
48
48
  'properties' => { 'n' => { 'enum' => arguments.keys.sort } },
49
49
  'allOf' => rules
50
50
  }
51
+ return schema unless property_key == 'v'
52
+
53
+ schema.delete 'allOf'
54
+ schema.merge(
55
+ 'if' => { '$ref' => '../defs/guards.json#/$defs/age_unknown_or_undefined' },
56
+ 'then' => {},
57
+ 'else' => { 'allOf' => rules }
58
+ )
51
59
  end
52
60
  end
53
61
  end
@@ -11,6 +11,12 @@ module RSMP
11
11
  { 'required' => ['q'] },
12
12
  { 'properties' => { 'q' => { 'enum' => %w[undefined unknown] } } }
13
13
  ]
14
+ },
15
+ 'age_unknown_or_undefined' => {
16
+ 'allOf' => [
17
+ { 'required' => ['age'] },
18
+ { 'properties' => { 'age' => { 'enum' => %w[undefined unknown] } } }
19
+ ]
14
20
  }
15
21
  }
16
22
  }.freeze
@@ -67,6 +73,15 @@ module RSMP
67
73
 
68
74
  # convert commands to json schema
69
75
  def self.output_commands(out, items)
76
+ out['defs/guards.json'] ||= output_json(GUARDS_JSON)
77
+ out['commands/commands.json'] = output_json commands_schema(items)
78
+ out['commands/command_requests.json'] = output_json command_requests_schema(items)
79
+ out['commands/command_responses.json'] = output_json command_responses_schema
80
+
81
+ items.each_pair { |key, item| output_command out, key, item }
82
+ end
83
+
84
+ def self.commands_schema(items)
70
85
  list = [{ 'properties' => { 'cCI' => { 'enum' => items.keys.sort } } }]
71
86
  items.keys.sort.each do |key|
72
87
  list << {
@@ -74,25 +89,67 @@ module RSMP
74
89
  'then' => { '$ref' => "#{key}.json" }
75
90
  }
76
91
  end
77
- json = {
92
+ {
78
93
  '$schema' => 'https://json-schema.org/draft/2020-12/schema',
79
94
  'items' => { 'allOf' => list }
80
95
  }
81
- out['commands/commands.json'] = output_json json
96
+ end
82
97
 
83
- json = {
98
+ def self.command_requests_schema(items)
99
+ {
84
100
  '$schema' => 'https://json-schema.org/draft/2020-12/schema',
85
- 'properties' => { 'arg' => { '$ref' => 'commands.json' } }
101
+ 'properties' => { 'arg' => command_request_arg_schema(items) }
86
102
  }
87
- out['commands/command_requests.json'] = output_json json
103
+ end
88
104
 
89
- json = {
105
+ def self.command_responses_schema
106
+ {
90
107
  '$schema' => 'https://json-schema.org/draft/2020-12/schema',
91
108
  'properties' => { 'rvs' => { '$ref' => 'commands.json' } }
92
109
  }
93
- out['commands/command_responses.json'] = output_json json
110
+ end
94
111
 
95
- items.each_pair { |key, item| output_command out, key, item }
112
+ def self.command_request_arg_schema(items)
113
+ schema = { '$ref' => 'commands.json' }
114
+ required_rules = command_required_argument_rules(items)
115
+ return schema if required_rules.empty?
116
+
117
+ { 'allOf' => [schema] + required_rules }
118
+ end
119
+
120
+ def self.command_required_argument_rules(items)
121
+ items.keys.sort.filter_map do |key|
122
+ required = required_argument_names(items[key])
123
+ next if required.empty?
124
+
125
+ {
126
+ 'if' => {
127
+ 'contains' => {
128
+ 'required' => ['cCI'],
129
+ 'properties' => { 'cCI' => { 'const' => key } }
130
+ }
131
+ },
132
+ 'then' => {
133
+ 'allOf' => required.map { |name| command_argument_contains_rule(key, name) }
134
+ }
135
+ }
136
+ end
137
+ end
138
+
139
+ def self.command_argument_contains_rule(command_code, name)
140
+ {
141
+ 'contains' => {
142
+ 'required' => %w[cCI n],
143
+ 'properties' => {
144
+ 'cCI' => { 'const' => command_code },
145
+ 'n' => { 'const' => name }
146
+ }
147
+ }
148
+ }
149
+ end
150
+
151
+ def self.required_argument_names(item)
152
+ (item['arguments'] || {}).reject { |_name, argument| argument['optional'] == true }.keys.sort
96
153
  end
97
154
 
98
155
  # convert a command to json schema
@@ -103,23 +160,6 @@ module RSMP
103
160
  out["commands/#{key}.json"] = output_json json
104
161
  end
105
162
 
106
- def self.output_sxl_index(out, sxl)
107
- out['sxl_index.json'] = output_json({
108
- 'meta' => sxl[:meta],
109
- 'statuses' => index_items(sxl[:statuses]),
110
- 'commands' => index_items(sxl[:commands]),
111
- 'alarms' => index_items(sxl[:alarms])
112
- })
113
- end
114
-
115
- def self.index_items(items)
116
- items.keys.sort.to_h do |key|
117
- [key, {
118
- 'arguments' => (items[key]['arguments'] || {}).keys.sort
119
- }]
120
- end
121
- end
122
-
123
163
  # output the json schema root
124
164
  def self.output_root(out, meta)
125
165
  json = {
@@ -3,6 +3,21 @@ module RSMP
3
3
  module Export
4
4
  # Converts SXL definitions to JSON Schema files.
5
5
  module JSONSchema
6
+ DIRECT_JSON_TYPES = {
7
+ 'boolean' => 'boolean',
8
+ 'integer' => 'integer',
9
+ 'number' => 'number',
10
+ 'object' => 'object',
11
+ 'null' => 'null'
12
+ }.freeze
13
+
14
+ DEFINITION_REFS = {
15
+ 'boolean_as_string' => '../defs/definitions.json#/boolean',
16
+ 'timestamp' => '../defs/definitions.json#/timestamp',
17
+ 'integer_as_string' => '../defs/definitions.json#/integer',
18
+ 'long_as_string' => '../defs/definitions.json#/integer'
19
+ }.freeze
20
+
6
21
  # convert a yaml item to json schema
7
22
  def self.build_value(item)
8
23
  out = {}
@@ -19,20 +34,27 @@ module RSMP
19
34
 
20
35
  # convert an item which is not a string-list, to json schema
21
36
  def self.handle_types(item, out)
22
- case item['type']
23
- when 'boolean'
24
- out['$ref'] = '../defs/definitions.json#/boolean'
25
- when 'timestamp'
26
- out['$ref'] = '../defs/definitions.json#/timestamp'
27
- when 'integer', 'ordinal', 'unit', 'scale', 'long'
28
- out['$ref'] = '../defs/definitions.json#/integer'
29
- when 'array' # a json array
37
+ type = item['type']
38
+ return build_json_array_type(item, out) if type == 'array'
39
+ return build_number_as_string_type(out) if type == 'number_as_string'
40
+ return out['$ref'] = DEFINITION_REFS[type] if DEFINITION_REFS.key?(type)
41
+
42
+ out['type'] = DIRECT_JSON_TYPES.fetch(type, 'string')
43
+ end
44
+
45
+ def self.build_json_array_type(item, out)
46
+ if item['items']
30
47
  build_json_array item['items'], out
31
- else # string, base64, and any unknown types
32
- out['type'] = 'string'
48
+ else
49
+ out['type'] = 'array'
33
50
  end
34
51
  end
35
52
 
53
+ def self.build_number_as_string_type(out)
54
+ out['type'] = 'string'
55
+ out['pattern'] = '^-?(?:0|[1-9][0-9]*)(?:\\.[0-9]+)?$'
56
+ end
57
+
36
58
  # convert an yaml item with type: array to json schema
37
59
  def self.build_json_array(item, out)
38
60
  required = item.reject { |_k, v| v['optional'] == true }.keys.sort
@@ -83,7 +105,14 @@ module RSMP
83
105
  def self.handle_enum(item, out)
84
106
  return unless item['values']
85
107
 
86
- out['enum'] = stringify_values(enum_keys(item))
108
+ values = enum_keys(item)
109
+ values = stringify_values(values) if string_type? item
110
+ out['enum'] = values
111
+ end
112
+
113
+ def self.string_type?(item)
114
+ type = item['type'].to_s
115
+ type == 'string' || type.end_with?('_as_string') || %w[base64 timestamp].include?(type)
87
116
  end
88
117
 
89
118
  def self.enum_keys(item)
@@ -7,6 +7,7 @@ require 'fileutils'
7
7
  require_relative 'json_schema/values'
8
8
  require_relative 'json_schema/items'
9
9
  require_relative 'json_schema/outputs'
10
+ require_relative 'json_schema/index'
10
11
 
11
12
  module RSMP
12
13
  module Convert
@@ -19,7 +20,8 @@ module RSMP
19
20
  object_nl: "\n",
20
21
  indent: ' ',
21
22
  space_before: ' ',
22
- space: ' '
23
+ space: ' ',
24
+ ascii_only: true
23
25
  }.freeze
24
26
 
25
27
  def self.output_json(item)
@@ -0,0 +1,194 @@
1
+ module RSMP
2
+ # Encodes and decodes SXL argument values for message payloads.
3
+ module MessageSxlCodec
4
+ SXL_ITEM_SHAPES = {
5
+ 'StatusResponse' => { kind: :statuses, list: 'sS', code: 'sCI', name: 'n', value: 's' },
6
+ 'StatusUpdate' => { kind: :statuses, list: 'sS', code: 'sCI', name: 'n', value: 's' },
7
+ 'CommandRequest' => { kind: :commands, list: 'arg', code: 'cCI', name: 'n', value: 'v' },
8
+ 'CommandResponse' => { kind: :commands, list: 'rvs', code: 'cCI', name: 'n', value: 'v' },
9
+ 'Alarm' => { kind: :alarms, list: 'rvs', code: nil, name: 'n', value: 'v' }
10
+ }.freeze
11
+
12
+ def self.included(base)
13
+ base.extend ClassMethods
14
+ end
15
+
16
+ def encode_for(schemas)
17
+ transform_sxl_items(schemas, :encode_sxl_value)
18
+ self
19
+ end
20
+
21
+ def decode_for(schemas)
22
+ transform_sxl_items(schemas, :decode_sxl_value)
23
+ self
24
+ end
25
+
26
+ private
27
+
28
+ def transform_sxl_items(schemas, transformer)
29
+ shape = SXL_ITEM_SHAPES[type]
30
+ return unless shape
31
+
32
+ resolved = RSMP::Schema.resolve_sxl(@attributes, schemas: schemas)
33
+ return unless resolved
34
+
35
+ sxl_type, version = resolved
36
+ Array(@attributes[shape[:list]]).each do |item|
37
+ transform_sxl_item(item, shape, sxl_type, version, transformer)
38
+ end
39
+ end
40
+
41
+ def transform_sxl_item(item, shape, sxl_type, version, transformer)
42
+ item_code = shape[:code] ? item[shape[:code]] : @attributes['aCId']
43
+ name = item[shape[:name]]
44
+ return unless item_code && name && item.key?(shape[:value])
45
+
46
+ descriptor = RSMP::Schema.sxl_argument_descriptor(sxl_type, version, shape[:kind], item_code, name)
47
+ return unless descriptor
48
+
49
+ item[shape[:value]] = self.class.public_send(transformer, item[shape[:value]], descriptor)
50
+ end
51
+
52
+ # Class-level value transforms used by Message and command collectors.
53
+ module ClassMethods
54
+ STRING_TYPES = %w[string base64 timestamp].freeze
55
+ INTEGER_AS_STRING_TYPES = %w[integer_as_string long_as_string].freeze
56
+
57
+ def encode_sxl_value(value, descriptor)
58
+ return nil if value.nil?
59
+
60
+ type = descriptor_type(descriptor)
61
+ return encode_sxl_boolean(value) if type == 'boolean_as_string'
62
+ return encode_sxl_list(value) if list_type?(type)
63
+ return value.is_a?(String) ? value : value.to_s if encode_string_type?(type)
64
+ return encode_sxl_array(value, descriptor) if type == 'array'
65
+ return encode_sxl_object(value, descriptor['properties']) if type == 'object'
66
+
67
+ value
68
+ end
69
+
70
+ def decode_sxl_value(value, descriptor)
71
+ return nil if value.nil?
72
+
73
+ type = descriptor_type(descriptor)
74
+ return decode_sxl_boolean(value) if type == 'boolean_as_string'
75
+ return decode_sxl_integer(value) if INTEGER_AS_STRING_TYPES.include?(type)
76
+ return decode_sxl_number(value) if type == 'number_as_string'
77
+ return decode_sxl_list(value, type) if list_type?(type)
78
+ return decode_sxl_array(value, descriptor) if type == 'array'
79
+ return decode_sxl_object(value, descriptor['properties']) if type == 'object'
80
+
81
+ value
82
+ end
83
+
84
+ def descriptor_type(descriptor)
85
+ descriptor.is_a?(Hash) ? descriptor['type'] : descriptor.to_s
86
+ end
87
+
88
+ def list_type?(type)
89
+ type.match?(/_list(_as_string)?\z/)
90
+ end
91
+
92
+ def encode_string_type?(type)
93
+ STRING_TYPES.include?(type) || INTEGER_AS_STRING_TYPES.include?(type) || type == 'number_as_string'
94
+ end
95
+
96
+ def encode_sxl_boolean(value)
97
+ case value
98
+ when true
99
+ 'True'
100
+ when false
101
+ 'False'
102
+ else
103
+ value
104
+ end
105
+ end
106
+
107
+ def encode_sxl_list(value)
108
+ return value if value.is_a?(String)
109
+ return encode_sxl_boolean(value).to_s unless value.is_a?(Array)
110
+
111
+ value.map { |item| encode_sxl_boolean(item) }.join(',')
112
+ end
113
+
114
+ def encode_sxl_array(value, descriptor)
115
+ return value unless value.is_a?(Array)
116
+
117
+ items = descriptor['items']
118
+ return value unless items.is_a?(Hash)
119
+
120
+ value.map { |item| encode_sxl_object(item, items) }
121
+ end
122
+
123
+ def encode_sxl_object(value, properties)
124
+ transform_sxl_object(value, properties, :encode_sxl_value)
125
+ end
126
+
127
+ def decode_sxl_boolean(value)
128
+ case value
129
+ when 'True'
130
+ true
131
+ when 'False'
132
+ false
133
+ else
134
+ value
135
+ end
136
+ end
137
+
138
+ def decode_sxl_integer(value)
139
+ return value unless value.is_a?(String) && value.match?(/\A[+-]?\d+\z/)
140
+
141
+ value.to_i
142
+ end
143
+
144
+ def decode_sxl_number(value)
145
+ return value unless value.is_a?(String)
146
+
147
+ Float(value)
148
+ rescue ArgumentError
149
+ value
150
+ end
151
+
152
+ def decode_sxl_list(value, type)
153
+ items = value.is_a?(String) ? value.split(',') : Array(value)
154
+ descriptor = list_item_descriptor(type)
155
+ items.map { |item| decode_sxl_value(item, descriptor) }
156
+ end
157
+
158
+ def list_item_descriptor(type)
159
+ case type
160
+ when /\Aboolean_list/ then 'boolean_as_string'
161
+ when /\Ainteger_list/ then 'integer_as_string'
162
+ when /\Anumber_list/ then 'number_as_string'
163
+ else 'string'
164
+ end
165
+ end
166
+
167
+ def decode_sxl_array(value, descriptor)
168
+ return value unless value.is_a?(Array)
169
+
170
+ items = descriptor['items']
171
+ return value unless items.is_a?(Hash)
172
+
173
+ value.map { |item| decode_sxl_array_item(item, items) }
174
+ end
175
+
176
+ def decode_sxl_array_item(item, descriptor)
177
+ descriptor['type'] ? decode_sxl_value(item, descriptor) : decode_sxl_object(item, descriptor)
178
+ end
179
+
180
+ def decode_sxl_object(value, properties)
181
+ transform_sxl_object(value, properties, :decode_sxl_value)
182
+ end
183
+
184
+ def transform_sxl_object(value, properties, transformer)
185
+ return value unless value.is_a?(Hash) && properties.is_a?(Hash)
186
+
187
+ value.each_with_object({}) do |(key, item_value), memo|
188
+ descriptor = properties[key] || properties[key.to_sym]
189
+ memo[key] = descriptor ? public_send(transformer, item_value, descriptor) : item_value
190
+ end
191
+ end
192
+ end
193
+ end
194
+ end
data/lib/rsmp/message.rb CHANGED
@@ -2,6 +2,8 @@
2
2
  module RSMP
3
3
  # Base RSMP message class used to represent parsed and built messages.
4
4
  class Message
5
+ include MessageSxlCodec
6
+
5
7
  attr_reader :now, :attributes, :out, :timestamp # this is an internal timestamp recording when we receive/send
6
8
  attr_accessor :json, :direction
7
9
 
@@ -0,0 +1,80 @@
1
+ module RSMP
2
+ # Connection handling for site instances.
3
+ module SiteConnections
4
+ def build_proxies
5
+ return if server_role?
6
+
7
+ @site_settings['supervisors'].each do |supervisor_settings|
8
+ @proxies << SupervisorProxy.new(supervisor_proxy_options(supervisor_settings))
9
+ end
10
+ end
11
+
12
+ def listen_for_supervisors
13
+ ip = @site_settings['ip'] || '0.0.0.0'
14
+ port = @site_settings['port']
15
+ log "Starting #{site_type_name} listener on #{ip}:#{port}", level: :info, timestamp: @clock.now
16
+ @endpoint = IO::Endpoint.tcp(ip, port)
17
+ @accept_task = Async::Task.current.async do |task|
18
+ task.annotate 'site accept loop'
19
+ accept_supervisor_connections
20
+ end
21
+
22
+ @ready_condition.signal
23
+ @accept_task.wait
24
+ end
25
+
26
+ def accept_supervisor_connections
27
+ @endpoint.accept do |socket|
28
+ accept_supervisor_connection socket
29
+ rescue StandardError => e
30
+ distribute_error e, level: :internal
31
+ end
32
+ rescue Async::Stop
33
+ # Expected during shutdown - no action needed
34
+ rescue StandardError => e
35
+ distribute_error e, level: :internal
36
+ end
37
+
38
+ def accept_supervisor_connection(socket)
39
+ remote_port = socket.remote_address.ip_port
40
+ remote_ip = socket.remote_address.ip_address
41
+ proxy = SupervisorProxy.new(accepted_supervisor_options(socket, remote_ip, remote_port))
42
+ @proxies << proxy
43
+ @proxies_condition.signal
44
+ proxy.start
45
+ proxy.wait
46
+ end
47
+
48
+ def connect_to_supervisor(_task, supervisor_settings)
49
+ proxy = build_proxy(supervisor_proxy_options(supervisor_settings))
50
+ @proxies << proxy
51
+ proxy.start
52
+ @proxies_condition.signal
53
+ end
54
+
55
+ private
56
+
57
+ def supervisor_proxy_options(supervisor_settings)
58
+ {
59
+ site: self,
60
+ task: @task,
61
+ settings: @site_settings,
62
+ ip: supervisor_settings['ip'],
63
+ port: supervisor_settings['port'],
64
+ logger: @logger,
65
+ archive: @archive,
66
+ collect: @collect
67
+ }
68
+ end
69
+
70
+ def accepted_supervisor_options(socket, remote_ip, remote_port)
71
+ stream = IO::Stream::Buffered.new(socket)
72
+ supervisor_proxy_options('ip' => remote_ip, 'port' => remote_port).merge(
73
+ socket: socket,
74
+ stream: stream,
75
+ protocol: RSMP::Protocol.new(stream),
76
+ info: { ip: remote_ip, port: remote_port, hostname: remote_ip, now: Clock.now }
77
+ )
78
+ end
79
+ end
80
+ end