Browse Source

Reconnect button

master
Eduard Kuzmenko 4 years ago
parent
commit
07dff5479c
  1. 55
      src/components/connectionStatus.ts
  2. 2
      src/config/app.ts
  3. 1
      src/lang.ts
  4. 22
      src/lib/mtproto/connectionStatus.ts
  5. 6
      src/lib/mtproto/mtprotoworker.ts
  6. 20
      src/lib/mtproto/networker.ts
  7. 3
      src/lib/mtproto/networkerFactory.ts
  8. 9
      src/lib/mtproto/transports/tcpObfuscated.ts
  9. 2
      src/lib/rootScope.ts
  10. 9
      src/scss/partials/_leftSidebar.scss
  11. 2
      src/scss/style.scss
  12. 11
      src/types.d.ts

55
src/components/connectionStatus.ts

@ -15,6 +15,9 @@ import Button from "./button";
import ProgressivePreloader from "./preloader"; import ProgressivePreloader from "./preloader";
import SetTransition from "./singleTransition"; import SetTransition from "./singleTransition";
import sessionStorage from '../lib/sessionStorage'; import sessionStorage from '../lib/sessionStorage';
import { ConnectionStatus } from "../lib/mtproto/connectionStatus";
import { cancelEvent } from "../helpers/dom/cancelEvent";
import apiManager from "../lib/mtproto/mtprotoworker";
export default class ConnectionStatusComponent { export default class ConnectionStatusComponent {
public static CHANGE_STATE_DELAY = 1000; public static CHANGE_STATE_DELAY = 1000;
@ -23,9 +26,10 @@ export default class ConnectionStatusComponent {
private statusEl: HTMLElement; private statusEl: HTMLElement;
private statusPreloader: ProgressivePreloader; private statusPreloader: ProgressivePreloader;
private currentLangPackKey = ''; private currentLangPackKey: LangPackKey;
private connectingTimeout: number; private hadConnect = false;
private retryAt: number;
private connecting = false; private connecting = false;
private updating = false; private updating = false;
@ -77,13 +81,13 @@ export default class ConnectionStatusComponent {
/* let bool = true; /* let bool = true;
document.addEventListener('dblclick', () => { document.addEventListener('dblclick', () => {
rootScope.broadcast('connection_status_change', { rootScope.dispatchEvent('connection_status_change', {
dcId: 2, dcId: 2,
isFileDownload: false, isFileDownload: false,
isFileNetworker: false, isFileNetworker: false,
isFileUpload: false, isFileUpload: false,
name: "NET-2", name: "NET-2",
online: bool = !bool, status: bool ? (bool = false, ConnectionStatus.Closed) : (bool = true, ConnectionStatus.Connected),
_: "networkerStatus" _: "networkerStatus"
}); });
}); */ }); */
@ -101,34 +105,61 @@ export default class ConnectionStatusComponent {
} }
const status = rootScope.connectionStatus['NET-' + baseDcId]; const status = rootScope.connectionStatus['NET-' + baseDcId];
const online = status && status.online; const online = status && status.status === ConnectionStatus.Connected;
if(this.connecting && online) { if(this.connecting && online) {
apiUpdatesManager.forceGetDifference(); apiUpdatesManager.forceGetDifference();
} }
if(online && !this.hadConnect) {
this.hadConnect = true;
}
this.connecting = !online; this.connecting = !online;
this.connectingTimeout = status && status.timeout; this.retryAt = status && status.retryAt;
DEBUG && this.log('connecting', this.connecting); DEBUG && this.log('connecting', this.connecting);
this.setState(); this.setState();
}); });
}; };
private setStatusText = (langPackKey: LangPackKey) => { private setStatusText = (langPackKey: LangPackKey, args?: any[]) => {
if(this.currentLangPackKey === langPackKey) return; if(this.currentLangPackKey === langPackKey) return;
this.currentLangPackKey = langPackKey; this.currentLangPackKey = langPackKey;
replaceContent(this.statusEl, i18n(langPackKey)); replaceContent(this.statusEl, i18n(langPackKey, args));
this.statusPreloader.attach(this.statusEl); this.statusPreloader.attach(this.statusEl);
}; };
private setState = () => { private setState = () => {
const timeout = ConnectionStatusComponent.CHANGE_STATE_DELAY; const timeout = ConnectionStatusComponent.CHANGE_STATE_DELAY;
if(this.connecting) { if(this.connecting) {
// if(this.connectingTimeout) { if(this.hadConnect) {
// this.setStatusText('ConnectionStatus.Reconnect'); if(this.retryAt !== undefined) {
// } else { const timerSpan = document.createElement('span');
const retryAt = this.retryAt;
const setTime = () => {
const now = Date.now();
timerSpan.innerText = '' + Math.round((retryAt - now) / 1000);
if(now > retryAt) {
clearInterval(interval);
}
};
setTime();
const interval = setInterval(setTime, 1e3);
const a = document.createElement('a');
a.classList.add('force-reconnect');
a.append(i18n('ConnectionStatus.Reconnect'));
a.addEventListener('click', (e) => {
cancelEvent(e);
apiManager.forceReconnect();
});
this.setStatusText('ConnectionStatus.ReconnectIn', [timerSpan, a]);
} else {
this.setStatusText('ConnectionStatus.Reconnecting');
}
} else {
this.setStatusText('ConnectionStatus.Waiting'); this.setStatusText('ConnectionStatus.Waiting');
// } }
} else if(this.updating) { } else if(this.updating) {
this.setStatusText('Updating'); this.setStatusText('Updating');
} }

2
src/config/app.ts

@ -15,7 +15,7 @@ const App = {
id: 1025907, id: 1025907,
hash: '452b0359b988148995f22ff0f4229750', hash: '452b0359b988148995f22ff0f4229750',
version: '0.5.7', version: '0.5.7',
langPackVersion: '0.2.3', langPackVersion: '0.2.4',
langPack: 'macos', langPack: 'macos',
langPackCode: 'en', langPackCode: 'en',
domains: [] as string[], domains: [] as string[],

1
src/lang.ts

@ -47,6 +47,7 @@ const lang = {
"ChatList.Menu.SwitchTo.Z": "Switch to Z version", "ChatList.Menu.SwitchTo.Z": "Switch to Z version",
"ConnectionStatus.ReconnectIn": "Reconnect in %ds, %s", "ConnectionStatus.ReconnectIn": "Reconnect in %ds, %s",
"ConnectionStatus.Reconnect": "reconnect", "ConnectionStatus.Reconnect": "reconnect",
"ConnectionStatus.Reconnecting": "Reconnecting...",
"ConnectionStatus.Waiting": "Waiting for network...", "ConnectionStatus.Waiting": "Waiting for network...",
"Deactivated.Title": "Too many tabs...", "Deactivated.Title": "Too many tabs...",
"Deactivated.Subtitle": "Telegram supports only one active tab with the app.\nClick anywhere to continue using this tab.", "Deactivated.Subtitle": "Telegram supports only one active tab with the app.\nClick anywhere to continue using this tab.",

22
src/lib/mtproto/connectionStatus.ts

@ -0,0 +1,22 @@
/*
* https://github.com/morethanwords/tweb
* Copyright (C) 2019-2021 Eduard Kuzmenko
* https://github.com/morethanwords/tweb/blob/master/LICENSE
*/
export enum ConnectionStatus {
Connected,
Connecting,
Closed
};
export type ConnectionStatusChange = {
_: 'networkerStatus',
status: ConnectionStatus,
dcId: number,
name: string,
isFileNetworker: boolean,
isFileDownload: boolean,
isFileUpload: boolean,
retryAt?: number
};

6
src/lib/mtproto/mtprotoworker.ts

@ -189,7 +189,7 @@ export class ApiManagerProxy extends CryptoWorkerMethods {
}); });
window.addEventListener('online', (event) => { window.addEventListener('online', (event) => {
this.postMessage({type: 'online'}); this.forceReconnect();
}); });
/// #if !MTPROTO_SW /// #if !MTPROTO_SW
@ -543,6 +543,10 @@ export class ApiManagerProxy extends CryptoWorkerMethods {
public startAll() { public startAll() {
return this.performTaskWorkerVoid('startAll'); return this.performTaskWorkerVoid('startAll');
} }
public forceReconnect() {
this.postMessage({type: 'online'});
}
} }
const apiManagerProxy = new ApiManagerProxy(); const apiManagerProxy = new ApiManagerProxy();

