import React, { useCallback, useEffect, useRef, useState } from "react";
import { useSelector } from "react-redux";
import * as immutable from 'object-path-immutable';
import { SignalRContext } from "../../_core/contexts";
import { booleanString, useHooks } from "../..";
const signalR = require("@microsoft/signalr");
/**
* Componente que crea un contexto de signalr para todos los watcher que contenga
* @name Reactor.Components.Data.SignalROqt
* @param {string} hub Url del endpoint de SignalR
* @param {BooleanString} [debug = "true"]
* @class
* @example
<signalr hub="http://www.orquesta.com.ar/signalr">
<watcher monitor="mensajes" hooks="ActualizarMensajes"></watcher>
<watcher monitor="saldo" hooks="ActualizarSaldo"></watcher>
<div>
...lista de mensajes
</div>
</signalr>
*/
const SignalROqt = ({hub, children, onreconnect, debug = "false"}) => {
//const isAuth = useSelector(state => state.app.isAuth);
//const online = useSelector(state => state.app.variables.app.online);
//const variables = useVariables();
const jwt = useSelector(state => state.app.jwt?.token);
const connection = useRef();
const subscriptions = useRef({});
const [state, setState] = useState("stop");
const { procesarHooks } = useHooks({silent: "true", onreconnect, debug});
useEffect(()=>{
booleanString(debug) && console.log("SignalR", {event: "load", jwt, hub});
if(!hub) return;
if(!jwt && connection.current){
connection.current?.stop();
connection.current = undefined;
return;
}
if(!jwt)return;
connection.current = new signalR.HubConnectionBuilder()
.withUrl(hub, {
accessTokenFactory: () => jwt,
withCredentials: false
})
.configureLogging(debug === "true" ? signalR.LogLevel.Debug : signalR.LogLevel.None)
.withAutomaticReconnect()
.build();
connection.current.onreconnected(onReconnected);
start()
.then(()=>{
setState("start");
})
.catch(e => {
booleanString(debug) && console.log("SignalR", e);
});
}, [jwt, hub]);
const onResponse = useCallback((message)=>{
booleanString(debug) && console.log("SignalR", {event: "response", message, subscriptions: subscriptions.current});
if(message.monitor && subscriptions.current[message.monitor]){
try{
subscriptions.current[message.monitor]?.callback();
}catch(e){}
}
/*
if(data.mensaje === "stop"){
connection.current.stop().then(()=>{
console.log("se desconecto")
});
}
connection.current.on("close", function (data) { });
*/
}, []);
const onReconnected = useCallback(()=>{
booleanString(debug) && console.log("SignalR", {subscriptions: subscriptions.current})
procesarHooks();
Object.values(subscriptions.current).forEach(subscription => {
subscription.reconnectCallback()
});
}, []);
useEffect(()=>{
if(state === "start"){
connection.current?.on("response", onResponse);
}
return ()=>{
connection.current?.off("response");
}
}, [state, onResponse])
const start = async () => {
await connection.current.start();
}
const subscribe = useCallback(({monitor, callback, reconnectCallback}) => {
connection.current.invoke("Subscribe", monitor)
.then(()=>{
subscriptions.current[monitor] = {callback, reconnectCallback};
booleanString(debug) && console.log("SignalR", {event: "subscribe", subscriptions: subscriptions.current});
})
.catch(e => booleanString(debug) && console.log(e));
}, [debug]);
const unsubscribe = useCallback(({monitor}) => {
connection.current.invoke("Unsubscribe", monitor).catch(e => booleanString(debug) && console.log(e));
delete subscriptions.current[monitor];
booleanString(debug) && console.log("SignalR", {event: "unsubscribe", monitor,subscriptions: subscriptions.current})
}, [])
return (
<SignalRContext.Provider value={{subscribe, unsubscribe}}>
{children}
</SignalRContext.Provider>
);
}
export default SignalROqt;