@adcops/autocore-react 3.1.1 → 3.3.2
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/additional-docs/react_performance_notes.md +94 -0
- package/dist/components/AutoCoreDevPanel.d.ts.map +1 -1
- package/dist/components/AutoCoreDevPanel.js +1 -1
- package/dist/components/FileList.d.ts.map +1 -1
- package/dist/components/FileList.js +1 -1
- package/dist/components/FileSelect.d.ts.map +1 -1
- package/dist/components/FileSelect.js +1 -1
- package/dist/core/AutoCoreTagContext.d.ts +59 -185
- package/dist/core/AutoCoreTagContext.d.ts.map +1 -1
- package/dist/core/AutoCoreTagContext.js +1 -1
- package/dist/core/AutoCoreTagTypes.d.ts +127 -6
- package/dist/core/AutoCoreTagTypes.d.ts.map +1 -1
- package/dist/core/CoreStreamTypes.d.ts +345 -0
- package/dist/core/CoreStreamTypes.d.ts.map +1 -0
- package/dist/core/CoreStreamTypes.js +1 -0
- package/dist/core/EventEmitterContext.d.ts +91 -473
- package/dist/core/EventEmitterContext.d.ts.map +1 -1
- package/dist/core/EventEmitterContext.js +1 -1
- package/dist/hooks/adsHooks.d.ts.map +1 -1
- package/dist/hooks/adsHooks.js +1 -1
- package/dist/hooks/commandHooks.d.ts +3 -3
- package/dist/hooks/commandHooks.d.ts.map +1 -1
- package/dist/hooks/commandHooks.js +1 -1
- package/dist/hooks/useAutoCoreTag.js +1 -1
- package/dist/hub/CommandMessage.d.ts +18 -9
- package/dist/hub/CommandMessage.d.ts.map +1 -1
- package/dist/hub/CommandMessage.js +1 -1
- package/dist/hub/DebugPanel.d.ts +31 -0
- package/dist/hub/DebugPanel.d.ts.map +1 -0
- package/dist/hub/DebugPanel.js +1 -0
- package/dist/hub/HubBase.d.ts +83 -129
- package/dist/hub/HubBase.d.ts.map +1 -1
- package/dist/hub/HubBase.js +1 -1
- package/dist/hub/HubSimulate.d.ts +41 -8
- package/dist/hub/HubSimulate.d.ts.map +1 -1
- package/dist/hub/HubSimulate.js +1 -1
- package/dist/hub/HubTauri.d.ts +24 -60
- package/dist/hub/HubTauri.d.ts.map +1 -1
- package/dist/hub/HubTauri.js +1 -1
- package/dist/hub/HubWebSocket.d.ts +33 -17
- package/dist/hub/HubWebSocket.d.ts.map +1 -1
- package/dist/hub/HubWebSocket.js +1 -1
- package/dist/hub/debug.d.ts +23 -0
- package/dist/hub/debug.d.ts.map +1 -0
- package/dist/hub/debug.js +1 -0
- package/dist/hub/index.d.ts +19 -4
- package/dist/hub/index.d.ts.map +1 -1
- package/dist/hub/index.js +1 -1
- package/package.json +4 -4
- package/src/components/AutoCoreDevPanel.tsx +14 -11
- package/src/components/FileList.tsx +5 -4
- package/src/components/FileSelect.tsx +2 -1
- package/src/core/ActionMode.ts +1 -1
- package/src/core/AutoCoreTagContext.tsx +247 -330
- package/src/core/AutoCoreTagTypes.ts +236 -104
- package/src/core/CoreStreamTypes.ts +512 -0
- package/src/core/EventEmitterContext.tsx +182 -520
- package/src/core/IndicatorButtonState.ts +1 -1
- package/src/core/hoc.tsx +1 -1
- package/src/hooks/adsHooks.tsx +21 -22
- package/src/hooks/commandHooks.tsx +23 -19
- package/src/hooks/index.ts +1 -1
- package/src/hooks/useAutoCoreTag.ts +2 -2
- package/src/hooks/useScaledValue.tsx +1 -1
- package/src/hub/CommandMessage.ts +71 -19
- package/src/hub/DebugPanel.ts +280 -0
- package/src/hub/HubBase.ts +147 -223
- package/src/hub/HubSimulate.ts +93 -24
- package/src/hub/HubTauri.ts +87 -96
- package/src/hub/HubWebSocket.ts +118 -140
- package/src/hub/debug.ts +211 -0
- package/src/hub/index.ts +49 -39
- package/docs/.nojekyll +0 -1
- package/docs/assets/hierarchy.js +0 -1
- package/docs/assets/highlight.css +0 -134
- package/docs/assets/icons.js +0 -18
- package/docs/assets/icons.svg +0 -1
- package/docs/assets/main.js +0 -60
- package/docs/assets/navigation.js +0 -1
- package/docs/assets/search.js +0 -1
- package/docs/assets/style.css +0 -1633
- package/docs/classes/components_CodeEditor.CodeEditor.html +0 -135
- package/docs/classes/components_Indicator.Indicator.html +0 -122
- package/docs/classes/components_IndicatorRect.IndicatorRect.html +0 -121
- package/docs/classes/components_JogPanel.JogPanel.html +0 -136
- package/docs/classes/components_Lamp.Lamp.html +0 -122
- package/docs/classes/components_OskDialog.OskDialog.html +0 -125
- package/docs/classes/components_TextInput.TextInput.html +0 -125
- package/docs/classes/components_ValueDisplay.ValueDisplay.html +0 -148
- package/docs/classes/components_ValueIndicator.ValueIndicator.html +0 -126
- package/docs/classes/core_ValueSimulator.ValueSimulator.html +0 -51
- package/docs/classes/hub_HubBase.HubBase.html +0 -106
- package/docs/classes/hub_HubSimulate.HubSimulate.html +0 -75
- package/docs/classes/hub_HubTauri.HubTauri.html +0 -93
- package/docs/classes/hub_HubWebSocket.HubWebSocket.html +0 -112
- package/docs/documents/core_AutoCoreTagContext.AutoCoreTagContext.html +0 -148
- package/docs/enums/components_JogPanel.JogDistanceAction.html +0 -5
- package/docs/enums/components_JogPanel.JogPanelAction.html +0 -18
- package/docs/enums/components_JogPanel.JogSpeedAction.html +0 -5
- package/docs/enums/core_ActionMode.ActionMode.html +0 -6
- package/docs/enums/core_IndicatorColor.IndicatorColor.html +0 -23
- package/docs/functions/assets.BlocklyLogo.html +0 -1
- package/docs/functions/assets.Distance.html +0 -1
- package/docs/functions/assets.JogLong.html +0 -1
- package/docs/functions/assets.JogMedium.html +0 -1
- package/docs/functions/assets.JogShort.html +0 -1
- package/docs/functions/assets.PythonLogo.html +0 -1
- package/docs/functions/assets.Rotation3D.html +0 -1
- package/docs/functions/assets.RotationCcw.html +0 -1
- package/docs/functions/assets.RotationCcwA.html +0 -1
- package/docs/functions/assets.RotationCcwB.html +0 -1
- package/docs/functions/assets.RotationCcwC.html +0 -1
- package/docs/functions/assets.RotationCw.html +0 -1
- package/docs/functions/assets.RotationCwA.html +0 -1
- package/docs/functions/assets.RotationCwB.html +0 -1
- package/docs/functions/assets.RotationCwC.html +0 -1
- package/docs/functions/assets.Run.html +0 -1
- package/docs/functions/assets.Speed.html +0 -1
- package/docs/functions/assets.SpeedFast.html +0 -1
- package/docs/functions/assets.SpeedMedium.html +0 -1
- package/docs/functions/assets.SpeedNone.html +0 -1
- package/docs/functions/assets.SpeedSlow.html +0 -1
- package/docs/functions/assets.Walk.html +0 -1
- package/docs/functions/components_BlocklyEditor.createCustomToolbox.html +0 -6
- package/docs/functions/core_UniqueId.UniqueId.html +0 -9
- package/docs/functions/core_hoc.hocAddSubscription.html +0 -6
- package/docs/functions/hooks_adsHooks.useAdsRegisterSymbols.html +0 -16
- package/docs/functions/hooks_adsHooks.useAdsTapValue.html +0 -8
- package/docs/functions/hooks_adsHooks.useAdsWriteScaledValue.html +0 -18
- package/docs/functions/hooks_adsHooks.useAdsWriteValue.html +0 -9
- package/docs/functions/hooks_commandHooks.useRegisterSymbols.html +0 -16
- package/docs/functions/hooks_commandHooks.useTapValue.html +0 -10
- package/docs/functions/hooks_commandHooks.useWriteScaledValue.html +0 -18
- package/docs/functions/hooks_commandHooks.useWriteValue.html +0 -11
- package/docs/functions/hooks_useAutoCoreTag.ts.makeAutoCoreTagHooks.html +0 -12
- package/docs/functions/hooks_useScaledValue.useScaledValue.html +0 -18
- package/docs/functions/hub.createHub.html +0 -3
- package/docs/hierarchy.html +0 -1
- package/docs/index.html +0 -148
- package/docs/interfaces/components_IndicatorButton.IndicatorButtonProps.html +0 -654
- package/docs/interfaces/components_IndicatorRect.IndicatorRectProps.html +0 -37
- package/docs/interfaces/components_JogPanel.JogPanelButtonDefinition.html +0 -5
- package/docs/interfaces/components_ToggleGroup.ToggleGroupProps.html +0 -644
- package/docs/interfaces/core_AutoCoreTagTypes.BaseContextValue.html +0 -12
- package/docs/interfaces/core_AutoCoreTagTypes.ScaleConfig.html +0 -13
- package/docs/interfaces/core_EventEmitterContext.Action.html +0 -8
- package/docs/interfaces/core_EventEmitterContext.EventEmitterContextType.html +0 -33
- package/docs/interfaces/core_EventEmitterContext.State.html +0 -8
- package/docs/interfaces/core_EventEmitterContext.Subscription.html +0 -6
- package/docs/interfaces/core_IndicatorButtonState.IndicatorButtonState.html +0 -10
- package/docs/interfaces/core_PositionContext.IPositionContext.html +0 -17
- package/docs/interfaces/hub_CommandMessage.CommandMessage.html +0 -6
- package/docs/interfaces/hub_CommandMessage.CommandMessageResult.html +0 -4
- package/docs/modules/assets.html +0 -1
- package/docs/modules/assets_BlocklyLogo.html +0 -1
- package/docs/modules/assets_Distance.html +0 -1
- package/docs/modules/assets_JogLong.html +0 -1
- package/docs/modules/assets_JogMedium.html +0 -1
- package/docs/modules/assets_JogShort.html +0 -1
- package/docs/modules/assets_PythonLogo.html +0 -1
- package/docs/modules/assets_Rotation3D.html +0 -1
- package/docs/modules/assets_RotationCcw.html +0 -1
- package/docs/modules/assets_RotationCcwA.html +0 -1
- package/docs/modules/assets_RotationCcwB.html +0 -1
- package/docs/modules/assets_RotationCcwC.html +0 -1
- package/docs/modules/assets_RotationCw.html +0 -1
- package/docs/modules/assets_RotationCwA.html +0 -1
- package/docs/modules/assets_RotationCwB.html +0 -1
- package/docs/modules/assets_RotationCwC.html +0 -1
- package/docs/modules/assets_Run.html +0 -1
- package/docs/modules/assets_Speed.html +0 -1
- package/docs/modules/assets_SpeedFast.html +0 -1
- package/docs/modules/assets_SpeedMedium.html +0 -1
- package/docs/modules/assets_SpeedNone.html +0 -1
- package/docs/modules/assets_SpeedSlow.html +0 -1
- package/docs/modules/assets_Walk.html +0 -1
- package/docs/modules/components_AutoCoreDevPanel.html +0 -20
- package/docs/modules/components_BlocklyEditor.html +0 -1
- package/docs/modules/components_CodeEditor.html +0 -1
- package/docs/modules/components_FileList.html +0 -1
- package/docs/modules/components_FileSelect.html +0 -1
- package/docs/modules/components_FitText.html +0 -1
- package/docs/modules/components_Indicator.html +0 -1
- package/docs/modules/components_IndicatorButton.html +0 -1
- package/docs/modules/components_IndicatorRect.html +0 -1
- package/docs/modules/components_JogPanel.html +0 -1
- package/docs/modules/components_Lamp.html +0 -1
- package/docs/modules/components_Osk.html +0 -1
- package/docs/modules/components_OskDialog.html +0 -1
- package/docs/modules/components_ProgressBarWithValue.html +0 -1
- package/docs/modules/components_TextInput.html +0 -1
- package/docs/modules/components_ToggleGroup.html +0 -1
- package/docs/modules/components_ValueDisplay.html +0 -1
- package/docs/modules/components_ValueIndicator.html +0 -1
- package/docs/modules/components_ValueInput.html +0 -1
- package/docs/modules/core_ActionMode.html +0 -1
- package/docs/modules/core_AutoCoreTagContext.html +0 -11
- package/docs/modules/core_AutoCoreTagTypes.html +0 -1
- package/docs/modules/core_EventEmitterContext.html +0 -53
- package/docs/modules/core_IndicatorButtonState.html +0 -1
- package/docs/modules/core_IndicatorColor.html +0 -1
- package/docs/modules/core_MaskPatterns.html +0 -1
- package/docs/modules/core_NumerableTypes.html +0 -1
- package/docs/modules/core_PositionContext.html +0 -1
- package/docs/modules/core_UniqueId.html +0 -1
- package/docs/modules/core_ValueSimulator.html +0 -1
- package/docs/modules/core_hoc.html +0 -1
- package/docs/modules/hooks.html +0 -1
- package/docs/modules/hooks_adsHooks.html +0 -1
- package/docs/modules/hooks_commandHooks.html +0 -1
- package/docs/modules/hooks_useAutoCoreTag.ts.html +0 -52
- package/docs/modules/hooks_useScaledValue.html +0 -1
- package/docs/modules/hub.html +0 -1
- package/docs/modules/hub_CommandMessage.html +0 -1
- package/docs/modules/hub_HubBase.html +0 -1
- package/docs/modules/hub_HubSimulate.html +0 -1
- package/docs/modules/hub_HubTauri.html +0 -1
- package/docs/modules/hub_HubWebSocket.html +0 -1
- package/docs/modules.html +0 -23
- package/docs/types/components_IndicatorButton.IndicatorButtonOptionsType.html +0 -1
- package/docs/types/core_AutoCoreTagTypes.ExtractByTag.html +0 -2
- package/docs/types/core_AutoCoreTagTypes.PrimitiveKind.html +0 -1
- package/docs/types/core_AutoCoreTagTypes.TagConfig.html +0 -16
- package/docs/types/core_AutoCoreTagTypes.TagValueMap.html +0 -1
- package/docs/types/core_AutoCoreTagTypes.TagValueOf.html +0 -1
- package/docs/types/core_EventEmitterContext.EmitterDispatchFunction.html +0 -3
- package/docs/types/core_EventEmitterContext.EmitterSubscribeFunction.html +0 -3
- package/docs/types/core_EventEmitterContext.EmitterUnsubscribeFunction.html +0 -3
- package/docs/types/core_NumerableTypes.NumerableFormatOptions.html +0 -4
- package/docs/types/core_hoc.HocAddSubscriptionProps.html +0 -6
- package/docs/variables/components_AutoCoreDevPanel.AutoCoreDevPanel.html +0 -43
- package/docs/variables/components_BlocklyEditor.BlocklyEditor.html +0 -13
- package/docs/variables/components_BlocklyEditor.StandardToolbox.html +0 -1
- package/docs/variables/components_FileList.FileList.html +0 -23
- package/docs/variables/components_FileSelect.FileSelect.html +0 -1
- package/docs/variables/components_FitText.FitText.html +0 -4
- package/docs/variables/components_IndicatorButton.IndicatorButton.html +0 -1
- package/docs/variables/components_JogPanel.DefaultLinearJogButtons.html +0 -2
- package/docs/variables/components_JogPanel.DefaultRotationJogButtons.html +0 -2
- package/docs/variables/components_Osk.Osk.html +0 -1
- package/docs/variables/components_ProgressBarWithValue.ProgressBarWithValue.html +0 -1
- package/docs/variables/components_ToggleGroup.ToggleGroup.html +0 -1
- package/docs/variables/components_ValueInput.ValueInput.html +0 -4
- package/docs/variables/core_AutoCoreTagContext.AutoCoreTagContext.html +0 -1
- package/docs/variables/core_AutoCoreTagContext.AutoCoreTagProvider.html +0 -7
- package/docs/variables/core_EventEmitterContext.EventEmitterContext.html +0 -64
- package/docs/variables/core_EventEmitterContext.EventEmitterProvider.html +0 -10
- package/docs/variables/core_MaskPatterns.PrimeReactMaskPatterns.html +0 -14
- package/docs/variables/core_MaskPatterns.RegExMaskPatterns.html +0 -15
- package/docs/variables/core_PositionContext.DimensionsContext.html +0 -6
- package/docs/variables/hooks_useScaledValue.kMillimeters2Inches.html +0 -2
- package/docs/variables/hooks_useScaledValue.kNewtons2Pounds.html +0 -2
package/src/hub/HubTauri.ts
CHANGED
|
@@ -3,87 +3,49 @@
|
|
|
3
3
|
* Created Date: 2023-12-17 09:50:23
|
|
4
4
|
* Author: Thomas C. Bitsky Jr.
|
|
5
5
|
* -----
|
|
6
|
-
* Last Modified:
|
|
6
|
+
* Last Modified: 2026-01-29 09:34:21
|
|
7
7
|
* Modified By: ADC
|
|
8
8
|
* -----
|
|
9
|
-
*
|
|
9
|
+
*
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
|
-
import type { InvokeArgs } from '@tauri-apps/api/tauri';
|
|
13
12
|
import { HubBase } from './HubBase';
|
|
14
|
-
import {
|
|
15
|
-
import
|
|
13
|
+
import { invoke as tauriInvoke } from '@tauri-apps/api/core';
|
|
14
|
+
import { listen } from '@tauri-apps/api/event';
|
|
15
|
+
import type { CommandMessage } from "./CommandMessage";
|
|
16
|
+
import { MessageType } from "./CommandMessage";
|
|
17
|
+
|
|
18
|
+
type InvokeArgs = Record<string, unknown>;
|
|
16
19
|
|
|
17
20
|
/**
|
|
18
21
|
* Hub for integrating with the Tauri backend.
|
|
19
|
-
*
|
|
20
|
-
* The
|
|
22
|
+
*
|
|
23
|
+
* The Tauri backend is expected to broadcast messages on the event
|
|
21
24
|
* name: 'autocore://broadcast_event'
|
|
22
|
-
*
|
|
23
|
-
* This hub will capture those messages and dispatch them globally to any
|
|
25
|
+
*
|
|
26
|
+
* This hub will capture those messages and dispatch them globally to any
|
|
24
27
|
* listeners in the web app.
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
* Example: Listen to an event 'xarm-position':
|
|
28
|
-
* ```
|
|
29
|
-
* const {subscribe, unsubscribe} = useContext(EventEmitterContext);
|
|
30
|
-
* useEffect(() => {
|
|
31
|
-
* const unsubscripeMp = subscribe('xarm-position', (value) => {
|
|
32
|
-
* // The rust backend sent a JSON object of 3D position values.
|
|
33
|
-
* setX(value.x);
|
|
34
|
-
* setY(value.y);
|
|
35
|
-
* setZ(value.z);
|
|
36
|
-
* setA(value.roll);
|
|
37
|
-
* setB(value.yaw);
|
|
38
|
-
* setC(value.pitch);
|
|
39
|
-
* });
|
|
40
|
-
*
|
|
41
|
-
* return () => {
|
|
42
|
-
* unsubscribe(unsubscripeMp);
|
|
43
|
-
* }
|
|
44
|
-
*
|
|
45
|
-
* }, [] );
|
|
46
28
|
*
|
|
29
|
+
* ## Usage Examples
|
|
30
|
+
*
|
|
31
|
+
* ```typescript
|
|
32
|
+
* const { hub } = useContext(EventEmitterContext);
|
|
33
|
+
*
|
|
34
|
+
* // Read a value
|
|
35
|
+
* const result = await hub.read("ads.plc1.gio.bControlPowerOk");
|
|
36
|
+
*
|
|
37
|
+
* // Write a value
|
|
38
|
+
* await hub.write("ads.plc1.gio.nSetpoint", 100);
|
|
39
|
+
*
|
|
40
|
+
* // Subscribe to changes
|
|
41
|
+
* await hub.subscribe("modbus.holding_registers.5");
|
|
47
42
|
* ```
|
|
48
|
-
*
|
|
49
|
-
* The hub should also be used for invoking events in the Tauri backend.
|
|
50
|
-
* This example will call the function "update_count" in the rust backend, passing
|
|
51
|
-
* the expected argument "count".
|
|
52
|
-
* ```
|
|
53
|
-
* const {invoke} = useContext(EventEmitterContext);
|
|
54
|
-
* const incrementCount = () => {
|
|
55
|
-
* count += 1;
|
|
56
|
-
* invoke('update_count', {"count": count});
|
|
57
|
-
* };
|
|
58
|
-
* ```
|
|
59
|
-
*
|
|
60
|
-
* Of course, like any class derived from HubBase, the hub can be used to publish and subscribe to
|
|
61
|
-
* topics in the front-end, without need of interacting with the Tauri backed.
|
|
62
|
-
*
|
|
63
|
-
* ```
|
|
64
|
-
* const {dispatch, subscribe, unsubscribe} = useContext(EventEmitterContext);
|
|
65
|
-
* const [controlPower, setControlPower] = useState(false);
|
|
66
|
-
* useEffect(() => {
|
|
67
|
-
* const unsubscribeControlPower = subscribe('value-simulator-bBit1', (value) => {
|
|
68
|
-
* setControlPower(value);
|
|
69
|
-
* });
|
|
70
43
|
*
|
|
44
|
+
* The hub can also publish/subscribe to frontend-only events:
|
|
71
45
|
*
|
|
72
|
-
*
|
|
73
|
-
*
|
|
74
|
-
* }
|
|
75
|
-
* }, [] );
|
|
76
|
-
*
|
|
77
|
-
* const onPbPressed = () => {
|
|
78
|
-
* let count = 1;
|
|
79
|
-
* dispatch({
|
|
80
|
-
* topic: "my-awesome-topic",
|
|
81
|
-
* payload: count
|
|
82
|
-
* });
|
|
83
|
-
* }
|
|
84
|
-
*
|
|
46
|
+
* ```typescript
|
|
47
|
+
* hub.publish("ui/panel-opened", { panelId: "settings" });
|
|
85
48
|
* ```
|
|
86
|
-
*
|
|
87
49
|
*/
|
|
88
50
|
export class HubTauri extends HubBase {
|
|
89
51
|
|
|
@@ -93,57 +55,86 @@ export class HubTauri extends HubBase {
|
|
|
93
55
|
constructor() {
|
|
94
56
|
super();
|
|
95
57
|
|
|
58
|
+
// Mark as connected since Tauri IPC is always available
|
|
59
|
+
this.setIsConnected(true);
|
|
96
60
|
|
|
97
61
|
/**
|
|
98
62
|
* Receive broadcasts from the Tauri backend. Data is received as a payload object,
|
|
99
63
|
* {topic: string, payload: any | null}
|
|
100
64
|
* From here, we extract into a form HubBase can use, then pass on to the
|
|
101
65
|
* dispatcher.
|
|
102
|
-
*
|
|
66
|
+
*
|
|
103
67
|
* Events without a topic are ignored.
|
|
104
68
|
*/
|
|
105
|
-
|
|
106
|
-
|
|
69
|
+
listen('autocore://broadcast_event', (ev: any) => {
|
|
107
70
|
let objPayload = JSON.parse(ev.payload);
|
|
108
71
|
|
|
109
|
-
if (objPayload.topic !== undefined && objPayload.topic !== null
|
|
110
|
-
|
|
111
|
-
if ( objPayload.payload !== undefined && objPayload.payload !== null ) {
|
|
72
|
+
if (objPayload.topic !== undefined && objPayload.topic !== null) {
|
|
73
|
+
if (objPayload.payload !== undefined && objPayload.payload !== null) {
|
|
112
74
|
this.publish(objPayload.topic, objPayload.payload);
|
|
113
75
|
}
|
|
114
76
|
else {
|
|
115
77
|
this.publish(objPayload.topic, undefined);
|
|
116
78
|
}
|
|
117
|
-
|
|
118
79
|
}
|
|
119
|
-
|
|
120
80
|
});
|
|
121
|
-
|
|
122
81
|
}
|
|
123
82
|
|
|
124
83
|
/**
|
|
125
|
-
*
|
|
126
|
-
*
|
|
127
|
-
*
|
|
128
|
-
*
|
|
129
|
-
*
|
|
84
|
+
* Send a message to the Tauri backend.
|
|
85
|
+
*
|
|
86
|
+
* The topic and messageType are passed to a generic Tauri command handler
|
|
87
|
+
* that routes the request appropriately.
|
|
88
|
+
*
|
|
89
|
+
* @param topic The FQDN of the resource (e.g., "ads.plc1.gio.bControlPowerOk")
|
|
90
|
+
* @param messageType The action to perform (Read, Write, Subscribe, etc.)
|
|
91
|
+
* @param payload Optional data payload (e.g., value to write)
|
|
92
|
+
* @returns Promise<CommandMessage> The response from the backend
|
|
130
93
|
*/
|
|
131
|
-
invoke(
|
|
132
|
-
|
|
133
|
-
console.log(JSON.stringify(event));
|
|
94
|
+
invoke(topic: string, messageType: MessageType, payload?: object): Promise<CommandMessage> {
|
|
95
|
+
console.log(`HubTauri.invoke: topic=${topic}, type=${MessageType[messageType]}`);
|
|
134
96
|
|
|
135
|
-
|
|
136
|
-
|
|
97
|
+
// Build the command arguments
|
|
98
|
+
const args: InvokeArgs = {
|
|
99
|
+
topic: topic,
|
|
100
|
+
message_type: messageType,
|
|
101
|
+
...(payload ?? {})
|
|
102
|
+
};
|
|
137
103
|
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
104
|
+
// Call the generic autocore handler in Tauri backend
|
|
105
|
+
return new Promise((resolve, reject) => {
|
|
106
|
+
tauriInvoke('autocore_invoke', args)
|
|
107
|
+
.then((result: any) => {
|
|
108
|
+
// If the result is already a CommandMessage, use it directly
|
|
109
|
+
if (result && typeof result === 'object' && 'topic' in result) {
|
|
110
|
+
resolve(result as CommandMessage);
|
|
111
|
+
} else {
|
|
112
|
+
// Wrap raw result in CommandMessage
|
|
113
|
+
const response: CommandMessage = {
|
|
114
|
+
transaction_id: 0,
|
|
115
|
+
timecode: Date.now(),
|
|
116
|
+
topic: topic,
|
|
117
|
+
message_type: MessageType.Response,
|
|
118
|
+
data: result,
|
|
119
|
+
success: true,
|
|
120
|
+
error_message: ''
|
|
121
|
+
};
|
|
122
|
+
resolve(response);
|
|
123
|
+
}
|
|
124
|
+
})
|
|
125
|
+
.catch((error: any) => {
|
|
126
|
+
// Wrap error in CommandMessage
|
|
127
|
+
const response: CommandMessage = {
|
|
128
|
+
transaction_id: 0,
|
|
129
|
+
timecode: Date.now(),
|
|
130
|
+
topic: topic,
|
|
131
|
+
message_type: MessageType.Response,
|
|
132
|
+
data: null,
|
|
133
|
+
success: false,
|
|
134
|
+
error_message: error?.toString() || 'Unknown error'
|
|
135
|
+
};
|
|
136
|
+
reject(response);
|
|
137
|
+
});
|
|
138
|
+
});
|
|
147
139
|
}
|
|
148
|
-
|
|
149
|
-
}
|
|
140
|
+
}
|
package/src/hub/HubWebSocket.ts
CHANGED
|
@@ -2,36 +2,40 @@
|
|
|
2
2
|
* Copyright (C) 2024 Automated Design Corp.. All Rights Reserved.
|
|
3
3
|
* Created Date: 2024-04-17 09:13:07
|
|
4
4
|
* -----
|
|
5
|
-
* Last Modified:
|
|
5
|
+
* Last Modified: 2026-01-29 09:34:31
|
|
6
|
+
* Modified By: ADC
|
|
6
7
|
* -----
|
|
7
8
|
*
|
|
8
9
|
*/
|
|
9
10
|
|
|
10
|
-
/**
|
|
11
|
+
/**
|
|
12
|
+
* @module hub/HubWebSocket
|
|
11
13
|
*
|
|
12
|
-
*
|
|
13
|
-
* The result field of CommandMessages used for broadcast must have
|
|
14
|
-
* success set to true, and must contain the field "topic." The topic field, along
|
|
15
|
-
* with the domain field of the CommandMessage will be combined for the topic used
|
|
16
|
-
* by the websocket client.
|
|
14
|
+
* Implementation of `HubBase` using standard WebSockets.
|
|
17
15
|
*
|
|
18
|
-
*
|
|
16
|
+
* ## Functionality
|
|
19
17
|
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
18
|
+
* - **Transport**: Connects to `ws://host:port/ws/` (or `wss://`).
|
|
19
|
+
* - **Request/Response**: Correlates requests to responses using `transaction_id`.
|
|
20
|
+
* - **Broadcasts**: Handles unsolicited messages (subscriptions) and routes them via `HubBase.publish`.
|
|
21
|
+
* - **Binary Data**: Handles `FILE_DOWNLOAD` events by decoding Base64 payloads into Blobs.
|
|
22
|
+
*
|
|
23
|
+
* ## Protocol
|
|
24
|
+
*
|
|
25
|
+
* Messages are JSON-serialized `CommandMessage` objects.
|
|
26
|
+
* - **Requests**: Client sends `message_type` (Read/Write/etc) + `transaction_id`.
|
|
27
|
+
* - **Responses**: Server replies with same `transaction_id` + `success`/`data`.
|
|
28
|
+
* - **Broadcasts**: Server sends `message_type: Broadcast` + `topic` (FQDN) + `data`.
|
|
22
29
|
*/
|
|
23
30
|
|
|
24
31
|
import { HubBase } from './HubBase';
|
|
25
|
-
import
|
|
26
|
-
|
|
27
|
-
// Function to parse the JSON string received from the server into a CommandMessage object
|
|
28
|
-
// function parseCommandMessage(jsonString: string): CommandMessage {
|
|
29
|
-
// const parsed: CommandMessage = JSON.parse(jsonString);
|
|
30
|
-
// // Assuming the JSON structure directly matches the TypeScript interfaces
|
|
31
|
-
// return parsed;
|
|
32
|
-
// }
|
|
33
|
-
|
|
32
|
+
import { MessageType, type CommandMessage } from "./CommandMessage";
|
|
33
|
+
import { getDebugPanel } from './DebugPanel';
|
|
34
34
|
|
|
35
|
+
/**
|
|
36
|
+
* Internal tracking record for pending requests.
|
|
37
|
+
* Allows the `invoke` promise to be resolved/rejected when the response arrives.
|
|
38
|
+
*/
|
|
35
39
|
interface RequestRecord {
|
|
36
40
|
resolve: (value?: any) => void;
|
|
37
41
|
reject: (reason?: any) => void;
|
|
@@ -40,21 +44,12 @@ interface RequestRecord {
|
|
|
40
44
|
|
|
41
45
|
/**
|
|
42
46
|
* Converts a Base64 encoded string into a Blob object.
|
|
47
|
+
* Used for file downloads.
|
|
43
48
|
*
|
|
44
|
-
*
|
|
45
|
-
*
|
|
46
|
-
*
|
|
47
|
-
*
|
|
48
|
-
* and constructs a Blob from the resulting byte arrays.
|
|
49
|
-
*
|
|
50
|
-
* @param {string} b64Data The base64 encoded string you want to convert to a Blob.
|
|
51
|
-
* @param {string} [contentType='application/octet-stream'] The MIME type of the Blob.
|
|
52
|
-
* This parameter is optional and defaults to 'application/octet-stream'.
|
|
53
|
-
* @param {number} [sliceSize=512] The size of each chunk used to slice the Base64 string.
|
|
54
|
-
* Smaller slice sizes can improve the function's handling of large Base64 strings.
|
|
55
|
-
* This parameter is optional and defaults to 512.
|
|
56
|
-
*
|
|
57
|
-
* @returns {Blob} A Blob object representing the decoded binary data.
|
|
49
|
+
* @param {string} b64Data The base64 encoded string.
|
|
50
|
+
* @param {string} [contentType='application/octet-stream'] The MIME type.
|
|
51
|
+
* @param {number} [sliceSize=512] Chunk size for processing.
|
|
52
|
+
* @returns {Blob} The decoded binary blob.
|
|
58
53
|
*/
|
|
59
54
|
function b64toBlob(
|
|
60
55
|
b64Data: string,
|
|
@@ -71,7 +66,7 @@ function b64toBlob(
|
|
|
71
66
|
for (let i = 0; i < slice.length; i++) byteNumbers[i] = slice.charCodeAt(i);
|
|
72
67
|
|
|
73
68
|
const uint8 = new Uint8Array(byteNumbers);
|
|
74
|
-
buffers.push(uint8.buffer as ArrayBuffer);
|
|
69
|
+
buffers.push(uint8.buffer as ArrayBuffer);
|
|
75
70
|
}
|
|
76
71
|
|
|
77
72
|
return new Blob(buffers, { type: contentType });
|
|
@@ -80,187 +75,170 @@ function b64toBlob(
|
|
|
80
75
|
|
|
81
76
|
|
|
82
77
|
/**
|
|
83
|
-
*
|
|
78
|
+
* Triggers a browser download for a Blob object.
|
|
84
79
|
*
|
|
85
|
-
*
|
|
86
|
-
*
|
|
87
|
-
* dynamically created anchor tag (`<a>`), sets the suggested filename, and then simulates a click on
|
|
88
|
-
* this link to start the download. After the download is triggered, the link is removed and the URL
|
|
89
|
-
* is revoked to free up memory.
|
|
90
|
-
*
|
|
91
|
-
* @param {Blob} blob The Blob object containing the data to be downloaded.
|
|
92
|
-
* @param {string} filename The filename to be used for the downloaded file.
|
|
80
|
+
* @param {Blob} blob The binary data.
|
|
81
|
+
* @param {string} filename The suggested filename.
|
|
93
82
|
*/
|
|
94
83
|
function downloadBlob(blob: Blob, filename: string): void {
|
|
95
|
-
// Create a URL for the blob object
|
|
96
84
|
const url = window.URL.createObjectURL(blob);
|
|
97
|
-
|
|
98
|
-
// Create a temporary anchor tag (`<a>`) element
|
|
99
85
|
const a = document.createElement('a');
|
|
100
|
-
a.href = url;
|
|
101
|
-
a.download = filename;
|
|
102
|
-
|
|
103
|
-
// Append the anchor tag to the body of the document
|
|
86
|
+
a.href = url;
|
|
87
|
+
a.download = filename;
|
|
104
88
|
document.body.appendChild(a);
|
|
105
|
-
|
|
106
|
-
// Programmatically trigger a click on the anchor tag
|
|
107
89
|
a.click();
|
|
108
|
-
|
|
109
|
-
// Remove the anchor tag from the document
|
|
110
90
|
document.body.removeChild(a);
|
|
111
|
-
|
|
112
|
-
// Revoke the blob URL to free up resources
|
|
113
91
|
window.URL.revokeObjectURL(url);
|
|
114
92
|
}
|
|
115
93
|
|
|
116
94
|
|
|
117
|
-
|
|
118
|
-
|
|
95
|
+
/**
|
|
96
|
+
* WebSocket implementation of the Hub communication layer.
|
|
97
|
+
*/
|
|
119
98
|
export class HubWebSocket extends HubBase {
|
|
120
99
|
private socket: WebSocket;
|
|
121
100
|
private requestId = 0;
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Map of pending Transaction ID -> Promise Resolvers.
|
|
104
|
+
* Used to match asynchronous WebSocket responses to their original requests.
|
|
105
|
+
*/
|
|
122
106
|
private pendingRequests = new Map<number, RequestRecord>();
|
|
123
107
|
|
|
124
108
|
/**
|
|
125
|
-
*
|
|
109
|
+
* Initializes the WebSocket connection immediately.
|
|
126
110
|
*/
|
|
127
111
|
constructor() {
|
|
128
112
|
super();
|
|
113
|
+
console.log("[HubWebSocket] Constructor called");
|
|
114
|
+
getDebugPanel().hubCreated();
|
|
129
115
|
|
|
130
|
-
const host = window.location.hostname;
|
|
131
|
-
|
|
132
|
-
// Default to using autocore-server.
|
|
133
|
-
let port = undefined; // window.location.port; // Get the port from the address bar, if any
|
|
116
|
+
const host = window.location.hostname;
|
|
117
|
+
const port = window.location.port;
|
|
134
118
|
|
|
135
|
-
const proto = window.location.protocol === 'https:' ? 'wss://' : 'ws://';
|
|
136
|
-
const wsUrl = `${proto}${host}${port ? ':' + port : ''}/ws/`;
|
|
119
|
+
const proto = window.location.protocol === 'https:' ? 'wss://' : 'ws://';
|
|
120
|
+
const wsUrl = `${proto}${host}${port ? ':' + port : ''}/ws/`;
|
|
137
121
|
|
|
138
122
|
this.socket = new WebSocket(wsUrl);
|
|
139
|
-
|
|
140
|
-
|
|
141
123
|
let self = this;
|
|
142
124
|
|
|
143
|
-
//
|
|
144
|
-
|
|
145
|
-
//
|
|
125
|
+
// --- Connection Handlers ---
|
|
126
|
+
|
|
146
127
|
this.socket.onopen = function () {
|
|
147
128
|
console.log("WebSocket connection established.");
|
|
129
|
+
getDebugPanel().wsOpened(wsUrl);
|
|
130
|
+
// Notify app that we are online
|
|
148
131
|
self.publish("HUB/connected", true);
|
|
149
132
|
self.setIsConnected(true);
|
|
150
133
|
};
|
|
151
134
|
|
|
135
|
+
// --- Message Handler ---
|
|
152
136
|
|
|
153
|
-
// Message recevied via the websocket connection.
|
|
154
|
-
//
|
|
155
137
|
this.socket.onmessage = (event) => {
|
|
156
138
|
const data: CommandMessage = JSON.parse(event.data);
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
139
|
+
getDebugPanel().messageReceived(
|
|
140
|
+
MessageType[data.message_type] || String(data.message_type),
|
|
141
|
+
data.topic,
|
|
142
|
+
data.transaction_id
|
|
143
|
+
);
|
|
144
|
+
|
|
145
|
+
console.log(`HUB MSG RX: ${JSON.stringify(data)}`);
|
|
146
|
+
|
|
147
|
+
// Check if this message is a response to a pending request (has ID)
|
|
148
|
+
if (data.transaction_id && this.pendingRequests.has(data.transaction_id)) {
|
|
149
|
+
const { resolve, reject } = this.pendingRequests.get(data.transaction_id)!;
|
|
150
|
+
|
|
151
|
+
// SPECIAL CASE: File Download Response
|
|
152
|
+
if (data.topic === "FILE_DOWNLOAD"
|
|
153
|
+
&& data.data["file_name"] !== undefined && data.data["file_name"] !== null
|
|
154
|
+
&& data.data["file_name"].length > 0
|
|
167
155
|
) {
|
|
168
|
-
|
|
169
|
-
// The file name was supplied in the original request
|
|
170
|
-
let tokens = data.args["file_name"].split("/");
|
|
171
|
-
|
|
156
|
+
let tokens = data.data["file_name"].split("/");
|
|
172
157
|
const filename = tokens[tokens.length - 1];
|
|
173
|
-
|
|
174
|
-
|
|
158
|
+
|
|
159
|
+
if (data.success) {
|
|
160
|
+
// Decode and trigger download
|
|
161
|
+
const blob = b64toBlob(data.data);
|
|
175
162
|
downloadBlob(blob, filename);
|
|
176
163
|
|
|
177
|
-
//
|
|
178
|
-
data.
|
|
179
|
-
|
|
180
|
-
// Signal the function that initiated the download that all is well.
|
|
181
|
-
resolve(data.result);
|
|
182
|
-
|
|
164
|
+
// Clean up response data to avoid passing giant string to app
|
|
165
|
+
data.data = filename;
|
|
166
|
+
resolve(data);
|
|
183
167
|
} else {
|
|
184
|
-
|
|
185
|
-
reject(new Error(data.result?.error_message));
|
|
168
|
+
reject(new Error(data.error_message));
|
|
186
169
|
}
|
|
187
|
-
|
|
188
170
|
}
|
|
171
|
+
// STANDARD CASE: Normal Command Response
|
|
189
172
|
else {
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
// Return the result to the function that initiated the request.
|
|
193
|
-
reject(new Error(data.result?.error_message));
|
|
173
|
+
if (!data.success) {
|
|
174
|
+
reject(new Error(data.error_message));
|
|
194
175
|
} else {
|
|
195
|
-
//
|
|
196
|
-
resolve(data
|
|
176
|
+
// Success: resolve with the full message
|
|
177
|
+
resolve(data);
|
|
197
178
|
}
|
|
198
179
|
}
|
|
199
|
-
|
|
180
|
+
// Cleanup request record
|
|
181
|
+
this.pendingRequests.delete(data.transaction_id);
|
|
200
182
|
} else {
|
|
183
|
+
// No transaction ID means it's an unsolicited broadcast (subscription update)
|
|
184
|
+
console.log(`HUB BROADCAST: ${JSON.stringify(data)}`);
|
|
201
185
|
this.handleUnsolicitedMessage(data);
|
|
202
186
|
}
|
|
203
187
|
};
|
|
204
188
|
|
|
205
|
-
//
|
|
206
|
-
// Error occurred in the Websocket connection.
|
|
207
|
-
//
|
|
208
189
|
this.socket.onerror = (error: Event) => {
|
|
209
190
|
console.error('WebSocket error:', error);
|
|
191
|
+
getDebugPanel().wsError(String(error));
|
|
210
192
|
};
|
|
211
193
|
|
|
212
|
-
|
|
213
|
-
// The Websocket connection has closed.
|
|
214
|
-
//
|
|
215
|
-
this.socket.onclose = () => {
|
|
194
|
+
this.socket.onclose = (event: CloseEvent) => {
|
|
216
195
|
self.setIsConnected(false);
|
|
217
196
|
console.log('WebSocket connection closed.');
|
|
197
|
+
getDebugPanel().wsClosed(event.code, event.reason || 'No reason');
|
|
218
198
|
};
|
|
219
199
|
}
|
|
220
200
|
|
|
221
201
|
|
|
222
202
|
/**
|
|
223
|
-
*
|
|
224
|
-
*
|
|
225
|
-
*
|
|
226
|
-
*
|
|
227
|
-
* @returns Promise<CommandMessageResult>
|
|
203
|
+
* Sends a command to the server via WebSocket.
|
|
204
|
+
*
|
|
205
|
+
* Wraps the operation in a Promise that resolves when the server replies
|
|
206
|
+
* with a matching `transaction_id`.
|
|
228
207
|
*/
|
|
229
|
-
invoke = (
|
|
208
|
+
invoke = (topic: string, messageType: MessageType, payload?: object): Promise<CommandMessage> => {
|
|
230
209
|
|
|
231
210
|
return new Promise((resolve, reject) => {
|
|
232
|
-
const id = ++this.requestId; //
|
|
211
|
+
const id = ++this.requestId; // Generate unique ID
|
|
233
212
|
this.pendingRequests.set(id, { resolve, reject });
|
|
234
213
|
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
214
|
+
const data = payload ? payload : {};
|
|
215
|
+
|
|
216
|
+
const cm: CommandMessage = {
|
|
217
|
+
transaction_id: id,
|
|
218
|
+
topic: topic,
|
|
219
|
+
data: data,
|
|
220
|
+
timecode: Date.now(),
|
|
221
|
+
message_type: messageType,
|
|
222
|
+
success: false,
|
|
223
|
+
error_message: ''
|
|
241
224
|
};
|
|
242
225
|
|
|
226
|
+
getDebugPanel().messageSent(MessageType[messageType], topic, id);
|
|
243
227
|
this.socket.send(JSON.stringify(cm));
|
|
244
228
|
});
|
|
245
229
|
}
|
|
246
230
|
|
|
231
|
+
/**
|
|
232
|
+
* Processes messages that are not responses to a specific request.
|
|
233
|
+
* Usually these are subscription updates (Broadcasts).
|
|
234
|
+
*/
|
|
247
235
|
handleUnsolicitedMessage = (msg: CommandMessage) => {
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
&& msg.result.data !== undefined && msg.result.data !== null
|
|
254
|
-
) {
|
|
255
|
-
|
|
256
|
-
let topic = `${msg.domain}/${msg.result.data["topic"]}`;
|
|
257
|
-
|
|
258
|
-
//console.log(`HUB PUBLISHING: ${topic} : ${JSON.stringify(msg.result.data)}`);
|
|
259
|
-
this.publish(topic, msg.result.data);
|
|
236
|
+
if (msg.message_type == MessageType.Broadcast && msg.topic.length > 1) {
|
|
237
|
+
console.log(`HUB PUBLISHING: ${msg.topic} : ${JSON.stringify(msg.data)}`);
|
|
238
|
+
|
|
239
|
+
// Pass to HubBase to map the FQDN topic to a local tagName and dispatch
|
|
240
|
+
this.publish(msg.topic, msg.data);
|
|
260
241
|
}
|
|
261
|
-
// else {
|
|
262
|
-
// console.error("INVALID BROADCAST RECEIVED!");
|
|
263
|
-
// }
|
|
264
242
|
}
|
|
265
243
|
|
|
266
244
|
disconnect = (): void => {
|
|
@@ -270,4 +248,4 @@ export class HubWebSocket extends HubBase {
|
|
|
270
248
|
protected emit = (eventName: string, payload?: object): void => {
|
|
271
249
|
this.socket.send(JSON.stringify({ eventName, payload }));
|
|
272
250
|
}
|
|
273
|
-
}
|
|
251
|
+
}
|