20
src/lib/mtproto/networker.ts

@ -33,6 +33,7 @@ import HTTP from './transports/http';
import type TcpObfuscated from './transports/tcpObfuscated'; import type TcpObfuscated from './transports/tcpObfuscated';
import { bigInt2str, rightShift_, str2bigInt } from '../../vendor/leemon'; import { bigInt2str, rightShift_, str2bigInt } from '../../vendor/leemon';
import { forEachReverse } from '../../helpers/array'; import { forEachReverse } from '../../helpers/array';
import { ConnectionStatus } from './connectionStatus';
//console.error('networker included!', new Error().stack); //console.error('networker included!', new Error().stack);
@ -121,6 +122,7 @@ export default class MTPNetworker {
private log: ReturnType<typeof logger>; private log: ReturnType<typeof logger>;
public isOnline = false; public isOnline = false;
public status: ConnectionStatus = ConnectionStatus.Closed;
private lastResponseTime = 0; private lastResponseTime = 0;
private debug = DEBUG /* && false */ || Modes.debug; private debug = DEBUG /* && false */ || Modes.debug;
@ -190,7 +192,7 @@ export default class MTPNetworker {
// } // }
if((this.transport as TcpObfuscated).connected) { if((this.transport as TcpObfuscated).connected) {
this.setConnectionStatus(true); this.setConnectionStatus(ConnectionStatus.Connected);
} }
} }
@ -694,7 +696,7 @@ export default class MTPNetworker {
} }
this.log.error('timeout', message); this.log.error('timeout', message);
this.setConnectionStatus(false); this.setConnectionStatus(ConnectionStatus.Closed);
/* this.getEncryptedOutput(message).then(bytes => { /* this.getEncryptedOutput(message).then(bytes => {
this.log.error('timeout encrypted', bytes); this.log.error('timeout encrypted', bytes);
@ -703,7 +705,7 @@ export default class MTPNetworker {
promise.finally(() => { promise.finally(() => {
clearTimeout(timeout); clearTimeout(timeout);
this.setConnectionStatus(true); this.setConnectionStatus(ConnectionStatus.Connected);
if(!--this.activeRequests && this.onDrain) { if(!--this.activeRequests && this.onDrain) {
this.onDrainTimeout = self.setTimeout(() => { this.onDrainTimeout = self.setTimeout(() => {
@ -722,21 +724,23 @@ export default class MTPNetworker {
return promise; return promise;
} }
public setConnectionStatus(online: boolean, timeout?: number) { public setConnectionStatus(status: ConnectionStatus, retryAt?: number) {
const willChange = this.isOnline !== online; const isOnline = status === ConnectionStatus.Connected;
this.isOnline = online; const willChange = this.status !== status;
this.isOnline = isOnline;
this.status = status;
if(willChange) { if(willChange) {
if(networkerFactory.onConnectionStatusChange) { if(networkerFactory.onConnectionStatusChange) {
networkerFactory.onConnectionStatusChange({ networkerFactory.onConnectionStatusChange({
_: 'networkerStatus', _: 'networkerStatus',
online: this.isOnline, status,
dcId: this.dcId, dcId: this.dcId,
name: this.name, name: this.name,
isFileNetworker: this.isFileNetworker, isFileNetworker: this.isFileNetworker,
isFileDownload: this.isFileDownload, isFileDownload: this.isFileDownload,
isFileUpload: this.isFileUpload, isFileUpload: this.isFileUpload,
timeout retryAt
}); });
} }

3
src/lib/mtproto/networkerFactory.ts

@ -9,8 +9,9 @@
* https://github.com/zhukov/webogram/blob/master/LICENSE * https://github.com/zhukov/webogram/blob/master/LICENSE
*/ */
import type { ConnectionStatusChange } from "./connectionStatus";
import MTPNetworker from "./networker"; import MTPNetworker from "./networker";
import { ConnectionStatusChange, InvokeApiOptions } from "../../types"; import { InvokeApiOptions } from "../../types";
import MTTransport from "./transports/transport"; import MTTransport from "./transports/transport";
import App from "../../config/app"; import App from "../../config/app";
import { MOUNT_CLASS_TO } from "../../config/debug"; import { MOUNT_CLASS_TO } from "../../config/debug";

