Browse Source

MTProto networker refactor

State manager improvements
Fix local storage parse
New layer (119)
master
morethanwords 4 years ago
parent
commit
a25b5e9823
  1. 6
      package-lock.json
  2. 1
      package.json
  3. 3
      src/components/animationIntersector.ts
  4. 2
      src/components/appMediaPlaybackController.ts
  5. 5
      src/components/appSearch.ts
  6. 3
      src/components/appSelectPeers.ts
  7. 2
      src/components/avatar.ts
  8. 3
      src/components/bubbleGroups.ts
  9. 3
      src/components/chat/audio.ts
  10. 3
      src/components/chat/contextMenu.ts
  11. 6
      src/components/chat/input.ts
  12. 3
      src/components/chat/search.ts
  13. 10
      src/components/emoticonsDropdown/index.ts
  14. 2
      src/components/emoticonsDropdown/tabs/stickers.ts
  15. 13
      src/components/horizontalMenu.ts
  16. 9
      src/components/misc.ts
  17. 7
      src/components/poll.ts
  18. 2
      src/components/popupCreatePoll.ts
  19. 4
      src/components/ripple.ts
  20. 4
      src/components/scrollable_new.ts
  21. 3
      src/components/sidebarLeft/chatFolders.ts
  22. 2
      src/components/sidebarLeft/contacts.ts
  23. 2
      src/components/sidebarLeft/editProfile.ts
  24. 3
      src/components/sidebarLeft/includedChats.ts
  25. 6
      src/components/sidebarLeft/settings.ts
  26. 13
      src/components/sidebarRight/sharedMedia.ts
  27. 5
      src/helpers/json.ts
  28. 2
      src/helpers/touchSupport.ts
  29. 638
      src/layer.d.ts
  30. 88
      src/lib/appManagers/apiUpdatesManager.ts
  31. 3
      src/lib/appManagers/appChatsManager.ts
  32. 15
      src/lib/appManagers/appDialogsManager.ts
  33. 3
      src/lib/appManagers/appDocsManager.ts
  34. 2
      src/lib/appManagers/appDownloadManager.ts
  35. 32
      src/lib/appManagers/appImManager.ts
  36. 9
      src/lib/appManagers/appMediaViewer.ts
  37. 191
      src/lib/appManagers/appMessagesManager.ts
  38. 15
      src/lib/appManagers/appPeersManager.ts
  39. 2
      src/lib/appManagers/appPollsManager.ts
  40. 9
      src/lib/appManagers/appSidebarLeft.ts
  41. 165
      src/lib/appManagers/appStateManager.ts
  42. 2
      src/lib/appManagers/appStickersManager.ts
  43. 40
      src/lib/appManagers/appUsersManager.ts
  44. 3
      src/lib/appManagers/appWebPagesManager.ts
  45. 9
      src/lib/bin_utils.ts
  46. 8
      src/lib/cacheStorage.ts
  47. 26
      src/lib/config.ts
  48. 12
      src/lib/mediaPlayer.ts
  49. 30
      src/lib/mtproto/apiManager.ts
  50. 38
      src/lib/mtproto/dcConfigurator.ts
  51. 6
      src/lib/mtproto/mtproto.worker.ts
  52. 15
      src/lib/mtproto/mtproto_config.ts
  53. 10
      src/lib/mtproto/mtprotoworker.ts
  54. 152
      src/lib/mtproto/networker.ts
  55. 2
      src/lib/mtproto/schema.ts
  56. 7
      src/lib/mtproto/tl_utils.ts
  57. 8
      src/lib/polyfill.ts
  58. 92
      src/lib/rootScope.ts
  59. 7
      src/lib/storage.ts
  60. 100
      src/lib/utils.ts
  61. 2
      src/pages/pageSignIn.ts
  62. 2
      src/scripts/in/schema.json
  63. 18
      src/test_cache_and_local_storage_speed.js
  64. 1
      webpack.common.js

6
package-lock.json generated

@ -9102,12 +9102,6 @@ @@ -9102,12 +9102,6 @@
"invert-kv": "^2.0.0"
}
},
"leemon": {
"version": "6.2.0",
"resolved": "https://registry.npmjs.org/leemon/-/leemon-6.2.0.tgz",
"integrity": "sha512-a5ieuGSGEb5ezCL6UNds5//cVFaKpeexVK0VDCE8/eOF0r0/9Og94LQ33U2Px5dUcHVCDPWQY8gXLgDlDJnyyg==",
"dev": true
},
"left-pad": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/left-pad/-/left-pad-1.3.0.tgz",

1
package.json

@ -47,7 +47,6 @@ @@ -47,7 +47,6 @@
"ifdef-loader": "^2.1.5",
"install": "^0.13.0",
"jest": "^24.9.0",
"leemon": "^6.2.0",
"media-query-plugin": "^1.3.1",
"mini-css-extract-plugin": "^0.9.0",
"node-sass": "^4.14.1",

3
src/components/animationIntersector.ts

