403Webshell
Server IP : 80.87.202.40  /  Your IP : 216.73.216.169
Web Server : Apache
System : Linux rospirotorg.ru 5.14.0-539.el9.x86_64 #1 SMP PREEMPT_DYNAMIC Thu Dec 5 22:26:13 UTC 2024 x86_64
User : bitrix ( 600)
PHP Version : 8.2.27
Disable Function : NONE
MySQL : OFF |  cURL : ON |  WGET : ON |  Perl : ON |  Python : OFF |  Sudo : ON |  Pkexec : ON
Directory :  /home/bitrix/ext_www/rospirotorg.ru/bitrix/js/pull/client/src/

Upload File :
current_dir [ Writeable] document_root [ Writeable]

 

Command :


[ Back ]     

Current File : /home/bitrix/ext_www/rospirotorg.ru/bitrix/js/pull/client/src/emitter.js
/* eslint-disable @bitrix24/bitrix24-rules/no-typeof */
/* eslint-disable @bitrix24/bitrix24-rules/no-bx */
/* eslint-disable @bitrix24/bitrix24-rules/no-bx-message */
// noinspection JSUnusedAssignment

import { clone, isArray, isFunction, isNotEmptyString, isObject, isPlainObject } from 'pull.util';
import { SenderType, SubscriptionType } from './consts';

interface Logger
{
	log(message: string, ...params): void
}

type PullEvent = {
	module_id: string,
	command: string,
	params: Object,
	extra: ?EventExtraFields
}

type InternalEvent = {
	type: $Values<typeof SubscriptionType>,
	moduleId: string,
	data: CallbackData,
}

type CallbackData = {
	command: string,
	params: Object,
	extra: ?EventExtraFields
}

type EmitterOptions = {
	logger: ?Logger,
}

type EventExtraFields = {
	sender: Sender
}

type Sender = {
	type: $Values<typeof SenderType>,
}

type SubscriptionParams = {
	// Subscription type (for possible values @see SubscriptionType); SubscriptionType.Server by default
	type: ?string,
	// Name of the module.
	moduleId: string,
	// Command to be subscribed to
	command: string,
	// Function, that will be called for incoming messages.
	callback: HandlerFunc
}

export type HandlerFunc = (params: Object, extra: Object, command: string) => void;

export type Handler = {
	getSubscriptionType: ? () => string,
	getModuleId: ? () => string,
	getMap: ? () => { [string]: HandlerFunc },
}

export class Emitter
{
	#subscribers = {};
	#logger: Logger;

	debug = false;
	userStatusCallbacks = {}; // [userId] => array of callbacks

	constructor(options: EmitterOptions = {})
	{
		this.#logger = options.logger;
	}

