2021-04-08 17:13:05 +02:00
|
|
|
|
/*
|
|
|
|
|
* https://github.com/morethanwords/tweb
|
|
|
|
|
* Copyright (C) 2019-2021 Eduard Kuzmenko
|
|
|
|
|
* https://github.com/morethanwords/tweb/blob/master/LICENSE
|
2022-08-04 08:49:54 +02:00
|
|
|
|
*
|
2021-04-08 17:13:05 +02:00
|
|
|
|
* Originally from:
|
|
|
|
|
* https://github.com/zhukov/webogram
|
|
|
|
|
* Copyright (C) 2014 Igor Zhukov <igor.beatle@gmail.com>
|
|
|
|
|
* https://github.com/zhukov/webogram/blob/master/LICENSE
|
|
|
|
|
*/
|
|
|
|
|
|
2022-08-04 08:49:54 +02:00
|
|
|
|
import type {MyTopPeer} from './appUsersManager';
|
|
|
|
|
import tsNow from '../../helpers/tsNow';
|
|
|
|
|
import {ChannelParticipantsFilter, ChannelsChannelParticipants, ChannelParticipant, Chat, ChatFull, ChatParticipants, ChatPhoto, ExportedChatInvite, InputChannel, InputFile, SendMessageAction, Update, UserFull, Photo, PhotoSize, Updates} from '../../layer';
|
|
|
|
|
import SearchIndex from '../searchIndex';
|
|
|
|
|
import {AppManager} from './manager';
|
|
|
|
|
import getServerMessageId from './utils/messageId/getServerMessageId';
|
|
|
|
|
import getPhotoInput from './utils/photos/getPhotoInput';
|
|
|
|
|
import getParticipantPeerId from './utils/chats/getParticipantPeerId';
|
|
|
|
|
import ctx from '../../environment/ctx';
|
|
|
|
|
import {ReferenceContext} from '../mtproto/referenceDatabase';
|
2023-01-06 20:27:29 +01:00
|
|
|
|
import generateMessageId from './utils/messageId/generateMessageId';
|
2023-02-27 14:11:37 +01:00
|
|
|
|
import assumeType from '../../helpers/assumeType';
|
|
|
|
|
import makeError from '../../helpers/makeError';
|
2023-03-07 22:25:07 +01:00
|
|
|
|
import callbackify from '../../helpers/callbackify';
|
2021-04-08 17:13:05 +02:00
|
|
|
|
|
2021-10-21 15:16:43 +02:00
|
|
|
|
export type UserTyping = Partial<{userId: UserId, action: SendMessageAction, timeout: number}>;
|
2021-04-08 17:13:05 +02:00
|
|
|
|
|
2022-09-25 19:49:33 +02:00
|
|
|
|
const PEER_FULL_TTL = 3 * 60e3;
|
|
|
|
|
|
2022-04-25 16:54:30 +02:00
|
|
|
|
export class AppProfileManager extends AppManager {
|
2022-08-04 08:49:54 +02:00
|
|
|
|
// private botInfos: any = {};
|
2022-02-08 20:18:01 +01:00
|
|
|
|
private usersFull: {[id: UserId]: UserFull.userFull} = {};
|
|
|
|
|
private chatsFull: {[id: ChatId]: ChatFull} = {};
|
2022-09-25 19:49:33 +02:00
|
|
|
|
private fullExpiration: {[peerId: PeerId]: number} = {};
|
2023-01-06 20:27:29 +01:00
|
|
|
|
private typingsInPeer: {[key: string]: UserTyping[]};
|
2021-04-08 17:13:05 +02:00
|
|
|
|
|
2022-06-17 18:01:43 +02:00
|
|
|
|
protected after() {
|
|
|
|
|
this.apiUpdatesManager.addMultipleEventsListeners({
|
2023-02-27 14:11:37 +01:00
|
|
|
|
updateChatParticipants: this.onUpdateChatParticipants,
|
2021-04-08 17:13:05 +02:00
|
|
|
|
|
2023-02-27 14:11:37 +01:00
|
|
|
|
updateChatParticipantAdd: this.onUpdateChatParticipantAdd,
|
2021-04-24 19:06:24 +02:00
|
|
|
|
|
2023-02-27 14:11:37 +01:00
|
|
|
|
updateChatParticipantDelete: this.onUpdateChatParticipantDelete,
|
2021-06-18 14:00:30 +02:00
|
|
|
|
|
|
|
|
|
updateUserTyping: this.onUpdateUserTyping,
|
|
|
|
|
updateChatUserTyping: this.onUpdateUserTyping,
|
2021-09-25 21:47:43 +02:00
|
|
|
|
updateChannelUserTyping: this.onUpdateUserTyping,
|
|
|
|
|
|
|
|
|
|
updatePeerBlocked: this.onUpdatePeerBlocked
|
2021-04-08 17:13:05 +02:00
|
|
|
|
});
|
2021-04-24 19:06:24 +02:00
|
|
|
|
|
2022-06-17 18:01:43 +02:00
|
|
|
|
this.rootScope.addEventListener('chat_update', (chatId) => {
|
2021-04-08 17:13:05 +02:00
|
|
|
|
const fullChat = this.chatsFull[chatId];
|
2022-04-25 16:54:30 +02:00
|
|
|
|
const chat: Chat.chat | Chat.channel | Chat.chatForbidden | Chat.channelForbidden = this.appChatsManager.getChat(chatId);
|
2021-12-11 17:37:08 +01:00
|
|
|
|
if(!fullChat || !chat) {
|
2021-04-08 17:13:05 +02:00
|
|
|
|
return;
|
|
|
|
|
}
|
2021-05-03 22:02:53 +02:00
|
|
|
|
|
2021-12-11 17:37:08 +01:00
|
|
|
|
let updated = false;
|
|
|
|
|
if(!!fullChat.call !== !!(chat as Chat.chat).pFlags?.call_active) {
|
|
|
|
|
updated = true;
|
2021-04-08 17:13:05 +02:00
|
|
|
|
}
|
2021-12-11 17:37:08 +01:00
|
|
|
|
|
|
|
|
|
const {photo} = chat as Chat.chat;
|
|
|
|
|
if(photo) {
|
|
|
|
|
const hasChatPhoto = photo._ !== 'chatPhotoEmpty';
|
2022-02-08 20:18:01 +01:00
|
|
|
|
const hasFullChatPhoto = !!(fullChat.chat_photo && fullChat.chat_photo._ !== 'photoEmpty'); // chat_photo can be missing
|
2022-02-21 16:29:25 +01:00
|
|
|
|
if(
|
|
|
|
|
hasChatPhoto !== hasFullChatPhoto || (
|
2022-08-04 08:49:54 +02:00
|
|
|
|
hasChatPhoto &&
|
2022-02-21 16:29:25 +01:00
|
|
|
|
photo.photo_id !== fullChat.chat_photo?.id
|
|
|
|
|
)
|
|
|
|
|
) {
|
2021-12-11 17:37:08 +01:00
|
|
|
|
updated = true;
|
|
|
|
|
}
|
2021-04-08 17:13:05 +02:00
|
|
|
|
}
|
|
|
|
|
|
2021-12-11 17:37:08 +01:00
|
|
|
|
if(updated) {
|
|
|
|
|
this.refreshFullPeer(chatId.toPeerId(true));
|
2021-04-08 17:13:05 +02:00
|
|
|
|
}
|
|
|
|
|
});
|
2021-06-18 14:00:30 +02:00
|
|
|
|
|
2022-06-17 18:01:43 +02:00
|
|
|
|
this.rootScope.addEventListener('channel_update', (chatId) => {
|
2022-02-20 16:37:37 +01:00
|
|
|
|
this.refreshFullPeer(chatId.toPeerId(true));
|
|
|
|
|
});
|
|
|
|
|
|
2021-12-11 17:37:08 +01:00
|
|
|
|
// * genius
|
2022-06-17 18:01:43 +02:00
|
|
|
|
this.rootScope.addEventListener('chat_full_update', (chatId) => {
|
|
|
|
|
this.rootScope.dispatchEvent('peer_full_update', chatId.toPeerId(true));
|
2021-12-11 17:37:08 +01:00
|
|
|
|
});
|
2022-08-04 08:49:54 +02:00
|
|
|
|
|
2021-12-11 17:37:08 +01:00
|
|
|
|
// * genius
|
2022-06-17 18:01:43 +02:00
|
|
|
|
this.rootScope.addEventListener('user_full_update', (userId) => {
|
|
|
|
|
this.rootScope.dispatchEvent('peer_full_update', userId.toPeerId(false));
|
2021-12-11 17:37:08 +01:00
|
|
|
|
});
|
|
|
|
|
|
2022-06-17 18:01:43 +02:00
|
|
|
|
this.rootScope.addEventListener('invalidate_participants', (chatId) => {
|
2021-06-18 14:00:30 +02:00
|
|
|
|
this.invalidateChannelParticipants(chatId);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
this.typingsInPeer = {};
|
2021-04-08 17:13:05 +02:00
|
|
|
|
}
|
|
|
|
|
|
2021-05-25 21:00:33 +02:00
|
|
|
|
/* public saveBotInfo(botInfo: any) {
|
2021-04-08 17:13:05 +02:00
|
|
|
|
const botId = botInfo && botInfo.user_id;
|
|
|
|
|
if(!botId) {
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const commands: any = {};
|
|
|
|
|
botInfo.commands.forEach((botCommand: any) => {
|
|
|
|
|
commands[botCommand.command] = botCommand.description;
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
return this.botInfos[botId] = {
|
|
|
|
|
id: botId,
|
|
|
|
|
version: botInfo.version,
|
|
|
|
|
shareText: botInfo.share_text,
|
|
|
|
|
description: botInfo.description,
|
|
|
|
|
commands: commands
|
|
|
|
|
};
|
2021-05-25 21:00:33 +02:00
|
|
|
|
} */
|
2021-04-08 17:13:05 +02:00
|
|
|
|
|
2022-02-08 20:18:01 +01:00
|
|
|
|
public getProfile(id: UserId, override?: true) {
|
2022-09-25 19:49:33 +02:00
|
|
|
|
if(this.usersFull[id] && !override && Date.now() < this.fullExpiration[id.toPeerId()]) {
|
2022-02-08 20:18:01 +01:00
|
|
|
|
return this.usersFull[id];
|
2021-04-08 17:13:05 +02:00
|
|
|
|
}
|
|
|
|
|
|
2022-06-17 18:01:43 +02:00
|
|
|
|
return this.apiManager.invokeApiSingleProcess({
|
2022-08-04 08:49:54 +02:00
|
|
|
|
method: 'users.getFullUser',
|
2021-12-11 17:37:08 +01:00
|
|
|
|
params: {
|
2022-04-25 16:54:30 +02:00
|
|
|
|
id: this.appUsersManager.getUserInput(id)
|
2021-12-11 17:37:08 +01:00
|
|
|
|
},
|
2022-01-08 13:52:14 +01:00
|
|
|
|
processResult: (usersUserFull) => {
|
2022-04-25 16:54:30 +02:00
|
|
|
|
this.appChatsManager.saveApiChats(usersUserFull.chats, true);
|
|
|
|
|
this.appUsersManager.saveApiUsers(usersUserFull.users);
|
2022-01-08 13:52:14 +01:00
|
|
|
|
|
|
|
|
|
const userFull = usersUserFull.full_user;
|
2021-12-11 17:37:08 +01:00
|
|
|
|
const peerId = id.toPeerId(false);
|
|
|
|
|
if(userFull.profile_photo) {
|
2022-04-25 16:54:30 +02:00
|
|
|
|
userFull.profile_photo = this.appPhotosManager.savePhoto(userFull.profile_photo, {type: 'profilePhoto', peerId});
|
2021-12-11 17:37:08 +01:00
|
|
|
|
}
|
2021-04-08 17:13:05 +02:00
|
|
|
|
|
2022-07-20 18:58:08 +02:00
|
|
|
|
const botInfo = userFull.bot_info;
|
|
|
|
|
if(botInfo) {
|
|
|
|
|
const referenceContext: ReferenceContext = {type: 'userFull', userId: id};
|
|
|
|
|
botInfo.description_document = this.appDocsManager.saveDoc(botInfo.description_document, referenceContext);
|
|
|
|
|
botInfo.description_photo = this.appPhotosManager.savePhoto(botInfo.description_photo, referenceContext);
|
|
|
|
|
}
|
|
|
|
|
|
2022-04-25 16:54:30 +02:00
|
|
|
|
this.appNotificationsManager.savePeerSettings({
|
2022-08-04 08:49:54 +02:00
|
|
|
|
peerId,
|
2021-12-11 17:37:08 +01:00
|
|
|
|
settings: userFull.notify_settings
|
|
|
|
|
});
|
2021-04-08 17:13:05 +02:00
|
|
|
|
|
2022-01-08 13:52:14 +01:00
|
|
|
|
this.usersFull[id] = userFull;
|
2022-09-25 19:49:33 +02:00
|
|
|
|
this.fullExpiration[peerId] = Date.now() + PEER_FULL_TTL;
|
2021-04-08 17:13:05 +02:00
|
|
|
|
|
2021-12-11 17:37:08 +01:00
|
|
|
|
/* if(userFull.bot_info) {
|
|
|
|
|
userFull.bot_info = this.saveBotInfo(userFull.bot_info) as any;
|
|
|
|
|
} */
|
2021-04-08 17:13:05 +02:00
|
|
|
|
|
2022-08-04 08:49:54 +02:00
|
|
|
|
// appMessagesManager.savePinnedMessage(id, userFull.pinned_msg_id);
|
2021-04-08 17:13:05 +02:00
|
|
|
|
|
2022-06-17 18:01:43 +02:00
|
|
|
|
this.rootScope.dispatchEvent('user_full_update', id);
|
2022-01-08 13:52:14 +01:00
|
|
|
|
return userFull;
|
2021-12-11 17:37:08 +01:00
|
|
|
|
}
|
|
|
|
|
});
|
2021-04-08 17:13:05 +02:00
|
|
|
|
}
|
|
|
|
|
|
2022-02-08 20:18:01 +01:00
|
|
|
|
public getProfileByPeerId(peerId: PeerId, override?: true) {
|
2022-04-25 16:54:30 +02:00
|
|
|
|
if(this.appPeersManager.isAnyChat(peerId)) return this.getChatFull(peerId.toChatId(), override);
|
2021-10-21 15:16:43 +02:00
|
|
|
|
else return this.getProfile(peerId.toUserId(), override);
|
2021-04-08 17:13:05 +02:00
|
|
|
|
}
|
|
|
|
|
|
2021-12-11 17:37:08 +01:00
|
|
|
|
public getCachedFullChat(chatId: ChatId) {
|
|
|
|
|
return this.chatsFull[chatId];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public getCachedFullUser(userId: UserId) {
|
|
|
|
|
return this.usersFull[userId];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public getCachedProfileByPeerId(peerId: PeerId) {
|
|
|
|
|
return peerId.isUser() ? this.getCachedFullUser(peerId.toUserId()) : this.getCachedFullChat(peerId.toChatId());
|
|
|
|
|
}
|
|
|
|
|
|
2022-02-08 20:18:01 +01:00
|
|
|
|
public async getFullPhoto(peerId: PeerId) {
|
|
|
|
|
const profile = await this.getProfileByPeerId(peerId);
|
|
|
|
|
switch(profile._) {
|
|
|
|
|
case 'userFull':
|
|
|
|
|
return profile.profile_photo;
|
|
|
|
|
case 'channelFull':
|
|
|
|
|
case 'chatFull':
|
|
|
|
|
return profile.chat_photo;
|
|
|
|
|
}
|
2021-04-08 17:13:05 +02:00
|
|
|
|
}
|
|
|
|
|
|
2021-10-21 15:16:43 +02:00
|
|
|
|
/* public getPeerBots(peerId: PeerId) {
|
2021-04-08 17:13:05 +02:00
|
|
|
|
var peerBots: any[] = [];
|
|
|
|
|
if(peerId >= 0 && !appUsersManager.isBot(peerId) ||
|
|
|
|
|
(appPeersManager.isChannel(peerId) && !appPeersManager.isMegagroup(peerId))) {
|
|
|
|
|
return Promise.resolve(peerBots);
|
|
|
|
|
}
|
|
|
|
|
if(peerId >= 0) {
|
|
|
|
|
return this.getProfile(peerId).then((userFull: any) => {
|
|
|
|
|
var botInfo = userFull.bot_info;
|
|
|
|
|
if(botInfo && botInfo._ !== 'botInfoEmpty') {
|
|
|
|
|
peerBots.push(botInfo);
|
|
|
|
|
}
|
|
|
|
|
return peerBots;
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
2021-10-21 15:16:43 +02:00
|
|
|
|
return this.getChatFull(peerId.toChatId()).then((chatFull: any) => {
|
2021-04-08 17:13:05 +02:00
|
|
|
|
chatFull.bot_info.forEach((botInfo: any) => {
|
|
|
|
|
peerBots.push(this.saveBotInfo(botInfo))
|
|
|
|
|
});
|
|
|
|
|
return peerBots;
|
|
|
|
|
});
|
|
|
|
|
} */
|
|
|
|
|
|
2022-02-08 20:18:01 +01:00
|
|
|
|
public getChatFull(id: ChatId, override?: true) {
|
2022-04-25 16:54:30 +02:00
|
|
|
|
if(this.appChatsManager.isChannel(id)) {
|
2021-04-08 17:13:05 +02:00
|
|
|
|
return this.getChannelFull(id, override);
|
|
|
|
|
}
|
|
|
|
|
|
2022-09-25 19:49:33 +02:00
|
|
|
|
const peerId = id.toPeerId(true);
|
2021-04-08 17:13:05 +02:00
|
|
|
|
const fullChat = this.chatsFull[id] as ChatFull.chatFull;
|
2022-09-25 19:49:33 +02:00
|
|
|
|
if(fullChat && !override && Date.now() < this.fullExpiration[peerId]) {
|
2023-01-06 20:27:29 +01:00
|
|
|
|
const chat = this.appChatsManager.getChat(id) as Chat.chat;
|
2022-11-27 14:09:10 +01:00
|
|
|
|
if(
|
|
|
|
|
chat.pFlags.left ||
|
|
|
|
|
chat.pFlags.deactivated ||
|
|
|
|
|
chat.version === (fullChat.participants as ChatParticipants.chatParticipants).version
|
|
|
|
|
) {
|
2022-02-08 20:18:01 +01:00
|
|
|
|
return fullChat as ChatFull;
|
2021-04-08 17:13:05 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
2022-08-04 08:49:54 +02:00
|
|
|
|
|
2022-06-17 18:01:43 +02:00
|
|
|
|
return this.apiManager.invokeApiSingleProcess({
|
2022-08-04 08:49:54 +02:00
|
|
|
|
method: 'messages.getFullChat',
|
2021-12-11 17:37:08 +01:00
|
|
|
|
params: {
|
|
|
|
|
chat_id: id
|
|
|
|
|
},
|
|
|
|
|
processResult: (result) => {
|
2022-04-25 16:54:30 +02:00
|
|
|
|
this.appChatsManager.saveApiChats(result.chats, true);
|
|
|
|
|
this.appUsersManager.saveApiUsers(result.users);
|
2022-06-17 18:01:43 +02:00
|
|
|
|
const chatFull = result.full_chat as ChatFull.chatFull;
|
|
|
|
|
if(chatFull && chatFull.chat_photo && chatFull.chat_photo.id) {
|
|
|
|
|
chatFull.chat_photo = this.appPhotosManager.savePhoto(chatFull.chat_photo, {type: 'profilePhoto', peerId});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(chatFull.call) {
|
|
|
|
|
this.appGroupCallsManager.saveGroupCall(chatFull.call, id);
|
2021-12-11 17:37:08 +01:00
|
|
|
|
}
|
2021-04-08 17:13:05 +02:00
|
|
|
|
|
2022-08-04 08:49:54 +02:00
|
|
|
|
// appMessagesManager.savePinnedMessage(peerId, fullChat.pinned_msg_id);
|
2022-04-25 16:54:30 +02:00
|
|
|
|
this.appNotificationsManager.savePeerSettings({
|
2022-08-04 08:49:54 +02:00
|
|
|
|
peerId,
|
2022-06-17 18:01:43 +02:00
|
|
|
|
settings: chatFull.notify_settings
|
2021-12-11 17:37:08 +01:00
|
|
|
|
});
|
2022-08-04 08:49:54 +02:00
|
|
|
|
|
2022-06-17 18:01:43 +02:00
|
|
|
|
this.chatsFull[id] = chatFull;
|
2022-09-25 19:49:33 +02:00
|
|
|
|
this.fullExpiration[peerId] = Date.now() + PEER_FULL_TTL;
|
2022-06-17 18:01:43 +02:00
|
|
|
|
this.rootScope.dispatchEvent('chat_full_update', id);
|
2021-04-08 17:13:05 +02:00
|
|
|
|
|
2022-06-17 18:01:43 +02:00
|
|
|
|
return chatFull;
|
2021-04-08 17:13:05 +02:00
|
|
|
|
}
|
2021-12-11 17:37:08 +01:00
|
|
|
|
});
|
2021-04-08 17:13:05 +02:00
|
|
|
|
}
|
|
|
|
|
|
2022-02-08 20:18:01 +01:00
|
|
|
|
public async getChatInviteLink(id: ChatId, force?: boolean) {
|
|
|
|
|
const chatFull = await this.getChatFull(id);
|
|
|
|
|
if(!force &&
|
|
|
|
|
chatFull.exported_invite &&
|
|
|
|
|
chatFull.exported_invite._ == 'chatInviteExported') {
|
|
|
|
|
return chatFull.exported_invite.link;
|
|
|
|
|
}
|
2022-08-04 08:49:54 +02:00
|
|
|
|
|
2022-06-17 18:01:43 +02:00
|
|
|
|
return this.apiManager.invokeApi('messages.exportChatInvite', {
|
2022-04-25 16:54:30 +02:00
|
|
|
|
peer: this.appPeersManager.getInputPeerById(id.toPeerId(true))
|
2022-02-08 20:18:01 +01:00
|
|
|
|
}).then((exportedInvite) => {
|
|
|
|
|
if(this.chatsFull[id] !== undefined) {
|
|
|
|
|
this.chatsFull[id].exported_invite = exportedInvite;
|
2021-04-08 17:13:05 +02:00
|
|
|
|
}
|
|
|
|
|
|
2022-02-08 20:18:01 +01:00
|
|
|
|
return (exportedInvite as ExportedChatInvite.chatInviteExported).link;
|
2021-04-08 17:13:05 +02:00
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
2023-02-27 14:11:37 +01:00
|
|
|
|
public getParticipants(
|
|
|
|
|
id: ChatId,
|
|
|
|
|
filter: ChannelParticipantsFilter = {_: 'channelParticipantsRecent'},
|
|
|
|
|
limit = 200,
|
|
|
|
|
offset = 0
|
|
|
|
|
) {
|
|
|
|
|
if(this.appChatsManager.isChannel(id)) {
|
|
|
|
|
return this.getChannelParticipants(id, filter, limit, offset);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return Promise.resolve(this.getChatFull(id)).then((chatFull) => {
|
|
|
|
|
const chatParticipants = (chatFull as ChatFull.chatFull).participants;
|
|
|
|
|
if(chatParticipants._ !== 'chatParticipants') {
|
|
|
|
|
throw makeError('CHAT_PRIVATE');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(filter._ === 'channelParticipantsSearch' && filter.q.trim()) {
|
|
|
|
|
const index = this.appUsersManager.createSearchIndex();
|
|
|
|
|
chatParticipants.participants.forEach((chatParticipant) => {
|
|
|
|
|
const userId = chatParticipant.user_id;
|
|
|
|
|
index.indexObject(userId, this.appUsersManager.getUserSearchText(userId));
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
const found = index.search(filter.q);
|
|
|
|
|
const filteredParticipants = chatParticipants.participants.filter((chatParticipant) => {
|
|
|
|
|
return found.has(chatParticipant.user_id);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
return {...chatParticipants, participants: filteredParticipants};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return chatParticipants;
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public getParticipant(id: ChatId, peerId: PeerId) {
|
|
|
|
|
if(this.appChatsManager.isChannel(id)) {
|
|
|
|
|
return this.getChannelParticipant(id, peerId);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return this.getParticipants(id).then((chatParticipants) => {
|
|
|
|
|
assumeType<ChatParticipants.chatParticipants>(chatParticipants);
|
|
|
|
|
const found = chatParticipants.participants.find((chatParticipant) => {
|
|
|
|
|
if(getParticipantPeerId(chatParticipant) === peerId) {
|
|
|
|
|
return chatParticipant;
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
if(!found) {
|
|
|
|
|
throw makeError('USER_NOT_PARTICIPANT');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return found;
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public getChannelParticipants(
|
|
|
|
|
id: ChatId,
|
|
|
|
|
filter: ChannelParticipantsFilter = {_: 'channelParticipantsRecent'},
|
|
|
|
|
limit = 200,
|
|
|
|
|
offset = 0
|
|
|
|
|
) {
|
2021-04-08 17:13:05 +02:00
|
|
|
|
if(filter._ === 'channelParticipantsRecent') {
|
2022-04-25 16:54:30 +02:00
|
|
|
|
const chat = this.appChatsManager.getChat(id);
|
2023-01-06 20:27:29 +01:00
|
|
|
|
if(chat?.pFlags && (
|
2022-08-04 08:49:54 +02:00
|
|
|
|
// chat.pFlags.kicked ||
|
2023-01-06 20:27:29 +01:00
|
|
|
|
(chat as Chat.channel).pFlags.broadcast &&
|
|
|
|
|
!(chat as Chat.channel).pFlags.creator &&
|
|
|
|
|
!(chat as Chat.channel).admin_rights
|
2022-08-04 08:49:54 +02:00
|
|
|
|
)) {
|
2021-04-08 17:13:05 +02:00
|
|
|
|
return Promise.reject();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-06-17 18:01:43 +02:00
|
|
|
|
return this.apiManager.invokeApiCacheable('channels.getParticipants', {
|
2022-04-25 16:54:30 +02:00
|
|
|
|
channel: this.appChatsManager.getChannelInput(id),
|
2021-04-08 17:13:05 +02:00
|
|
|
|
filter,
|
|
|
|
|
offset,
|
|
|
|
|
limit,
|
2021-10-21 15:16:43 +02:00
|
|
|
|
hash: '0'
|
2022-06-17 18:01:43 +02:00
|
|
|
|
}, {cacheSeconds: 60}).then((result) => {
|
2022-04-25 16:54:30 +02:00
|
|
|
|
this.appUsersManager.saveApiUsers((result as ChannelsChannelParticipants.channelsChannelParticipants).users);
|
2021-04-08 17:13:05 +02:00
|
|
|
|
return result as ChannelsChannelParticipants.channelsChannelParticipants;
|
|
|
|
|
});
|
|
|
|
|
/* let maybeAddSelf = (participants: any[]) => {
|
|
|
|
|
let chat = appChatsManager.getChat(id);
|
|
|
|
|
let selfMustBeFirst = filter._ === 'channelParticipantsRecent' &&
|
|
|
|
|
!offset &&
|
|
|
|
|
!chat.pFlags.kicked &&
|
|
|
|
|
!chat.pFlags.left;
|
|
|
|
|
|
|
|
|
|
if(selfMustBeFirst) {
|
|
|
|
|
participants = copy(participants);
|
|
|
|
|
let myID = appUsersManager.getSelf().id;
|
2022-06-17 18:01:43 +02:00
|
|
|
|
let myIndex = participants.findIndex((p) => p.user_id === myID);
|
2021-04-08 17:13:05 +02:00
|
|
|
|
let myParticipant;
|
|
|
|
|
|
|
|
|
|
if(myIndex !== -1) {
|
|
|
|
|
myParticipant = participants[myIndex];
|
|
|
|
|
participants.splice(myIndex, 1);
|
|
|
|
|
} else {
|
|
|
|
|
myParticipant = {_: 'channelParticipantSelf', user_id: myID};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
participants.unshift(myParticipant);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return participants;
|
|
|
|
|
} */
|
|
|
|
|
}
|
|
|
|
|
|
2021-10-21 15:16:43 +02:00
|
|
|
|
public getChannelParticipant(id: ChatId, peerId: PeerId) {
|
2022-06-17 18:01:43 +02:00
|
|
|
|
return this.apiManager.invokeApiSingle('channels.getParticipant', {
|
2022-04-25 16:54:30 +02:00
|
|
|
|
channel: this.appChatsManager.getChannelInput(id),
|
2022-08-04 08:49:54 +02:00
|
|
|
|
participant: this.appPeersManager.getInputPeerById(peerId)
|
2022-06-17 18:01:43 +02:00
|
|
|
|
}).then((channelParticipant) => {
|
2022-04-25 16:54:30 +02:00
|
|
|
|
this.appUsersManager.saveApiUsers(channelParticipant.users);
|
2021-04-08 17:13:05 +02:00
|
|
|
|
return channelParticipant.participant;
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
2022-02-11 20:29:25 +01:00
|
|
|
|
public getChannelFull(id: ChatId, override?: true) {
|
2022-09-25 19:49:33 +02:00
|
|
|
|
const peerId = id.toPeerId(true);
|
|
|
|
|
if(this.chatsFull[id] !== undefined && !override && Date.now() < this.fullExpiration[peerId]) {
|
2022-02-11 20:29:25 +01:00
|
|
|
|
return this.chatsFull[id] as ChatFull.channelFull;
|
2021-04-08 17:13:05 +02:00
|
|
|
|
}
|
|
|
|
|
|
2022-06-17 18:01:43 +02:00
|
|
|
|
return this.apiManager.invokeApiSingleProcess({
|
2022-08-04 08:49:54 +02:00
|
|
|
|
method: 'channels.getFullChannel',
|
2021-12-11 17:37:08 +01:00
|
|
|
|
params: {
|
2022-04-25 16:54:30 +02:00
|
|
|
|
channel: this.appChatsManager.getChannelInput(id)
|
2022-08-04 08:49:54 +02:00
|
|
|
|
},
|
2021-12-11 17:37:08 +01:00
|
|
|
|
processResult: (result) => {
|
2022-04-25 16:54:30 +02:00
|
|
|
|
this.appChatsManager.saveApiChats(result.chats, true);
|
|
|
|
|
this.appUsersManager.saveApiUsers(result.users);
|
2021-12-11 17:37:08 +01:00
|
|
|
|
const fullChannel = result.full_chat as ChatFull.channelFull;
|
|
|
|
|
if(fullChannel && fullChannel.chat_photo.id) {
|
2022-04-25 16:54:30 +02:00
|
|
|
|
fullChannel.chat_photo = this.appPhotosManager.savePhoto(fullChannel.chat_photo, {type: 'profilePhoto', peerId});
|
2022-08-04 08:49:54 +02:00
|
|
|
|
// appPhotosManager.savePhoto(fullChannel.chat_photo);
|
2021-12-11 17:37:08 +01:00
|
|
|
|
}
|
2022-06-17 18:01:43 +02:00
|
|
|
|
|
|
|
|
|
if(fullChannel.call) {
|
|
|
|
|
this.appGroupCallsManager.saveGroupCall(fullChannel.call, id);
|
|
|
|
|
}
|
|
|
|
|
|
2022-04-25 16:54:30 +02:00
|
|
|
|
this.appNotificationsManager.savePeerSettings({
|
2022-08-04 08:49:54 +02:00
|
|
|
|
peerId,
|
2021-12-11 17:37:08 +01:00
|
|
|
|
settings: fullChannel.notify_settings
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
this.chatsFull[id] = fullChannel;
|
2022-09-25 19:49:33 +02:00
|
|
|
|
this.fullExpiration[peerId] = Date.now() + PEER_FULL_TTL;
|
2022-06-17 18:01:43 +02:00
|
|
|
|
this.rootScope.dispatchEvent('chat_full_update', id);
|
2021-12-11 17:37:08 +01:00
|
|
|
|
|
|
|
|
|
return fullChannel;
|
2022-08-04 08:49:54 +02:00
|
|
|
|
},
|
2021-12-11 17:37:08 +01:00
|
|
|
|
processError: (error) => {
|
|
|
|
|
switch(error.type) {
|
|
|
|
|
case 'CHANNEL_PRIVATE':
|
2023-01-06 20:27:29 +01:00
|
|
|
|
const channel = this.appChatsManager.getChat(id) as Chat.channel | Chat.channelForbidden;
|
2022-04-25 16:54:30 +02:00
|
|
|
|
this.apiUpdatesManager.processUpdateMessage({
|
2021-12-11 17:37:08 +01:00
|
|
|
|
_: 'updates',
|
|
|
|
|
updates: [{
|
|
|
|
|
_: 'updateChannel',
|
|
|
|
|
channel_id: id
|
2022-06-17 18:01:43 +02:00
|
|
|
|
}],
|
2023-01-06 20:27:29 +01:00
|
|
|
|
chats: [channel._ === 'channelForbidden' ? channel : {
|
2022-06-17 18:01:43 +02:00
|
|
|
|
_: 'channelForbidden',
|
|
|
|
|
id,
|
|
|
|
|
access_hash: channel.access_hash,
|
|
|
|
|
title: channel.title,
|
|
|
|
|
pFlags: channel.pFlags
|
|
|
|
|
}],
|
2021-12-11 17:37:08 +01:00
|
|
|
|
users: []
|
2022-06-17 18:01:43 +02:00
|
|
|
|
} as Updates.updates);
|
2021-12-11 17:37:08 +01:00
|
|
|
|
break;
|
|
|
|
|
}
|
2021-04-08 17:13:05 +02:00
|
|
|
|
|
2021-12-11 17:37:08 +01:00
|
|
|
|
throw error;
|
2021-04-08 17:13:05 +02:00
|
|
|
|
}
|
2021-12-11 17:37:08 +01:00
|
|
|
|
});
|
2021-04-08 17:13:05 +02:00
|
|
|
|
}
|
|
|
|
|
|
2021-10-21 15:16:43 +02:00
|
|
|
|
public getMentions(chatId: ChatId, query: string, threadId?: number): Promise<PeerId[]> {
|
2021-08-03 03:57:44 +02:00
|
|
|
|
const processUserIds = (topPeers: MyTopPeer[]) => {
|
2021-07-23 21:16:17 +02:00
|
|
|
|
const startsWithAt = query.charAt(0) === '@';
|
|
|
|
|
if(startsWithAt) query = query.slice(1);
|
2021-07-15 17:34:34 +02:00
|
|
|
|
/* const startsWithAt = query.charAt(0) === '@';
|
|
|
|
|
if(startsWithAt) query = query.slice(1);
|
2022-08-04 08:49:54 +02:00
|
|
|
|
|
2021-07-15 17:34:34 +02:00
|
|
|
|
const index = new SearchIndex<number>(!startsWithAt, !startsWithAt); */
|
2021-10-21 15:16:43 +02:00
|
|
|
|
const index = new SearchIndex<PeerId>({
|
2021-07-23 21:16:17 +02:00
|
|
|
|
ignoreCase: true
|
|
|
|
|
});
|
2021-08-03 03:57:44 +02:00
|
|
|
|
|
2021-10-21 15:16:43 +02:00
|
|
|
|
const ratingMap: Map<PeerId, number> = new Map();
|
2022-06-17 18:01:43 +02:00
|
|
|
|
topPeers.forEach((peer) => {
|
2022-04-25 16:54:30 +02:00
|
|
|
|
index.indexObject(peer.id, this.appUsersManager.getUserSearchText(peer.id));
|
2021-08-03 03:57:44 +02:00
|
|
|
|
ratingMap.set(peer.id, peer.rating);
|
2021-05-29 15:06:55 +02:00
|
|
|
|
});
|
|
|
|
|
|
2021-08-03 03:57:44 +02:00
|
|
|
|
const peerIds = Array.from(index.search(query));
|
|
|
|
|
peerIds.sort((a, b) => ratingMap.get(b) - ratingMap.get(a));
|
|
|
|
|
return peerIds;
|
2021-06-01 04:06:41 +02:00
|
|
|
|
};
|
|
|
|
|
|
2021-10-21 15:16:43 +02:00
|
|
|
|
let promise: Promise<PeerId[]>;
|
2022-04-25 16:54:30 +02:00
|
|
|
|
if(this.appChatsManager.isChannel(chatId)) {
|
2021-07-23 21:16:17 +02:00
|
|
|
|
promise = this.getChannelParticipants(chatId, {
|
2021-06-01 04:06:41 +02:00
|
|
|
|
_: 'channelParticipantsMentions',
|
|
|
|
|
q: query,
|
2022-06-17 18:01:43 +02:00
|
|
|
|
top_msg_id: getServerMessageId(threadId)
|
|
|
|
|
}, 50, 0).then((cP) => {
|
|
|
|
|
return cP.participants.map((p) => getParticipantPeerId(p));
|
2021-06-01 04:06:41 +02:00
|
|
|
|
});
|
2021-07-23 21:16:17 +02:00
|
|
|
|
} else if(chatId) {
|
2022-06-17 18:01:43 +02:00
|
|
|
|
promise = Promise.resolve(this.getChatFull(chatId)).then((chatFull) => {
|
|
|
|
|
return ((chatFull as ChatFull.chatFull).participants as ChatParticipants.chatParticipants).participants.map((p) => p.user_id.toPeerId());
|
2021-06-01 04:06:41 +02:00
|
|
|
|
});
|
2021-07-23 21:16:17 +02:00
|
|
|
|
} else {
|
|
|
|
|
promise = Promise.resolve([]);
|
2021-06-01 04:06:41 +02:00
|
|
|
|
}
|
2021-07-23 21:16:17 +02:00
|
|
|
|
|
|
|
|
|
return Promise.all([
|
2021-08-03 03:57:44 +02:00
|
|
|
|
// [],
|
2022-08-04 08:49:54 +02:00
|
|
|
|
this.appUsersManager.getTopPeers('bots_inline').catch(() => [] as MyTopPeer[]),
|
2021-07-23 21:16:17 +02:00
|
|
|
|
promise
|
2022-06-17 18:01:43 +02:00
|
|
|
|
]).then((results) => {
|
|
|
|
|
const peers = results[0].concat(results[1].map((peerId) => ({id: peerId, rating: 0})));
|
2021-07-23 21:16:17 +02:00
|
|
|
|
|
2021-08-03 03:57:44 +02:00
|
|
|
|
return processUserIds(peers);
|
2021-07-23 21:16:17 +02:00
|
|
|
|
});
|
2021-05-29 15:06:55 +02:00
|
|
|
|
}
|
|
|
|
|
|
2022-06-17 18:01:43 +02:00
|
|
|
|
private invalidateChannelParticipants(id: ChatId) {
|
|
|
|
|
this.apiManager.clearCache('channels.getParticipants', (params) => (params.channel as InputChannel.inputChannel).channel_id === id);
|
2021-12-11 17:37:08 +01:00
|
|
|
|
this.refreshFullPeer(id.toPeerId(true));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private refreshFullPeer(peerId: PeerId) {
|
2022-02-20 16:37:37 +01:00
|
|
|
|
if(peerId.isUser()) {
|
|
|
|
|
const userId = peerId.toUserId();
|
|
|
|
|
delete this.usersFull[userId];
|
2022-06-17 18:01:43 +02:00
|
|
|
|
this.rootScope.dispatchEvent('user_full_update', userId);
|
2022-02-20 16:37:37 +01:00
|
|
|
|
} else {
|
|
|
|
|
const chatId = peerId.toChatId();
|
|
|
|
|
delete this.chatsFull[chatId];
|
2022-06-17 18:01:43 +02:00
|
|
|
|
this.rootScope.dispatchEvent('chat_full_update', chatId);
|
2022-02-20 16:37:37 +01:00
|
|
|
|
}
|
2021-12-11 17:37:08 +01:00
|
|
|
|
|
|
|
|
|
// ! эта строчка будет создавать race condition:
|
|
|
|
|
// ! запрос вернёт chat с установленным флагом call_not_empty, хотя сам апдейт уже будет применён
|
|
|
|
|
// this.getProfileByPeerId(peerId, true);
|
2021-04-08 17:13:05 +02:00
|
|
|
|
}
|
|
|
|
|
|
2022-02-20 22:01:12 +01:00
|
|
|
|
public updateProfile(first_name?: string, last_name?: string, about?: string) {
|
2022-06-17 18:01:43 +02:00
|
|
|
|
return this.apiManager.invokeApi('account.updateProfile', {
|
2021-04-08 17:13:05 +02:00
|
|
|
|
first_name,
|
|
|
|
|
last_name,
|
|
|
|
|
about
|
2022-06-17 18:01:43 +02:00
|
|
|
|
}).then((user) => {
|
2022-04-25 16:54:30 +02:00
|
|
|
|
this.appUsersManager.saveApiUser(user);
|
2022-02-20 22:01:12 +01:00
|
|
|
|
|
|
|
|
|
if(about !== undefined) {
|
|
|
|
|
const peerId = user.id.toPeerId();
|
|
|
|
|
const userFull = this.usersFull[user.id];
|
|
|
|
|
if(userFull) {
|
|
|
|
|
userFull.about = about;
|
|
|
|
|
}
|
2022-08-04 08:49:54 +02:00
|
|
|
|
|
2022-06-17 18:01:43 +02:00
|
|
|
|
this.rootScope.dispatchEvent('peer_bio_edit', peerId);
|
2022-02-20 22:01:12 +01:00
|
|
|
|
}
|
2022-08-04 08:49:54 +02:00
|
|
|
|
|
2022-09-25 19:49:33 +02:00
|
|
|
|
return this.getProfile(user.id, true);
|
2021-04-08 17:13:05 +02:00
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public uploadProfilePhoto(inputFile: InputFile) {
|
2022-06-17 18:01:43 +02:00
|
|
|
|
return this.apiManager.invokeApi('photos.uploadProfilePhoto', {
|
2021-04-08 17:13:05 +02:00
|
|
|
|
file: inputFile
|
|
|
|
|
}).then((updateResult) => {
|
2022-02-22 14:53:27 +01:00
|
|
|
|
// ! sometimes can have no user in users
|
|
|
|
|
const photo = updateResult.photo as Photo.photo;
|
|
|
|
|
if(!updateResult.users.length) {
|
2022-06-17 18:01:43 +02:00
|
|
|
|
const strippedThumb = photo.sizes.find((size) => size._ === 'photoStrippedSize') as PhotoSize.photoStrippedSize;
|
2022-02-22 14:53:27 +01:00
|
|
|
|
updateResult.users.push({
|
2022-08-04 08:49:54 +02:00
|
|
|
|
...this.appUsersManager.getSelf(),
|
2022-02-22 14:53:27 +01:00
|
|
|
|
photo: {
|
|
|
|
|
_: 'userProfilePhoto',
|
|
|
|
|
dc_id: photo.dc_id,
|
|
|
|
|
photo_id: photo.id,
|
|
|
|
|
stripped_thumb: strippedThumb?.bytes,
|
|
|
|
|
pFlags: {
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
2022-04-25 16:54:30 +02:00
|
|
|
|
this.appUsersManager.saveApiUsers(updateResult.users);
|
2021-04-08 17:13:05 +02:00
|
|
|
|
|
2022-06-17 18:01:43 +02:00
|
|
|
|
const myId = this.appPeersManager.peerId;
|
2022-04-25 16:54:30 +02:00
|
|
|
|
this.appPhotosManager.savePhoto(updateResult.photo, {
|
2021-04-08 17:13:05 +02:00
|
|
|
|
type: 'profilePhoto',
|
|
|
|
|
peerId: myId
|
|
|
|
|
});
|
|
|
|
|
|
2021-12-11 17:37:08 +01:00
|
|
|
|
const userId = myId.toUserId();
|
2023-01-06 20:27:29 +01:00
|
|
|
|
// this.apiUpdatesManager.processLocalUpdate({
|
|
|
|
|
// _: 'updateUserPhoto',
|
|
|
|
|
// user_id: userId,
|
|
|
|
|
// date: tsNow(true),
|
|
|
|
|
// photo: this.appUsersManager.getUser(userId).photo,
|
|
|
|
|
// previous: true
|
|
|
|
|
// });
|
2022-04-25 16:54:30 +02:00
|
|
|
|
this.apiUpdatesManager.processLocalUpdate({
|
2023-01-06 20:27:29 +01:00
|
|
|
|
_: 'updateUser',
|
|
|
|
|
user_id: userId
|
2021-04-08 17:13:05 +02:00
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
2021-09-23 17:22:30 +02:00
|
|
|
|
public deletePhotos(photoIds: string[]) {
|
2022-06-17 18:01:43 +02:00
|
|
|
|
return this.apiManager.invokeApiSingle('photos.deletePhotos', {
|
|
|
|
|
id: photoIds.map((photoId) => {
|
2022-04-25 16:54:30 +02:00
|
|
|
|
const photo = this.appPhotosManager.getPhoto(photoId);
|
|
|
|
|
return getPhotoInput(photo);
|
2021-09-23 17:22:30 +02:00
|
|
|
|
})
|
|
|
|
|
}).then((deletedList) => {
|
2022-08-04 08:49:54 +02:00
|
|
|
|
|
2021-09-23 17:22:30 +02:00
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
2021-10-29 17:33:37 +02:00
|
|
|
|
private verifyParticipantForOnlineCount(participant: {user_id: UserId}) {
|
2022-04-25 16:54:30 +02:00
|
|
|
|
const user = this.appUsersManager.getUser(participant.user_id);
|
2021-10-29 17:33:37 +02:00
|
|
|
|
return !!(user && user.status && user.status._ === 'userStatusOnline');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private reduceParticipantsForOnlineCount(participants: {user_id: UserId}[]) {
|
|
|
|
|
return participants.reduce((acc, participant) => {
|
|
|
|
|
return acc + +this.verifyParticipantForOnlineCount(participant);
|
|
|
|
|
}, 0);
|
|
|
|
|
}
|
|
|
|
|
|
2021-10-21 15:16:43 +02:00
|
|
|
|
public async getOnlines(id: ChatId): Promise<number> {
|
2021-10-29 17:33:37 +02:00
|
|
|
|
const minOnline = 1;
|
2022-04-25 16:54:30 +02:00
|
|
|
|
if(this.appChatsManager.isBroadcast(id)) {
|
2021-10-29 17:33:37 +02:00
|
|
|
|
return minOnline;
|
|
|
|
|
}
|
2022-08-04 08:49:54 +02:00
|
|
|
|
|
2021-10-29 17:33:37 +02:00
|
|
|
|
const chatInfo = await this.getChatFull(id);
|
2022-04-25 16:54:30 +02:00
|
|
|
|
if(this.appChatsManager.isMegagroup(id)) {
|
2021-10-29 17:33:37 +02:00
|
|
|
|
if((chatInfo as ChatFull.channelFull).participants_count <= 100) {
|
|
|
|
|
const channelParticipants = await this.getChannelParticipants(id, {_: 'channelParticipantsRecent'}, 100);
|
|
|
|
|
return this.reduceParticipantsForOnlineCount(channelParticipants.participants as ChannelParticipant.channelParticipant[]);
|
2021-04-08 17:13:05 +02:00
|
|
|
|
}
|
|
|
|
|
|
2022-06-17 18:01:43 +02:00
|
|
|
|
const res = await this.apiManager.invokeApiCacheable('messages.getOnlines', {
|
2022-04-25 16:54:30 +02:00
|
|
|
|
peer: this.appChatsManager.getChannelInputPeer(id)
|
2021-10-29 17:33:37 +02:00
|
|
|
|
}, {cacheSeconds: 60});
|
2021-04-08 17:13:05 +02:00
|
|
|
|
|
2021-10-29 17:33:37 +02:00
|
|
|
|
const onlines = res.onlines ?? minOnline;
|
2021-06-18 14:00:30 +02:00
|
|
|
|
return onlines;
|
|
|
|
|
}
|
2021-04-08 17:13:05 +02:00
|
|
|
|
|
2021-06-18 14:00:30 +02:00
|
|
|
|
const _participants = (chatInfo as ChatFull.chatFull).participants as ChatParticipants.chatParticipants;
|
2021-10-29 17:33:37 +02:00
|
|
|
|
if(_participants?.participants) {
|
|
|
|
|
return this.reduceParticipantsForOnlineCount(_participants.participants);
|
2021-04-08 17:13:05 +02:00
|
|
|
|
} else {
|
2021-10-29 17:33:37 +02:00
|
|
|
|
return minOnline;
|
2021-04-08 17:13:05 +02:00
|
|
|
|
}
|
2021-04-18 13:55:56 +02:00
|
|
|
|
}
|
|
|
|
|
|
2023-01-06 20:27:29 +01:00
|
|
|
|
private getTypingsKey(peerId: PeerId, threadId?: number) {
|
|
|
|
|
return peerId + (threadId ? `_${threadId}` : '');
|
|
|
|
|
}
|
|
|
|
|
|
2023-02-27 14:11:37 +01:00
|
|
|
|
public getPeerTypings(peerId: PeerId, threadId?: number) {
|
|
|
|
|
return this.typingsInPeer[this.getTypingsKey(peerId, threadId)];
|
|
|
|
|
}
|
|
|
|
|
|
2023-03-07 22:25:07 +01:00
|
|
|
|
public canGiftPremium(userId: UserId) {
|
|
|
|
|
const user = this.appUsersManager.getUser(userId);
|
2023-03-08 10:46:48 +01:00
|
|
|
|
if(user?.pFlags?.premium) {
|
2023-03-07 22:25:07 +01:00
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return callbackify(this.getProfile(userId), (userFull) => {
|
|
|
|
|
const user = this.appUsersManager.getUser(userId);
|
|
|
|
|
return !!userFull.premium_gifts && !user?.pFlags?.premium;
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
2023-02-27 14:11:37 +01:00
|
|
|
|
private onUpdateChatParticipants = (update: Update.updateChatParticipants) => {
|
|
|
|
|
const participants = update.participants;
|
|
|
|
|
if(participants._ !== 'chatParticipants') {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const chatId = participants.chat_id;
|
|
|
|
|
const chatFull = this.chatsFull[chatId] as ChatFull.chatFull;
|
|
|
|
|
if(chatFull !== undefined) {
|
|
|
|
|
chatFull.participants = participants;
|
|
|
|
|
this.rootScope.dispatchEvent('chat_full_update', chatId);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
private onUpdateChatParticipantAdd = (update: Update.updateChatParticipantAdd) => {
|
|
|
|
|
const chatFull = this.chatsFull[update.chat_id] as ChatFull.chatFull;
|
|
|
|
|
if(chatFull === undefined) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const _participants = chatFull.participants as ChatParticipants.chatParticipants;
|
|
|
|
|
const participants = _participants.participants || [];
|
|
|
|
|
for(let i = 0, length = participants.length; i < length; i++) {
|
|
|
|
|
if(participants[i].user_id === update.user_id) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
participants.push({
|
|
|
|
|
_: 'chatParticipant',
|
|
|
|
|
user_id: update.user_id,
|
|
|
|
|
inviter_id: update.inviter_id,
|
|
|
|
|
date: tsNow(true)
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
_participants.version = update.version;
|
|
|
|
|
this.rootScope.dispatchEvent('chat_full_update', update.chat_id);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
private onUpdateChatParticipantDelete = (update: Update.updateChatParticipantDelete) => {
|
|
|
|
|
const chatFull = this.chatsFull[update.chat_id] as ChatFull.chatFull;
|
|
|
|
|
if(chatFull === undefined) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const _participants = chatFull.participants as ChatParticipants.chatParticipants;
|
|
|
|
|
const participants = _participants.participants || [];
|
|
|
|
|
for(let i = 0, length = participants.length; i < length; i++) {
|
|
|
|
|
if(participants[i].user_id === update.user_id) {
|
|
|
|
|
participants.splice(i, 1);
|
|
|
|
|
_participants.version = update.version;
|
|
|
|
|
this.rootScope.dispatchEvent('chat_full_update', update.chat_id);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2021-06-18 14:00:30 +02:00
|
|
|
|
private onUpdateUserTyping = (update: Update.updateUserTyping | Update.updateChatUserTyping | Update.updateChannelUserTyping) => {
|
2022-08-04 08:49:54 +02:00
|
|
|
|
const fromId = (update as Update.updateUserTyping).user_id ?
|
|
|
|
|
(update as Update.updateUserTyping).user_id.toPeerId() :
|
2022-07-26 17:24:29 +02:00
|
|
|
|
this.appPeersManager.getPeerId((update as Update.updateChatUserTyping).from_id);
|
2022-06-17 18:01:43 +02:00
|
|
|
|
if(this.appPeersManager.peerId === fromId || update.action._ === 'speakingInGroupCallAction') {
|
2021-06-18 14:00:30 +02:00
|
|
|
|
return;
|
|
|
|
|
}
|
2022-08-04 08:49:54 +02:00
|
|
|
|
|
2023-01-06 20:27:29 +01:00
|
|
|
|
const topMsgId = (update as Update.updateChannelUserTyping).top_msg_id;
|
|
|
|
|
const threadId = topMsgId ? generateMessageId(topMsgId) : undefined;
|
2022-07-26 17:24:29 +02:00
|
|
|
|
const peerId = this.appPeersManager.getPeerId(update);
|
2023-01-06 20:27:29 +01:00
|
|
|
|
const key = this.getTypingsKey(peerId, threadId);
|
|
|
|
|
const typings = this.typingsInPeer[key] ??= [];
|
2022-06-17 18:01:43 +02:00
|
|
|
|
let typing = typings.find((t) => t.userId === fromId);
|
2021-06-18 14:00:30 +02:00
|
|
|
|
|
|
|
|
|
const cancelAction = () => {
|
|
|
|
|
delete typing.timeout;
|
2022-08-04 08:49:54 +02:00
|
|
|
|
// typings.findAndSplice((t) => t === typing);
|
2021-06-18 14:00:30 +02:00
|
|
|
|
const idx = typings.indexOf(typing);
|
|
|
|
|
if(idx !== -1) {
|
|
|
|
|
typings.splice(idx, 1);
|
2021-04-08 17:13:05 +02:00
|
|
|
|
}
|
|
|
|
|
|
2023-01-06 20:27:29 +01:00
|
|
|
|
this.rootScope.dispatchEvent('peer_typings', {peerId, threadId, typings});
|
2021-06-01 17:20:03 +02:00
|
|
|
|
|
2021-06-18 14:00:30 +02:00
|
|
|
|
if(!typings.length) {
|
2023-01-06 20:27:29 +01:00
|
|
|
|
delete this.typingsInPeer[key];
|
2021-06-18 14:00:30 +02:00
|
|
|
|
}
|
|
|
|
|
};
|
2021-04-08 17:13:05 +02:00
|
|
|
|
|
2023-01-06 20:27:29 +01:00
|
|
|
|
if(typing?.timeout !== undefined) {
|
2021-06-18 14:00:30 +02:00
|
|
|
|
clearTimeout(typing.timeout);
|
2021-04-08 17:13:05 +02:00
|
|
|
|
}
|
|
|
|
|
|
2021-06-18 14:00:30 +02:00
|
|
|
|
if(update.action._ === 'sendMessageCancelAction') {
|
|
|
|
|
if(!typing) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
2021-04-08 17:13:05 +02:00
|
|
|
|
|
2021-06-18 14:00:30 +02:00
|
|
|
|
cancelAction();
|
2021-04-08 17:13:05 +02:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-18 14:00:30 +02:00
|
|
|
|
if(!typing) {
|
|
|
|
|
typing = {
|
|
|
|
|
userId: fromId
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
typings.push(typing);
|
2021-04-08 17:13:05 +02:00
|
|
|
|
}
|
|
|
|
|
|
2022-08-04 08:49:54 +02:00
|
|
|
|
// console.log('updateChatUserTyping', update, typings);
|
|
|
|
|
|
2021-06-18 14:00:30 +02:00
|
|
|
|
typing.action = update.action;
|
2022-08-04 08:49:54 +02:00
|
|
|
|
|
2022-04-25 16:54:30 +02:00
|
|
|
|
const hasUser = this.appUsersManager.hasUser(fromId);
|
2021-06-18 14:00:30 +02:00
|
|
|
|
if(!hasUser) {
|
|
|
|
|
// let's load user here
|
|
|
|
|
if(update._ === 'updateChatUserTyping') {
|
2022-04-25 16:54:30 +02:00
|
|
|
|
if(update.chat_id && this.appChatsManager.hasChat(update.chat_id) && !this.appChatsManager.isChannel(update.chat_id)) {
|
2022-02-08 20:18:01 +01:00
|
|
|
|
Promise.resolve(this.getChatFull(update.chat_id)).then(() => {
|
2022-04-25 16:54:30 +02:00
|
|
|
|
if(typing.timeout !== undefined && this.appUsersManager.hasUser(fromId)) {
|
2023-01-06 20:27:29 +01:00
|
|
|
|
this.rootScope.dispatchEvent('peer_typings', {peerId, threadId, typings});
|
2021-06-18 14:00:30 +02:00
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
2021-04-08 17:13:05 +02:00
|
|
|
|
}
|
2022-08-04 08:49:54 +02:00
|
|
|
|
|
|
|
|
|
// return;
|
2021-06-18 14:00:30 +02:00
|
|
|
|
} else {
|
2022-04-25 16:54:30 +02:00
|
|
|
|
this.appUsersManager.forceUserOnline(fromId);
|
2021-04-08 17:13:05 +02:00
|
|
|
|
}
|
|
|
|
|
|
2022-06-17 18:01:43 +02:00
|
|
|
|
typing.timeout = ctx.setTimeout(cancelAction, 6000);
|
2021-06-18 14:00:30 +02:00
|
|
|
|
if(hasUser) {
|
2023-01-06 20:27:29 +01:00
|
|
|
|
this.rootScope.dispatchEvent('peer_typings', {peerId, threadId, typings});
|
2021-04-08 17:13:05 +02:00
|
|
|
|
}
|
2021-06-18 14:00:30 +02:00
|
|
|
|
};
|
|
|
|
|
|
2021-09-25 21:47:43 +02:00
|
|
|
|
private onUpdatePeerBlocked = (update: Update.updatePeerBlocked) => {
|
2022-07-26 17:24:29 +02:00
|
|
|
|
const peerId = this.appPeersManager.getPeerId(update.peer_id);
|
2022-04-25 16:54:30 +02:00
|
|
|
|
if(this.appPeersManager.isUser(peerId)) {
|
2021-12-11 17:37:08 +01:00
|
|
|
|
const userId = peerId.toUserId();
|
|
|
|
|
const userFull = this.usersFull[userId];
|
2021-09-25 21:47:43 +02:00
|
|
|
|
if(userFull) {
|
|
|
|
|
if(update.blocked) userFull.pFlags.blocked = true;
|
|
|
|
|
else delete userFull.pFlags.blocked;
|
|
|
|
|
}
|
2021-12-11 17:37:08 +01:00
|
|
|
|
|
2022-06-17 18:01:43 +02:00
|
|
|
|
this.rootScope.dispatchEvent('user_full_update', userId);
|
2021-09-25 21:47:43 +02:00
|
|
|
|
}
|
|
|
|
|
|
2022-06-17 18:01:43 +02:00
|
|
|
|
this.rootScope.dispatchEvent('peer_block', {peerId, blocked: update.blocked});
|
2021-09-25 21:47:43 +02:00
|
|
|
|
};
|
2021-04-08 17:13:05 +02:00
|
|
|
|
}
|