import { IElementState, IElementParams, EventType, InternalType, ElementId } from "../types"; import { Processor } from "../Processor"; import { IPartialObserver } from "../types/subscriptions"; import { isArgsEqual } from "../util"; import { CallbacksManager } from "../CallbacksManager"; import { EventsManager } from "../EventsManager"; import { mergeContexts } from "../util/mergeContexts"; export const subscribeHook = ( processor: Processor, eventsManager: EventsManager, callbacksManager: CallbacksManager, elementId: ElementId, state: IElementState, params: IElementParams, observer: IPartialObserver, ): { ___type: InternalType; elementId: ElementId; } => { const ret = { ___type: InternalType.Subscribe, }; // Looking for existing subscription with this arguments const existsSubscriptionIndex = state.subscriptions.findIndex((sub) => { const childState = processor.getElementStateById(sub.elementId); return childState.func === params.func && isArgsEqual(childState.props, params.args); }); if (existsSubscriptionIndex > -1) { if (state.subscriptions[existsSubscriptionIndex].isCompleted) { return { ...ret, elementId: state.subscriptions[existsSubscriptionIndex].elementId }; } const existsElementState = processor.getElementStateById( state.subscriptions[existsSubscriptionIndex].elementId, ); if (existsElementState.observer.next && observer.next) { callbacksManager.changeCallback(existsElementState.observer.next, observer.next); } else if (!existsElementState.observer.next && !observer.next) { // there is not observer } else { throw new Error("Unexpected observer"); } if (observer.error && existsElementState.observer.error) { callbacksManager.releaseCallback(existsElementState.observer.error); } if (observer.error) { existsElementState.observer.error = callbacksManager.addCallback(observer.error)[0]; } state.tickState.usedSubscriptions.push(existsSubscriptionIndex); return { ...ret, elementId: state.subscriptions[existsSubscriptionIndex].elementId }; } // create subscription // const callbacks = createCallbackFromObserver(callbacksManager, observer); // create element const subscriptionElementId = processor.createElement(params); // add to subscriptions state.subscriptions.push({ elementId: subscriptionElementId, isCompleted: false }); // add to usedSubscriptions state.tickState.usedSubscriptions.push(state.subscriptions.length - 1); // trigger CreateEvent eventsManager.triggerEvent({ elementId: subscriptionElementId, type: EventType.Create, params: {}, value: undefined, }); const subscriptionElementState = processor.getElementStateById(subscriptionElementId); // create contexts subscriptionElementState.contexts = mergeContexts(state.contexts, state.tickState.contexts); // create observer subscriptionElementState.observer = { next: observer.next ? callbacksManager.addCallback(observer.next)[0] : undefined, error: observer.error ? callbacksManager.addCallback(observer.error)[0] : eventsManager.createEvent(elementId, EventType.SubscribeError, {})[0], complete: eventsManager.createEvent(elementId, EventType.SubscribeComplete, {})[0], }; return { ...ret, elementId: subscriptionElementId }; };