import { Api as GramJs, errors } from '../../../lib/gramjs'; import type { RegularLangKey } from '../../../types/language'; import type { RegularLangFnParameters } from '../../../util/localization'; import { DEBUG } from '../../../config'; import { DAY, getDays, getHours, getMinutes, HOUR, MINUTE, } from '../../../util/dates/units'; import { getApiChatIdFromMtpPeer } from '../apiBuilders/peers'; const LOG_BACKGROUND = '#111111DD'; const LOG_PREFIX_COLOR = '#E4D00A'; const LOG_SUFFIX = { INVOKE: '#49DBF5', BEACON: '#F549DB', RESPONSE: '#6887F7', CONNECTING: '#E4D00A', CONNECTED: '#26D907', 'CONNECTING ERROR': '#D1191C', 'INVOKE ERROR': '#D1191C', UPDATE: '#0DD151', 'UNEXPECTED UPDATE': '#9C9C9C', 'UNEXPECTED RESPONSE': '#D1191C', }; const ERROR_KEYS: Record = { PHONE_NUMBER_INVALID: 'ErrorPhoneNumberInvalid', PHONE_CODE_INVALID: 'ErrorCodeInvalid', PASSWORD_HASH_INVALID: 'ErrorIncorrectPassword', PHONE_PASSWORD_FLOOD: 'ErrorPasswordFlood', PHONE_NUMBER_BANNED: 'ErrorPhoneBanned', EMAIL_UNCONFIRMED: 'ErrorEmailUnconfirmed', EMAIL_HASH_EXPIRED: 'ErrorEmailHashExpired', NEW_SALT_INVALID: 'ErrorNewSaltInvalid', SRP_PASSWORD_CHANGED: 'ErrorPasswordChanged', CODE_INVALID: 'ErrorEmailCodeInvalid', PASSWORD_MISSING: 'ErrorPasswordMissing', }; export type MessageRepairContext = Pick; export type MediaRepairContext = MessageRepairContext; export type WrappedError = { messageKey: RegularLangFnParameters; errorMessage?: string; error: T; }; export function resolveMessageApiChatId(mtpMessage: GramJs.TypeMessage) { if (!(mtpMessage instanceof GramJs.Message || mtpMessage instanceof GramJs.MessageService)) { return undefined; } return getApiChatIdFromMtpPeer(mtpMessage.peerId); } export function isChatFolder( filter?: GramJs.TypeDialogFilter, ): filter is GramJs.DialogFilter | GramJs.DialogFilterChatlist { return filter instanceof GramJs.DialogFilter || filter instanceof GramJs.DialogFilterChatlist; } export function serializeBytes(value: Buffer) { return String.fromCharCode(...value); } export function deserializeBytes(value: string) { return Buffer.from(value, 'binary'); } export function log(suffix: keyof typeof LOG_SUFFIX, ...data: any) { /* eslint-disable max-len */ /* eslint-disable no-console */ const func = suffix === 'UNEXPECTED RESPONSE' ? console.error : suffix === 'INVOKE ERROR' || suffix === 'UNEXPECTED UPDATE' ? console.warn : console.log; /* eslint-enable no-console */ func( `%cGramJS%c${suffix}`, `color: ${LOG_PREFIX_COLOR}; background: ${LOG_BACKGROUND}; padding: 0.25rem; border-radius: 0.25rem;`, `color: ${LOG_SUFFIX[suffix]}; background: ${LOG_BACKGROUND}; padding: 0.25rem; border-radius: 0.25rem; margin-left: 0.25rem;`, ...data, ); /* eslint-enable max-len */ } export function isResponseUpdate(result: T['__response']): result is GramJs.TypeUpdate { return result instanceof GramJs.UpdatesTooLong || result instanceof GramJs.UpdateShortMessage || result instanceof GramJs.UpdateShortChatMessage || result instanceof GramJs.UpdateShort || result instanceof GramJs.UpdatesCombined || result instanceof GramJs.Updates || result instanceof GramJs.UpdateShortSentMessage; } export function checkErrorType(error: unknown): error is Error { if (!(error instanceof Error)) { // eslint-disable-next-line no-console if (DEBUG) console.warn('Unexpected error type', error); return false; } return true; } export function wrapError(error: T): WrappedError { let messageKey: RegularLangFnParameters | undefined; const errorMessage = error instanceof errors.RPCError ? error.errorMessage : undefined; if (error instanceof errors.FloodWaitError) { messageKey = { key: 'ErrorFloodTime', variables: { time: formatWait(error.seconds) }, }; } else if (error instanceof errors.PasswordFreshError) { messageKey = { key: 'ErrorPasswordFresh', variables: { time: formatWait(error.seconds) }, }; } else if (error instanceof errors.RPCError) { messageKey = { key: ERROR_KEYS[error.errorMessage], }; } if (!messageKey) { if (error.message) { messageKey = { key: 'ErrorUnexpectedMessage', variables: { error: error.message }, }; } else { messageKey = { key: 'ErrorUnexpected', }; } } return { messageKey, errorMessage, error, }; } function formatWait(seconds: number): RegularLangFnParameters { if (seconds < MINUTE) { return { key: 'Seconds', variables: { count: seconds }, options: { pluralValue: seconds }, }; } if (seconds < HOUR) { const minutes = getMinutes(seconds); return { key: 'Minutes', variables: { count: minutes }, options: { pluralValue: minutes }, }; } if (seconds < DAY) { const hours = getHours(seconds); return { key: 'Hours', variables: { count: hours }, options: { pluralValue: hours }, }; } const days = getDays(seconds); return { key: 'Days', variables: { count: days }, options: { pluralValue: days }, }; }