124 lines
3.9 KiB
TypeScript
124 lines
3.9 KiB
TypeScript
// This program has been developed by students from the bachelor Computer Science at Utrecht
|
|
// University within the Software Project course.
|
|
// © Copyright Utrecht University (Department of Information and Computing Sciences)
|
|
import React, { useEffect } from 'react';
|
|
|
|
const API_BASE = "http://localhost:8000";
|
|
const API_BASE_BP = API_BASE + "/button_pressed"; //UserInterruptAgent endpoint
|
|
|
|
/**
|
|
* HELPER: Unified sender function
|
|
*/
|
|
export const sendAPICall = async (type: string, context: string, endpoint?: string) => {
|
|
try {
|
|
const response = await fetch(`${API_BASE_BP}${endpoint ?? ""}`, {
|
|
method: "POST",
|
|
headers: { "Content-Type": "application/json" },
|
|
body: JSON.stringify({ type, context }),
|
|
});
|
|
if (!response.ok) throw new Error("Backend response error");
|
|
console.log(`API Call send - Type: ${type}, Context: ${context} ${endpoint ? `, Endpoint: ${endpoint}` : ""}`);
|
|
} catch (err) {
|
|
console.error(`Failed to send api call:`, err);
|
|
}
|
|
};
|
|
|
|
|
|
/**
|
|
* Sends an API call to the CB for going to the next phase.
|
|
* In case we can't go to the next phase, the function will throw an error.
|
|
*/
|
|
export async function nextPhase(): Promise<void> {
|
|
const type = "next_phase"
|
|
const context = ""
|
|
sendAPICall(type, context)
|
|
}
|
|
|
|
|
|
/**
|
|
* Sends an API call to the CB for going to pause experiment
|
|
*/
|
|
export async function pauseExperiment(): Promise<void> {
|
|
const type = "pause"
|
|
const context = "true"
|
|
sendAPICall(type, context)
|
|
}
|
|
|
|
/**
|
|
* Sends an API call to the CB for going to resume experiment
|
|
*/
|
|
export async function playExperiment(): Promise<void> {
|
|
const type = "pause"
|
|
const context = "false"
|
|
sendAPICall(type, context)
|
|
}
|
|
|
|
|
|
/**
|
|
* Types for the experiment stream messages
|
|
*/
|
|
export type PhaseUpdate = { type: 'phase_update'; id: string };
|
|
export type GoalUpdate = { type: 'goal_update'; id: string };
|
|
export type TriggerUpdate = { type: 'trigger_update'; id: string; achieved: boolean };
|
|
export type CondNormsStateUpdate = { type: 'cond_norms_state_update'; norms: { id: string; active: boolean }[] };
|
|
export type ExperimentStreamData = PhaseUpdate | GoalUpdate | TriggerUpdate | CondNormsStateUpdate | Record<string, unknown>;
|
|
|
|
/**
|
|
* A hook that listens to the experiment stream that updates current state of the program
|
|
* via updates sent from the backend
|
|
*/
|
|
export function useExperimentLogger(onUpdate?: (data: ExperimentStreamData) => void) {
|
|
const callbackRef = React.useRef(onUpdate);
|
|
// Ref is updated every time with on update
|
|
React.useEffect(() => {
|
|
callbackRef.current = onUpdate;
|
|
}, [onUpdate]);
|
|
|
|
useEffect(() => {
|
|
console.log("Connecting to Experiment Stream...");
|
|
const eventSource = new EventSource(`${API_BASE}/experiment_stream`);
|
|
|
|
eventSource.onmessage = (event) => {
|
|
try {
|
|
const parsedData = JSON.parse(event.data) as ExperimentStreamData;
|
|
//call function using the ref
|
|
callbackRef.current?.(parsedData);
|
|
} catch (err) {
|
|
console.warn("Stream parse error:", err);
|
|
}
|
|
};
|
|
|
|
eventSource.onerror = (err) => {
|
|
console.error("SSE Connection Error:", err);
|
|
eventSource.close();
|
|
};
|
|
|
|
return () => {
|
|
console.log("Closing Experiment Stream...");
|
|
eventSource.close();
|
|
};
|
|
}, []);
|
|
}
|
|
|
|
/**
|
|
* A hook that listens to the status stream that updates active conditional norms
|
|
* via updates sent from the backend
|
|
*/
|
|
export function useStatusLogger(onUpdate?: (data: ExperimentStreamData) => void) {
|
|
const callbackRef = React.useRef(onUpdate);
|
|
|
|
React.useEffect(() => {
|
|
callbackRef.current = onUpdate;
|
|
}, [onUpdate]);
|
|
|
|
useEffect(() => {
|
|
const eventSource = new EventSource(`${API_BASE}/status_stream`);
|
|
eventSource.onmessage = (event) => {
|
|
try {
|
|
const parsedData = JSON.parse(event.data);
|
|
callbackRef.current?.(parsedData);
|
|
} catch (err) { console.warn("Status stream error:", err); }
|
|
};
|
|
return () => eventSource.close();
|
|
}, []);
|
|
} |