	/**
	 * Creates a subscription to incoming messages.
	 *
	 * @returns {Function} - Unsubscribe callback function
	 */
	subscribe(params: SubscriptionParams): () => void
	{
		/**
		 * After modify this method, copy to follow scripts:
		 * mobile/install/mobileapp/mobile/extensions/bitrix/pull/client/events/extension.js
		 * mobile/install/js/mobile/pull/client/src/client.js
		 */

		if (!isObject(params))
		{
			throw new TypeError('params must be an object');
		}

		if (!isPlainObject(params))
		{
			return this.attachCommandHandler(params);
		}

		const { command, moduleId, callback, type = SubscriptionType.Server } = params;

		if (type === SubscriptionType.Server || type === SubscriptionType.Client)
		{
			if (typeof (this.#subscribers[type]) === 'undefined')
			{
				this.#subscribers[type] = {};
			}

			if (typeof (this.#subscribers[type][moduleId]) === 'undefined')
			{
				this.#subscribers[type][moduleId] = {
					callbacks: [],
					commands: {},
				};
			}

			if (command)
			{
				if (!isArray(this.#subscribers[type][moduleId].commands[command]))
				{
					this.#subscribers[type][moduleId].commands[command] = [];
				}

				this.#subscribers[type][moduleId].commands[command].push(callback);

				return () => {
					// eslint-disable-next-line max-len
					this.#subscribers[type][moduleId].commands[command] = this.#subscribers[type][moduleId].commands[command].filter((element) => {
						return element !== callback;
					});
				};
			}

			this.#subscribers[type][moduleId].callbacks.push(callback);

			return () => {
				this.#subscribers[type][moduleId].callbacks = this.#subscribers[type][moduleId].callbacks.filter((element) => {
					return element !== callback;
				});
			};
		}

		if (typeof (this.#subscribers[type]) === 'undefined')
		{
			this.#subscribers[type] = [];
		}

		this.#subscribers[type].push(callback);

		return () => {
			this.#subscribers[type] = this.#subscribers[type].filter((element) => {
				return element !== callback;
			});
		};
	}

	/*
	 Subscribes provided handler to pull events.
	 @return {() => void} Returns function, that can be called to unsubscribe the handler.
	 */
	attachCommandHandler(handler: Handler): () => void
	{
		/**
		 * After modify this method, copy to follow scripts:
		 * mobile/install/mobileapp/mobile/extensions/bitrix/pull/client/events/extension.js
		 */
		const moduleId = isFunction(handler.getModuleId) ? handler.getModuleId() : '';
		if (!isNotEmptyString(moduleId))
		{
			throw new TypeError('handler.getModuleId() must return a string');
		}

		let type = SubscriptionType.Server;
		if (isFunction(handler.getSubscriptionType))
		{
			type = handler.getSubscriptionType();
			if (!Object.values(SubscriptionType).includes(type))
			{
				throw new Error('result of handler.getSubscriptionType() must return valid SubscriptionType element');
			}
		}

		return this.subscribe({
			type,
			moduleId,
			callback: (data: CallbackData) => {
				const method = findHandlerMethod(handler, data.command);

				if (method)
				{
					let loggableData = '';
					try
					{
						loggableData = JSON.stringify(data);
					}
					catch
					{
						loggableData = '(contains circular references)';
					}

					this.#logger?.log(`Pull.attachCommandHandler: receive command ${loggableData}`);
					method(data.params, data.extra, data.command);
				}
			},
		});
	}

	/**
	 *
	 * @param params {Object}
	 * @returns {boolean}
	 */
	emit(params: InternalEvent = {}): boolean
	{
		/**
		 * After modify this method, copy to follow scripts:
		 * mobile/install/mobileapp/mobile/extensions/bitrix/pull/client/events/extension.js
		 * mobile/install/js/mobile/pull/client/src/client.js
		 */
		if (params.type === SubscriptionType.Server || params.type === SubscriptionType.Client)
		{
			if (typeof (this.#subscribers[params.type]) === 'undefined')
			{
				this.#subscribers[params.type] = {};
			}

			if (typeof (this.#subscribers[params.type][params.moduleId]) === 'undefined')
			{
				this.#subscribers[params.type][params.moduleId] = {
					callbacks: [],
					commands: {},
				};
			}

			if (this.#subscribers[params.type][params.moduleId].callbacks.length > 0)
			{
				this.#subscribers[params.type][params.moduleId].callbacks.forEach((callback) => {
					callback(params.data, { type: params.type, moduleId: params.moduleId });
				});
			}

			if (
				this.#subscribers[params.type][params.moduleId].commands[params.data.command]
				&& this.#subscribers[params.type][params.moduleId].commands[params.data.command].length > 0)
			{
				this.#subscribers[params.type][params.moduleId].commands[params.data.command].forEach((callback) => {
					callback(params.data.params, params.data.extra, params.data.command, {
						type: params.type,
						moduleId: params.moduleId,
					});
				});
			}

			return true;
		}

		if (typeof (this.#subscribers[params.type]) === 'undefined')
		{
			this.#subscribers[params.type] = [];
		}

		if (this.#subscribers[params.type].length <= 0)
		{
			return true;
		}

		this.#subscribers[params.type].forEach((callback) => {
			callback(params.data, { type: params.type });
		});

		return true;
	}

	broadcastMessage(message: PullEvent)
	{
		const moduleId = message.module_id.toLowerCase();
		const command = message.command;
		const params = message.params;
		const extra = message.extra ?? {};

		this.logMessage(message);
		try
		{
			if (extra.sender && extra.sender.type === SenderType.Client)
			{
				this.emitClientEvent(moduleId, command, clone(params), clone(extra));
			}
			else if (moduleId === 'online')
			{
				if (extra.server_time_ago < 240)
				{
					this.emitOnlineEvent(moduleId, command, clone(params), clone(extra));
				}

				if (command === 'userStatusChange')
				{
					this.emitUserStatusChange(params.user_id, params.online);
				}
			}
			else
			{
				this.emitServerEvent(moduleId, command, clone(params), clone(extra));
			}
		}
		catch (e)
		{
			if (typeof (console) === 'object')
			{
				console.error('\n========= PULL ERROR ===========\n'
					+ 'Error type: broadcastMessages execute error\n'
					+ 'Error event: ', e, '\n'
					+ 'Message: ', message, '\n'
					+ '================================\n');
				if (isFunction(BX.debug))
				{
					BX.debug(e);
				}
			}
		}
	}

	emitServerEvent(moduleId: string, command: string, params: any, extra: any)
	{
		if ('BX' in globalThis && isFunction(BX.onCustomEvent))
		{
			BX.onCustomEvent(window, `onPullEvent-${moduleId}`, [command, params, extra], true);
			BX.onCustomEvent(window, 'onPullEvent', [moduleId, command, params, extra], true);
		}

		this.emit({ type: SubscriptionType.Server, moduleId, data: { command, params, extra } });
	}

	emitClientEvent(moduleId: string, command: string, params: any, extra: any)
	{
		if (isFunction(BX.onCustomEvent))
		{
			BX.onCustomEvent(window, `onPullClientEvent-${moduleId}`, [command, params, extra], true);
			BX.onCustomEvent(window, 'onPullClientEvent', [moduleId, command, params, extra], true);
		}

		this.emit({ type: SubscriptionType.Client, moduleId, data: { command, params, extra } });
	}

	emitOnlineEvent(moduleId: string, command: string, params: any, extra: any)
	{
		if (isFunction(BX.onCustomEvent))
		{
			BX.onCustomEvent(window, 'onPullOnlineEvent', [command, params, extra], true);
		}

		this.emit({ type: SubscriptionType.Online, data: { command, params, extra } });
	}

	addUserStatusCallback(userId: number, callback: UserStatusCallback)
	{
		if (!this.userStatusCallbacks[userId])
		{
			this.userStatusCallbacks[userId] = [];
		}

		if (isFunction(callback))
		{
			this.userStatusCallbacks[userId].push(callback);
		}
	}

	removeUserStatusCallback(userId: number, callback: UserStatusCallback)
	{
		if (this.userStatusCallbacks[userId])
		{
			this.userStatusCallbacks[userId] = this.userStatusCallbacks[userId].filter((cb) => cb !== callback);
		}
	}

	hasUserStatusCallbacks(userId: number): boolean
	{
		return this.userStatusCallbacks[userId].length > 0;
	}

	emitUserStatusChange(userId, isOnline)
	{
		if (this.userStatusCallbacks[userId])
		{
			this.userStatusCallbacks[userId].forEach((cb) => cb({ userId, isOnline }));
		}
	}

	getSubscribedUsersList(): number[]
	{
		const result = [];
		for (const userId of Object.keys(this.userStatusCallbacks))
		{
			if (this.userStatusCallbacks[userId].length > 0)
			{
				result.push(Number(userId));
			}
		}

		return result;
	}

	capturePullEvent(debugFlag: boolean = true)
	{
		this.debug = debugFlag;
	}

	logMessage(message: PullEvent)
	{
		if (!this.debug)
		{
			return;
		}

		if (message.extra.sender && message.extra.sender.type === SenderType.Client)
		{
			console.info(`onPullClientEvent-${message.module_id}`, message.command, message.params, message.extra);
		}
		else if (message.module_id === 'online')
		{
			console.info('onPullOnlineEvent', message.command, message.params, message.extra);
		}
		else
		{
			console.info('onPullEvent', message.module_id, message.command, message.params, message.extra);
		}
	}
}

function findHandlerMethod(handler: Handler, command: string): HandlerFunc | null
{
	let method = null;

	if (isFunction(handler.getMap))
	{
		const mapping = handler.getMap();
		if (isPlainObject(mapping))
		{
			if (isFunction(mapping[command]))
			{
				method = mapping[command].bind(handler);
			}
			else if (typeof mapping[command] === 'string' && isFunction(handler[mapping[command]]))
			{
				method = handler[mapping[command]].bind(handler);
			}
		}
	}

	if (!method)
	{
		const methodName = getDefaultHandlerMethodName(command);
		if (isFunction(handler[methodName]))
		{
			method = handler[methodName].bind(handler);
		}
	}

	return method;
}

function getDefaultHandlerMethodName(command: string): string
{
	return `handle${command.charAt(0).toUpperCase()}${command.slice(1)}`;
}

Youez - 2016 - github.com/yon3zu
LinuXploit