tweb-i2p/src/lib/appManagers/appPollsManager.ts
Eduard Kuzmenko 37d5b2a9ad Peer-to-Peer calls
Refactor bigInt
Refactor factorizing
2022-03-23 17:15:07 +02:00

215 lines
6.5 KiB
TypeScript

/*
* https://github.com/morethanwords/tweb
* Copyright (C) 2019-2021 Eduard Kuzmenko
* https://github.com/morethanwords/tweb/blob/master/LICENSE
*/
import { MOUNT_CLASS_TO } from "../../config/debug";
import copy from "../../helpers/object/copy";
import { InputMedia, Message, MessageEntity, MessageMedia, Poll, PollResults } from "../../layer";
import { logger, LogTypes } from "../logger";
import apiManager from "../mtproto/mtprotoworker";
import { RichTextProcessor } from "../richtextprocessor";
import rootScope from "../rootScope";
import apiUpdatesManager from "./apiUpdatesManager";
import appMessagesIdsManager from "./appMessagesIdsManager";
import appMessagesManager from './appMessagesManager';
import appPeersManager from './appPeersManager';
import appUsersManager from "./appUsersManager";
export class AppPollsManager {
public polls: {[id: string]: Poll} = {};
public results: {[id: string]: PollResults} = {};
public pollToMessages: {[id: string]: Set<string>} = {};
private log = logger('POLLS', LogTypes.Error);
constructor() {
rootScope.addMultipleEventsListeners({
updateMessagePoll: (update) => {
this.log('updateMessagePoll:', update);
let poll: Poll = update.poll || this.polls[update.poll_id];
if(!poll) {
return;
}
let results = update.results;
const ret = this.savePoll(poll, results as any);
poll = ret.poll;
results = ret.results;
rootScope.dispatchEvent('poll_update', {poll, results: results as any});
}
});
}
public savePoll(poll: Poll, results: PollResults, message?: Message.message) {
if(message) {
this.updatePollToMessage(message, true);
}
const id = poll.id;
if(this.polls[id]) {
poll = Object.assign(this.polls[id], poll);
results = this.saveResults(poll, results);
} else {
this.polls[id] = poll;
poll.rQuestion = RichTextProcessor.wrapEmojiText(poll.question);
poll.rReply = RichTextProcessor.wrapEmojiText('📊') + ' ' + (poll.rQuestion || 'poll');
poll.chosenIndexes = [];
results = this.saveResults(poll, results);
}
return {poll, results};
}
public saveResults(poll: Poll, results: PollResults) {
if(this.results[poll.id]) {
results = Object.assign(this.results[poll.id], results);
} else {
this.results[poll.id] = results;
}
if(!results.pFlags.min) { // ! https://core.telegram.org/constructor/pollResults - min
poll.chosenIndexes.length = 0;
if(results?.results?.length) {
results.results.forEach((answer, idx) => {
if(answer.pFlags?.chosen) {
poll.chosenIndexes.push(idx);
}
});
}
}
return results;
}
public getPoll(pollId: string): {poll: Poll, results: PollResults} {
return {
poll: this.polls[pollId],
results: this.results[pollId]
};
}
public getInputMediaPoll(poll: Poll, correctAnswers?: Uint8Array[], solution?: string, solutionEntities?: MessageEntity[]): InputMedia.inputMediaPoll {
if(solution) {
if(!solutionEntities) {
solutionEntities = [];
}
solution = RichTextProcessor.parseMarkdown(solution, solutionEntities);
} else {
solution = undefined; // can be string here
}
return {
_: 'inputMediaPoll',
poll,
correct_answers: correctAnswers,
solution,
solution_entities: solution ? solutionEntities : undefined
};
}
public updatePollToMessage(message: Message.message, add: boolean) {
const {id} = (message.media as MessageMedia.messageMediaPoll).poll;
let set = this.pollToMessages[id];
if(!add && !set) {
return;
}
if(!set) {
set = this.pollToMessages[id] = new Set();
}
const key = message.peerId + '_' + message.mid;
if(add) set.add(key);
else set.delete(key);
if(!add && !set.size) {
delete this.polls[id];
delete this.results[id];
delete this.pollToMessages[id];
}
}
public sendVote(message: any, optionIds: number[]): Promise<void> {
const poll: Poll = message.media.poll;
const options: Uint8Array[] = optionIds.map(index => {
return poll.answers[index].option;
});
const messageId = message.mid;
const peerId = message.peerId;
const inputPeer = appPeersManager.getInputPeerById(peerId);
if(message.pFlags.is_outgoing) {
return appMessagesManager.invokeAfterMessageIsSent(messageId, 'sendVote', (message) => {
this.log('invoke sendVote callback');
return this.sendVote(message, optionIds);
});
}
return apiManager.invokeApi('messages.sendVote', {
peer: inputPeer,
msg_id: appMessagesIdsManager.getServerMessageId(message.mid),
options
}).then(updates => {
this.log('sendVote updates:', updates);
apiUpdatesManager.processUpdateMessage(updates);
});
}
public getResults(message: any) {
const inputPeer = appPeersManager.getInputPeerById(message.peerId);
return apiManager.invokeApi('messages.getPollResults', {
peer: inputPeer,
msg_id: appMessagesIdsManager.getServerMessageId(message.mid)
}).then(updates => {
apiUpdatesManager.processUpdateMessage(updates);
this.log('getResults updates:', updates);
});
}
public getVotes(message: any, option?: Uint8Array, offset?: string, limit = 20) {
return apiManager.invokeApi('messages.getPollVotes', {
peer: appPeersManager.getInputPeerById(message.peerId),
id: appMessagesIdsManager.getServerMessageId(message.mid),
option,
offset,
limit
}).then((votesList) => {
this.log('getPollVotes messages:', votesList);
appUsersManager.saveApiUsers(votesList.users);
return votesList;
});
}
public stopPoll(message: any) {
const poll: Poll = message.media.poll;
if(poll.pFlags.closed) return Promise.resolve();
const newPoll = copy(poll);
newPoll.pFlags.closed = true;
return appMessagesManager.editMessage(message, undefined, {
newMedia: this.getInputMediaPoll(newPoll)
}).then(() => {
//console.log('stopped poll');
}, err => {
this.log.error('stopPoll error:', err);
});
}
}
const appPollsManager = new AppPollsManager();
MOUNT_CLASS_TO.appPollsManager = appPollsManager;
export default appPollsManager;