568 lines
14 KiB
TypeScript
568 lines
14 KiB
TypeScript
import BigInt from 'big-integer';
|
|
import { Api as GramJs } from '../../../lib/gramjs';
|
|
|
|
import type {
|
|
ApiBotApp,
|
|
ApiChat, ApiPeer, ApiThemeParameters, ApiUser, OnApiUpdate,
|
|
} from '../../types';
|
|
|
|
import { WEB_APP_PLATFORM } from '../../../config';
|
|
import { buildCollectionByKey } from '../../../util/iteratees';
|
|
import {
|
|
buildApiAttachBot,
|
|
buildApiBotApp,
|
|
buildApiBotInlineMediaResult,
|
|
buildApiBotInlineResult,
|
|
buildBotSwitchPm,
|
|
buildBotSwitchWebview,
|
|
} from '../apiBuilders/bots';
|
|
import { buildApiChatFromPreview } from '../apiBuilders/chats';
|
|
import { omitVirtualClassFields } from '../apiBuilders/helpers';
|
|
import { buildApiUrlAuthResult } from '../apiBuilders/misc';
|
|
import { buildApiUser } from '../apiBuilders/users';
|
|
import {
|
|
buildInputBotApp,
|
|
buildInputEntity,
|
|
buildInputPeer,
|
|
buildInputReplyToMessage,
|
|
buildInputThemeParams,
|
|
generateRandomBigInt,
|
|
} from '../gramjsBuilders';
|
|
import { addEntitiesToLocalDb, addUserToLocalDb, deserializeBytes } from '../helpers';
|
|
import localDb from '../localDb';
|
|
import { invokeRequest } from './client';
|
|
|
|
let onUpdate: OnApiUpdate;
|
|
|
|
export function init(_onUpdate: OnApiUpdate) {
|
|
onUpdate = _onUpdate;
|
|
}
|
|
|
|
export async function answerCallbackButton({
|
|
chatId, accessHash, messageId, data, isGame,
|
|
}: {
|
|
chatId: string; accessHash?: string; messageId: number; data?: string; isGame?: boolean;
|
|
}) {
|
|
const result = await invokeRequest(new GramJs.messages.GetBotCallbackAnswer({
|
|
peer: buildInputPeer(chatId, accessHash),
|
|
msgId: messageId,
|
|
data: data ? deserializeBytes(data) : undefined,
|
|
game: isGame || undefined,
|
|
}));
|
|
|
|
return result ? omitVirtualClassFields(result) : undefined;
|
|
}
|
|
|
|
export async function fetchTopInlineBots() {
|
|
const topPeers = await invokeRequest(new GramJs.contacts.GetTopPeers({
|
|
botsInline: true,
|
|
}));
|
|
|
|
if (!(topPeers instanceof GramJs.contacts.TopPeers)) {
|
|
return undefined;
|
|
}
|
|
|
|
const users = topPeers.users.map(buildApiUser).filter(Boolean);
|
|
const ids = users.map(({ id }) => id);
|
|
|
|
return {
|
|
ids,
|
|
users,
|
|
};
|
|
}
|
|
|
|
export async function fetchInlineBot({ username }: { username: string }) {
|
|
const resolvedPeer = await invokeRequest(new GramJs.contacts.ResolveUsername({ username }));
|
|
|
|
if (
|
|
!resolvedPeer
|
|
|| !(
|
|
resolvedPeer.users[0] instanceof GramJs.User
|
|
&& resolvedPeer.users[0].bot
|
|
&& resolvedPeer.users[0].botInlinePlaceholder
|
|
)
|
|
) {
|
|
return undefined;
|
|
}
|
|
|
|
addUserToLocalDb(resolvedPeer.users[0]);
|
|
|
|
return {
|
|
user: buildApiUser(resolvedPeer.users[0]),
|
|
chat: buildApiChatFromPreview(resolvedPeer.users[0]),
|
|
};
|
|
}
|
|
|
|
export async function fetchInlineBotResults({
|
|
bot, chat, query, offset = '',
|
|
}: {
|
|
bot: ApiUser; chat: ApiChat; query: string; offset?: string;
|
|
}) {
|
|
const result = await invokeRequest(new GramJs.messages.GetInlineBotResults({
|
|
bot: buildInputPeer(bot.id, bot.accessHash),
|
|
peer: buildInputPeer(chat.id, chat.accessHash),
|
|
query,
|
|
offset,
|
|
}));
|
|
|
|
if (!result) {
|
|
return undefined;
|
|
}
|
|
|
|
addEntitiesToLocalDb(result.users);
|
|
|
|
return {
|
|
isGallery: Boolean(result.gallery),
|
|
help: bot.botPlaceholder,
|
|
nextOffset: getInlineBotResultsNextOffset(bot.usernames![0].username, result.nextOffset),
|
|
switchPm: buildBotSwitchPm(result.switchPm),
|
|
switchWebview: buildBotSwitchWebview(result.switchWebview),
|
|
users: result.users.map(buildApiUser).filter(Boolean),
|
|
results: processInlineBotResult(String(result.queryId), result.results),
|
|
cacheTime: result.cacheTime,
|
|
};
|
|
}
|
|
|
|
export async function sendInlineBotResult({
|
|
chat, replyingToTopId, resultId, queryId, replyingTo, sendAs, isSilent, scheduleDate,
|
|
}: {
|
|
chat: ApiChat;
|
|
replyingToTopId?: number;
|
|
resultId: string;
|
|
queryId: string;
|
|
replyingTo?: number;
|
|
sendAs?: ApiPeer;
|
|
isSilent?: boolean;
|
|
scheduleDate?: number;
|
|
}) {
|
|
const randomId = generateRandomBigInt();
|
|
|
|
await invokeRequest(new GramJs.messages.SendInlineBotResult({
|
|
clearDraft: true,
|
|
randomId,
|
|
queryId: BigInt(queryId),
|
|
peer: buildInputPeer(chat.id, chat.accessHash),
|
|
id: resultId,
|
|
scheduleDate,
|
|
...(replyingToTopId && { topMsgId: replyingToTopId }),
|
|
...(isSilent && { silent: true }),
|
|
...(replyingTo && { replyToMsgId: replyingTo }),
|
|
...(sendAs && { sendAs: buildInputPeer(sendAs.id, sendAs.accessHash) }),
|
|
}));
|
|
}
|
|
|
|
export async function startBot({
|
|
bot, startParam,
|
|
}: {
|
|
bot: ApiUser;
|
|
startParam?: string;
|
|
}) {
|
|
const randomId = generateRandomBigInt();
|
|
|
|
await invokeRequest(new GramJs.messages.StartBot({
|
|
bot: buildInputPeer(bot.id, bot.accessHash),
|
|
peer: buildInputPeer(bot.id, bot.accessHash),
|
|
randomId,
|
|
startParam,
|
|
}));
|
|
}
|
|
|
|
export async function requestWebView({
|
|
isSilent,
|
|
peer,
|
|
bot,
|
|
url,
|
|
startParam,
|
|
replyToMessageId,
|
|
threadId,
|
|
theme,
|
|
sendAs,
|
|
isFromBotMenu,
|
|
}: {
|
|
isSilent?: boolean;
|
|
peer: ApiPeer;
|
|
bot: ApiUser;
|
|
url?: string;
|
|
startParam?: string;
|
|
replyToMessageId?: number;
|
|
threadId?: number;
|
|
theme?: ApiThemeParameters;
|
|
sendAs?: ApiPeer;
|
|
isFromBotMenu?: boolean;
|
|
}) {
|
|
const result = await invokeRequest(new GramJs.messages.RequestWebView({
|
|
silent: isSilent || undefined,
|
|
peer: buildInputPeer(peer.id, peer.accessHash),
|
|
bot: buildInputPeer(bot.id, bot.accessHash),
|
|
url,
|
|
startParam,
|
|
themeParams: theme ? buildInputThemeParams(theme) : undefined,
|
|
fromBotMenu: isFromBotMenu || undefined,
|
|
platform: WEB_APP_PLATFORM,
|
|
...(replyToMessageId && { replyTo: buildInputReplyToMessage(replyToMessageId, threadId) }),
|
|
...(sendAs && { sendAs: buildInputPeer(sendAs.id, sendAs.accessHash) }),
|
|
}));
|
|
|
|
if (result instanceof GramJs.WebViewResultUrl) {
|
|
return {
|
|
url: result.url,
|
|
queryId: result.queryId.toString(),
|
|
};
|
|
}
|
|
|
|
return undefined;
|
|
}
|
|
|
|
export async function requestSimpleWebView({
|
|
bot,
|
|
url,
|
|
theme,
|
|
startParam,
|
|
isFromSwitchWebView,
|
|
isFromSideMenu,
|
|
}: {
|
|
bot: ApiUser;
|
|
url?: string;
|
|
theme?: ApiThemeParameters;
|
|
startParam?: string;
|
|
isFromSwitchWebView?: boolean;
|
|
isFromSideMenu?: boolean;
|
|
}) {
|
|
const result = await invokeRequest(new GramJs.messages.RequestSimpleWebView({
|
|
url,
|
|
bot: buildInputPeer(bot.id, bot.accessHash),
|
|
themeParams: theme ? buildInputThemeParams(theme) : undefined,
|
|
platform: WEB_APP_PLATFORM,
|
|
startParam,
|
|
fromSwitchWebview: isFromSwitchWebView || undefined,
|
|
fromSideMenu: isFromSideMenu || undefined,
|
|
}));
|
|
|
|
return result?.url;
|
|
}
|
|
|
|
export async function fetchBotApp({
|
|
bot,
|
|
appName,
|
|
}: {
|
|
bot: ApiUser;
|
|
appName: string;
|
|
}) {
|
|
const result = await invokeRequest(new GramJs.messages.GetBotApp({
|
|
app: new GramJs.InputBotAppShortName({
|
|
botId: buildInputEntity(bot.id, bot.accessHash) as GramJs.InputUser,
|
|
shortName: appName,
|
|
}),
|
|
}));
|
|
|
|
if (!result || result instanceof GramJs.BotAppNotModified) {
|
|
return undefined;
|
|
}
|
|
|
|
return buildApiBotApp(result);
|
|
}
|
|
|
|
export async function requestAppWebView({
|
|
peer,
|
|
app,
|
|
startParam,
|
|
theme,
|
|
isWriteAllowed,
|
|
}: {
|
|
peer: ApiPeer;
|
|
app: ApiBotApp;
|
|
startParam?: string;
|
|
theme?: ApiThemeParameters;
|
|
isWriteAllowed?: boolean;
|
|
}) {
|
|
const result = await invokeRequest(new GramJs.messages.RequestAppWebView({
|
|
peer: buildInputPeer(peer.id, peer.accessHash),
|
|
app: buildInputBotApp(app),
|
|
startParam,
|
|
themeParams: theme ? buildInputThemeParams(theme) : undefined,
|
|
platform: WEB_APP_PLATFORM,
|
|
writeAllowed: isWriteAllowed || undefined,
|
|
}));
|
|
|
|
return result?.url;
|
|
}
|
|
|
|
export function prolongWebView({
|
|
isSilent,
|
|
peer,
|
|
bot,
|
|
queryId,
|
|
replyToMessageId,
|
|
threadId,
|
|
sendAs,
|
|
}: {
|
|
isSilent?: boolean;
|
|
peer: ApiPeer;
|
|
bot: ApiUser;
|
|
queryId: string;
|
|
replyToMessageId?: number;
|
|
threadId?: number;
|
|
sendAs?: ApiPeer;
|
|
}) {
|
|
return invokeRequest(new GramJs.messages.ProlongWebView({
|
|
silent: isSilent || undefined,
|
|
peer: buildInputPeer(peer.id, peer.accessHash),
|
|
bot: buildInputPeer(bot.id, bot.accessHash),
|
|
queryId: BigInt(queryId),
|
|
...(replyToMessageId && { replyTo: buildInputReplyToMessage(replyToMessageId, threadId) }),
|
|
...(sendAs && { sendAs: buildInputPeer(sendAs.id, sendAs.accessHash) }),
|
|
}));
|
|
}
|
|
|
|
export async function sendWebViewData({
|
|
bot, buttonText, data,
|
|
}: {
|
|
bot: ApiUser;
|
|
buttonText: string;
|
|
data: string;
|
|
}) {
|
|
const randomId = generateRandomBigInt();
|
|
await invokeRequest(new GramJs.messages.SendWebViewData({
|
|
bot: buildInputPeer(bot.id, bot.accessHash),
|
|
buttonText,
|
|
data,
|
|
randomId,
|
|
}));
|
|
}
|
|
|
|
export async function loadAttachBots({
|
|
hash,
|
|
}: {
|
|
hash?: string;
|
|
}) {
|
|
const result = await invokeRequest(new GramJs.messages.GetAttachMenuBots({
|
|
hash: hash ? BigInt(hash) : undefined,
|
|
}));
|
|
|
|
if (result instanceof GramJs.AttachMenuBots) {
|
|
addEntitiesToLocalDb(result.users);
|
|
return {
|
|
hash: result.hash.toString(),
|
|
bots: buildCollectionByKey(result.bots.map(buildApiAttachBot), 'id'),
|
|
users: result.users.map(buildApiUser).filter(Boolean),
|
|
};
|
|
}
|
|
return undefined;
|
|
}
|
|
|
|
export async function loadAttachBot({
|
|
bot,
|
|
}: {
|
|
bot: ApiUser;
|
|
}) {
|
|
const result = await invokeRequest(new GramJs.messages.GetAttachMenuBot({
|
|
bot: buildInputPeer(bot.id, bot.accessHash),
|
|
}));
|
|
|
|
if (result instanceof GramJs.AttachMenuBotsBot) {
|
|
addEntitiesToLocalDb(result.users);
|
|
return {
|
|
bot: buildApiAttachBot(result.bot),
|
|
users: result.users.map(buildApiUser).filter(Boolean),
|
|
};
|
|
}
|
|
return undefined;
|
|
}
|
|
|
|
export function toggleAttachBot({
|
|
bot,
|
|
isWriteAllowed,
|
|
isEnabled,
|
|
}: {
|
|
bot: ApiUser;
|
|
isWriteAllowed?: boolean;
|
|
isEnabled: boolean;
|
|
}) {
|
|
return invokeRequest(new GramJs.messages.ToggleBotInAttachMenu({
|
|
bot: buildInputPeer(bot.id, bot.accessHash),
|
|
writeAllowed: isWriteAllowed || undefined,
|
|
enabled: isEnabled,
|
|
}));
|
|
}
|
|
|
|
export async function requestBotUrlAuth({
|
|
chat, buttonId, messageId,
|
|
}: {
|
|
chat: ApiChat;
|
|
buttonId: number;
|
|
messageId: number;
|
|
}) {
|
|
const result = await invokeRequest(new GramJs.messages.RequestUrlAuth({
|
|
peer: buildInputPeer(chat.id, chat.accessHash),
|
|
buttonId,
|
|
msgId: messageId,
|
|
}));
|
|
|
|
if (!result) return undefined;
|
|
|
|
const authResult = buildApiUrlAuthResult(result);
|
|
if (authResult?.type === 'request') {
|
|
onUpdate({
|
|
'@type': 'updateUser',
|
|
id: authResult.bot.id,
|
|
user: authResult.bot,
|
|
});
|
|
}
|
|
return authResult;
|
|
}
|
|
|
|
export async function acceptBotUrlAuth({
|
|
chat,
|
|
messageId,
|
|
buttonId,
|
|
isWriteAllowed,
|
|
}: {
|
|
chat: ApiChat;
|
|
messageId: number;
|
|
buttonId: number;
|
|
isWriteAllowed?: boolean;
|
|
}) {
|
|
const result = await invokeRequest(new GramJs.messages.AcceptUrlAuth({
|
|
peer: buildInputPeer(chat.id, chat.accessHash),
|
|
msgId: messageId,
|
|
buttonId,
|
|
writeAllowed: isWriteAllowed || undefined,
|
|
}));
|
|
|
|
if (!result) return undefined;
|
|
|
|
const authResult = buildApiUrlAuthResult(result);
|
|
if (authResult?.type === 'request') {
|
|
onUpdate({
|
|
'@type': 'updateUser',
|
|
id: authResult.bot.id,
|
|
user: authResult.bot,
|
|
});
|
|
}
|
|
return authResult;
|
|
}
|
|
|
|
export async function requestLinkUrlAuth({ url }: { url: string }) {
|
|
const result = await invokeRequest(new GramJs.messages.RequestUrlAuth({
|
|
url,
|
|
}));
|
|
|
|
if (!result) return undefined;
|
|
|
|
const authResult = buildApiUrlAuthResult(result);
|
|
if (authResult?.type === 'request') {
|
|
onUpdate({
|
|
'@type': 'updateUser',
|
|
id: authResult.bot.id,
|
|
user: authResult.bot,
|
|
});
|
|
}
|
|
return authResult;
|
|
}
|
|
|
|
export async function acceptLinkUrlAuth({ url, isWriteAllowed }: { url: string; isWriteAllowed?: boolean }) {
|
|
const result = await invokeRequest(new GramJs.messages.AcceptUrlAuth({
|
|
url,
|
|
writeAllowed: isWriteAllowed || undefined,
|
|
}));
|
|
|
|
if (!result) return undefined;
|
|
|
|
const authResult = buildApiUrlAuthResult(result);
|
|
if (authResult?.type === 'request') {
|
|
onUpdate({
|
|
'@type': 'updateUser',
|
|
id: authResult.bot.id,
|
|
user: authResult.bot,
|
|
});
|
|
}
|
|
return authResult;
|
|
}
|
|
|
|
export function fetchBotCanSendMessage({ bot } : { bot: ApiUser }) {
|
|
return invokeRequest(new GramJs.bots.CanSendMessage({
|
|
bot: buildInputEntity(bot.id, bot.accessHash) as GramJs.InputUser,
|
|
}));
|
|
}
|
|
|
|
export function allowBotSendMessages({ bot } : { bot: ApiUser }) {
|
|
return invokeRequest(new GramJs.bots.AllowSendMessage({
|
|
bot: buildInputEntity(bot.id, bot.accessHash) as GramJs.InputUser,
|
|
}), {
|
|
shouldReturnTrue: true,
|
|
});
|
|
}
|
|
|
|
export async function invokeWebViewCustomMethod({
|
|
bot,
|
|
customMethod,
|
|
parameters,
|
|
}: {
|
|
bot: ApiUser;
|
|
customMethod: string;
|
|
parameters: string;
|
|
}): Promise<{
|
|
result: object;
|
|
} | {
|
|
error: string;
|
|
}> {
|
|
try {
|
|
const result = await invokeRequest(new GramJs.bots.InvokeWebViewCustomMethod({
|
|
bot: buildInputPeer(bot.id, bot.accessHash),
|
|
params: new GramJs.DataJSON({
|
|
data: parameters,
|
|
}),
|
|
customMethod,
|
|
}), {
|
|
shouldThrow: true,
|
|
});
|
|
|
|
return {
|
|
result: JSON.parse(result!.data),
|
|
};
|
|
} catch (e) {
|
|
const error = e as Error;
|
|
return {
|
|
error: error.message,
|
|
};
|
|
}
|
|
}
|
|
|
|
function processInlineBotResult(queryId: string, results: GramJs.TypeBotInlineResult[]) {
|
|
return results.map((result) => {
|
|
if (result instanceof GramJs.BotInlineMediaResult) {
|
|
if (result.document instanceof GramJs.Document) {
|
|
addDocumentToLocalDb(result.document);
|
|
}
|
|
|
|
if (result.photo instanceof GramJs.Photo) {
|
|
addPhotoToLocalDb(result.photo);
|
|
}
|
|
|
|
return buildApiBotInlineMediaResult(result, queryId);
|
|
}
|
|
|
|
if (result.thumb) {
|
|
addWebDocumentToLocalDb(result.thumb);
|
|
}
|
|
|
|
return buildApiBotInlineResult(result, queryId);
|
|
});
|
|
}
|
|
|
|
function getInlineBotResultsNextOffset(username: string, nextOffset?: string) {
|
|
return username === 'gif' && nextOffset === '0' ? '' : nextOffset;
|
|
}
|
|
|
|
function addDocumentToLocalDb(document: GramJs.Document) {
|
|
localDb.documents[String(document.id)] = document;
|
|
}
|
|
|
|
function addPhotoToLocalDb(photo: GramJs.Photo) {
|
|
localDb.photos[String(photo.id)] = photo;
|
|
}
|
|
|
|
function addWebDocumentToLocalDb(webDocument: GramJs.TypeWebDocument) {
|
|
localDb.webDocuments[webDocument.url] = webDocument;
|
|
}
|