@synnaxlabs/client 0.2.0 → 0.13.5
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.
- package/.eslintrc.cjs +18 -0
- package/.pytest_cache/README.md +8 -0
- package/.turbo/turbo-build.log +16 -0
- package/LICENSE +4 -21
- package/{build/main/lib → dist/auth}/auth.d.ts +16 -19
- package/dist/auth/index.d.ts +1 -0
- package/dist/cdc/external.d.ts +1 -0
- package/dist/cdc/index.d.ts +1 -0
- package/dist/cdc/observable.d.ts +17 -0
- package/dist/channel/client.d.ts +58 -0
- package/dist/channel/creator.d.ts +8 -0
- package/dist/channel/external.d.ts +4 -0
- package/dist/channel/index.d.ts +1 -0
- package/dist/channel/payload.d.ts +63 -0
- package/dist/channel/retriever.d.ts +49 -0
- package/dist/client.cjs.js +23050 -0
- package/dist/client.cjs.js.map +1 -0
- package/dist/client.d.ts +73 -0
- package/dist/client.es.js +23050 -0
- package/dist/client.es.js.map +1 -0
- package/dist/connection/checker.d.ts +66 -0
- package/dist/connection/index.d.ts +1 -0
- package/dist/control/authority.d.ts +6 -0
- package/dist/control/external.d.ts +2 -0
- package/dist/control/index.d.ts +1 -0
- package/dist/control/state.d.ts +81 -0
- package/{build/main/lib → dist}/errors.d.ts +6 -3
- package/dist/framer/adapter.d.ts +21 -0
- package/dist/framer/client.d.ts +44 -0
- package/dist/framer/external.d.ts +5 -0
- package/dist/framer/frame.d.ts +251 -0
- package/dist/framer/index.d.ts +1 -0
- package/{build/module/lib/segment → dist/framer}/iterator.d.ts +32 -64
- package/dist/framer/streamProxy.d.ts +12 -0
- package/dist/framer/streamer.d.ts +17 -0
- package/dist/framer/writer.d.ts +257 -0
- package/dist/index.d.ts +16 -0
- package/dist/label/client.d.ts +25 -0
- package/dist/label/external.d.ts +4 -0
- package/dist/label/index.d.ts +1 -0
- package/dist/label/payload.d.ts +20 -0
- package/dist/label/retriever.d.ts +13 -0
- package/dist/label/writer.d.ts +26 -0
- package/dist/ontology/cdc.d.ts +25 -0
- package/dist/ontology/client.d.ts +25 -0
- package/dist/ontology/external.d.ts +3 -0
- package/dist/ontology/group/client.d.ts +11 -0
- package/dist/ontology/group/external.d.ts +2 -0
- package/dist/ontology/group/group.d.ts +7 -0
- package/dist/ontology/group/index.d.ts +1 -0
- package/dist/ontology/group/payload.d.ts +40 -0
- package/dist/ontology/group/writer.d.ts +13 -0
- package/dist/ontology/index.d.ts +1 -0
- package/dist/ontology/ontology.spec.d.ts +1 -0
- package/dist/ontology/payload.d.ts +235 -0
- package/dist/ontology/retriever.d.ts +12 -0
- package/dist/ontology/signals.d.ts +25 -0
- package/dist/ontology/writer.d.ts +9 -0
- package/dist/ranger/active.d.ts +9 -0
- package/dist/ranger/alias.d.ts +32 -0
- package/dist/ranger/client.d.ts +31 -0
- package/dist/ranger/external.d.ts +6 -0
- package/dist/ranger/index.d.ts +1 -0
- package/dist/ranger/kv.d.ts +50 -0
- package/dist/ranger/payload.d.ts +94 -0
- package/dist/ranger/range.d.ts +29 -0
- package/dist/ranger/ranger.spec.d.ts +1 -0
- package/dist/ranger/retriever.d.ts +10 -0
- package/dist/ranger/writer.d.ts +9 -0
- package/{build/main → dist}/setupspecs.d.ts +2 -2
- package/dist/signals/external.d.ts +1 -0
- package/dist/signals/index.d.ts +1 -0
- package/dist/signals/observable.d.ts +17 -0
- package/dist/transport.d.ts +10 -0
- package/dist/user/index.d.ts +1 -0
- package/{build/main/lib → dist}/user/payload.d.ts +3 -3
- package/dist/util/telem.d.ts +2 -0
- package/dist/workspace/client.d.ts +22 -0
- package/dist/workspace/external.d.ts +2 -0
- package/dist/workspace/index.d.ts +1 -0
- package/dist/workspace/lineplot/client.d.ts +15 -0
- package/dist/workspace/lineplot/external.d.ts +2 -0
- package/dist/workspace/lineplot/index.d.ts +1 -0
- package/dist/workspace/lineplot/linePlot.spec.d.ts +1 -0
- package/dist/workspace/lineplot/payload.d.ts +31 -0
- package/dist/workspace/lineplot/retriever.d.ts +9 -0
- package/dist/workspace/lineplot/writer.d.ts +39 -0
- package/dist/workspace/payload.d.ts +31 -0
- package/dist/workspace/pid/client.d.ts +16 -0
- package/dist/workspace/pid/external.d.ts +2 -0
- package/dist/workspace/pid/index.d.ts +1 -0
- package/dist/workspace/pid/payload.d.ts +37 -0
- package/dist/workspace/pid/pid.spec.d.ts +1 -0
- package/dist/workspace/pid/retriever.d.ts +9 -0
- package/dist/workspace/pid/writer.d.ts +46 -0
- package/dist/workspace/retriever.d.ts +12 -0
- package/dist/workspace/workspace.spec.d.ts +1 -0
- package/dist/workspace/writer.d.ts +55 -0
- package/package.json +27 -98
- package/src/auth/auth.spec.ts +46 -0
- package/src/auth/auth.ts +83 -0
- package/src/auth/index.ts +10 -0
- package/src/cdc/external.ts +10 -0
- package/src/cdc/index.ts +10 -0
- package/src/cdc/observable.ts +80 -0
- package/src/channel/channel.spec.ts +82 -0
- package/src/channel/client.ts +209 -0
- package/src/channel/creator.ts +43 -0
- package/src/channel/external.ts +13 -0
- package/src/channel/index.ts +10 -0
- package/src/channel/payload.ts +52 -0
- package/src/channel/retriever.ts +160 -0
- package/src/client.ts +112 -0
- package/src/connection/checker.ts +104 -0
- package/src/connection/connection.spec.ts +35 -0
- package/src/connection/index.ts +10 -0
- package/src/control/authority.ts +25 -0
- package/src/control/external.ts +11 -0
- package/src/control/index.ts +10 -0
- package/src/control/state.spec.ts +24 -0
- package/src/control/state.ts +117 -0
- package/src/errors.ts +153 -0
- package/src/framer/adapter.ts +116 -0
- package/src/framer/client.ts +116 -0
- package/src/framer/external.ts +14 -0
- package/src/framer/frame.spec.ts +317 -0
- package/src/framer/frame.ts +412 -0
- package/src/framer/index.ts +10 -0
- package/src/framer/iterator.spec.ts +62 -0
- package/src/framer/iterator.ts +240 -0
- package/src/framer/streamProxy.ts +59 -0
- package/src/framer/streamer.spec.ts +42 -0
- package/src/framer/streamer.ts +86 -0
- package/src/framer/writer.spec.ts +52 -0
- package/src/framer/writer.ts +236 -0
- package/src/index.ts +43 -4
- package/src/ontology/cdc.ts +135 -0
- package/src/ontology/client.ts +103 -0
- package/src/ontology/external.ts +12 -0
- package/src/ontology/group/client.ts +40 -0
- package/src/ontology/group/external.ts +11 -0
- package/src/ontology/group/group.spec.ts +46 -0
- package/src/ontology/group/group.ts +27 -0
- package/src/ontology/group/index.ts +10 -0
- package/src/ontology/group/payload.ts +65 -0
- package/src/ontology/group/writer.ts +48 -0
- package/src/ontology/index.ts +10 -0
- package/src/ontology/ontology.spec.ts +114 -0
- package/src/ontology/payload.ts +121 -0
- package/src/ontology/retriever.ts +91 -0
- package/src/ontology/writer.ts +49 -0
- package/src/ranger/active.ts +56 -0
- package/src/ranger/alias.ts +183 -0
- package/src/ranger/client.ts +124 -0
- package/src/ranger/external.ts +15 -0
- package/src/ranger/index.ts +10 -0
- package/src/ranger/kv.ts +91 -0
- package/src/ranger/payload.ts +70 -0
- package/src/ranger/range.ts +74 -0
- package/src/ranger/ranger.spec.ts +167 -0
- package/src/ranger/retriever.ts +50 -0
- package/src/ranger/writer.ts +80 -0
- package/src/setupspecs.ts +14 -5
- package/src/transport.ts +39 -0
- package/src/user/index.ts +10 -0
- package/src/user/payload.ts +17 -0
- package/src/util/telem.ts +19 -0
- package/src/vite-env.d.ts +11 -0
- package/src/workspace/client.ts +75 -0
- package/src/workspace/external.ts +11 -0
- package/src/workspace/index.ts +10 -0
- package/src/workspace/lineplot/client.ts +51 -0
- package/src/workspace/lineplot/external.ts +11 -0
- package/src/workspace/lineplot/index.ts +10 -0
- package/src/workspace/lineplot/linePlot.spec.ts +78 -0
- package/src/workspace/lineplot/payload.ts +29 -0
- package/src/workspace/lineplot/retriever.ts +49 -0
- package/src/workspace/lineplot/writer.ts +109 -0
- package/src/workspace/payload.ts +29 -0
- package/src/workspace/pid/client.ts +55 -0
- package/src/workspace/pid/external.ts +11 -0
- package/src/workspace/pid/index.ts +10 -0
- package/src/workspace/pid/payload.ts +31 -0
- package/src/workspace/pid/pid.spec.ts +111 -0
- package/src/workspace/pid/retriever.ts +45 -0
- package/src/workspace/pid/writer.ts +130 -0
- package/src/workspace/retriever.ts +67 -0
- package/src/workspace/workspace.spec.ts +62 -0
- package/src/workspace/writer.ts +103 -0
- package/tsconfig.json +3 -43
- package/tsconfig.vite.json +4 -0
- package/vite.config.ts +25 -0
- package/.DS_Store +0 -0
- package/.editorconfig +0 -15
- package/.eslintrc.json +0 -33
- package/.gitignore +0 -9
- package/.nyc_output/20720f2d-6abe-420f-a3c5-304d52d60827.json +0 -1
- package/.nyc_output/4725921c-6f1b-4ae9-9819-e455f702d31c.json +0 -1
- package/.nyc_output/47478588-5ffd-4332-873c-facaa4a2fc38.json +0 -1
- package/.nyc_output/48180641-e0b2-49ab-a6eb-e7910e9eac2f.json +0 -1
- package/.nyc_output/cb0abf31-740f-47db-b94a-8e3f8f117cb8.json +0 -1
- package/.nyc_output/fc77fce2-dad0-49a8-8d4b-0a9014ecf8c5.json +0 -1
- package/.nyc_output/processinfo/20720f2d-6abe-420f-a3c5-304d52d60827.json +0 -1
- package/.nyc_output/processinfo/4725921c-6f1b-4ae9-9819-e455f702d31c.json +0 -1
- package/.nyc_output/processinfo/47478588-5ffd-4332-873c-facaa4a2fc38.json +0 -1
- package/.nyc_output/processinfo/48180641-e0b2-49ab-a6eb-e7910e9eac2f.json +0 -1
- package/.nyc_output/processinfo/cb0abf31-740f-47db-b94a-8e3f8f117cb8.json +0 -1
- package/.nyc_output/processinfo/fc77fce2-dad0-49a8-8d4b-0a9014ecf8c5.json +0 -1
- package/.nyc_output/processinfo/index.json +0 -1
- package/.prettierignore +0 -2
- package/CHANGELOG.md +0 -5
- package/build/main/index.d.ts +0 -4
- package/build/main/index.js +0 -35
- package/build/main/lib/auth.js +0 -62
- package/build/main/lib/auth.spec.js +0 -39
- package/build/main/lib/channel/channel.spec.js +0 -49
- package/build/main/lib/channel/client.d.ts +0 -94
- package/build/main/lib/channel/client.js +0 -134
- package/build/main/lib/channel/creator.d.ts +0 -19
- package/build/main/lib/channel/creator.js +0 -44
- package/build/main/lib/channel/payload.d.ts +0 -25
- package/build/main/lib/channel/payload.js +0 -18
- package/build/main/lib/channel/registry.d.ts +0 -9
- package/build/main/lib/channel/registry.js +0 -37
- package/build/main/lib/channel/retriever.d.ts +0 -11
- package/build/main/lib/channel/retriever.js +0 -39
- package/build/main/lib/client.d.ts +0 -30
- package/build/main/lib/client.js +0 -46
- package/build/main/lib/errors.js +0 -122
- package/build/main/lib/segment/client.d.ts +0 -62
- package/build/main/lib/segment/client.js +0 -95
- package/build/main/lib/segment/iterator.d.ts +0 -134
- package/build/main/lib/segment/iterator.js +0 -253
- package/build/main/lib/segment/iterator.spec.js +0 -73
- package/build/main/lib/segment/payload.d.ts +0 -16
- package/build/main/lib/segment/payload.js +0 -13
- package/build/main/lib/segment/splitter.d.ts +0 -7
- package/build/main/lib/segment/splitter.js +0 -25
- package/build/main/lib/segment/typed.d.ts +0 -15
- package/build/main/lib/segment/typed.js +0 -49
- package/build/main/lib/segment/validator.d.ts +0 -22
- package/build/main/lib/segment/validator.js +0 -64
- package/build/main/lib/segment/writer.d.ts +0 -98
- package/build/main/lib/segment/writer.js +0 -183
- package/build/main/lib/segment/writer.spec.js +0 -90
- package/build/main/lib/telem.d.ts +0 -395
- package/build/main/lib/telem.js +0 -553
- package/build/main/lib/telem.spec.js +0 -152
- package/build/main/lib/transport.d.ts +0 -10
- package/build/main/lib/transport.js +0 -22
- package/build/main/lib/user/payload.js +0 -9
- package/build/main/lib/util/telem.d.ts +0 -2
- package/build/main/lib/util/telem.js +0 -13
- package/build/main/setupspecs.js +0 -17
- package/build/module/index.d.ts +0 -4
- package/build/module/index.js +0 -5
- package/build/module/lib/auth.d.ts +0 -54
- package/build/module/lib/auth.js +0 -63
- package/build/module/lib/auth.spec.js +0 -34
- package/build/module/lib/channel/channel.spec.js +0 -44
- package/build/module/lib/channel/client.d.ts +0 -94
- package/build/module/lib/channel/client.js +0 -134
- package/build/module/lib/channel/creator.d.ts +0 -19
- package/build/module/lib/channel/creator.js +0 -42
- package/build/module/lib/channel/payload.d.ts +0 -25
- package/build/module/lib/channel/payload.js +0 -15
- package/build/module/lib/channel/registry.d.ts +0 -9
- package/build/module/lib/channel/registry.js +0 -36
- package/build/module/lib/channel/retriever.d.ts +0 -11
- package/build/module/lib/channel/retriever.js +0 -37
- package/build/module/lib/client.d.ts +0 -30
- package/build/module/lib/client.js +0 -44
- package/build/module/lib/errors.d.ts +0 -53
- package/build/module/lib/errors.js +0 -113
- package/build/module/lib/segment/client.d.ts +0 -62
- package/build/module/lib/segment/client.js +0 -94
- package/build/module/lib/segment/iterator.js +0 -248
- package/build/module/lib/segment/iterator.spec.js +0 -68
- package/build/module/lib/segment/payload.d.ts +0 -16
- package/build/module/lib/segment/payload.js +0 -10
- package/build/module/lib/segment/splitter.d.ts +0 -7
- package/build/module/lib/segment/splitter.js +0 -26
- package/build/module/lib/segment/typed.d.ts +0 -15
- package/build/module/lib/segment/typed.js +0 -49
- package/build/module/lib/segment/validator.d.ts +0 -22
- package/build/module/lib/segment/validator.js +0 -60
- package/build/module/lib/segment/writer.d.ts +0 -98
- package/build/module/lib/segment/writer.js +0 -183
- package/build/module/lib/segment/writer.spec.js +0 -85
- package/build/module/lib/telem.d.ts +0 -395
- package/build/module/lib/telem.js +0 -545
- package/build/module/lib/telem.spec.js +0 -147
- package/build/module/lib/transport.d.ts +0 -10
- package/build/module/lib/transport.js +0 -22
- package/build/module/lib/user/payload.d.ts +0 -12
- package/build/module/lib/user/payload.js +0 -6
- package/build/module/lib/util/telem.d.ts +0 -2
- package/build/module/lib/util/telem.js +0 -9
- package/build/module/setupspecs.d.ts +0 -4
- package/build/module/setupspecs.js +0 -16
- package/build/tsconfig.module.tsbuildinfo +0 -1
- package/build/tsconfig.tsbuildinfo +0 -1
- package/coverage/base.css +0 -224
- package/coverage/block-navigation.js +0 -87
- package/coverage/favicon.png +0 -0
- package/coverage/index.html +0 -191
- package/coverage/lcov-report/base.css +0 -224
- package/coverage/lcov-report/block-navigation.js +0 -87
- package/coverage/lcov-report/favicon.png +0 -0
- package/coverage/lcov-report/index.html +0 -191
- package/coverage/lcov-report/prettify.css +0 -1
- package/coverage/lcov-report/prettify.js +0 -2
- package/coverage/lcov-report/sort-arrow-sprite.png +0 -0
- package/coverage/lcov-report/sorter.js +0 -196
- package/coverage/lcov-report/src/index.html +0 -116
- package/coverage/lcov-report/src/lib/auth.ts.html +0 -340
- package/coverage/lcov-report/src/lib/channel/client.ts.html +0 -604
- package/coverage/lcov-report/src/lib/channel/creator.ts.html +0 -304
- package/coverage/lcov-report/src/lib/channel/index.html +0 -176
- package/coverage/lcov-report/src/lib/channel/payload.ts.html +0 -139
- package/coverage/lcov-report/src/lib/channel/registry.ts.html +0 -202
- package/coverage/lcov-report/src/lib/channel/retriever.ts.html +0 -244
- package/coverage/lcov-report/src/lib/client.ts.html +0 -244
- package/coverage/lcov-report/src/lib/errors.ts.html +0 -484
- package/coverage/lcov-report/src/lib/index.html +0 -176
- package/coverage/lcov-report/src/lib/segment/client.ts.html +0 -463
- package/coverage/lcov-report/src/lib/segment/index.html +0 -206
- package/coverage/lcov-report/src/lib/segment/iterator.ts.html +0 -928
- package/coverage/lcov-report/src/lib/segment/payload.ts.html +0 -139
- package/coverage/lcov-report/src/lib/segment/splitter.ts.html +0 -181
- package/coverage/lcov-report/src/lib/segment/typed.ts.html +0 -307
- package/coverage/lcov-report/src/lib/segment/validator.ts.html +0 -331
- package/coverage/lcov-report/src/lib/segment/writer.ts.html +0 -727
- package/coverage/lcov-report/src/lib/telem.ts.html +0 -2056
- package/coverage/lcov-report/src/lib/transport.ts.html +0 -196
- package/coverage/lcov-report/src/lib/user/index.html +0 -116
- package/coverage/lcov-report/src/lib/user/payload.ts.html +0 -109
- package/coverage/lcov-report/src/lib/util/index.html +0 -116
- package/coverage/lcov-report/src/lib/util/telem.ts.html +0 -124
- package/coverage/lcov-report/src/setupspecs.ts.html +0 -133
- package/coverage/lcov.info +0 -1230
- package/coverage/prettify.css +0 -1
- package/coverage/prettify.js +0 -2
- package/coverage/sort-arrow-sprite.png +0 -0
- package/coverage/sorter.js +0 -196
- package/coverage/src/index.html +0 -116
- package/coverage/src/lib/auth.ts.html +0 -340
- package/coverage/src/lib/channel/client.ts.html +0 -604
- package/coverage/src/lib/channel/creator.ts.html +0 -304
- package/coverage/src/lib/channel/index.html +0 -176
- package/coverage/src/lib/channel/payload.ts.html +0 -139
- package/coverage/src/lib/channel/registry.ts.html +0 -202
- package/coverage/src/lib/channel/retriever.ts.html +0 -244
- package/coverage/src/lib/client.ts.html +0 -244
- package/coverage/src/lib/errors.ts.html +0 -484
- package/coverage/src/lib/index.html +0 -176
- package/coverage/src/lib/segment/client.ts.html +0 -463
- package/coverage/src/lib/segment/index.html +0 -206
- package/coverage/src/lib/segment/iterator.ts.html +0 -928
- package/coverage/src/lib/segment/payload.ts.html +0 -139
- package/coverage/src/lib/segment/splitter.ts.html +0 -181
- package/coverage/src/lib/segment/typed.ts.html +0 -307
- package/coverage/src/lib/segment/validator.ts.html +0 -331
- package/coverage/src/lib/segment/writer.ts.html +0 -727
- package/coverage/src/lib/telem.ts.html +0 -2056
- package/coverage/src/lib/transport.ts.html +0 -196
- package/coverage/src/lib/user/index.html +0 -116
- package/coverage/src/lib/user/payload.ts.html +0 -109
- package/coverage/src/lib/util/index.html +0 -116
- package/coverage/src/lib/util/telem.ts.html +0 -124
- package/coverage/src/setupspecs.ts.html +0 -133
- package/src/lib/.DS_Store +0 -0
- package/src/lib/auth.spec.ts +0 -36
- package/src/lib/auth.ts +0 -85
- package/src/lib/channel/channel.spec.ts +0 -49
- package/src/lib/channel/client.ts +0 -173
- package/src/lib/channel/creator.ts +0 -73
- package/src/lib/channel/payload.ts +0 -18
- package/src/lib/channel/registry.ts +0 -39
- package/src/lib/channel/retriever.ts +0 -53
- package/src/lib/client.ts +0 -53
- package/src/lib/errors.ts +0 -133
- package/src/lib/segment/client.ts +0 -126
- package/src/lib/segment/iterator.spec.ts +0 -78
- package/src/lib/segment/iterator.ts +0 -281
- package/src/lib/segment/payload.ts +0 -18
- package/src/lib/segment/splitter.ts +0 -32
- package/src/lib/segment/typed.ts +0 -74
- package/src/lib/segment/validator.ts +0 -82
- package/src/lib/segment/writer.spec.ts +0 -85
- package/src/lib/segment/writer.ts +0 -214
- package/src/lib/telem.spec.ts +0 -200
- package/src/lib/telem.ts +0 -657
- package/src/lib/transport.ts +0 -37
- package/src/lib/user/payload.ts +0 -8
- package/src/lib/util/telem.ts +0 -13
- package/tsconfig.module.json +0 -9
- package/yarn-error.log +0 -5756
- package/yarn.lock +0 -5936
- /package/{build/main/lib → dist/auth}/auth.spec.d.ts +0 -0
- /package/{build/main/lib → dist}/channel/channel.spec.d.ts +0 -0
- /package/{build/main/lib/segment/iterator.spec.d.ts → dist/connection/connection.spec.d.ts} +0 -0
- /package/{build/main/lib/segment/writer.spec.d.ts → dist/control/state.spec.d.ts} +0 -0
- /package/{build/main/lib/telem.spec.d.ts → dist/framer/frame.spec.d.ts} +0 -0
- /package/{build/module/lib/segment → dist/framer}/iterator.spec.d.ts +0 -0
- /package/{build/module/lib/auth.spec.d.ts → dist/framer/streamer.spec.d.ts} +0 -0
- /package/{build/module/lib/segment → dist/framer}/writer.spec.d.ts +0 -0
- /package/{build/module/lib/channel/channel.spec.d.ts → dist/label/label.spec.d.ts} +0 -0
- /package/{build/module/lib/telem.spec.d.ts → dist/ontology/group/group.spec.d.ts} +0 -0
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
// Copyright 2023 Synnax Labs, Inc.
|
|
2
|
+
//
|
|
3
|
+
// Use of this software is governed by the Business Source License included in the file
|
|
4
|
+
// licenses/BSL.txt.
|
|
5
|
+
//
|
|
6
|
+
// As of the Change Date specified in that file, in accordance with the Business Source
|
|
7
|
+
// License, use of this software will be governed by the Apache License, Version 2.0,
|
|
8
|
+
// included in the file licenses/APL.txt.
|
|
9
|
+
|
|
10
|
+
import type { UnaryClient } from "@synnaxlabs/freighter";
|
|
11
|
+
import { toArray } from "@synnaxlabs/x";
|
|
12
|
+
import { z } from "zod";
|
|
13
|
+
|
|
14
|
+
import {
|
|
15
|
+
type Key,
|
|
16
|
+
type KeyOrName,
|
|
17
|
+
type Keys,
|
|
18
|
+
type KeysOrNames,
|
|
19
|
+
type Name,
|
|
20
|
+
type Names,
|
|
21
|
+
type Params,
|
|
22
|
+
type Payload,
|
|
23
|
+
payload,
|
|
24
|
+
} from "@/channel/payload";
|
|
25
|
+
import { QueryError } from "@/errors";
|
|
26
|
+
|
|
27
|
+
const reqZ = z.object({
|
|
28
|
+
leaseholder: z.number().optional(),
|
|
29
|
+
keys: z.number().array().optional(),
|
|
30
|
+
names: z.string().array().optional(),
|
|
31
|
+
search: z.string().optional(),
|
|
32
|
+
searchRangeKey: z.string().optional(),
|
|
33
|
+
limit: z.number().optional(),
|
|
34
|
+
offset: z.number().optional(),
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
type Request = z.infer<typeof reqZ>;
|
|
38
|
+
|
|
39
|
+
const resZ = z.object({
|
|
40
|
+
channels: payload.array(),
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
export interface Retriever {
|
|
44
|
+
retrieve: (channels: Params) => Promise<Payload[]>;
|
|
45
|
+
search: (term: string, rangeKey?: string) => Promise<Payload[]>;
|
|
46
|
+
page: (offset: number, limit: number) => Promise<Payload[]>;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export class ClusterRetriever implements Retriever {
|
|
50
|
+
private static readonly ENDPOINT = "/channel/retrieve";
|
|
51
|
+
private readonly client: UnaryClient;
|
|
52
|
+
|
|
53
|
+
constructor(client: UnaryClient) {
|
|
54
|
+
this.client = client;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
async search(term: string, rangeKey?: string): Promise<Payload[]> {
|
|
58
|
+
return await this.execute({ search: term, searchRangeKey: rangeKey });
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
async retrieve(channels: Params): Promise<Payload[]> {
|
|
62
|
+
const { variant, normalized } = analyzeParams(channels);
|
|
63
|
+
return await this.execute({ [variant]: normalized });
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
async page(offset: number, limit: number): Promise<Payload[]> {
|
|
67
|
+
return await this.execute({ offset, limit });
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
private async execute(request: Request): Promise<Payload[]> {
|
|
71
|
+
const [res, err] = await this.client.send(ClusterRetriever.ENDPOINT, request, resZ);
|
|
72
|
+
if (err != null) throw err;
|
|
73
|
+
return res.channels;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export class CacheRetriever implements Retriever {
|
|
78
|
+
private readonly cache: Map<number, Payload>;
|
|
79
|
+
private readonly namesToKeys: Map<string, number>;
|
|
80
|
+
private readonly wrapped: Retriever;
|
|
81
|
+
|
|
82
|
+
constructor(wrapped: Retriever) {
|
|
83
|
+
this.cache = new Map();
|
|
84
|
+
this.namesToKeys = new Map();
|
|
85
|
+
this.wrapped = wrapped;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
async search(term: string, searchRangeKey?: string): Promise<Payload[]> {
|
|
89
|
+
return await this.wrapped.search(term, searchRangeKey);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
async page(offset: number, limit: number): Promise<Payload[]> {
|
|
93
|
+
return await this.wrapped.page(offset, limit);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
async retrieve(channels: Params): Promise<Payload[]> {
|
|
97
|
+
const { normalized } = analyzeParams(channels);
|
|
98
|
+
const results: Payload[] = [];
|
|
99
|
+
const toFetch: KeysOrNames = [];
|
|
100
|
+
normalized.forEach((keyOrName) => {
|
|
101
|
+
const c = this.getFromCache(keyOrName);
|
|
102
|
+
if (c != null) results.push(c);
|
|
103
|
+
else toFetch.push(keyOrName as never);
|
|
104
|
+
});
|
|
105
|
+
if (toFetch.length === 0) return results;
|
|
106
|
+
const fetched = await this.wrapped.retrieve(toFetch);
|
|
107
|
+
this.updateCache(fetched);
|
|
108
|
+
return results.concat(fetched);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
private updateCache(channels: Payload[]): void {
|
|
112
|
+
channels.forEach((channel) => {
|
|
113
|
+
this.cache.set(channel.key, channel);
|
|
114
|
+
this.namesToKeys.set(channel.name, channel.key);
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
private getFromCache(channel: KeyOrName): Payload | undefined {
|
|
119
|
+
const key = typeof channel === "number" ? channel : this.namesToKeys.get(channel);
|
|
120
|
+
if (key == null) return undefined;
|
|
121
|
+
return this.cache.get(key);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
export type ParamAnalysisResult =
|
|
126
|
+
| {
|
|
127
|
+
single: true;
|
|
128
|
+
variant: "names";
|
|
129
|
+
normalized: Names;
|
|
130
|
+
actual: Name;
|
|
131
|
+
}
|
|
132
|
+
| {
|
|
133
|
+
single: true;
|
|
134
|
+
variant: "keys";
|
|
135
|
+
normalized: Keys;
|
|
136
|
+
actual: Key;
|
|
137
|
+
}
|
|
138
|
+
| {
|
|
139
|
+
single: false;
|
|
140
|
+
variant: "keys";
|
|
141
|
+
normalized: Keys;
|
|
142
|
+
actual: Keys;
|
|
143
|
+
}
|
|
144
|
+
| {
|
|
145
|
+
single: false;
|
|
146
|
+
variant: "names";
|
|
147
|
+
normalized: Names;
|
|
148
|
+
actual: Names;
|
|
149
|
+
};
|
|
150
|
+
|
|
151
|
+
export const analyzeParams = (channels: Params): ParamAnalysisResult => {
|
|
152
|
+
const normal = toArray(channels) as KeysOrNames;
|
|
153
|
+
if (normal.length === 0) throw new QueryError("No channels provided");
|
|
154
|
+
return {
|
|
155
|
+
single: !Array.isArray(channels),
|
|
156
|
+
variant: typeof normal[0] === "number" ? "keys" : "names",
|
|
157
|
+
normalized: normal,
|
|
158
|
+
actual: channels,
|
|
159
|
+
} as const as ParamAnalysisResult;
|
|
160
|
+
};
|
package/src/client.ts
ADDED
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
// Copyright 2023 Synnax Labs, Inc.
|
|
2
|
+
//
|
|
3
|
+
// Use of this software is governed by the Business Source License included in the file
|
|
4
|
+
// licenses/BSL.txt.
|
|
5
|
+
//
|
|
6
|
+
// As of the Change Date specified in that file, in accordance with the Business Source
|
|
7
|
+
// License, use of this software will be governed by the Apache License, Version 2.0,
|
|
8
|
+
// included in the file licenses/APL.txt.
|
|
9
|
+
|
|
10
|
+
import { TimeSpan, TimeStamp, URL } from "@synnaxlabs/x";
|
|
11
|
+
import { z } from "zod";
|
|
12
|
+
|
|
13
|
+
import { auth } from "@/auth";
|
|
14
|
+
import { channel } from "@/channel";
|
|
15
|
+
import { connection } from "@/connection";
|
|
16
|
+
import { errorsMiddleware } from "@/errors";
|
|
17
|
+
import { framer } from "@/framer";
|
|
18
|
+
import { ontology } from "@/ontology";
|
|
19
|
+
import { ranger } from "@/ranger";
|
|
20
|
+
import { Transport } from "@/transport";
|
|
21
|
+
import { workspace } from "@/workspace";
|
|
22
|
+
|
|
23
|
+
export const synnaxPropsZ = z.object({
|
|
24
|
+
host: z.string().min(1),
|
|
25
|
+
port: z.number().or(z.string()),
|
|
26
|
+
username: z.string().optional(),
|
|
27
|
+
password: z.string().optional(),
|
|
28
|
+
connectivityPollFrequency: TimeSpan.z.default(TimeSpan.seconds(30)),
|
|
29
|
+
secure: z.boolean().optional().default(false),
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
export type SynnaxProps = z.input<typeof synnaxPropsZ>;
|
|
33
|
+
export type ParsedSynnaxProps = z.output<typeof synnaxPropsZ>;
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Client to perform operations against a Synnax cluster.
|
|
37
|
+
*
|
|
38
|
+
* @property channel - Channel client for creating and retrieving channels.
|
|
39
|
+
* @property data - Data client for reading and writing telemetry.
|
|
40
|
+
* @property connectivity - Client for retrieving connectivity information.
|
|
41
|
+
* @property ontology - Client for querying the cluster's ontology.
|
|
42
|
+
*/
|
|
43
|
+
// eslint-disable-next-line import/no-default-export
|
|
44
|
+
export default class Synnax {
|
|
45
|
+
private readonly transport: Transport;
|
|
46
|
+
readonly createdAt: TimeStamp;
|
|
47
|
+
readonly telem: framer.Client;
|
|
48
|
+
readonly ranges: ranger.Client;
|
|
49
|
+
readonly channels: channel.Client;
|
|
50
|
+
readonly auth: auth.Client | undefined;
|
|
51
|
+
readonly connectivity: connection.Checker;
|
|
52
|
+
readonly ontology: ontology.Client;
|
|
53
|
+
readonly props: ParsedSynnaxProps;
|
|
54
|
+
readonly workspaces: workspace.Client;
|
|
55
|
+
static readonly connectivity = connection.Checker;
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* @param props.host - Hostname of a node in the cluster.
|
|
59
|
+
* @param props.port - Port of the node in the cluster.
|
|
60
|
+
* @param props.username - Username for authentication. Not required if the
|
|
61
|
+
* cluster is insecure.
|
|
62
|
+
* @param props.password - Password for authentication. Not required if the
|
|
63
|
+
* cluster is insecure.
|
|
64
|
+
* @param props.connectivityPollFrequency - Frequency at which to poll the
|
|
65
|
+
* cluster for connectivity information. Defaults to 5 seconds.
|
|
66
|
+
* @param props.secure - Whether to connect to the cluster using TLS. The cluster
|
|
67
|
+
* must be configured to support TLS. Defaults to false.
|
|
68
|
+
*
|
|
69
|
+
* A Synnax client must be closed when it is no longer needed. This will stop
|
|
70
|
+
* the client from polling the cluster for connectivity information.
|
|
71
|
+
*/
|
|
72
|
+
constructor(props: SynnaxProps) {
|
|
73
|
+
this.createdAt = TimeStamp.now();
|
|
74
|
+
this.props = synnaxPropsZ.parse(props);
|
|
75
|
+
const { host, port, username, password, connectivityPollFrequency, secure } =
|
|
76
|
+
this.props;
|
|
77
|
+
this.transport = new Transport(new URL({ host, port: Number(port) }), secure);
|
|
78
|
+
this.transport.use(errorsMiddleware);
|
|
79
|
+
if (username != null && password != null) {
|
|
80
|
+
this.auth = new auth.Client(this.transport.unary, {
|
|
81
|
+
username,
|
|
82
|
+
password,
|
|
83
|
+
});
|
|
84
|
+
this.transport.use(this.auth.middleware());
|
|
85
|
+
}
|
|
86
|
+
const chRetriever = new channel.CacheRetriever(
|
|
87
|
+
new channel.ClusterRetriever(this.transport.unary),
|
|
88
|
+
);
|
|
89
|
+
const chCreator = new channel.Creator(this.transport.unary);
|
|
90
|
+
this.telem = new framer.Client(this.transport.stream, chRetriever);
|
|
91
|
+
this.channels = new channel.Client(this.telem, chRetriever, chCreator);
|
|
92
|
+
this.connectivity = new connection.Checker(
|
|
93
|
+
this.transport.unary,
|
|
94
|
+
connectivityPollFrequency,
|
|
95
|
+
);
|
|
96
|
+
this.ontology = new ontology.Client(this.transport.unary, this.telem);
|
|
97
|
+
const rangeRetriever = new ranger.Retriever(this.transport.unary);
|
|
98
|
+
const rangeWriter = new ranger.Writer(this.transport.unary);
|
|
99
|
+
this.ranges = new ranger.Client(
|
|
100
|
+
this.telem,
|
|
101
|
+
rangeRetriever,
|
|
102
|
+
rangeWriter,
|
|
103
|
+
this.transport.unary,
|
|
104
|
+
chRetriever,
|
|
105
|
+
);
|
|
106
|
+
this.workspaces = new workspace.Client(this.transport.unary);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
close(): void {
|
|
110
|
+
this.connectivity.stopChecking();
|
|
111
|
+
}
|
|
112
|
+
}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
// Copyright 2023 Synnax Labs, Inc.
|
|
2
|
+
//
|
|
3
|
+
// Use of this software is governed by the Business Source License included in the file
|
|
4
|
+
// licenses/BSL.txt.
|
|
5
|
+
//
|
|
6
|
+
// As of the Change Date specified in that file, in accordance with the Business Source
|
|
7
|
+
// License, use of this software will be governed by the Apache License, Version 2.0,
|
|
8
|
+
// included in the file licenses/APL.txt.
|
|
9
|
+
|
|
10
|
+
import type { UnaryClient } from "@synnaxlabs/freighter";
|
|
11
|
+
import { TimeSpan } from "@synnaxlabs/x";
|
|
12
|
+
import { z } from "zod";
|
|
13
|
+
|
|
14
|
+
const STATUSES = ["disconnected", "connecting", "connected", "failed"] as const;
|
|
15
|
+
export const status = z.enum(STATUSES);
|
|
16
|
+
export type Status = z.infer<typeof status>;
|
|
17
|
+
|
|
18
|
+
export const state = z.object({
|
|
19
|
+
status,
|
|
20
|
+
error: z.instanceof(Error).optional(),
|
|
21
|
+
message: z.string().optional(),
|
|
22
|
+
clusterKey: z.string(),
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
export type State = z.infer<typeof state>;
|
|
26
|
+
|
|
27
|
+
const responseZ = z.object({
|
|
28
|
+
clusterKey: z.string(),
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
const DEFAULT: State = {
|
|
32
|
+
clusterKey: "",
|
|
33
|
+
status: "disconnected",
|
|
34
|
+
error: undefined,
|
|
35
|
+
message: "Disconnected",
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
/** Polls a synnax cluster for connectivity information. */
|
|
39
|
+
export class Checker {
|
|
40
|
+
private static readonly ENDPOINT = "/connectivity/check";
|
|
41
|
+
static readonly DEFAULT: State = DEFAULT;
|
|
42
|
+
private readonly _state: State;
|
|
43
|
+
private readonly pollFrequency = TimeSpan.seconds(30);
|
|
44
|
+
private readonly client: UnaryClient;
|
|
45
|
+
private interval?: NodeJS.Timeout;
|
|
46
|
+
private readonly onChangeHandlers: Array<(state: State) => void> = [];
|
|
47
|
+
static readonly connectionStateZ = state;
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* @param client - The transport client to use for connectivity checks.
|
|
51
|
+
* @param pollFreq - The frequency at which to poll the cluster for
|
|
52
|
+
* connectivity information.
|
|
53
|
+
*/
|
|
54
|
+
constructor(client: UnaryClient, pollFreq: TimeSpan = TimeSpan.seconds(30)) {
|
|
55
|
+
this._state = { ...DEFAULT };
|
|
56
|
+
this.client = client;
|
|
57
|
+
this.pollFrequency = pollFreq;
|
|
58
|
+
void this.check();
|
|
59
|
+
this.startChecking();
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/** Stops the connectivity client from polling the cluster for connectivity */
|
|
63
|
+
stopChecking(): void {
|
|
64
|
+
if (this.interval != null) clearInterval(this.interval);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Executes a connectivity check and updates the client status and error, as
|
|
69
|
+
* well as calling any registered change handlers.
|
|
70
|
+
*/
|
|
71
|
+
async check(): Promise<State> {
|
|
72
|
+
const prevStatus = this._state.status;
|
|
73
|
+
try {
|
|
74
|
+
const [res, err] = await this.client.send(Checker.ENDPOINT, null, responseZ);
|
|
75
|
+
if (err != null) throw err;
|
|
76
|
+
this._state.status = "connected";
|
|
77
|
+
this._state.message = `Connected to cluster ${res.clusterKey}`;
|
|
78
|
+
this._state.clusterKey = res.clusterKey;
|
|
79
|
+
} catch (err) {
|
|
80
|
+
this._state.status = "failed";
|
|
81
|
+
this._state.error = err as Error;
|
|
82
|
+
this._state.message = this.state.error?.message;
|
|
83
|
+
}
|
|
84
|
+
if (this.onChangeHandlers.length > 0 && prevStatus !== this._state.status)
|
|
85
|
+
this.onChangeHandlers.forEach((handler) => handler(this.state));
|
|
86
|
+
return this.state;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/** @returns a copy of the current client state. */
|
|
90
|
+
get state(): State {
|
|
91
|
+
return { ...this._state };
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/** @param callback - The function to call when the client status changes. */
|
|
95
|
+
onChange(callback: (state: State) => void): void {
|
|
96
|
+
this.onChangeHandlers.push(callback);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
private startChecking(): void {
|
|
100
|
+
this.interval = setInterval(() => {
|
|
101
|
+
void this.check();
|
|
102
|
+
}, this.pollFrequency.milliseconds);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
// Copyright 2023 Synnax Labs, Inc.
|
|
2
|
+
//
|
|
3
|
+
// Use of this software is governed by the Business Source License included in the file
|
|
4
|
+
// licenses/BSL.txt.
|
|
5
|
+
//
|
|
6
|
+
// As of the Change Date specified in that file, in accordance with the Business Source
|
|
7
|
+
// License, use of this software will be governed by the Apache License, Version 2.0,
|
|
8
|
+
// included in the file licenses/APL.txt.
|
|
9
|
+
|
|
10
|
+
import { URL } from "@synnaxlabs/x";
|
|
11
|
+
import { describe, expect, it } from "vitest";
|
|
12
|
+
|
|
13
|
+
import { auth } from "@/auth";
|
|
14
|
+
import { Checker } from "@/connection/checker";
|
|
15
|
+
import { HOST, PORT } from "@/setupspecs";
|
|
16
|
+
import { Transport } from "@/transport";
|
|
17
|
+
|
|
18
|
+
describe("connectivity", () => {
|
|
19
|
+
it("should connect to the server", async () => {
|
|
20
|
+
const transport = new Transport(new URL({ host: HOST, port: PORT }));
|
|
21
|
+
const client = new auth.Client(transport.unary, {
|
|
22
|
+
username: "synnax",
|
|
23
|
+
password: "seldon",
|
|
24
|
+
});
|
|
25
|
+
await client.authenticating;
|
|
26
|
+
expect(client.authenticated).toBeTruthy();
|
|
27
|
+
|
|
28
|
+
transport.use(client.middleware());
|
|
29
|
+
|
|
30
|
+
const connectivity = new Checker(transport.unary);
|
|
31
|
+
|
|
32
|
+
await connectivity.check();
|
|
33
|
+
expect(connectivity.state.status).toEqual("connected");
|
|
34
|
+
});
|
|
35
|
+
});
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
// Copyright 2023 Synnax Labs, Inc.
|
|
2
|
+
//
|
|
3
|
+
// Use of this software is governed by the Business Source License included in the file
|
|
4
|
+
// licenses/BSL.txt.
|
|
5
|
+
//
|
|
6
|
+
// As of the Change Date specified in that file, in accordance with the Business Source
|
|
7
|
+
// License, use of this software will be governed by the Apache License, Version 2.0,
|
|
8
|
+
// included in the file licenses/APL.txt.
|
|
9
|
+
|
|
10
|
+
export * as connection from "@/connection/checker";
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
// Copyright 2023 Synnax Labs, Inc.
|
|
2
|
+
//
|
|
3
|
+
// Use of this software is governed by the Business Source License included in the file
|
|
4
|
+
// licenses/BSL.txt.
|
|
5
|
+
//
|
|
6
|
+
// As of the Change Date specified in that file, in accordance with the Business Source
|
|
7
|
+
// License, use of this software will be governed by the Apache License, Version 2.0,
|
|
8
|
+
// included in the file licenses/APL.txt.
|
|
9
|
+
|
|
10
|
+
import { z } from "zod";
|
|
11
|
+
|
|
12
|
+
export class Authority extends Number {
|
|
13
|
+
static readonly ABSOLUTE = 255;
|
|
14
|
+
static readonly DEFAULT = 1;
|
|
15
|
+
|
|
16
|
+
static readonly z = z.union([
|
|
17
|
+
z.instanceof(Authority),
|
|
18
|
+
z
|
|
19
|
+
.number()
|
|
20
|
+
.int()
|
|
21
|
+
.min(0)
|
|
22
|
+
.max(255)
|
|
23
|
+
.transform((n) => new Authority(n)),
|
|
24
|
+
]);
|
|
25
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
// Copyright 2023 Synnax Labs, Inc.
|
|
2
|
+
//
|
|
3
|
+
// Use of this software is governed by the Business Source License included in the file
|
|
4
|
+
// licenses/BSL.txt.
|
|
5
|
+
//
|
|
6
|
+
// As of the Change Date specified in that file, in accordance with the Business Source
|
|
7
|
+
// License, use of this software will be governed by the Apache License, Version 2.0,
|
|
8
|
+
// included in the file licenses/APL.txt.
|
|
9
|
+
|
|
10
|
+
export * from "@/control/authority";
|
|
11
|
+
export * from "@/control/state";
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
// Copyright 2023 Synnax Labs, Inc.
|
|
2
|
+
//
|
|
3
|
+
// Use of this software is governed by the Business Source License included in the file
|
|
4
|
+
// licenses/BSL.txt.
|
|
5
|
+
//
|
|
6
|
+
// As of the Change Date specified in that file, in accordance with the Business Source
|
|
7
|
+
// License, use of this software will be governed by the Apache License, Version 2.0,
|
|
8
|
+
// included in the file licenses/APL.txt.
|
|
9
|
+
|
|
10
|
+
export * as control from "@/control/external";
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
// Copyright 2023 Synnax Labs, Inc.
|
|
2
|
+
//
|
|
3
|
+
// Use of this software is governed by the Business Source License included in the file
|
|
4
|
+
// licenses/BSL.txt.
|
|
5
|
+
//
|
|
6
|
+
// As of the Change Date specified in that file, in accordance with the Business Source
|
|
7
|
+
// License, use of this software will be governed by the Apache License, Version 2.0,
|
|
8
|
+
// included in the file licenses/APL.txt.
|
|
9
|
+
|
|
10
|
+
import { describe, expect, it } from "vitest";
|
|
11
|
+
|
|
12
|
+
import { control } from "@/control";
|
|
13
|
+
import { newClient } from "@/setupspecs";
|
|
14
|
+
|
|
15
|
+
const client = newClient();
|
|
16
|
+
|
|
17
|
+
describe("state", () => {
|
|
18
|
+
it("should receive the initial control state from the cluster", async () => {
|
|
19
|
+
const s = await control.StateTracker.open(client.telem);
|
|
20
|
+
await new Promise((resolve) => setTimeout(resolve, 50));
|
|
21
|
+
expect(s.states.size).toBeGreaterThan(0);
|
|
22
|
+
s.close();
|
|
23
|
+
});
|
|
24
|
+
});
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
// Copyright 2023 Synnax Labs, Inc.
|
|
2
|
+
//
|
|
3
|
+
// Use of this software is governed by the Business Source License included in the file
|
|
4
|
+
// licenses/BSL.txt.
|
|
5
|
+
//
|
|
6
|
+
// As of the Change Date specified in that file, in accordance with the Business Source
|
|
7
|
+
// License, use of this software will be governed by the Apache License, Version 2.0,
|
|
8
|
+
// included in the file licenses/APL.txt.
|
|
9
|
+
|
|
10
|
+
import { type Destructor, binary, observe } from "@synnaxlabs/x";
|
|
11
|
+
import { z } from "zod";
|
|
12
|
+
|
|
13
|
+
import { type Key as ChannelKey } from "@/channel/payload";
|
|
14
|
+
import { type Authority } from "@/control/authority";
|
|
15
|
+
import { type Client as FrameClient } from "@/framer/client";
|
|
16
|
+
import { type Streamer as FrameStreamer } from "@/framer/streamer";
|
|
17
|
+
|
|
18
|
+
export const subjectZ = z.object({
|
|
19
|
+
name: z.string(),
|
|
20
|
+
key: z.string(),
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
export interface Subject {
|
|
24
|
+
name: string;
|
|
25
|
+
key: string;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export interface State {
|
|
29
|
+
subject: Subject;
|
|
30
|
+
resource: ChannelKey;
|
|
31
|
+
authority: Authority;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
interface Release {
|
|
35
|
+
from: State;
|
|
36
|
+
to?: null;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
interface Acquire {
|
|
40
|
+
from?: null;
|
|
41
|
+
to: State;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export type Transfer =
|
|
45
|
+
| {
|
|
46
|
+
from: State;
|
|
47
|
+
to: State;
|
|
48
|
+
}
|
|
49
|
+
| Release
|
|
50
|
+
| Acquire;
|
|
51
|
+
|
|
52
|
+
export const transferString = (t: Transfer): string => {
|
|
53
|
+
if (t.to == null) return `${t.from?.resource} - ${t.from?.subject.name} -> released`;
|
|
54
|
+
if (t.from == null)
|
|
55
|
+
return `${t.to.resource} - released -> ${
|
|
56
|
+
t.to.subject.name
|
|
57
|
+
} (${t.to.authority.toString()})`;
|
|
58
|
+
return `${t.to.resource} - ${t.from.subject.name} -> ${
|
|
59
|
+
t.to.subject.name
|
|
60
|
+
} (${t.to.authority.toString()})`;
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
interface Update {
|
|
64
|
+
transfers: Transfer[];
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export class StateTracker implements observe.Observable<Transfer[]> {
|
|
68
|
+
readonly states: Map<ChannelKey, State>;
|
|
69
|
+
private readonly streamer: FrameStreamer;
|
|
70
|
+
private readonly ecd: binary.EncoderDecoder;
|
|
71
|
+
private readonly observer: observe.Observer<Transfer[]>;
|
|
72
|
+
private readonly closePromise: Promise<void>;
|
|
73
|
+
|
|
74
|
+
private constructor(streamer: FrameStreamer) {
|
|
75
|
+
this.states = new Map();
|
|
76
|
+
this.ecd = new binary.JSONEncoderDecoder();
|
|
77
|
+
this.observer = new observe.Observer<Transfer[]>();
|
|
78
|
+
this.streamer = streamer;
|
|
79
|
+
this.closePromise = this.stream();
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
subjects(): Subject[] {
|
|
83
|
+
const subjects = new Map<string, Subject>();
|
|
84
|
+
this.states.forEach((s) => subjects.set(s.subject.key, s.subject));
|
|
85
|
+
return Array.from(subjects.values());
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
onChange(handler: observe.Handler<Transfer[]>): Destructor {
|
|
89
|
+
return this.observer.onChange(handler);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
async close(): Promise<void> {
|
|
93
|
+
this.streamer.close();
|
|
94
|
+
await this.closePromise;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
static async open(client: FrameClient): Promise<StateTracker> {
|
|
98
|
+
const streamer = await client.newStreamer("sy_node_1_control");
|
|
99
|
+
return new StateTracker(streamer);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
private async stream(): Promise<void> {
|
|
103
|
+
for await (const frame of this.streamer) {
|
|
104
|
+
const update: Update = this.ecd.decode(frame.series[0].buffer);
|
|
105
|
+
this.merge(update);
|
|
106
|
+
this.observer.notify(update.transfers);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
private merge(update: Update): void {
|
|
111
|
+
update.transfers.forEach((t) => {
|
|
112
|
+
if (t.from == null && t.to == null) console.warn("Invalid transfer: ", t);
|
|
113
|
+
if (t.to == null) this.states.delete(t.from.resource);
|
|
114
|
+
else this.states.set(t.to.resource, t.to);
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
}
|