9
src/lib/mtproto/transports/tcpObfuscated.ts

@ -10,6 +10,7 @@ import MTPNetworker from "../networker";
import Obfuscation from "./obfuscation"; import Obfuscation from "./obfuscation";
import MTTransport, { MTConnection, MTConnectionConstructable } from "./transport"; import MTTransport, { MTConnection, MTConnectionConstructable } from "./transport";
import intermediatePacketCodec from './intermediate'; import intermediatePacketCodec from './intermediate';
import { ConnectionStatus } from "../connectionStatus";
export default class TcpObfuscated implements MTTransport { export default class TcpObfuscated implements MTTransport {
private codec = intermediatePacketCodec; private codec = intermediatePacketCodec;
@ -58,7 +59,7 @@ export default class TcpObfuscated implements MTTransport {
if(this.networker) { if(this.networker) {
this.pending.length = 0; // ! clear queue and reformat messages to container, because if sending simultaneously 10+ messages, connection will die this.pending.length = 0; // ! clear queue and reformat messages to container, because if sending simultaneously 10+ messages, connection will die
this.networker.setConnectionStatus(true); this.networker.setConnectionStatus(ConnectionStatus.Connected);
this.networker.cleanupSent(); this.networker.cleanupSent();
this.networker.resend(); this.networker.resend();
} else { } else {
@ -113,15 +114,16 @@ export default class TcpObfuscated implements MTTransport {
private onClose = () => { private onClose = () => {
this.clear(); this.clear();
let needTimeout: number; let needTimeout: number, retryAt: number;
if(this.autoReconnect) { if(this.autoReconnect) {
const time = Date.now(); const time = Date.now();
const diff = time - this.lastCloseTime; const diff = time - this.lastCloseTime;
needTimeout = !isNaN(diff) && diff < this.retryTimeout ? this.retryTimeout - diff : 0; needTimeout = !isNaN(diff) && diff < this.retryTimeout ? this.retryTimeout - diff : 0;
retryAt = time + needTimeout;
} }
if(this.networker) { if(this.networker) {
this.networker.setConnectionStatus(false, needTimeout); this.networker.setConnectionStatus(ConnectionStatus.Closed, retryAt);
this.pending.length = 0; this.pending.length = 0;
} }
@ -168,6 +170,7 @@ export default class TcpObfuscated implements MTTransport {
} }
} }
this.networker.setConnectionStatus(ConnectionStatus.Connecting);
this.connect(); this.connect();
} }

2
src/lib/rootScope.ts

@ -9,7 +9,6 @@ import type { MyDocument } from "./appManagers/appDocsManager";
import type { AppMessagesManager, Dialog, MessagesStorage } from "./appManagers/appMessagesManager"; import type { AppMessagesManager, Dialog, MessagesStorage } from "./appManagers/appMessagesManager";
import type { Poll, PollResults } from "./appManagers/appPollsManager"; import type { Poll, PollResults } from "./appManagers/appPollsManager";
import type { MyDialogFilter } from "./storages/filters"; import type { MyDialogFilter } from "./storages/filters";
import type { ConnectionStatusChange } from "../types";
import type { UserTyping } from "./appManagers/appProfileManager"; import type { UserTyping } from "./appManagers/appProfileManager";
import type Chat from "../components/chat/chat"; import type Chat from "../components/chat/chat";
import type { UserAuth } from "./mtproto/mtproto_config"; import type { UserAuth } from "./mtproto/mtproto_config";
@ -17,6 +16,7 @@ import type { State, Theme } from "./appManagers/appStateManager";
import type { MyDraftMessage } from "./appManagers/appDraftsManager"; import type { MyDraftMessage } from "./appManagers/appDraftsManager";
import type { PushSubscriptionNotify } from "./mtproto/webPushApiManager"; import type { PushSubscriptionNotify } from "./mtproto/webPushApiManager";
import type { PushNotificationObject } from "./serviceWorker/push"; import type { PushNotificationObject } from "./serviceWorker/push";
import type { ConnectionStatusChange } from "./mtproto/connectionStatus";
import EventListenerBase from "../helpers/eventListenerBase"; import EventListenerBase from "../helpers/eventListenerBase";
import { MOUNT_CLASS_TO } from "../config/debug"; import { MOUNT_CLASS_TO } from "../config/debug";

9
src/scss/partials/_leftSidebar.scss

@ -442,11 +442,17 @@
&-button { &-button {
color: #2e3939; color: #2e3939;
align-self: center; align-self: center;
pointer-events: none; cursor: default;
padding-left: 4.5rem; padding-left: 4.5rem;
text-align: left; text-align: left;
height: 3.5rem; height: 3.5rem;
.force-reconnect {
cursor: pointer;
text-decoration: underline;
color: inherit;
}
transform: translateY(-100%); transform: translateY(-100%);
.preloader-container { .preloader-container {
@ -468,6 +474,7 @@
bottom: 0; bottom: 0;
right: 0; right: 0;
overflow: hidden; overflow: hidden;
background-color: var(--surface-color);
transform: translateY(0); transform: translateY(0);
height: 100%; height: 100%;

2
src/scss/style.scss

@ -557,7 +557,7 @@ input:-webkit-autofill:active {
} }
.bg-warning { .bg-warning {
background: #fed85a; background: #fed85a !important;
} }
.contextmenu { .contextmenu {

11
src/types.d.ts vendored

@ -79,14 +79,3 @@ export namespace AuthState {
_: 'authStateSignedIn' _: 'authStateSignedIn'
}; };
} }
export type ConnectionStatusChange = {
_: 'networkerStatus',
online: boolean,
dcId: number,
name: string,
isFileNetworker: boolean,
isFileDownload: boolean,
isFileUpload: boolean,
timeout?: number
};

Loading…
Cancel
Save