The communications platform that puts data protection first.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
Rocket.Chat/apps/meteor/client/providers/ServerProvider.tsx

127 lines
3.7 KiB

import type { Serialized } from '@rocket.chat/core-typings';
import { Emitter } from '@rocket.chat/emitter';
import type { Method, PathFor, OperationParams, OperationResult, UrlParams, PathPattern } from '@rocket.chat/rest-typings';
import type {
ServerMethodName,
ServerMethodParameters,
ServerMethodReturn,
StreamerCallbackArgs,
UploadResult,
StreamNames,
StreamKeys,
} from '@rocket.chat/ui-contexts';
import { ServerContext } from '@rocket.chat/ui-contexts';
import { Meteor } from 'meteor/meteor';
import { compile } from 'path-to-regexp';
import type { FC } from 'react';
import React from 'react';
import { Info as info } from '../../app/utils/client';
import { sdk } from '../../app/utils/client/lib/SDKClient';
const absoluteUrl = (path: string): string => Meteor.absoluteUrl(path);
const callMethod = <MethodName extends ServerMethodName>(
methodName: MethodName,
...args: ServerMethodParameters<MethodName>
): Promise<ServerMethodReturn<MethodName>> => Meteor.callAsync(methodName, ...args);
const callEndpoint = <TMethod extends Method, TPathPattern extends PathPattern>({
method,
pathPattern,
keys,
params,
}: {
method: TMethod;
pathPattern: TPathPattern;
keys: UrlParams<TPathPattern>;
params: OperationParams<TMethod, TPathPattern>;
}): Promise<Serialized<OperationResult<TMethod, TPathPattern>>> => {
const compiledPath = compile(pathPattern, { encode: encodeURIComponent })(keys) as any;
switch (method) {
case 'GET':
return sdk.rest.get(compiledPath, params as any) as any;
case 'POST':
return sdk.rest.post(compiledPath, params as any) as any;
case 'PUT':
return sdk.rest.put(compiledPath, params as never) as never;
case 'DELETE':
return sdk.rest.delete(compiledPath, params as any) as any;
default:
throw new Error('Invalid HTTP method');
}
};
const uploadToEndpoint = (endpoint: PathFor<'POST'>, formData: any): Promise<UploadResult> => sdk.rest.post(endpoint as any, formData);
const getStream = <N extends StreamNames, K extends StreamKeys<N>>(
streamName: N,
_options?: {
retransmit?: boolean | undefined;
retransmitToSelf?: boolean | undefined;
},
): ((eventName: K, callback: (...args: StreamerCallbackArgs<N, K>) => void) => () => void) => {
return (eventName, callback): (() => void) => {
return sdk.stream(streamName, [eventName], callback as (...args: any[]) => void).stop;
};
};
const ee = new Emitter<Record<string, void>>();
const events = new Map<string, () => void>();
const getSingleStream = <N extends StreamNames, K extends StreamKeys<N>>(
streamName: N,
_options?: {
retransmit?: boolean | undefined;
retransmitToSelf?: boolean | undefined;
},
): ((eventName: K, callback: (...args: StreamerCallbackArgs<N, K>) => void) => () => void) => {
const stream = getStream(streamName);
return (eventName, callback): (() => void) => {
ee.on(`${streamName}/${eventName}`, callback);
const handler = (...args: any[]): void => {
ee.emit(`${streamName}/${eventName}`, ...args);
};
const stop = (): void => {
// If someone is still listening, don't unsubscribe
ee.off(`${streamName}/${eventName}`, callback);
if (ee.has(`${streamName}/${eventName}`)) {
return;
}
const unsubscribe = events.get(`${streamName}/${eventName}`);
if (unsubscribe) {
unsubscribe();
events.delete(`${streamName}/${eventName}`);
}
};
if (!events.has(`${streamName}/${eventName}`)) {
events.set(`${streamName}/${eventName}`, stream(eventName, handler));
}
return stop;
};
};
const contextValue = {
info,
absoluteUrl,
callMethod,
callEndpoint,
uploadToEndpoint,
getStream,
getSingleStream,
};
const ServerProvider: FC = ({ children }) => <ServerContext.Provider children={children} value={contextValue} />;
export default ServerProvider;