Skip to content

Commit 9d3985d

Browse files
authored
Merge pull request #133 from ISISComputingGroup/use_callbacks
use callbacks instead of useeffects
2 parents ed34856 + b6627cc commit 9d3985d

File tree

3 files changed

+180
-159
lines changed

3 files changed

+180
-159
lines changed

app/commonVars.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,6 @@ export const instListSubscription: IfcPVWSRequest = {
99
type: PVWSRequestType.subscribe,
1010
pvs: [instListPV],
1111
};
12+
13+
export const webSocketReconnectInterval = 5000; // ms
14+
export const webSocketReconnectAttempts = 100000;

app/components/InstrumentData.tsx

Lines changed: 111 additions & 108 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,13 @@ import {
1919
yesToBoolean,
2020
} from "@/app/components/Instrument";
2121
import useWebSocket from "react-use-websocket";
22-
import { instListPV, instListSubscription, socketURL } from "@/app/commonVars";
22+
import {
23+
instListPV,
24+
instListSubscription,
25+
socketURL,
26+
webSocketReconnectAttempts,
27+
webSocketReconnectInterval,
28+
} from "@/app/commonVars";
2329
import {
2430
dehex_and_decompress,
2531
instListFromBytes,
@@ -36,11 +42,11 @@ import Groups from "@/app/components/Groups";
3642
export function InstrumentData({ instrumentName }: { instrumentName: string }) {
3743
const [showHiddenBlocks, setShowHiddenBlocks] = useState(false);
3844
const CONFIG_DETAILS = "CS:BLOCKSERVER:WD_CONF_DETAILS";
39-
const [instlist, setInstlist] = useState<instList | null>(null);
4045
const [currentInstrument, setCurrentInstrument] = useState<Instrument | null>(
4146
null,
4247
);
4348
const [lastUpdate, setLastUpdate] = useState<string>("");
49+
const [webSockErr, setWebSockErr] = useState("");
4450

4551
const instName = instrumentName;
4652

@@ -58,133 +64,129 @@ export function InstrumentData({ instrumentName }: { instrumentName: string }) {
5864
lastJsonMessage: IfcPVWSMessage;
5965
} = useWebSocket(socketURL, {
6066
shouldReconnect: (closeEvent) => true,
61-
});
62-
63-
useEffect(() => {
64-
// This is an initial useEffect to subscribe to lots of PVs including the instlist.
65-
sendJsonMessage(instListSubscription);
66-
67-
if (instName == "" || instName == null || instlist == null) {
68-
return;
69-
}
70-
71-
let prefix = getPrefix(instlist, instName);
72-
73-
if (!currentInstrument) {
74-
let instrument = new Instrument(prefix);
75-
setCurrentInstrument(instrument);
76-
77-
sendJsonMessage({
78-
type: PVWSRequestType.subscribe,
79-
pvs: [`${prefix}${CONFIG_DETAILS}`],
80-
});
67+
onOpen: () => {
68+
setWebSockErr("");
69+
setLastUpdate(""); // if this is called on a reconnect, we want to clear the last update so we can re-subscribe to everything again
70+
sendJsonMessage(instListSubscription);
71+
},
72+
onMessage: (m) => {
73+
const updatedPV: IfcPVWSMessage = JSON.parse(m.data);
74+
const updatedPVName: string = updatedPV.pv;
75+
const updatedPVbytes: string | null | undefined = updatedPV.b64byt;
76+
77+
if (updatedPVName == instListPV && updatedPVbytes != null) {
78+
const instlist = instListFromBytes(updatedPVbytes);
79+
const prefix = getPrefix(instlist, instName);
80+
const instrument = new Instrument(prefix);
81+
setCurrentInstrument(instrument);
8182

82-
// subscribe to dashboard and run info PVs
83-
for (const pv of instrument.runInfoPVs.concat(
84-
instrument.dashboard.flat(3),
85-
)) {
8683
sendJsonMessage({
8784
type: PVWSRequestType.subscribe,
88-
pvs: [pv.pvaddress],
85+
pvs: [`${prefix}${CONFIG_DETAILS}`],
8986
});
90-
}
91-
}
92-
}, [instlist, instName, sendJsonMessage, currentInstrument]);
93-
94-
useEffect(() => {
95-
// This gets run whenever there is a PV update ie. when lastJsonMessage changes.
96-
if (!lastJsonMessage) {
97-
return;
98-
}
99-
const updatedPV: IfcPVWSMessage = lastJsonMessage;
100-
const updatedPVName: string = updatedPV.pv;
101-
const updatedPVbytes: string | null | undefined = updatedPV.b64byt;
102-
103-
if (updatedPVName == instListPV && updatedPVbytes != null) {
104-
setInstlist(instListFromBytes(updatedPVbytes));
105-
return;
106-
}
107-
108-
if (!currentInstrument) {
109-
return;
110-
}
11187

112-
if (
113-
updatedPVName == `${currentInstrument.prefix}${CONFIG_DETAILS}` &&
114-
updatedPVbytes != null
115-
) {
116-
// config change, reset instrument groups
117-
if (updatedPVbytes == lastUpdate) {
118-
// config hasnt actually changed so do nothing
88+
// subscribe to dashboard and run info PVs
89+
for (const pv of instrument.runInfoPVs.concat(
90+
instrument.dashboard.flat(3),
91+
)) {
92+
sendJsonMessage({
93+
type: PVWSRequestType.subscribe,
94+
pvs: [pv.pvaddress],
95+
});
96+
}
11997
return;
12098
}
121-
setLastUpdate(updatedPVbytes);
122-
const res = dehex_and_decompress(atob(updatedPVbytes));
123-
currentInstrument.groups = getGroupsWithBlocksFromConfigOutput(
124-
JSON.parse(res),
125-
sendJsonMessage,
126-
currentInstrument.prefix,
127-
);
128-
} else {
129-
const pvVal = getPvValue(updatedPV);
13099

131-
if (pvVal == undefined) {
132-
console.debug(`initial/blank message from ${updatedPVName}`);
100+
if (!currentInstrument) {
133101
return;
134102
}
135103

136-
// Check if this is a dashboard, run info, or block PV update.
137-
const pv =
138-
findPVInDashboard(currentInstrument.dashboard, updatedPVName) ||
139-
findPVByAddress(currentInstrument.runInfoPVs, updatedPVName) ||
140-
findPVInGroups(
141-
currentInstrument.groups,
104+
if (
105+
updatedPVName == `${currentInstrument.prefix}${CONFIG_DETAILS}` &&
106+
updatedPVbytes != null
107+
) {
108+
// config change, reset instrument groups
109+
if (updatedPVbytes == lastUpdate) {
110+
// config hasnt actually changed so do nothing
111+
return;
112+
}
113+
setLastUpdate(updatedPVbytes);
114+
const res = dehex_and_decompress(atob(updatedPVbytes));
115+
currentInstrument.groups = getGroupsWithBlocksFromConfigOutput(
116+
JSON.parse(res),
117+
sendJsonMessage,
142118
currentInstrument.prefix,
143-
updatedPVName,
144119
);
145-
if (pv) {
146-
storePrecision(updatedPV, pv);
147-
pv.value = toPrecision(pv, pvVal);
148-
if (updatedPV.seconds) pv.updateSeconds = updatedPV.seconds;
149-
if (updatedPV.units) pv.units = updatedPV.units;
150-
if (updatedPV.severity) pv.severity = updatedPV.severity;
151120
} else {
152-
// OK, we haven't found the block, but we may have an update for
153-
// its object such as its run control status or SP:RBV
154-
if (updatedPVName.endsWith(RC_INRANGE)) {
155-
const underlyingBlock = findPVInGroups(
156-
currentInstrument.groups,
157-
currentInstrument.prefix,
158-
updatedPVName.replace(RC_INRANGE, ""),
159-
);
160-
if (underlyingBlock)
161-
underlyingBlock.runcontrol_inrange = yesToBoolean(pvVal);
162-
} else if (updatedPVName.endsWith(RC_ENABLE)) {
163-
const underlyingBlock = findPVInGroups(
164-
currentInstrument.groups,
165-
currentInstrument.prefix,
166-
updatedPVName.replace(RC_ENABLE, ""),
167-
);
168-
if (underlyingBlock)
169-
underlyingBlock.runcontrol_enabled = yesToBoolean(pvVal);
170-
} else if (updatedPVName.endsWith(SP_RBV)) {
171-
const underlyingBlock = findPVInGroups(
121+
const pvVal = getPvValue(updatedPV);
122+
123+
if (pvVal == undefined) {
124+
console.debug(`initial/blank message from ${updatedPVName}`);
125+
return;
126+
}
127+
128+
// Check if this is a dashboard, run info, or block PV update.
129+
const pv =
130+
findPVInDashboard(currentInstrument.dashboard, updatedPVName) ||
131+
findPVByAddress(currentInstrument.runInfoPVs, updatedPVName) ||
132+
findPVInGroups(
172133
currentInstrument.groups,
173134
currentInstrument.prefix,
174-
updatedPVName.replace(SP_RBV, ""),
135+
updatedPVName,
175136
);
176-
if (underlyingBlock)
177-
underlyingBlock.sp_value = toPrecision(underlyingBlock, pvVal);
137+
if (pv) {
138+
storePrecision(updatedPV, pv);
139+
pv.value = toPrecision(pv, pvVal);
140+
if (updatedPV.seconds) pv.updateSeconds = updatedPV.seconds;
141+
if (updatedPV.units) pv.units = updatedPV.units;
142+
if (updatedPV.severity) pv.severity = updatedPV.severity;
178143
} else {
179-
console.warn(
180-
`update from unknown PV: ${updatedPVName} with value ${pvVal}`,
181-
);
144+
// OK, we haven't found the block, but we may have an update for
145+
// its object such as its run control status or SP:RBV
146+
if (updatedPVName.endsWith(RC_INRANGE)) {
147+
const underlyingBlock = findPVInGroups(
148+
currentInstrument.groups,
149+
currentInstrument.prefix,
150+
updatedPVName.replace(RC_INRANGE, ""),
151+
);
152+
if (underlyingBlock)
153+
underlyingBlock.runcontrol_inrange = yesToBoolean(pvVal);
154+
} else if (updatedPVName.endsWith(RC_ENABLE)) {
155+
const underlyingBlock = findPVInGroups(
156+
currentInstrument.groups,
157+
currentInstrument.prefix,
158+
updatedPVName.replace(RC_ENABLE, ""),
159+
);
160+
if (underlyingBlock)
161+
underlyingBlock.runcontrol_enabled = yesToBoolean(pvVal);
162+
} else if (updatedPVName.endsWith(SP_RBV)) {
163+
const underlyingBlock = findPVInGroups(
164+
currentInstrument.groups,
165+
currentInstrument.prefix,
166+
updatedPVName.replace(SP_RBV, ""),
167+
);
168+
if (underlyingBlock)
169+
underlyingBlock.sp_value = toPrecision(underlyingBlock, pvVal);
170+
} else {
171+
console.warn(
172+
`update from unknown PV: ${updatedPVName} with value ${pvVal}`,
173+
);
174+
}
182175
}
183176
}
184-
}
185-
}, [lastJsonMessage, currentInstrument, sendJsonMessage, lastUpdate]);
177+
},
178+
onError: (err) => {
179+
setWebSockErr(
180+
"Failed to connect to websocket - please check your network connection and contact Experiment Controls if this persists.",
181+
);
182+
},
183+
share: true,
184+
retryOnError: true,
185+
reconnectInterval: webSocketReconnectInterval,
186+
reconnectAttempts: webSocketReconnectAttempts,
187+
});
186188

187-
if (!instName || !currentInstrument) {
189+
if (!currentInstrument) {
188190
return <h1>Loading...</h1>;
189191
}
190192
return (
@@ -194,6 +196,7 @@ export function InstrumentData({ instrumentName }: { instrumentName: string }) {
194196
instName={instName}
195197
runInfoPVs={currentInstrument.runInfoPVs}
196198
/>
199+
{webSockErr && <h1 className={"text-red-600"}>{webSockErr}</h1>}
197200
<div className="flex gap-2 ml-2 md:flex-row flex-col">
198201
<CheckToggle
199202
checked={showHiddenBlocks}

0 commit comments

Comments
 (0)