@ -1,6 +1,7 @@ @@ -1,6 +1,7 @@
import { isInDOM, $rootScope } from "../lib/utils";
import { isInDOM } from "../lib/utils";
import { RLottiePlayer } from "../lib/lottieLoader";
import { MOUNT_CLASS_TO } from "../lib/mtproto/mtproto_config";
import $rootScope from "../lib/rootScope";
export interface AnimationItem {
el: HTMLElement,

2
src/components/appMediaPlaybackController.ts

@ -1,4 +1,4 @@ @@ -1,4 +1,4 @@
import { $rootScope } from "../lib/utils";
import $rootScope from "../lib/rootScope";
import appMessagesManager from "../lib/appManagers/appMessagesManager";
import appDocsManager, {MyDocument} from "../lib/appManagers/appDocsManager";
import { CancellablePromise, deferredPromise } from "../helpers/cancellablePromise";

5
src/components/appSearch.ts

@ -4,11 +4,12 @@ import appMessagesIDsManager from "../lib/appManagers/appMessagesIDsManager"; @@ -4,11 +4,12 @@ import appMessagesIDsManager from "../lib/appManagers/appMessagesIDsManager";
import appUsersManager from "../lib/appManagers/appUsersManager";
import appPeersManager from '../lib/appManagers/appPeersManager';
import appMessagesManager from "../lib/appManagers/appMessagesManager";
import { $rootScope, escapeRegExp } from "../lib/utils";
import { escapeRegExp } from "../lib/utils";
import { formatPhoneNumber } from "./misc";
import appChatsManager from "../lib/appManagers/appChatsManager";
import SearchInput from "./searchInput";
import { Peer } from "../layer";
import $rootScope from "../lib/rootScope";
export class SearchGroup {
container: HTMLDivElement;
@ -269,7 +270,7 @@ export default class AppSearch { @@ -269,7 +270,7 @@ export default class AppSearch {
originalDialog = {
peerID: message.peerID,
pFlags: {},
peer: message.to_id
peer: message.peer_id
} as any;
}

3
src/components/appSelectPeers.ts

@ -1,11 +1,12 @@ @@ -1,11 +1,12 @@
import Scrollable from "./scrollable_new";
import appMessagesManager, { Dialog } from "../lib/appManagers/appMessagesManager";
import { $rootScope, cancelEvent, findUpClassName, findUpAttribute } from "../lib/utils";
import { cancelEvent, findUpClassName, findUpAttribute } from "../lib/utils";
import appDialogsManager from "../lib/appManagers/appDialogsManager";
import appChatsManager from "../lib/appManagers/appChatsManager";
import appUsersManager from "../lib/appManagers/appUsersManager";
import appPeersManager from "../lib/appManagers/appPeersManager";
import appPhotosManager from "../lib/appManagers/appPhotosManager";
import $rootScope from "../lib/rootScope";
type PeerType = 'contacts' | 'dialogs';

2
src/components/avatar.ts

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
import appProfileManager from "../lib/appManagers/appProfileManager";
import { $rootScope } from "../lib/utils";
import $rootScope from "../lib/rootScope";
$rootScope.$on('avatar_update', (e) => {
let peerID = e.detail;

3
src/components/bubbleGroups.ts

@ -1,4 +1,5 @@ @@ -1,4 +1,5 @@
import { generatePathData, $rootScope } from "../lib/utils";
import $rootScope from "../lib/rootScope";
import { generatePathData } from "../lib/utils";
export default class BubbleGroups {
bubblesByGroups: Array<{timestamp: number, fromID: number, mid: number, group: HTMLDivElement[]}> = []; // map to group

3
src/components/chat/audio.ts

@ -2,7 +2,8 @@ import appImManager from "../../lib/appManagers/appImManager"; @@ -2,7 +2,8 @@ import appImManager from "../../lib/appManagers/appImManager";
import appMessagesManager from "../../lib/appManagers/appMessagesManager";
import appPeersManager from "../../lib/appManagers/appPeersManager";
import { RichTextProcessor } from "../../lib/richtextprocessor";
import { cancelEvent, $rootScope } from "../../lib/utils";
import $rootScope from "../../lib/rootScope";
import { cancelEvent } from "../../lib/utils";
import appMediaPlaybackController from "../appMediaPlaybackController";
import { formatDate } from "../wrappers";

3
src/components/chat/contextMenu.ts

@ -3,7 +3,8 @@ import appImManager from "../../lib/appManagers/appImManager"; @@ -3,7 +3,8 @@ import appImManager from "../../lib/appManagers/appImManager";
import appMessagesManager from "../../lib/appManagers/appMessagesManager";
import appPeersManager from "../../lib/appManagers/appPeersManager";
import appSidebarRight from "../../lib/appManagers/appSidebarRight";
import { findUpClassName, $rootScope } from "../../lib/utils";
import $rootScope from "../../lib/rootScope";
import { findUpClassName } from "../../lib/utils";
import { parseMenuButtonsTo, attachContextMenuListener, positionMenu, openBtnMenu } from "../misc";
import { PopupButton, PopupPeer } from "../popup";

6
src/components/chat/input.ts

@ -10,11 +10,11 @@ import { Layouter, RectPart } from "../groupedLayout"; @@ -10,11 +10,11 @@ import { Layouter, RectPart } from "../groupedLayout";
import Recorder from '../../../public/recorder.min';
//import Recorder from '../opus-recorder/dist/recorder.min';
import opusDecodeController from "../../lib/opusDecodeController";
import { touchSupport } from "../../lib/config";
import appDocsManager from "../../lib/appManagers/appDocsManager";
import emoticonsDropdown from "../emoticonsDropdown";
import PopupCreatePoll from "../popupCreatePoll";
import { toast } from "../toast";
import { isTouchSupported } from "../../helpers/touchSupport";
const RECORD_MIN_TIME = 500;
@ -104,7 +104,7 @@ export class ChatInput { @@ -104,7 +104,7 @@ export class ChatInput {
this.updateSendBtn();
this.messageInput.addEventListener('keydown', (e: KeyboardEvent) => {
if(e.key == 'Enter' && !touchSupport) {
if(e.key == 'Enter' && !isTouchSupported) {
/* if(e.ctrlKey || e.metaKey) {
this.messageInput.innerHTML += '<br>';
placeCaretAtEnd(this.message)
@ -119,7 +119,7 @@ export class ChatInput { @@ -119,7 +119,7 @@ export class ChatInput {
}
});
if(touchSupport) {
if(isTouchSupported) {
this.messageInput.addEventListener('touchend', (e) => {
this.saveScroll();
emoticonsDropdown.toggle(false);

3
src/components/chat/search.ts

@ -1,5 +1,6 @@ @@ -1,5 +1,6 @@
import appImManager from "../../lib/appManagers/appImManager";
import { $rootScope, cancelEvent, whichChild, findUpTag } from "../../lib/utils";
import $rootScope from "../../lib/rootScope";
import { cancelEvent, whichChild, findUpTag } from "../../lib/utils";
import AppSearch, { SearchGroup } from "../appSearch";
import PopupDatePicker from "../popupDatepicker";
import { ripple } from "../ripple";

10
src/components/emoticonsDropdown/index.ts

@ -1,6 +1,5 @@ @@ -1,6 +1,5 @@
import LazyLoadQueue from "../lazyLoadQueue";
import GifsTab from "./tabs/gifs";
import { touchSupport } from "../../lib/config";
import { findUpClassName, findUpTag, whichChild } from "../../lib/utils";
import { horizontalMenu } from "../horizontalMenu";
import animationIntersector from "../animationIntersector";
@ -11,6 +10,7 @@ import EmojiTab from "./tabs/emoji"; @@ -11,6 +10,7 @@ import EmojiTab from "./tabs/emoji";
import StickersTab from "./tabs/stickers";
import StickyIntersector from "../stickyIntersector";
import { MOUNT_CLASS_TO } from "../../lib/mtproto/mtproto_config";
import { isTouchSupported } from "../../helpers/touchSupport";
export const EMOTICONSSTICKERGROUP = 'emoticons-dropdown';
@ -58,7 +58,7 @@ export class EmoticonsDropdown { @@ -58,7 +58,7 @@ export class EmoticonsDropdown {
let firstTime = true;
this.toggleEl = document.getElementById('toggle-emoticons');
if(touchSupport) {
if(isTouchSupported) {
this.toggleEl.addEventListener('click', () => {
if(firstTime) {
firstTime = false;
@ -172,7 +172,7 @@ export class EmoticonsDropdown { @@ -172,7 +172,7 @@ export class EmoticonsDropdown {
}
}
if(touchSupport) {
if(isTouchSupported) {
this.toggleEl.classList.toggle('flip-icon', willBeActive);
if(willBeActive) {
appImManager.chatInputC.saveScroll();
@ -204,7 +204,7 @@ export class EmoticonsDropdown { @@ -204,7 +204,7 @@ export class EmoticonsDropdown {
EmoticonsDropdown.lazyLoadQueue.refresh();
this.events.onOpenAfter.forEach(cb => cb());
}, touchSupport ? 0 : 200);
}, isTouchSupported ? 0 : 200);
/* if(touchSupport) {
this.restoreScroll();
@ -231,7 +231,7 @@ export class EmoticonsDropdown { @@ -231,7 +231,7 @@ export class EmoticonsDropdown {
EmoticonsDropdown.lazyLoadQueue.refresh();
this.events.onCloseAfter.forEach(cb => cb());
}, touchSupport ? 0 : 200);
}, isTouchSupported ? 0 : 200);
/* if(touchSupport) {
this.restoreScroll();

2
src/components/emoticonsDropdown/tabs/stickers.ts

@ -8,7 +8,7 @@ import { readBlobAsText } from "../../../helpers/blob"; @@ -8,7 +8,7 @@ import { readBlobAsText } from "../../../helpers/blob";
import lottieLoader from "../../../lib/lottieLoader";
import { renderImageFromUrl, putPreloader } from "../../misc";
import { RichTextProcessor } from "../../../lib/richtextprocessor";
import { $rootScope } from "../../../lib/utils";
import $rootScope from "../../../lib/rootScope";
import apiManager from "../../../lib/mtproto/mtprotoworker";
import StickyIntersector from "../../stickyIntersector";
import appDocsManager, {MyDocument} from "../../../lib/appManagers/appDocsManager";

13
src/components/horizontalMenu.ts

@ -28,6 +28,7 @@ function slideTabs(tabContent: HTMLElement, prevTabContent: HTMLElement, width: @@ -28,6 +28,7 @@ function slideTabs(tabContent: HTMLElement, prevTabContent: HTMLElement, width:
export function horizontalMenu(tabs: HTMLElement, content: HTMLElement, onClick?: (id: number, tabContent: HTMLDivElement) => void, onTransitionEnd?: () => void, transitionTime = 250) {
const hideTimeouts: {[id: number]: number} = {};
let transitionEndTimeout: number;
let prevTabContent: HTMLElement = null;
let prevId = -1;
@ -88,10 +89,16 @@ export function horizontalMenu(tabs: HTMLElement, content: HTMLElement, onClick? @@ -88,10 +89,16 @@ export function horizontalMenu(tabs: HTMLElement, content: HTMLElement, onClick?
}
delete hideTimeouts[_prevId];
if(onTransitionEnd) onTransitionEnd();
}, /* 420 */transitionTime);
}
if(onTransitionEnd) {
if(transitionEndTimeout) clearTimeout(transitionEndTimeout);
transitionEndTimeout = window.setTimeout(() => {
onTransitionEnd();
transitionEndTimeout = 0;
}, transitionTime);
}
}
prevId = id;
prevTabContent = tabContent;

9
src/components/misc.ts

@ -1,6 +1,7 @@ @@ -1,6 +1,7 @@
import mediaSizes from "../helpers/mediaSizes";
import { isTouchSupported } from "../helpers/touchSupport";
import { isApple } from "../helpers/userAgent";
import Config, { touchSupport } from "../lib/config";
import Config from "../lib/config";
export const loadedURLs: {[url: string]: boolean} = {};
const set = (elem: HTMLElement | HTMLImageElement | SVGImageElement | HTMLVideoElement, url: string) => {
@ -144,7 +145,7 @@ let closeBtnMenu = () => { @@ -144,7 +145,7 @@ let closeBtnMenu = () => {
//document.body.classList.remove('disable-hover');
if(touchSupport) {
if(isTouchSupported) {
window.removeEventListener('touchmove', onClick);
//window.removeEventListener('touchstart', onClick);
} else {
@ -182,7 +183,7 @@ export function openBtnMenu(menuElement: HTMLDivElement, onClose?: () => void) { @@ -182,7 +183,7 @@ export function openBtnMenu(menuElement: HTMLDivElement, onClose?: () => void) {
openedMenuOnClose = onClose;
if(touchSupport) {
if(isTouchSupported) {
window.addEventListener('touchmove', onClick, {once: true});
//window.addEventListener('touchstart', onClick);
} else {
@ -233,7 +234,7 @@ export function positionMenu({clientX, clientY}: {clientX: number, clientY: numb @@ -233,7 +234,7 @@ export function positionMenu({clientX, clientY}: {clientX: number, clientY: numb
}
export function attachContextMenuListener(element: HTMLElement, callback: (e: Touch | MouseEvent) => void) {
if(isApple && touchSupport) {
if(isApple && isTouchSupported) {
let timeout: number;
const onCancel = () => {

7
src/components/poll.ts

@ -1,12 +1,13 @@ @@ -1,12 +1,13 @@
import appPollsManager, { PollResults, Poll } from "../lib/appManagers/appPollsManager";
import { RichTextProcessor } from "../lib/richtextprocessor";
import { findUpClassName, $rootScope, cancelEvent } from "../lib/utils";
import { touchSupport } from "../lib/config";
import { findUpClassName, cancelEvent } from "../lib/utils";
import appSidebarRight from "../lib/appManagers/appSidebarRight";
import appImManager from "../lib/appManagers/appImManager";
import serverTimeManager from "../lib/mtproto/serverTimeManager";
import { ripple } from "./ripple";
import mediaSizes from "../helpers/mediaSizes";
import $rootScope from "../lib/rootScope";
import { isTouchSupported } from "../helpers/touchSupport";
let lineTotalLength = 0;
const tailLength = 9;
@ -126,7 +127,7 @@ const setQuizHint = (solution: string, solution_entities: any[], onHide: () => v @@ -126,7 +127,7 @@ const setQuizHint = (solution: string, solution_entities: any[], onHide: () => v
prevQuizHintOnHide = onHide;
prevQuizHintTimeout = window.setTimeout(() => {
hideQuizHint(element, onHide, prevQuizHintTimeout);
}, touchSupport ? 5000 : 7000);
}, isTouchSupported ? 5000 : 7000);
};
export default class PollElement extends HTMLElement {

2
src/components/popupCreatePoll.ts

@ -1,7 +1,7 @@ @@ -1,7 +1,7 @@
import { PopupElement } from "./popup";
import Scrollable from "./scrollable_new";
import appMessagesManager from "../lib/appManagers/appMessagesManager";
import { $rootScope } from "../lib/utils";
import $rootScope from "../lib/rootScope";
import { Poll } from "../lib/appManagers/appPollsManager";
import { toast } from "./toast";

4
src/components/ripple.ts

@ -1,4 +1,4 @@ @@ -1,4 +1,4 @@
import { touchSupport } from "../lib/config";
import {isTouchSupported} from "../helpers/touchSupport";
import { findUpClassName } from "../lib/utils";
let rippleClickID = 0;
@ -129,7 +129,7 @@ export function ripple(elem: HTMLElement, callback: (id: number) => Promise<bool @@ -129,7 +129,7 @@ export function ripple(elem: HTMLElement, callback: (id: number) => Promise<bool
// TODO: rename this variable
let touchStartFired = false;
if(touchSupport) {
if(isTouchSupported) {
let touchEnd = () => {
handler && handler();
};

4
src/components/scrollable_new.ts

@ -1,6 +1,6 @@ @@ -1,6 +1,6 @@
import { isTouchSupported } from "../helpers/touchSupport";
import { logger, LogLevels } from "../lib/logger";
import smoothscroll, { SCROLL_TIME, SmoothScrollToOptions } from '../vendor/smoothscroll';
import { touchSupport } from "../lib/config";
//import { CancellablePromise, deferredPromise } from "../lib/polyfill";
//import { isInDOM } from "../lib/utils";
(window as any).__forceSmoothScrollPolyfill__ = true;
@ -509,7 +509,7 @@ export class ScrollableX extends ScrollableBase { @@ -509,7 +509,7 @@ export class ScrollableX extends ScrollableBase {
this.container.classList.add('scrollable-x');
if(!touchSupport) {
if(!isTouchSupported) {
const scrollHorizontally = (e: any) => {
e = window.event || e;
if(e.which == 1) {

3
src/components/sidebarLeft/chatFolders.ts

@ -4,11 +4,12 @@ import apiManager from "../../lib/mtproto/mtprotoworker"; @@ -4,11 +4,12 @@ import apiManager from "../../lib/mtproto/mtprotoworker";
import appMessagesManager, { MyDialogFilter } from "../../lib/appManagers/appMessagesManager";
import { RichTextProcessor } from "../../lib/richtextprocessor";
import appPeersManager from "../../lib/appManagers/appPeersManager";
import { $rootScope, cancelEvent } from "../../lib/utils";
import { cancelEvent } from "../../lib/utils";
import appSidebarLeft from "../../lib/appManagers/appSidebarLeft";
import { ripple } from "../ripple";
import { toast } from "../toast";
import { DialogFilterSuggested, DialogFilter } from "../../layer";
import $rootScope from "../../lib/rootScope";
export default class AppChatFoldersTab implements SliderTab {
public container: HTMLElement;

2
src/components/sidebarLeft/contacts.ts

@ -4,7 +4,7 @@ import appDialogsManager from "../../lib/appManagers/appDialogsManager"; @@ -4,7 +4,7 @@ import appDialogsManager from "../../lib/appManagers/appDialogsManager";
import appUsersManager from "../../lib/appManagers/appUsersManager";
import appPhotosManager from "../../lib/appManagers/appPhotosManager";
import appSidebarLeft, { AppSidebarLeft } from "../../lib/appManagers/appSidebarLeft";
import { $rootScope } from "../../lib/utils";
import $rootScope from "../../lib/rootScope";
import SearchInput from "../searchInput";
// TODO: поиск по людям глобальный, если не нашло в контактах никого

2
src/components/sidebarLeft/editProfile.ts

@ -5,7 +5,7 @@ import appProfileManager from "../../lib/appManagers/appProfileManager"; @@ -5,7 +5,7 @@ import appProfileManager from "../../lib/appManagers/appProfileManager";
import appSidebarLeft from "../../lib/appManagers/appSidebarLeft";
import Scrollable from "../scrollable_new";
import appUsersManager from "../../lib/appManagers/appUsersManager";
import { $rootScope } from "../../lib/utils";
import $rootScope from "../../lib/rootScope";
import { InputFile } from "../../layer";
// TODO: аватарка не поменяется в этой вкладке после изменения почему-то (если поставить в другом клиенте, и потом тут проверить, для этого ещё вышел в чатлист)

3
src/components/sidebarLeft/includedChats.ts

@ -4,8 +4,9 @@ import appSidebarLeft, { AppSidebarLeft } from "../../lib/appManagers/appSidebar @@ -4,8 +4,9 @@ import appSidebarLeft, { AppSidebarLeft } from "../../lib/appManagers/appSidebar
import appDialogsManager from "../../lib/appManagers/appDialogsManager";
import appPeersManager from "../../lib/appManagers/appPeersManager";
import appUsersManager from "../../lib/appManagers/appUsersManager";
import { $rootScope, copy } from "../../lib/utils";
import { copy } from "../../lib/utils";
import { MyDialogFilter as DialogFilter } from "../../lib/appManagers/appMessagesManager";
import $rootScope from "../../lib/rootScope";
export default class AppIncludedChatsTab implements SliderTab {
public container: HTMLElement;

6
src/components/sidebarLeft/settings.ts

@ -1,7 +1,7 @@ @@ -1,7 +1,7 @@
import { SliderTab } from "../slider";
import AvatarElement from "../avatar";
import { parseMenuButtonsTo } from "../misc";
import { $rootScope } from "../../lib/utils";
//import $rootScope from "../../lib/rootScope";
import apiManager from "../../lib/mtproto/mtprotoworker";
import appSidebarLeft, { AppSidebarLeft } from "../../lib/appManagers/appSidebarLeft";
import appUsersManager from "../../lib/appManagers/appUsersManager";
@ -26,9 +26,9 @@ export default class AppSettingsTab implements SliderTab { @@ -26,9 +26,9 @@ export default class AppSettingsTab implements SliderTab {
constructor() {
parseMenuButtonsTo(this.buttons, this.container.querySelector('.profile-buttons').children);
$rootScope.$on('user_auth', (e) => {
/* $rootScope.$on('user_auth', (e) => {
this.fillElements();
});
}); */
this.logOutBtn.addEventListener('click', (e) => {
apiManager.logOut();

13
src/components/sidebarRight/sharedMedia.ts

@ -7,7 +7,7 @@ import appProfileManager from "../../lib/appManagers/appProfileManager"; @@ -7,7 +7,7 @@ import appProfileManager from "../../lib/appManagers/appProfileManager";
import appUsersManager from "../../lib/appManagers/appUsersManager";
import { logger, LogLevels } from "../../lib/logger";
import { RichTextProcessor } from "../../lib/richtextprocessor";
import { $rootScope } from "../../lib/utils";
import $rootScope from "../../lib/rootScope";
import AvatarElement from "../avatar";
import { horizontalMenu } from "../horizontalMenu";
import LazyLoadQueue from "../lazyLoadQueue";
@ -32,11 +32,11 @@ let setText = (text: string, el: HTMLDivElement) => { @@ -32,11 +32,11 @@ let setText = (text: string, el: HTMLDivElement) => {
});
};
type ContentType = 'contentMembers' | 'contentMedia' | 'contentDocuments' | 'contentLinks' | 'contentAudio';
type SharedMediaType = 'inputMessagesFilterContacts' | 'inputMessagesFilterPhotoVideo' | 'inputMessagesFilterDocument' | 'inputMessagesFilterUrl' | 'inputMessagesFilterMusic';
type ContentType = /* 'contentMembers' | */'contentMedia' | 'contentDocuments' | 'contentLinks' | 'contentAudio';
type SharedMediaType = /* 'inputMessagesFilterContacts' | */'inputMessagesFilterEmpty' | 'inputMessagesFilterPhotoVideo' | 'inputMessagesFilterDocument' | 'inputMessagesFilterUrl' | 'inputMessagesFilterMusic';
const contentToSharedMap: {[contentType in ContentType]: SharedMediaType} = {
contentMembers: 'inputMessagesFilterContacts',
//contentMembers: 'inputMessagesFilterContacts',
contentMedia: 'inputMessagesFilterPhotoVideo',
contentDocuments: 'inputMessagesFilterDocument',
contentLinks: 'inputMessagesFilterUrl',
@ -74,7 +74,8 @@ export default class AppSharedMediaTab implements SliderTab { @@ -74,7 +74,8 @@ export default class AppSharedMediaTab implements SliderTab {
public sharedMediaTypes: SharedMediaType[] = [
//'members',
'inputMessagesFilterContacts',
'inputMessagesFilterEmpty',
//'inputMessagesFilterContacts',
'inputMessagesFilterPhotoVideo',
'inputMessagesFilterDocument',
'inputMessagesFilterUrl',
@ -128,7 +129,7 @@ export default class AppSharedMediaTab implements SliderTab { @@ -128,7 +129,7 @@ export default class AppSharedMediaTab implements SliderTab {
};
this.sharedMedia = {
contentMembers: this.profileContentEl.querySelector('#content-members'),
//contentMembers: this.profileContentEl.querySelector('#content-members'),
contentMedia: this.profileContentEl.querySelector('#content-media'),
contentDocuments: this.profileContentEl.querySelector('#content-docs'),
contentLinks: this.profileContentEl.querySelector('#content-links'),

5
src/helpers/json.ts

@ -1,4 +1,5 @@ @@ -1,4 +1,5 @@
export function parse(text: string) {
// TOO SLOW
/* export function parse(text: string) {
let arr: number[] = [], performedValue: any = null;
return JSON.parse(text, (key, value) => {
//console.log(key, value);
@ -19,7 +20,7 @@ export function parse(text: string) { @@ -19,7 +20,7 @@ export function parse(text: string) {
return value;
});
}
} */
// parse('{"file_reference": {"type": "bytes", "value": [1,2,3]}, "file_reference2": {"type": "bytes", "value": [3,2,1]}}');
// -> {file_reference: Uint8Array}

2
src/helpers/touchSupport.ts

@ -0,0 +1,2 @@ @@ -0,0 +1,2 @@
// @ts-ignore
export const isTouchSupported = ('ontouchstart' in window) || (window.DocumentTouch && document instanceof DocumentTouch);

638
src/layer.d.ts vendored

File diff suppressed because it is too large Load Diff

88
src/lib/appManagers/apiUpdatesManager.ts

@ -1,11 +1,13 @@ @@ -1,11 +1,13 @@
//import apiManager from '../mtproto/apiManager';
import apiManager from '../mtproto/mtprotoworker';
//import networkerFactory from '../mtproto/networkerFactory';
import { $rootScope, tsNow } from "../utils";
import { tsNow } from "../utils";
import appPeersManager from "./appPeersManager";
import appUsersManager from "./appUsersManager";
import appChatsManager from "./appChatsManager";
import { logger, LogLevels } from '../logger';
import $rootScope from '../rootScope';
import appStateManager from './appStateManager';
export class ApiUpdatesManager {
public updatesState: {
@ -27,7 +29,18 @@ export class ApiUpdatesManager { @@ -27,7 +29,18 @@ export class ApiUpdatesManager {
public channelStates: any = {};
private attached = false;
private log = logger('UPDATES', LogLevels.error);
private log = logger('UPDATES'/* , LogLevels.error */);
constructor() {
appStateManager.addListener('save', () => {
const us = this.updatesState;
appStateManager.pushToState('updates', {
seq: us.seq,
pts: us.pts,
date: us.date
});
});
}
public popPendingSeqUpdate() {
var nextSeq = this.updatesState.seq + 1;
@ -135,12 +148,13 @@ export class ApiUpdatesManager { @@ -135,12 +148,13 @@ export class ApiUpdatesManager {
break;
case 'updateShortMessage':
case 'updateShortChatMessage':
var isOut = updateMessage.flags & 2;
var fromID = updateMessage.from_id || (isOut ? $rootScope.myID : updateMessage.user_id);
var toID = updateMessage.chat_id
case 'updateShortChatMessage': {
this.log('updateShortMessage | updateShortChatMessage', {...updateMessage});
const isOut = updateMessage.pFlags.out;
const fromID = updateMessage.from_id || (isOut ? $rootScope.myID : updateMessage.user_id);
const toID = updateMessage.chat_id
? -updateMessage.chat_id
: (isOut ? updateMessage.user_id : $rootScope.myID);
: (updateMessage.user_id || $rootScope.myID);
this.processUpdate({
_: 'updateNewMessage',
@ -149,8 +163,8 @@ export class ApiUpdatesManager { @@ -149,8 +163,8 @@ export class ApiUpdatesManager {
flags: updateMessage.flags,
pFlags: updateMessage.pFlags,
id: updateMessage.id,
from_id: fromID,
to_id: appPeersManager.getOutputPeer(toID),
from_id: appPeersManager.getOutputPeer(fromID),
peer_id: appPeersManager.getOutputPeer(toID),
date: updateMessage.date,
message: updateMessage.message,
fwd_from: updateMessage.fwd_from,
@ -161,6 +175,7 @@ export class ApiUpdatesManager { @@ -161,6 +175,7 @@ export class ApiUpdatesManager {
pts_count: updateMessage.pts_count
}, processOpts);
break;
}
case 'updatesCombined':
case 'updates':
@ -364,7 +379,7 @@ export class ApiUpdatesManager { @@ -364,7 +379,7 @@ export class ApiUpdatesManager {
switch(update._) {
case 'updateNewChannelMessage':
case 'updateEditChannelMessage':
channelID = -appPeersManager.getPeerID(update.message.to_id);
channelID = -appPeersManager.getPeerID(update.message.peer_id);
break;
case 'updateDeleteChannelMessages':
channelID = update.channel_id;
@ -399,11 +414,11 @@ export class ApiUpdatesManager { @@ -399,11 +414,11 @@ export class ApiUpdatesManager {
update._ == 'updateNewChannelMessage' ||
update._ == 'updateEditChannelMessage') {
var message = update.message;
var toPeerID = appPeersManager.getPeerID(message.to_id);
var toPeerID = appPeersManager.getPeerID(message.peer_id);
var fwdHeader = message.fwd_from || {};
var reason: any = false;
if(message.from_id && !appUsersManager.hasUser(message.from_id, message.pFlags.post/* || channelID*/) && (reason = 'author') ||
fwdHeader.from_id && !appUsersManager.hasUser(fwdHeader.from_id, !!fwdHeader.channel_id) && (reason = 'fwdAuthor') ||
if(message.from_id && !appUsersManager.hasUser(appPeersManager.getPeerID(message.from_id), message.pFlags.post/* || channelID*/) && (reason = 'author') ||
fwdHeader.from_id && !appUsersManager.hasUser(appPeersManager.getPeerID(fwdHeader.from_id), !!fwdHeader.channel_id) && (reason = 'fwdAuthor') ||
fwdHeader.channel_id && !appChatsManager.hasChat(fwdHeader.channel_id, true) && (reason = 'fwdChannel') ||
toPeerID > 0 && !appUsersManager.hasUser(toPeerID) && (reason = 'toPeer User') ||
toPeerID < 0 && !appChatsManager.hasChat(-toPeerID) && (reason = 'toPeer Chat')) {
@ -509,32 +524,37 @@ export class ApiUpdatesManager { @@ -509,32 +524,37 @@ export class ApiUpdatesManager {
$rootScope.$broadcast('apiUpdate', update);
}
public attach(state: Pick<ApiUpdatesManager['updatesState'], 'seq' | 'pts' | 'date'>) {
public attach() {
if(this.attached) return;
//return;
this.attached = true;
apiManager.setUpdatesProcessor(this.processUpdateMessage.bind(this));
if(!state || !state.pts || !state.date || !state.seq) {
apiManager.invokeApi('updates.getState', {}, {noErrorBox: true}).then((stateResult) => {
this.updatesState.seq = stateResult.seq;
this.updatesState.pts = stateResult.pts;
this.updatesState.date = stateResult.date;
setTimeout(() => {
this.updatesState.syncLoading = false;
}, 1000);
// updatesState.seq = 1
// updatesState.pts = stateResult.pts - 5000
// updatesState.date = 1
// getDifference()
});
} else {
Object.assign(this.updatesState, state);
this.getDifference();
}
appStateManager.getState().then(_state => {
const state = _state.updates;
apiManager.setUpdatesProcessor(this.processUpdateMessage.bind(this));
if(!state || !state.pts || !state.date || !state.seq) {
apiManager.invokeApi('updates.getState', {}, {noErrorBox: true}).then((stateResult) => {
this.updatesState.seq = stateResult.seq;
this.updatesState.pts = stateResult.pts;
this.updatesState.date = stateResult.date;
setTimeout(() => {
this.updatesState.syncLoading = false;
}, 1000);
// updatesState.seq = 1
// updatesState.pts = stateResult.pts - 5000
// updatesState.date = 1
// getDifference()
});
} else {
Object.assign(this.updatesState, state);
this.getDifference();
}
});
}
}

3
src/lib/appManagers/appChatsManager.ts

@ -1,4 +1,4 @@ @@ -1,4 +1,4 @@
import { $rootScope, isObject, safeReplaceObject, copy, numberWithCommas, getAbbreviation } from "../utils";
import { isObject, safeReplaceObject, copy, numberWithCommas, getAbbreviation } from "../utils";
import { RichTextProcessor } from "../richtextprocessor";
import appUsersManager from "./appUsersManager";
import apiManager from '../mtproto/mtprotoworker';
@ -6,6 +6,7 @@ import apiUpdatesManager from "./apiUpdatesManager"; @@ -6,6 +6,7 @@ import apiUpdatesManager from "./apiUpdatesManager";
import appProfileManager from "./appProfileManager";
import searchIndexManager from "../searchIndexManager";
import { InputPeer, InputChannel, Updates, InputChatPhoto } from "../../layer";
import $rootScope from "../rootScope";
export type Channel = {
_: 'channel',

15
src/lib/appManagers/appDialogsManager.ts

@ -1,4 +1,4 @@ @@ -1,4 +1,4 @@
import { findUpClassName, $rootScope, escapeRegExp, findUpTag, cancelEvent, positionElementByIndex } from "../utils";
import { findUpClassName, escapeRegExp, findUpTag, cancelEvent, positionElementByIndex } from "../utils";
import appImManager, { AppImManager } from "./appImManager";
import appPeersManager from './appPeersManager';
import appMessagesManager, { Dialog, MyDialogFilter as DialogFilter } from "./appMessagesManager";
@ -13,11 +13,12 @@ import AvatarElement from "../../components/avatar"; @@ -13,11 +13,12 @@ import AvatarElement from "../../components/avatar";
import { PopupButton, PopupPeer } from "../../components/popup";
import { SliderTab } from "../../components/slider";
import appStateManager from "./appStateManager";
import { touchSupport } from "../config";
import { horizontalMenu } from "../../components/horizontalMenu";
import { ripple } from "../../components/ripple";
import { isSafari } from "../../helpers/userAgent";
import { formatDateAccordingToToday, getWeekNumber } from "../../helpers/date";
import { formatDateAccordingToToday } from "../../helpers/date";
import $rootScope from "../rootScope";
import { isTouchSupported } from "../../helpers/touchSupport";
type DialogDom = {
avatarEl: AvatarElement,
@ -386,7 +387,7 @@ export class AppDialogsManager { @@ -386,7 +387,7 @@ export class AppDialogsManager {
this.scroll.setVirtualContainer(this.chatList);
//this.scroll.attachSentinels();
if(touchSupport && isSafari) {
if(isTouchSupported && isSafari) {
let allowUp: boolean, allowDown: boolean, slideBeginY: number;
const container = this.scroll.container;
container.addEventListener('touchstart', (event) => {
@ -981,8 +982,8 @@ export class AppDialogsManager { @@ -981,8 +982,8 @@ export class AppDialogsManager {
}
/* if(lastMessage.from_id == auth.id) { // You: */
if(peer._ != 'peerUser' && peerID != -lastMessage.from_id) {
let sender = appUsersManager.getUser(lastMessage.from_id);
if(peer._ != 'peerUser' && peerID != lastMessage.fromID) {
let sender = appUsersManager.getUser(lastMessage.fromID);
if(sender && sender.id) {
let senderBold = document.createElement('b');
@ -1030,7 +1031,7 @@ export class AppDialogsManager { @@ -1030,7 +1031,7 @@ export class AppDialogsManager {
const lastMessage = appMessagesManager.getMessage(dialog.top_message);
if(lastMessage._ != 'messageEmpty' && !lastMessage.deleted &&
lastMessage.from_id == $rootScope.myID && lastMessage.peerID != $rootScope.myID &&
lastMessage.fromID == $rootScope.myID && lastMessage.peerID != $rootScope.myID &&
dialog.read_outbox_max_id) { // maybe comment, 06.20.2020
const outgoing = (lastMessage.pFlags && lastMessage.pFlags.unread)
/* && dialog.read_outbox_max_id != 0 */; // maybe uncomment, 31.01.2020

3
src/lib/appManagers/appDocsManager.ts

@ -4,7 +4,6 @@ import opusDecodeController from '../opusDecodeController'; @@ -4,7 +4,6 @@ import opusDecodeController from '../opusDecodeController';
import { getFileNameByLocation } from '../bin_utils';
import appDownloadManager, { DownloadBlob } from './appDownloadManager';
import appPhotosManager from './appPhotosManager';
import { isServiceWorkerSupported } from '../config';
import { InputFileLocation, Document, PhotoSize } from '../../layer';
import referenceDatabase, { ReferenceContext } from '../mtproto/referenceDatabase';
import { MOUNT_CLASS_TO } from '../mtproto/mtproto_config';
@ -137,7 +136,7 @@ class AppDocsManager { @@ -137,7 +136,7 @@ class AppDocsManager {
}
}
if(isServiceWorkerSupported) {
if('serviceWorker' in navigator) {
if((doc.type == 'gif' && doc.size > 8e6) || doc.type == 'audio' || doc.type == 'video') {
doc.supportsStreaming = true;

2
src/lib/appManagers/appDownloadManager.ts

@ -1,4 +1,4 @@ @@ -1,4 +1,4 @@
import { $rootScope } from "../utils";
import $rootScope from "../rootScope";
import apiManager from "../mtproto/mtprotoworker";
import { deferredPromise, CancellablePromise } from "../../helpers/cancellablePromise";
import type { DownloadOptions } from "../mtproto/apiFileManager";

32
src/lib/appManagers/appImManager.ts

@ -1,6 +1,6 @@ @@ -1,6 +1,6 @@
//import apiManager from '../mtproto/apiManager';
import apiManager from '../mtproto/mtprotoworker';
import { $rootScope, numberWithCommas, findUpClassName, formatNumber, placeCaretAtEnd, findUpTag, langPack, whichChild, cancelEvent, getObjectKeysAndSort } from "../utils";
import { numberWithCommas, findUpClassName, formatNumber, placeCaretAtEnd, findUpTag, langPack, whichChild, cancelEvent, getObjectKeysAndSort } from "../utils";
import appUsersManager from "./appUsersManager";
import appMessagesManager, { Dialog } from "./appMessagesManager";
import appPeersManager from "./appPeersManager";
@ -27,7 +27,6 @@ import appStickersManager from './appStickersManager'; @@ -27,7 +27,6 @@ import appStickersManager from './appStickersManager';
import AvatarElement from '../../components/avatar';
import appInlineBotsManager from './AppInlineBotsManager';
import StickyIntersector from '../../components/stickyIntersector';
import { touchSupport } from '../config';
import animationIntersector from '../../components/animationIntersector';
import PopupStickers from '../../components/popupStickers';
import PopupDatePicker from '../../components/popupDatepicker';
@ -42,6 +41,9 @@ import { ChatSearch } from '../../components/chat/search'; @@ -42,6 +41,9 @@ import { ChatSearch } from '../../components/chat/search';
import mediaSizes from '../../helpers/mediaSizes';
import { isAndroid, isApple, isSafari } from '../../helpers/userAgent';
import { MOUNT_CLASS_TO } from '../mtproto/mtproto_config';
import $rootScope from '../rootScope';
import { isTouchSupported } from '../../helpers/touchSupport';
import apiUpdatesManager from './apiUpdatesManager';
//console.log('appImManager included33!');
@ -76,7 +78,6 @@ export class AppImManager { @@ -76,7 +78,6 @@ export class AppImManager {
delete: HTMLButtonElement
} = {} as any;
public myID = 0;
public peerID = 0;
public bubbles: {[mid: string]: HTMLDivElement} = {};
@ -146,7 +147,13 @@ export class AppImManager { @@ -146,7 +147,13 @@ export class AppImManager {
private closeBtn = this.topbar.querySelector('.sidebar-close-button') as HTMLButtonElement;
public hideRightSidebar = false;
get myID() {
return $rootScope.myID;
}
constructor() {
apiUpdatesManager.attach();
this.log = logger('IM', LogLevels.log | LogLevels.warn | LogLevels.debug | LogLevels.error);
this.chatInputC = new ChatInput();
this.preloader = new ProgressivePreloader(null, false);
@ -160,15 +167,6 @@ export class AppImManager { @@ -160,15 +167,6 @@ export class AppImManager {
this.chatAudio = new ChatAudio();
this.chatInfo.nextElementSibling.prepend(this.chatAudio.container);
apiManager.getUserID().then((id) => {
this.myID = $rootScope.myID = id;
});
$rootScope.$on('user_auth', (e) => {
let userAuth = e.detail;
this.myID = $rootScope.myID = userAuth ? userAuth.id : 0;
});
// will call when message is sent (only 1)
$rootScope.$on('history_append', (e) => {
let details = e.detail;
@ -619,7 +617,7 @@ export class AppImManager { @@ -619,7 +617,7 @@ export class AppImManager {
this.chatInputC.attachMediaPopUp.captionInput.focus();
}
if(e.key == 'Enter' && !touchSupport) {
if(e.key == 'Enter' && !isTouchSupported) {
this.chatInputC.attachMediaPopUp.sendBtn.click();
} else if(e.key == 'Escape') {
this.chatInputC.attachMediaPopUp.container.classList.remove('active');
@ -836,7 +834,7 @@ export class AppImManager { @@ -836,7 +834,7 @@ export class AppImManager {
this.onScrollRAF = window.requestAnimationFrame(() => {
//lottieLoader.checkAnimations(false, 'chat');
if(!touchSupport) {
if(!isTouchSupported) {
if(this.isScrollingTimeout) {
clearTimeout(this.isScrollingTimeout);
} else if(!this.chatInner.classList.contains('is-scrolling')) {
@ -885,7 +883,7 @@ export class AppImManager { @@ -885,7 +883,7 @@ export class AppImManager {
this.scroll.addEventListener('scroll', this.onScroll.bind(this));
this.scroll.parentElement.classList.add('scrolled-down');
if(touchSupport) {
if(isTouchSupported) {
this.scroll.addEventListener('touchmove', () => {
if(this.isScrollingTimeout) {
clearTimeout(this.isScrollingTimeout);
@ -2395,10 +2393,10 @@ export class AppImManager { @@ -2395,10 +2393,10 @@ export class AppImManager {
//this.log('performHistoryResult: will set scrollTop', this.scrollable.scrollHeight, newScrollTop, this.scrollable.container.clientHeight);
// touchSupport for safari iOS
touchSupport && isApple && (this.scrollable.container.style.overflow = 'hidden');
isTouchSupported && isApple && (this.scrollable.container.style.overflow = 'hidden');
this.scrollable.scrollTop = newScrollTop;
//this.scrollable.scrollTop = this.scrollable.scrollHeight;
touchSupport && isApple && (this.scrollable.container.style.overflow = '');
isTouchSupported && isApple && (this.scrollable.container.style.overflow = '');
//this.log('performHistoryResult: have set up scrollTop:', newScrollTop, this.scrollable.scrollTop);
}

9
src/lib/appManagers/appMediaViewer.ts

@ -4,18 +4,19 @@ import appMessagesManager from "./appMessagesManager"; @@ -4,18 +4,19 @@ import appMessagesManager from "./appMessagesManager";
import { RichTextProcessor } from "../richtextprocessor";
import { logger } from "../logger";
import ProgressivePreloader from "../../components/preloader";
import { findUpClassName, $rootScope, generatePathData, fillPropertyValue, cancelEvent } from "../utils";
import { findUpClassName, generatePathData, fillPropertyValue, cancelEvent } from "../utils";
import appDocsManager, {MyDocument} from "./appDocsManager";
import VideoPlayer from "../mediaPlayer";
import { renderImageFromUrl, parseMenuButtonsTo } from "../../components/misc";
import AvatarElement from "../../components/avatar";
import { LazyLoadQueueBase } from "../../components/lazyLoadQueue";
import { touchSupport } from "../config";
import appMediaPlaybackController from "../../components/appMediaPlaybackController";
import { deferredPromise } from "../../helpers/cancellablePromise";
import mediaSizes from "../../helpers/mediaSizes";
import { isSafari } from "../../helpers/userAgent";
import appSidebarRight, { AppSidebarRight } from "./appSidebarRight";
import $rootScope from "../rootScope";
import { isTouchSupported } from "../../helpers/touchSupport";
// TODO: масштабирование картинок (не SVG) при ресайзе, и правильный возврат на исходную позицию
// TODO: картинки "обрезаются" если возвращаются или появляются с места, где есть их перекрытие (топбар, поле ввода)
@ -211,7 +212,7 @@ export class AppMediaViewer { @@ -211,7 +212,7 @@ export class AppMediaViewer {
//this.content.mover.append(this.buttons.prev, this.buttons.next);
this.setNewMover();
if(touchSupport) {
if(isTouchSupported) {
const swipeHandler = new SwipeHandler(this.wholeDiv, (xDiff, yDiff) => {
if(VideoPlayer.isFullScreen()) {
return;
@ -266,7 +267,7 @@ export class AppMediaViewer { @@ -266,7 +267,7 @@ export class AppMediaViewer {
if(target.tagName == 'A') return;
cancelEvent(e);
if(touchSupport) {
if(isTouchSupported) {
if(this.highlightSwitchersTimeout) {
clearTimeout(this.highlightSwitchersTimeout);
} else {

191
src/lib/appManagers/appMessagesManager.ts

@ -1,10 +1,10 @@ @@ -1,10 +1,10 @@
import { $rootScope, copy, tsNow, safeReplaceObject, listMergeSorted, deepEqual, langPack } from "../utils";
import { copy, tsNow, safeReplaceObject, listMergeSorted, deepEqual, langPack } from "../utils";
import appMessagesIDsManager from "./appMessagesIDsManager";
import appChatsManager from "./appChatsManager";
import appUsersManager from "./appUsersManager";
import { RichTextProcessor } from "../richtextprocessor";
import { nextRandomInt, bigint } from "../bin_utils";
import { telegramMeWebService } from "../mtproto/mtproto";
//import { telegramMeWebService } from "../mtproto/mtproto";
import apiUpdatesManager from "./apiUpdatesManager";
import appPhotosManager, { MyPhoto } from "./appPhotosManager";
@ -26,6 +26,8 @@ import type {ApiFileManager} from '../mtproto/apiFileManager'; @@ -26,6 +26,8 @@ import type {ApiFileManager} from '../mtproto/apiFileManager';
import appDownloadManager from "./appDownloadManager";
import { DialogFilter, Message, InputMessage, MethodDeclMap, MessagesFilter, PhotoSize, DocumentAttribute, Dialog as MTDialog, MessagesDialogs, MessagesPeerDialogs, MessagesMessages, MessageMedia } from "../../layer";
import referenceDatabase, { ReferenceContext } from "../mtproto/referenceDatabase";
import $rootScope from "../rootScope";
import appStateManager from "./appStateManager";
//console.trace('include');
// TODO: если удалить сообщение в непрогруженном диалоге, то при обновлении, из-за стейта, последнего сообщения в чатлисте не будет
@ -461,6 +463,17 @@ export class FiltersStorage { @@ -461,6 +463,17 @@ export class FiltersStorage {
}
type MyMessage = Message.message | Message.messageService;
type MyInputMessagesFilter = 'inputMessagesFilterEmpty'
| 'inputMessagesFilterPhotos'
| 'inputMessagesFilterPhotoVideo'
| 'inputMessagesFilterVideo'
| 'inputMessagesFilterDocument'
| 'inputMessagesFilterVoice'
| 'inputMessagesFilterRoundVoice'
| 'inputMessagesFilterRoundVideo'
| 'inputMessagesFilterMusic'
| 'inputMessagesFilterUrl'
| 'inputMessagesFilterMyMentions';
export class AppMessagesManager {
public messagesStorage: {[mid: string]: any} = {};
@ -567,6 +580,91 @@ export class AppMessagesManager { @@ -567,6 +580,91 @@ export class AppMessagesManager {
});
}
}); */
appStateManager.addListener('save', () => {
const messages: any[] = [];
const dialogs: Dialog[] = [];
for(const folderID in this.dialogsStorage.byFolders) {
const folder = this.dialogsStorage.getFolder(+folderID);
for(let dialog of folder) {
const historyStorage = this.historiesStorage[dialog.peerID];
const history = [].concat(historyStorage?.pending ?? [], historyStorage?.history ?? []);
dialog = copy(dialog);
let removeUnread = 0;
for(const mid of history) {
const message = this.getMessage(mid);
if(/* message._ != 'messageEmpty' && */message.id > 0) {
messages.push(message);
if(message.fromID != dialog.peerID) {
appStateManager.setPeer(message.fromID, appPeersManager.getPeer(message.fromID));
}
dialog.top_message = message.mid;
break;
} else if(message.pFlags && message.pFlags.unread) {
++removeUnread;
}
}
if(removeUnread && dialog.unread_count) dialog.unread_count -= removeUnread;
dialogs.push(dialog);
appStateManager.setPeer(dialog.peerID, appPeersManager.getPeer(dialog.peerID));
}
}
appStateManager.pushToState('dialogs', dialogs);
appStateManager.pushToState('messages', messages);
appStateManager.pushToState('filters', this.filtersStorage.filters);
appStateManager.pushToState('allDialogsLoaded', this.dialogsStorage.allDialogsLoaded);
appStateManager.pushToState('maxSeenMsgID', this.maxSeenID);
});
appStateManager.getState().then(state => {
if(state.maxSeenMsgID && !appMessagesIDsManager.getMessageIDInfo(state.maxSeenMsgID)[1]) {
this.maxSeenID = state.maxSeenMsgID;
}
const messages = state.messages;
if(messages) {
/* let tempID = this.tempID;
for(let message of messages) {
if(message.id < tempID) {
tempID = message.id;
}
}
if(tempID != this.tempID) {
this.log('Set tempID to:', tempID);
this.tempID = tempID;
} */
this.saveMessages(messages);
}
if(state.allDialogsLoaded) {
this.dialogsStorage.allDialogsLoaded = state.allDialogsLoaded;
}
if(state.filters) {
for(const filterID in state.filters) {
this.filtersStorage.saveDialogFilter(state.filters[filterID], false);
}
}
if(state.dialogs) {
state.dialogs.forEachReverse(dialog => {
this.saveConversation(dialog);
});
}
});
}
@ -715,8 +813,8 @@ export class AppMessagesManager { @@ -715,8 +813,8 @@ export class AppMessagesManager {
message = {
_: 'message',
id: messageID,
from_id: fromID,
to_id: appPeersManager.getOutputPeer(peerID),
from_id: appPeersManager.getOutputPeer(fromID),
peer_id: appPeersManager.getOutputPeer(peerID),
flags: flags,
pFlags: pFlags,
date: tsNow(true) + serverTimeManager.serverTimeOffset,
@ -1071,8 +1169,8 @@ export class AppMessagesManager { @@ -1071,8 +1169,8 @@ export class AppMessagesManager {
const message: any = {
_: 'message',
id: messageID,
from_id: fromID,
to_id: appPeersManager.getOutputPeer(peerID),
from_id: appPeersManager.getOutputPeer(fromID),
peer_id: appPeersManager.getOutputPeer(peerID),
flags: flags,
pFlags: pFlags,
date: date,
@ -1349,9 +1447,9 @@ export class AppMessagesManager { @@ -1349,9 +1447,9 @@ export class AppMessagesManager {
let message = {
_: 'message',
id: messageID,
from_id: fromID,
from_id: appPeersManager.getOutputPeer(fromID),
grouped_id: groupID,
to_id: appPeersManager.getOutputPeer(peerID),
peer_id: appPeersManager.getOutputPeer(peerID),
flags: flags,
pFlags: pFlags,
date: date,
@ -1644,8 +1742,8 @@ export class AppMessagesManager { @@ -1644,8 +1742,8 @@ export class AppMessagesManager {
const message: any = {
_: 'message',
id: messageID,
from_id: fromID,
to_id: appPeersManager.getOutputPeer(peerID),
from_id: appPeersManager.getOutputPeer(fromID),
peer_id: appPeersManager.getOutputPeer(peerID),
flags: flags,
pFlags: pFlags,
date: tsNow(true) + ServerTimeManager.serverTimeOffset,
@ -1908,9 +2006,9 @@ export class AppMessagesManager { @@ -1908,9 +2006,9 @@ export class AppMessagesManager {
//this.log.error('messages.getDialogs result:', dialogsResult.dialogs, {...dialogsResult.dialogs[0]});
if(!offsetDate) {
/* if(!offsetDate) {
telegramMeWebService.setAuthorized(true);
}
} */
appUsersManager.saveApiUsers(dialogsResult.users);
appChatsManager.saveApiChats(dialogsResult.chats);
@ -2038,14 +2136,15 @@ export class AppMessagesManager { @@ -2038,14 +2136,15 @@ export class AppMessagesManager {
}
public getMessagePeer(message: any): number {
var toID = message.to_id && appPeersManager.getPeerID(message.to_id) || 0;
var toID = message.peer_id && appPeersManager.getPeerID(message.peer_id) || 0;
if(toID < 0) {
return toID;
/* if(toID < 0) {
return toID;
} else if(message.pFlags && message.pFlags.out || message.flags & 2) {
return toID;
}
return message.from_id;
return message.from_id; */
}
public getDialogByPeerID(peerID: number): [Dialog, number] | [] {
@ -2195,7 +2294,7 @@ export class AppMessagesManager { @@ -2195,7 +2294,7 @@ export class AppMessagesManager {
}
const peerID = this.getMessagePeer(apiMessage);
const isChannel = apiMessage.to_id._ == 'peerChannel';
const isChannel = apiMessage.peer_id._ == 'peerChannel';
const channelID = isChannel ? -peerID : 0;
const isBroadcast = isChannel && appChatsManager.isBroadcast(channelID);
@ -2223,12 +2322,18 @@ export class AppMessagesManager { @@ -2223,12 +2322,18 @@ export class AppMessagesManager {
apiMessage.date -= serverTimeManager.serverTimeOffset;
const myID = appUsersManager.getSelf().id;
apiMessage.peerID = peerID;
apiMessage.fromID = apiMessage.pFlags.post ? peerID : apiMessage.from_id;
if(apiMessage.peerID == myID && !apiMessage.from_id && !apiMessage.fwd_from) {
apiMessage.fromID = myID;
} else {
apiMessage.fromID = apiMessage.pFlags.post || peerID == myID ? peerID : appPeersManager.getPeerID(apiMessage.from_id);
}
const fwdHeader = apiMessage.fwd_from;
if(fwdHeader) {
if(peerID == appUsersManager.getSelf().id) {
if(peerID == myID) {
if(fwdHeader.saved_from_peer && fwdHeader.saved_from_msg_id) {
const savedFromPeerID = appPeersManager.getPeerID(fwdHeader.saved_from_peer);
const savedFromMid = appMessagesIDsManager.getFullMessageID(fwdHeader.saved_from_msg_id,
@ -2236,12 +2341,12 @@ export class AppMessagesManager { @@ -2236,12 +2341,12 @@ export class AppMessagesManager {
apiMessage.savedFrom = savedFromPeerID + '_' + savedFromMid;
}
apiMessage.fromID = fwdHeader.channel_id ? -fwdHeader.channel_id : fwdHeader.from_id;
apiMessage.fromID = fwdHeader.channel_id ? -fwdHeader.channel_id : appPeersManager.getPeerID(fwdHeader.from_id);
} else {
apiMessage.fwdPostID = fwdHeader.channel_post;
}
apiMessage.fwdFromID = fwdHeader.channel_id ? -fwdHeader.channel_id : fwdHeader.from_id;
apiMessage.fwdFromID = fwdHeader.channel_id ? -fwdHeader.channel_id : appPeersManager.getPeerID(fwdHeader.from_id);
fwdHeader.date -= serverTimeManager.serverTimeOffset;
}
@ -2718,8 +2823,8 @@ export class AppMessagesManager { @@ -2718,8 +2823,8 @@ export class AppMessagesManager {
_: 'message',
id: mid,
mid: mid,
from_id: appUsersManager.getSelf().id,
to_id: appPeersManager.getOutputPeer(peerID),
from_id: appPeersManager.getOutputPeer(appUsersManager.getSelf().id),
peer_id: appPeersManager.getOutputPeer(peerID),
deleted: true,
flags: 0,
pFlags: {unread: false, out: true},
@ -2817,7 +2922,7 @@ export class AppMessagesManager { @@ -2817,7 +2922,7 @@ export class AppMessagesManager {
mid: message.mid
}, messageReplyMarkup);
if(messageReplyMarkup._ != 'replyKeyboardHide') {
messageReplyMarkup.fromID = message.from_id;
messageReplyMarkup.fromID = appPeersManager.getPeerID(message.from_id);
}
historyStorage.reply_markup = messageReplyMarkup;
// this.log('set', historyStorage.reply_markup)
@ -2861,8 +2966,8 @@ export class AppMessagesManager { @@ -2861,8 +2966,8 @@ export class AppMessagesManager {
}
public getSearch(peerID = 0, query: string = '', inputFilter: {
_?: string
} = {_: 'inputMessagesFilterEmpty'}, maxID: number, limit: number, offsetRate = 0, backLimit = 0): Promise<{
_?: MyInputMessagesFilter
} = {_: 'inputMessagesFilterEmpty'}, maxID: number, limit = 20, offsetRate = 0, backLimit = 0): Promise<{
count: number,
next_rate: number,
history: number[]
@ -2886,10 +2991,9 @@ export class AppMessagesManager { @@ -2886,10 +2991,9 @@ export class AppMessagesManager {
if(historyStorage !== undefined && historyStorage.history.length) {
var neededContents: {
[type: string]: boolean
[messageMediaType: string]: boolean
} = {},
neededDocTypes: string[] = [];
var neededLimit = limit || 20;
var message;
switch(inputFilter._) {
@ -2958,7 +3062,7 @@ export class AppMessagesManager { @@ -2958,7 +3062,7 @@ export class AppMessagesManager {
}
foundMsgs.push(message.mid);
if(foundMsgs.length >= neededLimit) {
if(foundMsgs.length >= limit) {
break;
}
}
@ -2966,12 +3070,12 @@ export class AppMessagesManager { @@ -2966,12 +3070,12 @@ export class AppMessagesManager {
}
// this.log.warn(dT(), 'before append', foundMsgs)
if(foundMsgs.length < neededLimit && this.lastSearchResults.length && sameSearchCache) {
if(foundMsgs.length < limit && this.lastSearchResults.length && sameSearchCache) {
var minID = foundMsgs.length ? foundMsgs[foundMsgs.length - 1] : false;
for(let i = 0; i < this.lastSearchResults.length; i++) {
if(minID === false || this.lastSearchResults[i] < minID) {
foundMsgs.push(this.lastSearchResults[i]);
if(foundMsgs.length >= neededLimit) {
if(foundMsgs.length >= limit) {
break;
}
}
@ -2980,7 +3084,7 @@ export class AppMessagesManager { @@ -2980,7 +3084,7 @@ export class AppMessagesManager {
// this.log.warn(dT(), 'after append', foundMsgs)
}
if(foundMsgs.length || limit == 1000) {
if(foundMsgs.length) {
if(useSearchCache) {
this.lastSearchResults = listMergeSorted(this.lastSearchResults, foundMsgs)
}
@ -3001,7 +3105,7 @@ export class AppMessagesManager { @@ -3001,7 +3105,7 @@ export class AppMessagesManager {
filter: (inputFilter || {_: 'inputMessagesFilterEmpty'}) as any as MessagesFilter,
min_date: 0,
max_date: 0,
limit: limit,
limit,
offset_id: appMessagesIDsManager.getMessageLocalID(maxID) || 0,
add_offset: backLimit ? -backLimit : 0,
max_id: 0,
@ -3026,10 +3130,13 @@ export class AppMessagesManager { @@ -3026,10 +3130,13 @@ export class AppMessagesManager {
apiPromise = apiManager.invokeApi('messages.searchGlobal', {
flags: 0,
q: query,
filter: (inputFilter || {_: 'inputMessagesFilterEmpty'}) as any as MessagesFilter,
min_date: 0,
max_date: 0,
offset_rate: offsetRate,
offset_peer: appPeersManager.getInputPeerByID(offsetPeerID),
offset_id: appMessagesIDsManager.getMessageLocalID(offsetID),
limit: limit || 20
limit
}, {
//timeout: APITIMEOUT,
noErrorBox: true
@ -3068,12 +3175,6 @@ export class AppMessagesManager { @@ -3068,12 +3175,6 @@ export class AppMessagesManager {
next_rate: searchResult.next_rate,
history: foundMsgs
};
}, (error) => {
if(error.code == 400) {
error.handled = true;
}
return Promise.reject(error);
});
}
@ -3416,7 +3517,7 @@ export class AppMessagesManager { @@ -3416,7 +3517,7 @@ export class AppMessagesManager {
}
if(!message.pFlags.out && message.from_id) {
appUsersManager.forceUserOnline(message.from_id);
appUsersManager.forceUserOnline(appPeersManager.getPeerID(message.from_id));
}
var randomID = this.pendingByMessageID[message.mid],
@ -3617,7 +3718,7 @@ export class AppMessagesManager { @@ -3617,7 +3718,7 @@ export class AppMessagesManager {
case 'updateEditChannelMessage': {
var message = update.message;
var peerID = this.getMessagePeer(message);
var channelID = message.to_id._ == 'peerChannel' ? -peerID : 0;
var channelID = message.peer_id._ == 'peerChannel' ? -peerID : 0;
var mid = appMessagesIDsManager.getFullMessageID(message.id, channelID);
if(this.messagesStorage[mid] === undefined) {
break;
@ -3796,7 +3897,7 @@ export class AppMessagesManager { @@ -3796,7 +3897,7 @@ export class AppMessagesManager {
deleted: true,
id: messageID,
from_id: message.from_id,
to_id: message.to_id,
peer_id: message.peer_id,
flags: message.flags,
pFlags: message.pFlags,
date: message.date
@ -3928,8 +4029,8 @@ export class AppMessagesManager { @@ -3928,8 +4029,8 @@ export class AppMessagesManager {
var message: any = {
_: 'message',
id: messageID,
from_id: fromID,
to_id: appPeersManager.getOutputPeer(peerID),
from_id: appPeersManager.getOutputPeer(fromID),
peer_id: appPeersManager.getOutputPeer(peerID),
flags: 0,
pFlags: {unread: true},
date: (update.inbox_date || tsNow(true)) + serverTimeManager.serverTimeOffset,
@ -4290,7 +4391,7 @@ export class AppMessagesManager { @@ -4290,7 +4391,7 @@ export class AppMessagesManager {
_: 'messageService',
id: messageID,
from_id: peerID,
to_id: appPeersManager.getOutputPeer(peerID),
peer_id: appPeersManager.getOutputPeer(peerID),
flags: 0,
pFlags: {},
date: tsNow(true) + serverTimeManager.serverTimeOffset,

15
src/lib/appManagers/appPeersManager.ts

@ -3,6 +3,7 @@ import appChatsManager from "./appChatsManager"; @@ -3,6 +3,7 @@ import appChatsManager from "./appChatsManager";
import { isObject } from "../utils";
import { RichTextProcessor } from "../richtextprocessor";
import { InputPeer, InputDialogPeer, Peer } from "../../layer";
import appStateManager from "./appStateManager";
// https://github.com/eelcohn/Telegram-API/wiki/Calculating-color-for-a-Telegram-user-on-IRC
/*
@ -21,6 +22,20 @@ const DialogColors = ['#e17076', '#7bc862', '#e5ca77', '#65AADD', '#a695e7', '#e @@ -21,6 +22,20 @@ const DialogColors = ['#e17076', '#7bc862', '#e5ca77', '#65AADD', '#a695e7', '#e
const DialogColorsMap = [0, 7, 4, 1, 6, 3, 5];
export class AppPeersManager {
constructor() {
appStateManager.getState().then((state) => {
for(let peerID in state.peers) {
let peer = state.peers[peerID];
this.savePeerInstance(+peerID, peer);
}
});
}
public savePeerInstance(peerID: number, instance: any) {
if(+peerID < 0) appChatsManager.saveApiChat(instance);
else appUsersManager.saveApiUser(instance);
}
public getPeerPhoto(peerID: number) {
return peerID > 0
? appUsersManager.getUserPhoto(peerID)

2
src/lib/appManagers/appPollsManager.ts

@ -3,7 +3,7 @@ import appMessagesManager from './appMessagesManager'; @@ -3,7 +3,7 @@ import appMessagesManager from './appMessagesManager';
import appPeersManager from './appPeersManager';
import apiManager from "../mtproto/mtprotoworker";
import apiUpdatesManager from "./apiUpdatesManager";
import { $rootScope } from "../utils";
import $rootScope from "../rootScope";
import { logger, LogLevels } from "../logger";
import appUsersManager from "./appUsersManager";
import { MOUNT_CLASS_TO } from "../mtproto/mtproto_config";

9
src/lib/appManagers/appSidebarLeft.ts

@ -1,12 +1,11 @@ @@ -1,12 +1,11 @@
//import { logger } from "../polyfill";
import appDialogsManager, { AppArchivedTab, archivedTab } from "./appDialogsManager";
import { $rootScope, findUpTag, findUpClassName, formatNumber } from "../utils";
import { findUpTag, findUpClassName, formatNumber } from "../utils";
import appImManager from "./appImManager";
import AppSearch, { SearchGroup } from "../../components/appSearch";
import { parseMenuButtonsTo } from "../../components/misc";
import appUsersManager from "./appUsersManager";
import Scrollable, { ScrollableX } from "../../components/scrollable_new";
import appPeersManager from "../appManagers/appPeersManager";
import { ScrollableX } from "../../components/scrollable_new";
import AvatarElement from "../../components/avatar";
import AppNewChannelTab from "../../components/sidebarLeft/newChannel";
import AppAddMembersTab from "../../components/sidebarLeft/addMembers";
@ -22,6 +21,8 @@ import SearchInput from "../../components/searchInput"; @@ -22,6 +21,8 @@ import SearchInput from "../../components/searchInput";
import appStateManager from "./appStateManager";
import appChatsManager from "./appChatsManager";
import { MOUNT_CLASS_TO } from "../mtproto/mtproto_config";
import $rootScope from "../rootScope";
import appPeersManager from "./appPeersManager";
AvatarElement;
@ -167,7 +168,7 @@ export class AppSidebarLeft extends SidebarSlider { @@ -167,7 +168,7 @@ export class AppSidebarLeft extends SidebarSlider {
this.renderRecentSearch();
appStateManager.pushToState('recentSearch', this.recentSearch);
for(const peerID of this.recentSearch) {
appStateManager.pushPeer(peerID);
appStateManager.setPeer(peerID, appPeersManager.getPeer(peerID));
}
clearRecentSearchBtn.style.display = '';

165
src/lib/appManagers/appStateManager.ts

@ -1,14 +1,11 @@ @@ -1,14 +1,11 @@
import AppStorage from '../storage';
import appMessagesManager, { Dialog, DialogsStorage, FiltersStorage } from './appMessagesManager';
import appMessagesIDsManager from './appMessagesIDsManager';
import appPeersManager from './appPeersManager';
import appChatsManager from './appChatsManager';
import appUsersManager from './appUsersManager';
import apiUpdatesManager from './apiUpdatesManager';
import { $rootScope, copy } from '../utils';
import { logger } from '../logger';
import type { Dialog, DialogsStorage, FiltersStorage } from './appMessagesManager';
import type { AppStickersManager } from './appStickersManager';
import type { AppPeersManager } from './appPeersManager';
import { App, MOUNT_CLASS_TO } from '../mtproto/mtproto_config';
import EventListenerBase from '../../helpers/eventListenerBase';
import $rootScope from '../rootScope';
import AppStorage from '../storage';
import { logger } from '../logger';
const REFRESH_EVERY = 24 * 60 * 60 * 1000; // 1 day
const STATE_VERSION = App.version;
@ -16,7 +13,7 @@ const STATE_VERSION = App.version; @@ -16,7 +13,7 @@ const STATE_VERSION = App.version;
type State = Partial<{
dialogs: Dialog[],
allDialogsLoaded: DialogsStorage['allDialogsLoaded'],
peers: {[peerID: string]: any},
peers: {[peerID: string]: ReturnType<AppPeersManager['getPeer']>},
messages: any[],
contactsList: number[],
updates: any,
@ -33,22 +30,22 @@ type State = Partial<{ @@ -33,22 +30,22 @@ type State = Partial<{
const REFRESH_KEYS = ['dialogs', 'allDialogsLoaded', 'messages', 'contactsList', 'stateCreatedTime',
'updates', 'maxSeenMsgID', 'filters', 'topPeers'] as any as Array<keyof State>;
export class AppStateManager {
export class AppStateManager extends EventListenerBase<{
save: (state: State) => void
}> {
public loaded: Promise<State>;
private log = logger('STATE'/* , LogLevels.error */);
private state: State;
constructor() {
super();
this.loadSavedState();
$rootScope.$on('user_auth', (e) => {
apiUpdatesManager.attach(null);
});
}
public loadSavedState() {
if(this.loaded) return this.loaded;
console.time('load state');
return this.loaded = new Promise((resolve) => {
AppStorage.get<[State, {id: number}]>('state', 'user_auth').then(([state, auth]) => {
const time = Date.now();
@ -65,77 +62,26 @@ export class AppStateManager { @@ -65,77 +62,26 @@ export class AppStateManager {
}
// will not throw error because state can be `FALSE`
const {dialogs, allDialogsLoaded, peers, messages, contactsList, maxSeenMsgID, updates, filters} = state;
const {peers, updates} = state;
this.state = state || {};
this.state.peers = peers || {};
this.state.version = STATE_VERSION;
// ??= doesn't compiles
if(!this.state.hasOwnProperty('stateCreatedTime')) {
this.state.stateCreatedTime = Date.now();
}
this.log('state res', dialogs, messages);
if(maxSeenMsgID && !appMessagesIDsManager.getMessageIDInfo(maxSeenMsgID)[1]) {
appMessagesManager.maxSeenID = maxSeenMsgID;
}
//return resolve();
if(peers) {
for(let peerID in peers) {
let peer = peers[peerID];
if(+peerID < 0) appChatsManager.saveApiChat(peer);
else appUsersManager.saveApiUser(peer);
}
}
if(contactsList && Array.isArray(contactsList) && contactsList.length) {
contactsList.forEach(userID => {
appUsersManager.pushContact(userID);
});
appUsersManager.contactsFillPromise = Promise.resolve(appUsersManager.contactsList);
}
if(messages) {
/* let tempID = this.tempID;
for(let message of messages) {
if(message.id < tempID) {
tempID = message.id;
}
}
if(tempID != this.tempID) {
this.log('Set tempID to:', tempID);
this.tempID = tempID;
} */
appMessagesManager.saveMessages(messages);
}
this.log('state res', state);
if(allDialogsLoaded) {
appMessagesManager.dialogsStorage.allDialogsLoaded = allDialogsLoaded;
}
if(filters) {
for(const filterID in filters) {
appMessagesManager.filtersStorage.saveDialogFilter(filters[filterID], false);
}
}
if(dialogs) {
dialogs.forEachReverse(dialog => {
appMessagesManager.saveConversation(dialog);
});
}
//return resolve();
if(auth?.id) {
apiUpdatesManager.attach(updates ?? null);
$rootScope.$broadcast('user_auth', {id: auth.id});
}
console.timeEnd('load state');
resolve(state);
}).catch(resolve).finally(() => {
setInterval(() => this.saveState(), 10000);
@ -150,74 +96,12 @@ export class AppStateManager { @@ -150,74 +96,12 @@ export class AppStateManager {
public saveState() {
if(this.state === undefined) return;
const messages: any[] = [];
const dialogs: Dialog[] = [];
const peers = this.state.peers;
for(const folderID in appMessagesManager.dialogsStorage.byFolders) {
const folder = appMessagesManager.dialogsStorage.getFolder(+folderID);
for(let dialog of folder) {
const historyStorage = appMessagesManager.historiesStorage[dialog.peerID];
const history = [].concat(historyStorage?.pending ?? [], historyStorage?.history ?? []);
dialog = copy(dialog);
let removeUnread = 0;
for(const mid of history) {
const message = appMessagesManager.getMessage(mid);
if(/* message._ != 'messageEmpty' && */message.id > 0) {
messages.push(message);
if(message.fromID != dialog.peerID) {
peers[message.fromID] = appPeersManager.getPeer(message.fromID);
}
dialog.top_message = message.mid;
break;
} else if(message.pFlags && message.pFlags.unread) {
++removeUnread;
}
}
if(removeUnread && dialog.unread_count) dialog.unread_count -= removeUnread;
dialogs.push(dialog);
peers[dialog.peerID] = appPeersManager.getPeer(dialog.peerID);
}
}
const us = apiUpdatesManager.updatesState;
const updates = {
seq: us.seq,
pts: us.pts,
date: us.date
};
const contactsList = [...appUsersManager.contactsList];
for(const userID of contactsList) {
if(!peers[userID]) {
peers[userID] = appUsersManager.getUser(userID);
}
}
const filters = appMessagesManager.filtersStorage.filters;
this.setListenerResult('save', this.state);
//const pinnedOrders = appMessagesManager.dialogsStorage.pinnedOrders;
AppStorage.set({
state: Object.assign({}, this.state, {
dialogs,
messages,
allDialogsLoaded: appMessagesManager.dialogsStorage.allDialogsLoaded,
peers,
contactsList,
filters,
//pinnedOrders,
updates,
maxSeenMsgID: appMessagesManager.maxSeenID
})
state: this.state
});
}
@ -225,8 +109,9 @@ export class AppStateManager { @@ -225,8 +109,9 @@ export class AppStateManager {
this.state[key] = value;
}
public pushPeer(peerID: number) {
this.state.peers[peerID] = appPeersManager.getPeer(peerID);
public setPeer(peerID: number, peer: any) {
if(this.state.peers.hasOwnProperty(peerID)) return;
this.state.peers[peerID] = peer;
}
}

2
src/lib/appManagers/appStickersManager.ts

@ -1,6 +1,6 @@ @@ -1,6 +1,6 @@
import apiManager from '../mtproto/mtprotoworker';
import appDocsManager from './appDocsManager';
import { $rootScope } from '../utils';
import $rootScope from '../rootScope';
import { StickerSet, InputStickerSet, StickerSetCovered, MessagesRecentStickers, Document, InputFileLocation, MessagesStickerSet, PhotoSize } from '../../layer';
import { Modify } from '../../types';
import appStateManager from './appStateManager';

40
src/lib/appManagers/appUsersManager.ts

@ -1,4 +1,4 @@ @@ -1,4 +1,4 @@
import { safeReplaceObject, isObject, tsNow, copy, $rootScope, getAbbreviation } from "../utils";
import { safeReplaceObject, isObject, tsNow, getAbbreviation } from "../utils";
import { RichTextProcessor } from "../richtextprocessor";
import appChatsManager from "./appChatsManager";
//import apiManager from '../mtproto/apiManager';
@ -9,6 +9,7 @@ import searchIndexManager from "../searchIndexManager"; @@ -9,6 +9,7 @@ import searchIndexManager from "../searchIndexManager";
import appPeersManager from "./appPeersManager";
import appStateManager from "./appStateManager";
import { InputUser, User as MTUser } from "../../layer";
import $rootScope from "../rootScope";
/* export type User = {
_: 'user',
@ -55,20 +56,10 @@ export class AppUsersManager { @@ -55,20 +56,10 @@ export class AppUsersManager {
public contactsIndex = searchIndexManager.createIndex();
public contactsFillPromise: Promise<Set<number>>;
public contactsList: Set<number> = new Set();
public myID: number;
public getPeersPromise: Promise<number[]>;
constructor() {
apiManager.getUserID().then((id) => {
this.myID = id;
});
$rootScope.$on('user_auth', (e) => {
let userAuth = e.detail;
this.myID = userAuth ? userAuth.id : 0;
});
setInterval(this.updateUsersStatuses.bind(this), 60000);
$rootScope.$on('stateSynchronized', this.updateUsersStatuses.bind(this));
@ -123,6 +114,23 @@ export class AppUsersManager { @@ -123,6 +114,23 @@ export class AppUsersManager {
break; */
}
});
appStateManager.addListener('save', () => {
const contactsList = [...this.contactsList];
for(const userID of contactsList) {
appStateManager.setPeer(userID, this.getUser(userID));
}
});
appStateManager.getState().then((state) => {
const contactsList = state.contactsList;
if(contactsList && Array.isArray(contactsList) && contactsList.length) {
contactsList.forEach(userID => {
this.pushContact(userID);
});
this.contactsFillPromise = Promise.resolve(this.contactsList);
}
});
}
public fillContacts() {
@ -320,7 +328,7 @@ export class AppUsersManager { @@ -320,7 +328,7 @@ export class AppUsersManager {
}
public getSelf() {
return this.getUser(this.myID);
return this.getUser($rootScope.myID);
}
public getUserStatusString(userID: number) {
@ -565,13 +573,9 @@ export class AppUsersManager { @@ -565,13 +573,9 @@ export class AppUsersManager {
this.saveApiUsers(result.users);
appChatsManager.saveApiChats(result.chats);
peerIDs = result.categories[0].peers.map((topPeer: {
_: 'topPeer',
peer: any,
rating: number
}) => {
peerIDs = result.categories[0].peers.map((topPeer) => {
const peerID = appPeersManager.getPeerID(topPeer.peer);
appStateManager.pushPeer(peerID);
appStateManager.setPeer(peerID, this.getUser(peerID));
return peerID;
});
}

3
src/lib/appManagers/appWebPagesManager.ts

@ -1,8 +1,9 @@ @@ -1,8 +1,9 @@
import { $rootScope, safeReplaceObject } from "../utils";
import { safeReplaceObject } from "../utils";
import appPhotosManager from "./appPhotosManager";
import appDocsManager from "./appDocsManager";
import { RichTextProcessor } from "../richtextprocessor";
import { ReferenceContext } from "../mtproto/referenceDatabase";
import $rootScope from "../rootScope";
class AppWebPagesManager {
webpages: any = {};

9
src/lib/bin_utils.ts

@ -1,11 +1,4 @@ @@ -1,11 +1,4 @@
/*!
* Webogram v0.7.0 - messaging web application for MTProto
* https://github.com/zhukov/webogram
* Copyright (C) 2014 Igor Zhukov <igor.beatle@gmail.com>
* https://github.com/zhukov/webogram/blob/master/LICENSE
*/
import {str2bigInt, divInt_, int2bigInt, bigInt2str, bigInt2bytes} from '../vendor/leemon';
//import {str2bigInt, divInt_, int2bigInt, bigInt2str, bigInt2bytes} from '../vendor/leemon';
// @ts-ignore
import {BigInteger, SecureRandom} from 'jsbn';

8
src/lib/cacheStorage.ts

@ -47,6 +47,8 @@ class CacheStorageController { @@ -47,6 +47,8 @@ class CacheStorageController {
public getFile(fileName: string) {
//return Promise.reject();
// const str = `get fileName: ${fileName}`;
// console.time(str);
return this.timeoutOperation(async(cache) => {
const response = await cache.match('/' + fileName);
@ -55,7 +57,11 @@ class CacheStorageController { @@ -55,7 +57,11 @@ class CacheStorageController {
throw 'No response???';
}
return response.blob();
const promise = response.blob();
// promise.then(() => {
// console.timeEnd(str);
// });
return promise;
});
}

26
src/lib/config.ts

File diff suppressed because one or more lines are too long

12
src/lib/mediaPlayer.ts

@ -1,7 +1,7 @@ @@ -1,7 +1,7 @@
import { cancelEvent } from "./utils";
import { touchSupport } from "./config";
import appMediaPlaybackController from "../components/appMediaPlaybackController";
import { isAppleMobile } from "../helpers/userAgent";
import { isTouchSupported } from "../helpers/touchSupport";
type SUPEREVENT = MouseEvent | TouchEvent;
@ -69,7 +69,7 @@ export class ProgressLine { @@ -69,7 +69,7 @@ export class ProgressLine {
this.container.addEventListener('mousedown', this.onMouseDown);
this.container.addEventListener('mouseup', this.onMouseUp);
if(touchSupport) {
if(isTouchSupported) {
this.container.addEventListener('touchmove', this.onMouseMove);
this.container.addEventListener('touchstart', this.onMouseDown);
this.container.addEventListener('touchend', this.onMouseUp);
@ -109,7 +109,7 @@ export class ProgressLine { @@ -109,7 +109,7 @@ export class ProgressLine {
this.container.removeEventListener('mousedown', this.onMouseDown);
this.container.removeEventListener('mouseup', this.onMouseUp);
if(touchSupport) {
if(isTouchSupported) {
this.container.removeEventListener('touchmove', this.onMouseMove);
this.container.removeEventListener('touchstart', this.onMouseDown);
this.container.removeEventListener('touchend', this.onMouseUp);
@ -402,13 +402,13 @@ export default class VideoPlayer { @@ -402,13 +402,13 @@ export default class VideoPlayer {
});
video.addEventListener('click', () => {
if(!touchSupport) {
if(!isTouchSupported) {
this.togglePlay();
return;
}
});
if(touchSupport) {
if(isTouchSupported) {
let showControlsTimeout = 0;
const t = () => {
@ -456,7 +456,7 @@ export default class VideoPlayer { @@ -456,7 +456,7 @@ export default class VideoPlayer {
});
video.addEventListener('dblclick', () => {
if(touchSupport) {
if(isTouchSupported) {
return;
}

30
src/lib/mtproto/apiManager.ts

@ -3,15 +3,18 @@ import AppStorage from '../storage'; @@ -3,15 +3,18 @@ import AppStorage from '../storage';
import { MTPNetworker } from './networker';
import { bytesFromHex, bytesToHex, isObject } from '../bin_utils';
import networkerFactory from './networkerFactory';
import { telegramMeWebService } from './mtproto';
//import { telegramMeWebService } from './mtproto';
import authorizer from './authorizer';
import {App, Modes} from './mtproto_config';
import dcConfigurator from './dcConfigurator';
import HTTP from './transports/http';
import { logger } from '../logger';
/// #if MTPROTO_HTTP
import HTTP from './transports/http';
/// #endif
/// #if !MTPROTO_WORKER
import { $rootScope } from '../utils';
import $rootScope from '../rootScope';
import { InvokeApiOptions } from '../../types';
/// #endif
@ -53,7 +56,7 @@ export class ApiManager { @@ -53,7 +56,7 @@ export class ApiManager {
public telegramMeNotify(newValue: boolean) {
if(this.telegramMeNotified !== newValue) {
this.telegramMeNotified = newValue;
telegramMeWebService.setAuthorized(this.telegramMeNotified);
//telegramMeWebService.setAuthorized(this.telegramMeNotified);
}
}
@ -111,8 +114,17 @@ export class ApiManager { @@ -111,8 +114,17 @@ export class ApiManager {
// mtpGetNetworker
public async getNetworker(dcID: number, options: InvokeApiOptions): Promise<MTPNetworker> {
const transport = dcConfigurator.chooseServer(dcID, true);
/// #if MTPROTO_HTTP
// @ts-ignore
const upload = (options.fileUpload || options.fileDownload)
&& (dcConfigurator.chooseServer(dcID, true) instanceof HTTP || Modes.multipleConnections);
&& (transport instanceof HTTP || Modes.multipleConnections);
/// #else
// @ts-ignore
const upload = (options.fileUpload || options.fileDownload) && Modes.multipleConnections;
/// #endif
const cache = upload ? this.cachedUploadNetworkers : this.cachedNetworkers;
if(!dcID) {
@ -305,14 +317,6 @@ export class ApiManager { @@ -305,14 +317,6 @@ export class ApiManager {
}
});
}
// mtpGetUserID
public getUserID(): Promise<number> {
return AppStorage.get<any>('user_auth').then((auth) => {
this.telegramMeNotify(auth && auth.id > 0 || false);
return auth.id || 0;
});
}
}
export default new ApiManager();

38
src/lib/mtproto/dcConfigurator.ts

@ -1,9 +1,15 @@ @@ -1,9 +1,15 @@
import Socket from './transports/websocket';
import MTTransport from './transports/transport';
import HTTP from './transports/http';
import { Modes } from './mtproto_config';
type TransportTypes = 'websocket' | 'https' | 'http';
/// #if !MTPROTO_HTTP
import Socket from './transports/websocket';
// @ts-ignore
type TransportTypes = 'websocket';
/// #else
import HTTP from './transports/http';
// @ts-ignore
type TransportTypes = 'https' | 'http';
/// #endif
type Servers = {
[transportType in TransportTypes]: {
[dcID: number]: MTTransport[]
@ -27,17 +33,30 @@ export class DcConfigurator { @@ -27,17 +33,30 @@ export class DcConfigurator {
{id: 5, host: '149.154.171.5', port: 80}
];
/// #if !MTPROTO_HTTP
private chosenServers: Servers = {
websocket: {}
};
private chosenUploadServers: Servers = {
websocket: {}
};
/// #else
// @ts-ignore
private chosenServers: Servers = {
websocket: {},
// @ts-ignore
https: {},
http: {}
};
// @ts-ignore
private chosenUploadServers: Servers = {
websocket: {},
// @ts-ignore
https: {},
http: {}
};
/// #endif
public chooseServer(dcID: number, upload?: boolean, transportType: TransportTypes = 'websocket') {
const servers = upload && (transportType != 'websocket' || Modes.multipleConnections)
@ -53,12 +72,16 @@ export class DcConfigurator { @@ -53,12 +72,16 @@ export class DcConfigurator {
if(!transports.length || (upload && transports.length < 1)) {
let transport: MTTransport;
if(transportType == 'websocket') {
/// #if !MTPROTO_HTTP
//if(transportType == 'websocket') {
const subdomain = this.sslSubdomains[dcID - 1];
const path = Modes.test ? 'apiws_test' : 'apiws';
const chosenServer = 'wss://' + subdomain + '.web.telegram.org/' + path;
transport = new Socket(dcID, chosenServer);
} else if(Modes.ssl || !Modes.http || transportType == 'https') {
//} else
/// #else
// @ts-ignore
if(Modes.ssl || !Modes.http || transportType == 'https') {
const subdomain = this.sslSubdomains[dcID - 1] + (upload ? '-1' : '');
const path = Modes.test ? 'apiw_test1' : 'apiw1';
const chosenServer = 'https://' + subdomain + '.web.telegram.org/' + path;
@ -72,6 +95,7 @@ export class DcConfigurator { @@ -72,6 +95,7 @@ export class DcConfigurator {
}
}
}
/// #endif
if(!transport) {
console.error('No chosenServer!', dcID);

6
src/lib/mtproto/mtproto.worker.ts

@ -7,10 +7,10 @@ import AppStorage from '../storage'; @@ -7,10 +7,10 @@ import AppStorage from '../storage';
import cryptoWorker from "../crypto/cryptoworker";
import networkerFactory from "./networkerFactory";
import apiFileManager from './apiFileManager';
import { logger, LogLevels } from '../logger';
//import { logger, LogLevels } from '../logger';
import type { ServiceWorkerTask, ServiceWorkerTaskResponse } from './mtproto.service';
const log = logger('DW', LogLevels.error);
//const log = logger('DW', LogLevels.error);
const ctx = self as any as DedicatedWorkerGlobalScope;
@ -62,7 +62,7 @@ ctx.addEventListener('message', async(e) => { @@ -62,7 +62,7 @@ ctx.addEventListener('message', async(e) => {
const task = e.data;
const taskID = task.taskID;
log.debug('got message:', taskID, task);
//log.debug('got message:', taskID, task);
//debugger;

15
src/lib/mtproto/mtproto_config.ts

@ -1,3 +1,18 @@ @@ -1,3 +1,18 @@
export type UserAuth = {
dcID: number,
id: number
};
/*
IMPORTANT NOTICE
================
Do not publish your Webogram fork with my app credentials (below), or your application may be blocked.
You can get your own api_id, api_hash at https://my.telegram.org, see manual at https://core.telegram.org/api/obtaining_api_id.
*/
export const App = {
id: 1025907,
hash: '452b0359b988148995f22ff0f4229750',

10
src/lib/mtproto/mtprotoworker.ts

@ -1,4 +1,4 @@ @@ -1,4 +1,4 @@
import {isObject, $rootScope} from '../utils';
import {isObject} from '../utils';
import AppStorage from '../storage';
import CryptoWorkerMethods from '../crypto/crypto_methods';
import { logger } from '../logger';
@ -6,9 +6,9 @@ import webpWorkerController from '../webp/webpWorkerController'; @@ -6,9 +6,9 @@ import webpWorkerController from '../webp/webpWorkerController';
import MTProtoWorker from 'worker-loader!./mtproto.worker';
import type { DownloadOptions } from './apiFileManager';
import type { ServiceWorkerTask, ServiceWorkerTaskResponse } from './mtproto.service';
import { isServiceWorkerSupported } from '../config';
import { MethodDeclMap } from '../../layer';
import { MOUNT_CLASS_TO } from './mtproto_config';
import $rootScope from '../rootScope';
type Task = {
taskID: number,
@ -45,7 +45,7 @@ class ApiManagerProxy extends CryptoWorkerMethods { @@ -45,7 +45,7 @@ class ApiManagerProxy extends CryptoWorkerMethods {
}
private registerServiceWorker() {
if(!isServiceWorkerSupported) return;
if(!('serviceWorker' in navigator)) return;
navigator.serviceWorker.register('./sw.js', {scope: './'}).then(registration => {
@ -209,10 +209,6 @@ class ApiManagerProxy extends CryptoWorkerMethods { @@ -209,10 +209,6 @@ class ApiManagerProxy extends CryptoWorkerMethods {
return this.performTaskWorker('getNetworker', dc_id);
}
public getUserID(): Promise<number> {
return this.performTaskWorker('getUserID');
}
public logOut(): Promise<void> {
return this.performTaskWorker('logOut');
}

152
src/lib/mtproto/networker.ts

@ -10,12 +10,17 @@ import Schema from './schema'; @@ -10,12 +10,17 @@ import Schema from './schema';
import timeManager from './timeManager';
import NetworkerFactory from './networkerFactory';
import dcConfigurator from './dcConfigurator';
import Socket from './transports/websocket';
import HTTP from './transports/http';
import { logger, LogLevels } from '../logger';
import { Modes, App } from './mtproto_config';
import { InvokeApiOptions } from '../../types';
import { longToBytes } from '../crypto/crypto_utils';
import MTTransport from './transports/transport';
/// #if MTPROTO_HTTP
import type HTTP from './transports/http';
/// #else
import type Socket from './transports/websocket';
/// #endif
//console.error('networker included!', new Error().stack);
@ -61,31 +66,29 @@ class MTPNetworker { @@ -61,31 +66,29 @@ class MTPNetworker {
private pendingResends: Array<string> = [];
private connectionInited = false;
/// #if MTPROTO_HTTP
//private longPollInt: number;
private longPollPending = 0;
private nextReqTimeout: number;
private nextReq: number = 0;
private checkConnectionTimeout: number;
private checkConnectionPeriod = 0;
private onOnlineCb = this.checkConnection.bind(this);
private sleepAfter = 0;
/// #endif
private seqNo: number = 0;
private prevSessionID: Array<number> = [];
private sessionID: Array<number> = [];
private sleepAfter = 0;
private offline = false;
private checkConnectionTimeout: number;
private checkConnectionPeriod = 0;
private nextReqTimeout: number;
private nextReq: number = 0;
private onOnlineCb = this.checkConnection.bind(this);
private lastResendReq: {
req_msg_id: string,
resend_msg_ids: Array<string>
} | null = null;
private transport: Socket | HTTP;
private transport: MTTransport;
private log: ReturnType<typeof logger>;
@ -113,12 +116,15 @@ class MTPNetworker { @@ -113,12 +116,15 @@ class MTPNetworker {
this.transport = dcConfigurator.chooseServer(this.dcID, this.upload);
if(this.transport instanceof HTTP) {
/// #if MTPROTO_HTTP
//if(this.transport instanceof HTTP) {
/* this.longPollInt = */setInterval(this.checkLongPoll.bind(this), 10000);
this.checkLongPoll();
} else {
/// #else
//} else {
(this.transport as Socket).networker = this;
}
//}
/// #endif
}
public updateSession() {
@ -126,7 +132,6 @@ class MTPNetworker { @@ -126,7 +132,6 @@ class MTPNetworker {
this.prevSessionID = this.sessionID;
this.sessionID = new Array(8);
this.sessionID = [...new Uint8Array(this.sessionID.length).randomize()];
//MTProto.secureRandom.nextBytes(this.sessionID);
}
public updateSentMessage(sentMessageID: any) {
@ -278,6 +283,7 @@ class MTPNetworker { @@ -278,6 +283,7 @@ class MTPNetworker {
return this.pushMessage(message, options);
}
/// #if MTPROTO_HTTP
public checkLongPoll() {
const isClean = this.cleanupSent();
//this.log('Check lp', this.longPollPending, tsNow(), this.dcID, isClean, this);
@ -321,6 +327,7 @@ class MTPNetworker { @@ -321,6 +327,7 @@ class MTPNetworker {
this.log('Long-poll failed', error);
});
}
/// #endif
// тут можно сделать таймаут и выводить дисконнект
public pushMessage(message: {
@ -407,6 +414,7 @@ class MTPNetworker { @@ -407,6 +414,7 @@ class MTPNetworker {
});
}
/// #if MTPROTO_HTTP
public checkConnection(event: Event | string) {
/* $rootScope.offlineConnecting = true */
@ -442,6 +450,7 @@ class MTPNetworker { @@ -442,6 +450,7 @@ class MTPNetworker {
}, 1000); */
});
}
/// #endif
public toggleOffline(enabled: boolean) {
// this.log('toggle ', enabled, this.dcID, this.iii)
@ -453,11 +462,13 @@ class MTPNetworker { @@ -453,11 +462,13 @@ class MTPNetworker {
/* $rootScope.offline = enabled;
$rootScope.offlineConnecting = false; */
if(!(this.transport instanceof HTTP)) {
/// #if !MTPROTO_HTTP
//if(!(this.transport instanceof HTTP)) {
this.log('toggle ', enabled, this.dcID);
return;
}
//}
/// #else
if(this.offline) {
clearTimeout(this.nextReqTimeout);
this.nextReqTimeout = 0;
@ -483,6 +494,7 @@ class MTPNetworker { @@ -483,6 +494,7 @@ class MTPNetworker {
clearTimeout(this.checkConnectionTimeout);
this.checkConnectionTimeout = 0;
}
/// #endif
}
public performScheduledRequest() {
@ -582,7 +594,8 @@ class MTPNetworker { @@ -582,7 +594,8 @@ class MTPNetworker {
}
}
if(hasApiCall && !hasHttpWait && this.transport instanceof HTTP) {
/// #if MTPROTO_HTTP
if(hasApiCall && !hasHttpWait/* && this.transport instanceof HTTP */) {
var serializer = new TLSerialization({mtproto: true});
serializer.storeMethod('http_wait', {
max_delay: 500,
@ -596,6 +609,7 @@ class MTPNetworker { @@ -596,6 +609,7 @@ class MTPNetworker {
body: serializer.getBytes()
});
}
/// #endif
if(!messages.length) {
// this.log('no scheduled messages')
@ -653,56 +667,59 @@ class MTPNetworker { @@ -653,56 +667,59 @@ class MTPNetworker {
let promise = this.sendEncryptedRequest(message);
if(!(this.transport instanceof HTTP)) {
/// #if !MTPROTO_HTTP
//if(!(this.transport instanceof HTTP)) {
if(noResponseMsgs.length) this.log.error('noResponseMsgs length!', noResponseMsgs);
} else promise.then((result) => {
self.toggleOffline(false);
// this.log('parse for', message)
self.parseResponse(result).then((response) => {
if(Modes.debug) {
this.log('Server response', self.dcID, response);
}
//} else {
/// #else
promise.then((result) => {
self.toggleOffline(false);
// this.log('parse for', message)
self.parseResponse(result).then((response) => {
if(Modes.debug) {
this.log('Server response', self.dcID, response);
}
self.processMessage(response.response, response.messageID, response.sessionID);
noResponseMsgs.forEach((msgID) => {
if(self.sentMessages[msgID]) {
var deferred = self.sentMessages[msgID].deferred;
delete self.sentMessages[msgID];
deferred.resolve();
}
});
self.processMessage(response.response, response.messageID, response.sessionID);
self.checkLongPoll();
this.checkConnectionPeriod = Math.max(1.1, Math.sqrt(this.checkConnectionPeriod));
});
}, (error) => {
this.log.error('Encrypted request failed', error, message);
if(message.container) {
message.inner.forEach((msgID: string) => {
self.pendingMessages[msgID] = 0;
});
delete self.sentMessages[message.msg_id];
} else {
self.pendingMessages[message.msg_id] = 0;
}
noResponseMsgs.forEach((msgID) => {
if(self.sentMessages[msgID]) {
var deferred = self.sentMessages[msgID].deferred;
delete self.sentMessages[msgID];
deferred.resolve();
delete self.pendingMessages[msgID];
deferred.reject();
}
});
if(self.transport instanceof HTTP) {
self.checkLongPoll();
this.checkConnectionPeriod = Math.max(1.1, Math.sqrt(this.checkConnectionPeriod));
}
})
self.toggleOffline(true);
});
}, (error) => {
this.log.error('Encrypted request failed', error, message);
if(message.container) {
message.inner.forEach((msgID: string) => {
self.pendingMessages[msgID] = 0;
});
delete self.sentMessages[message.msg_id];
} else {
self.pendingMessages[message.msg_id] = 0;
}
noResponseMsgs.forEach((msgID) => {
if(self.sentMessages[msgID]) {
var deferred = self.sentMessages[msgID].deferred;
delete self.sentMessages[msgID];
delete self.pendingMessages[msgID];
deferred.reject();
}
})
self.toggleOffline(true);
});
//}
/// #endif
if(lengthOverflow || singlesCount > 1) {
this.scheduleRequest();
@ -780,7 +797,9 @@ class MTPNetworker { @@ -780,7 +797,9 @@ class MTPNetworker {
};
let promise = this.transport.send(requestData);
if(!(this.transport instanceof HTTP)) return promise;
/// #if !MTPROTO_HTTP
/* if(!(this.transport instanceof HTTP)) */ return promise;
/// #else
return promise.then((result) => {
if(!result || !result.byteLength) {
@ -797,6 +816,7 @@ class MTPNetworker { @@ -797,6 +816,7 @@ class MTPNetworker {
}
return Promise.reject(error);
});
/// #endif
});
}
@ -925,10 +945,9 @@ class MTPNetworker { @@ -925,10 +945,9 @@ class MTPNetworker {
}
public scheduleRequest(delay = 0) {
if(!(this.transport instanceof HTTP)) { // if socket
return this.performScheduledRequest();
}
/// #if !MTPROTO_HTTP
return this.performScheduledRequest();
/// #else
if(this.offline/* && this.transport instanceof HTTP */) {
this.checkConnection('forced schedule');
}
@ -955,6 +974,7 @@ class MTPNetworker { @@ -955,6 +974,7 @@ class MTPNetworker {
}
this.nextReq = nextReq;
/// #endif
}
public ackMessage(msgID: string) {

2
src/lib/mtproto/schema.ts

File diff suppressed because one or more lines are too long

7
src/lib/mtproto/tl_utils.ts

@ -1,10 +1,3 @@ @@ -1,10 +1,3 @@
/*!
* Webogram v0.7.0 - messaging web application for MTProto
* https://github.com/zhukov/webogram
* Copyright (C) 2014 Igor Zhukov <igor.beatle@gmail.com>
* https://github.com/zhukov/webogram/blob/master/LICENSE
*/
import {bigint, bigStringInt, bytesToHex, isObject} from '../bin_utils';
import Schema from './schema';

8
src/lib/polyfill.ts

@ -30,8 +30,8 @@ Uint8Array.prototype.concat = function(...args: Array<Uint8Array | ArrayBuffer | @@ -30,8 +30,8 @@ Uint8Array.prototype.concat = function(...args: Array<Uint8Array | ArrayBuffer |
}; */
Uint8Array.prototype.toJSON = function() {
//return [...this];
return {type: 'bytes', value: [...this]};
return [...this];
//return {type: 'bytes', value: [...this]};
};
Array.prototype.forEachReverse = function<T>(callback: (value: T, index?: number, array?: Array<T>) => void) {
@ -64,8 +64,8 @@ declare global { @@ -64,8 +64,8 @@ declare global {
randomize: () => Uint8Array,
concat: (...args: Array<Uint8Array | ArrayBuffer | number[]>) => Uint8Array,
//toString: () => string,
//toJSON: () => number[],
toJSON: () => {type: 'bytes', value: number[]},
toJSON: () => number[],
//toJSON: () => {type: 'bytes', value: number[]},
}
interface Array<T> {

92
src/lib/rootScope.ts

@ -0,0 +1,92 @@ @@ -0,0 +1,92 @@
import type { StickerSet } from "../layer";
import type { MyDocument } from "./appManagers/appDocsManager";
import type { Poll, PollResults } from "./appManagers/appPollsManager";
import type { AppMessagesManager, Dialog, MyDialogFilter } from "./appManagers/appMessagesManager";
import { MOUNT_CLASS_TO } from "./mtproto/mtproto_config";
type BroadcastEvents = {
'user_update': number,
'user_auth': {dcID?: number, id: number},
'peer_changed': number,
'filter_delete': MyDialogFilter,
'filter_update': MyDialogFilter,
'dialog_draft': {peerID: number, draft: any, index: number},
'dialog_unread': {peerID: number, count?: number},
'dialog_flush': {peerID: number},
'dialog_drop': {peerID: number, dialog?: Dialog},
'dialog_migrate': {migrateFrom: number, migrateTo: number},
'dialog_top': Dialog,
'dialog_notify_settings': number,
'dialogs_multiupdate': {[peerID: string]: Dialog},
'dialogs_archived_unread': {count: number},
'history_append': {peerID: number, messageID: number, my?: boolean},
'history_update': {peerID: number, mid: number},
'history_reply_markup': {peerID: number},
'history_multiappend': AppMessagesManager['newMessagesToHandle'],
'history_delete': {peerID: number, msgs: {[mid: number]: true}},
'history_forbidden': number,
'history_reload': number,
'history_request': void,
'message_edit': {peerID: number, id: number, mid: number, justMedia: boolean},
'message_views': {mid: number, views: number},
'message_sent': {tempID: number, mid: number},
'messages_pending': void,
'messages_read': void,
'messages_downloaded': number[],
'stickers_installed': StickerSet.stickerSet,
'stickers_deleted': StickerSet.stickerSet,
'audio_play': {doc: MyDocument, mid: number},
'audio_pause': void,
//'contacts_update': any,
'avatar_update': number,
'chat_full_update': number,
'peer_pinned_message': number,
'poll_update': {poll: Poll, results: PollResults},
'chat_update': number,
'stateSynchronized': void,
'channel_settings': {channelID: number},
'webpage_updated': {id: string, msgs: number[]},
'apiUpdate': any,
'download_progress': any,
//'draft_updated': any,
};
const $rootScope = {
$broadcast: <T extends keyof BroadcastEvents>(name: T, detail?: BroadcastEvents[T]) => {
/* if(name != 'user_update') {
console.debug(dT(), 'Broadcasting ' + name + ' event, with args:', detail);
} */
let myCustomEvent = new CustomEvent(name, {detail});
document.dispatchEvent(myCustomEvent);
},
$on: <T extends keyof BroadcastEvents>(name: T, callback: (e: Omit<CustomEvent, 'detail'> & {detail: BroadcastEvents[T]}) => any) => {
// @ts-ignore
document.addEventListener(name, callback);
},
$off: <T extends keyof BroadcastEvents>(name: T, callback: (e: Omit<CustomEvent, 'detail'> & {detail: BroadcastEvents[T]}) => any) => {
// @ts-ignore
document.removeEventListener(name, callback);
},
selectedPeerID: 0,
myID: 0,
idle: {
isIDLE: false
}
};
$rootScope.$on('user_auth', (e) => {
$rootScope.myID = e.detail.id;
});
MOUNT_CLASS_TO && (MOUNT_CLASS_TO.$rootScope = $rootScope);
export default $rootScope;

7
src/lib/storage.ts

@ -1,6 +1,6 @@ @@ -1,6 +1,6 @@
import { Modes } from './mtproto/mtproto_config';
import { notifySomeone, isWorker } from '../helpers/context';
import { parse, stringify } from '../helpers/json';
import { stringify } from '../helpers/json';
class ConfigStorage {
public keyPrefix = '';
@ -41,11 +41,14 @@ class ConfigStorage { @@ -41,11 +41,14 @@ class ConfigStorage {
this.useLs = false;
}
// const str = `[get] ${keys.join(', ')}`;
// console.time(str);
try {
value = (value === undefined || value === null) ? false : parse(value);
value = (value === undefined || value === null) ? false : JSON.parse(value);
} catch(e) {
value = false;
}
//console.timeEnd(str);
result.push(this.cache[key] = value);
} else {
allFound = false;

100
src/lib/utils.ts

@ -1,22 +1,6 @@ @@ -1,22 +1,6 @@
import type { StickerSet } from "../layer";
import type { MyDocument } from "./appManagers/appDocsManager";
import type { Poll, PollResults } from "./appManagers/appPollsManager";
import type { AppMessagesManager, Dialog, MyDialogFilter } from "./appManagers/appMessagesManager";
/*!
* Webogram v0.7.0 - messaging web application for MTProto
* https://github.com/zhukov/webogram
* Copyright (C) 2014 Igor Zhukov <igor.beatle@gmail.com>
* https://github.com/zhukov/webogram/blob/master/LICENSE
*/
import type { DownloadOptions } from "./mtproto/apiFileManager";
import { RichTextProcessor } from "./richtextprocessor";
var _logTimer = Date.now();
export function dT () {
return '[' + ((Date.now() - _logTimer) / 1000).toFixed(3) + ']';
}
/* export function isInDOM(element: Element, parentNode?: HTMLElement): boolean {
if(!element) {
return false;
@ -32,7 +16,7 @@ export function isInDOM(element: Element): boolean { @@ -32,7 +16,7 @@ export function isInDOM(element: Element): boolean {
return element?.isConnected;
}
export function checkDragEvent(e: any) {
/* export function checkDragEvent(e: any) {
if(!e || e.target && (e.target.tagName == 'IMG' || e.target.tagName == 'A')) return false
if(e.dataTransfer && e.dataTransfer.types) {
for(var i = 0; i < e.dataTransfer.types.length; i++) {
@ -45,7 +29,7 @@ export function checkDragEvent(e: any) { @@ -45,7 +29,7 @@ export function checkDragEvent(e: any) {
}
return false;
}
} */
export function cancelEvent (event: Event) {
event = event || window.event;
@ -159,86 +143,6 @@ export function getRichElementValue(node: any, lines: string[], line: string[], @@ -159,86 +143,6 @@ export function getRichElementValue(node: any, lines: string[], line: string[],
}
} */
type BroadcastEvents = {
'user_update': number,
'user_auth': {dcID?: number, id: number},
'peer_changed': number,
'filter_delete': MyDialogFilter,
'filter_update': MyDialogFilter,
'dialog_draft': {peerID: number, draft: any, index: number},
'dialog_unread': {peerID: number, count?: number},
'dialog_flush': {peerID: number},
'dialog_drop': {peerID: number, dialog?: Dialog},
'dialog_migrate': {migrateFrom: number, migrateTo: number},
'dialog_top': Dialog,
'dialog_notify_settings': number,
'dialogs_multiupdate': {[peerID: string]: Dialog},
'dialogs_archived_unread': {count: number},
'history_append': {peerID: number, messageID: number, my?: boolean},
'history_update': {peerID: number, mid: number},
'history_reply_markup': {peerID: number},
'history_multiappend': AppMessagesManager['newMessagesToHandle'],
'history_delete': {peerID: number, msgs: {[mid: number]: true}},
'history_forbidden': number,
'history_reload': number,
'history_request': void,
'message_edit': {peerID: number, id: number, mid: number, justMedia: boolean},
'message_views': {mid: number, views: number},
'message_sent': {tempID: number, mid: number},
'messages_pending': void,
'messages_read': void,
'messages_downloaded': number[],
'stickers_installed': StickerSet.stickerSet,
'stickers_deleted': StickerSet.stickerSet,
'audio_play': {doc: MyDocument, mid: number},
'audio_pause': void,
//'contacts_update': any,
'avatar_update': number,
'chat_full_update': number,
'peer_pinned_message': number,
'poll_update': {poll: Poll, results: PollResults},
'chat_update': number,
'stateSynchronized': void,
'channel_settings': {channelID: number},
'webpage_updated': {id: string, msgs: number[]},
'apiUpdate': any,
'download_progress': any,
//'draft_updated': any,
};
export const $rootScope = {
$broadcast: <T extends keyof BroadcastEvents>(name: T, detail?: BroadcastEvents[T]) => {
/* if(name != 'user_update') {
console.debug(dT(), 'Broadcasting ' + name + ' event, with args:', detail);
} */
let myCustomEvent = new CustomEvent(name, {detail});
document.dispatchEvent(myCustomEvent);
},
$on: <T extends keyof BroadcastEvents>(name: T, callback: (e: Omit<CustomEvent, 'detail'> & {detail: BroadcastEvents[T]}) => any) => {
// @ts-ignore
document.addEventListener(name, callback);
},
$off: <T extends keyof BroadcastEvents>(name: T, callback: (e: Omit<CustomEvent, 'detail'> & {detail: BroadcastEvents[T]}) => any) => {
// @ts-ignore
document.removeEventListener(name, callback);
},
selectedPeerID: 0,
myID: 0,
idle: {
isIDLE: false
}
};
// generate a path's arc data parameter
// http://www.w3.org/TR/SVG/paths.html#PathDataEllipticalArcCommands
var arcParameter = function(rx: number, ry: number, xAxisRotation: number, largeArcFlag: number, sweepFlag: number, x: number, y: number) {

2
src/pages/pageSignIn.ts

@ -138,7 +138,7 @@ let onFirstMount = () => { @@ -138,7 +138,7 @@ let onFirstMount = () => {
});
selectCountryCode.addEventListener('blur', function(this: typeof selectCountryCode, e) {
wrapper.classList.remove('active');
hideTimeout = setTimeout(() => {
hideTimeout = window.setTimeout(() => {
wrapper.classList.add('hide');
}, 200);

2
src/scripts/in/schema.json

File diff suppressed because one or more lines are too long

18
src/test_cache_and_local_storage_speed.js

@ -0,0 +1,18 @@ @@ -0,0 +1,18 @@
console.time('open');
caches.open('sessions').then(cache => {
console.timeEnd('open');
cache.put('/state', new Response(JSON.stringify(appStateManager.state), {headers: {'Content-Type': 'application/json'}}));
});
console.time('match');
caches.open('sessions').then(async(cache) => {
const response = await cache.match('/state');
const promise = response.json();
promise.then((json) => {
console.timeEnd('match');
});
});
console.time('getItem');
var value = JSON.parse(localStorage.getItem('state'));
console.timeEnd('getItem');

1
webpack.common.js

@ -14,6 +14,7 @@ console.log('DEVMODE:', devMode); @@ -14,6 +14,7 @@ console.log('DEVMODE:', devMode);
const opts = {
MTPROTO_WORKER: true,
MTPROTO_HTTP: false,
version: 3,
"ifdef-verbose": true, // add this for verbose output
"ifdef-triple-slash": true // add this to use double slash comment instead of default triple slash

Loading…
Cancel
Save