Source: data/SignalROqt.js

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;