telegram-tghub-better-new 0.1.2 → 0.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Utils.d.ts +3 -3
- package/Utils.js +8 -4
- package/Version.d.ts +1 -1
- package/Version.js +1 -1
- package/client/TelegramClient.d.ts +22 -3
- package/client/TelegramClient.js +23 -0
- package/client/chats.d.ts +2 -0
- package/client/chats.js +46 -0
- package/client/downloads.js +1 -1
- package/client/messageParse.js +3 -3
- package/client/messages.js +1 -1
- package/client/telegramBaseClient.d.ts +9 -2
- package/client/telegramBaseClient.js +12 -6
- package/client/uploads.js +10 -2
- package/client/users.js +3 -0
- package/extensions/MessagePacker.d.ts +1 -1
- package/extensions/MessagePacker.js +1 -1
- package/extensions/html.js +3 -0
- package/extensions/markdown.js +1 -1
- package/extensions/markdownv2.js +2 -1
- package/network/MTProtoSender.d.ts +8 -1
- package/network/MTProtoSender.js +50 -14
- package/network/connection/TCPFull.js +7 -0
- package/network/connection/TCPMTProxy.d.ts +9 -4
- package/network/connection/TCPMTProxy.js +1 -1
- package/package.json +1 -1
- package/sessions/StoreSession.js +3 -0
- package/tl/api.d.ts +83 -337
- package/tl/apiTl.js +61 -256
- package/tl/custom/forward.js +1 -0
- package/tl/custom/message.js +4 -2
- package/tl/patched/index.js +1 -0
package/Utils.d.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { Buffer } from "buffer/";
|
|
2
|
-
import type { Entity, EntityLike, MessageIDLike } from "./define";
|
|
3
|
-
import { Api } from "./tl";
|
|
4
2
|
import bigInt from "big-integer";
|
|
5
|
-
import { EntityCache } from "./entityCache";
|
|
6
3
|
import type { ParseInterface } from "./client/messageParse";
|
|
7
4
|
import { CustomFile } from "./client/uploads";
|
|
5
|
+
import type { Entity, EntityLike, MessageIDLike } from "./define";
|
|
6
|
+
import { EntityCache } from "./entityCache";
|
|
7
|
+
import { Api } from "./tl";
|
|
8
8
|
export declare function getFileInfo(fileLocation: Api.Message | Api.MessageMediaDocument | Api.MessageMediaPhoto | Api.TypeInputFileLocation): {
|
|
9
9
|
dcId?: number;
|
|
10
10
|
location: Api.TypeInputFileLocation;
|
package/Utils.js
CHANGED
|
@@ -35,11 +35,13 @@ exports.parseUsername = parseUsername;
|
|
|
35
35
|
exports.rtrim = rtrim;
|
|
36
36
|
exports.getDisplayName = getDisplayName;
|
|
37
37
|
const buffer_1 = require("buffer/");
|
|
38
|
-
const tl_1 = require("./tl");
|
|
39
38
|
const big_integer_1 = __importDefault(require("big-integer"));
|
|
40
39
|
const mime_1 = __importDefault(require("mime"));
|
|
40
|
+
const html_1 = require("./extensions/html");
|
|
41
41
|
const markdown_1 = require("./extensions/markdown");
|
|
42
42
|
const markdownv2_1 = require("./extensions/markdownv2");
|
|
43
|
+
const Helpers_1 = require("./Helpers");
|
|
44
|
+
const tl_1 = require("./tl");
|
|
43
45
|
function getFileInfo(fileLocation) {
|
|
44
46
|
if (!fileLocation || !fileLocation.SUBCLASS_OF_ID) {
|
|
45
47
|
_raiseCastFail(fileLocation, "InputFileLocation");
|
|
@@ -96,8 +98,6 @@ function* chunks(arr, size = 100) {
|
|
|
96
98
|
yield arr.slice(i, i + size);
|
|
97
99
|
}
|
|
98
100
|
}
|
|
99
|
-
const html_1 = require("./extensions/html");
|
|
100
|
-
const Helpers_1 = require("./Helpers");
|
|
101
101
|
const USERNAME_RE = new RegExp("@|(?:https?:\\/\\/)?(?:www\\.)?" +
|
|
102
102
|
"(?:telegram\\.(?:me|dog)|t\\.me)\\/(@|joinchat\\/)?", "i");
|
|
103
103
|
const JPEG_HEADER = buffer_1.Buffer.from("ffd8ffe000104a46494600010100000100010000ffdb004300281c1e231e19282321232d2b28303c64413c37373c7b585d4964918099968f808c8aa0b4e6c3a0aadaad8a8cc8ffcbdaeef5ffffff9bc1fffffffaffe6fdfff8ffdb0043012b2d2d3c353c76414176f8a58ca5f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8ffc00011080000000003012200021101031101ffc4001f0000010501010101010100000000000000000102030405060708090a0bffc400b5100002010303020403050504040000017d01020300041105122131410613516107227114328191a1082342b1c11552d1f02433627282090a161718191a25262728292a3435363738393a434445464748494a535455565758595a636465666768696a737475767778797a838485868788898a92939495969798999aa2a3a4a5a6a7a8a9aab2b3b4b5b6b7b8b9bac2c3c4c5c6c7c8c9cad2d3d4d5d6d7d8d9dae1e2e3e4e5e6e7e8e9eaf1f2f3f4f5f6f7f8f9faffc4001f0100030101010101010101010000000000000102030405060708090a0bffc400b51100020102040403040705040400010277000102031104052131061241510761711322328108144291a1b1c109233352f0156272d10a162434e125f11718191a262728292a35363738393a434445464748494a535455565758595a636465666768696a737475767778797a82838485868788898a92939495969798999aa2a3a4a5a6a7a8a9aab2b3b4b5b6b7b8b9bac2c3c4c5c6c7c8c9cad2d3d4d5d6d7d8d9dae2e3e4e5e6e7e8e9eaf2f3f4f5f6f7f8f9faffda000c03010002110311003f00", "hex");
|
|
@@ -676,7 +676,11 @@ function isVideo(file) {
|
|
|
676
676
|
*/
|
|
677
677
|
function getAttributes(file, { attributes = null, mimeType = undefined, forceDocument = false, voiceNote = false, videoNote = false, supportsStreaming = false, thumb = null, }) {
|
|
678
678
|
var _a, _b, _c, _d;
|
|
679
|
-
const name = typeof file == "string"
|
|
679
|
+
const name = typeof file == "string"
|
|
680
|
+
? file
|
|
681
|
+
: "name" in file
|
|
682
|
+
? file.name || "unnamed"
|
|
683
|
+
: "unnamed";
|
|
680
684
|
if (mimeType === undefined) {
|
|
681
685
|
mimeType = mime_1.default.getType(name) || "application/octet-stream";
|
|
682
686
|
}
|
package/Version.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const version = "10.
|
|
1
|
+
export declare const version = "10.1.1";
|
package/Version.js
CHANGED
|
@@ -733,6 +733,25 @@ export declare class TelegramClient extends TelegramBaseClient {
|
|
|
733
733
|
* @return
|
|
734
734
|
*/
|
|
735
735
|
getParticipants(entity: EntityLike, params?: chatMethods.IterParticipantsParams): Promise<import("../Helpers").TotalList<Api.User>>;
|
|
736
|
+
/**
|
|
737
|
+
* Kicks a user from a chat.
|
|
738
|
+
*
|
|
739
|
+
* Kicking yourself (`'me'`) will result in leaving the chat.
|
|
740
|
+
*
|
|
741
|
+
* @note
|
|
742
|
+
* Attempting to kick someone who was banned will remove their
|
|
743
|
+
* restrictions (and thus unbanning them), since kicking is just
|
|
744
|
+
* ban + unban.
|
|
745
|
+
*
|
|
746
|
+
* @example
|
|
747
|
+
* // Kick some user from some chat, and deleting the service message
|
|
748
|
+
* const msg = await client.kickParticipant(chat, user);
|
|
749
|
+
* await msg.delete();
|
|
750
|
+
*
|
|
751
|
+
* // Leaving chat
|
|
752
|
+
* await client.kickParticipant(chat, 'me');
|
|
753
|
+
*/
|
|
754
|
+
kickParticipant(entity: EntityLike, participant: EntityLike): Promise<Api.TypeMessage | Map<number, Api.Message> | (Api.Message | undefined)[] | undefined>;
|
|
736
755
|
/** TODO */
|
|
737
756
|
on(event: any): (f: {
|
|
738
757
|
(event: any): void;
|
|
@@ -924,11 +943,11 @@ export declare class TelegramClient extends TelegramBaseClient {
|
|
|
924
943
|
* @example
|
|
925
944
|
* ```ts
|
|
926
945
|
* const me = await client.getEntity("me");
|
|
927
|
-
* console.log("My name is",utils.getDisplayName(me));
|
|
946
|
+
* console.log("My name is", utils.getDisplayName(me));
|
|
928
947
|
*
|
|
929
948
|
* const chat = await client.getInputEntity("username");
|
|
930
|
-
* for await (const message of client.iterMessages(chat){
|
|
931
|
-
* console.log("Message text is",message.text);
|
|
949
|
+
* for await (const message of client.iterMessages(chat)) {
|
|
950
|
+
* console.log("Message text is", message.text);
|
|
932
951
|
* }
|
|
933
952
|
*
|
|
934
953
|
* // Note that you could have used the username directly, but it's
|
package/client/TelegramClient.js
CHANGED
|
@@ -806,6 +806,27 @@ class TelegramClient extends telegramBaseClient_1.TelegramBaseClient {
|
|
|
806
806
|
getParticipants(entity, params = {}) {
|
|
807
807
|
return chatMethods.getParticipants(this, entity, params);
|
|
808
808
|
}
|
|
809
|
+
/**
|
|
810
|
+
* Kicks a user from a chat.
|
|
811
|
+
*
|
|
812
|
+
* Kicking yourself (`'me'`) will result in leaving the chat.
|
|
813
|
+
*
|
|
814
|
+
* @note
|
|
815
|
+
* Attempting to kick someone who was banned will remove their
|
|
816
|
+
* restrictions (and thus unbanning them), since kicking is just
|
|
817
|
+
* ban + unban.
|
|
818
|
+
*
|
|
819
|
+
* @example
|
|
820
|
+
* // Kick some user from some chat, and deleting the service message
|
|
821
|
+
* const msg = await client.kickParticipant(chat, user);
|
|
822
|
+
* await msg.delete();
|
|
823
|
+
*
|
|
824
|
+
* // Leaving chat
|
|
825
|
+
* await client.kickParticipant(chat, 'me');
|
|
826
|
+
*/
|
|
827
|
+
kickParticipant(entity, participant) {
|
|
828
|
+
return chatMethods.kickParticipant(this, entity, participant);
|
|
829
|
+
}
|
|
809
830
|
//endregion
|
|
810
831
|
//region updates
|
|
811
832
|
/** TODO */
|
|
@@ -1051,6 +1072,8 @@ class TelegramClient extends telegramBaseClient_1.TelegramBaseClient {
|
|
|
1051
1072
|
client: this,
|
|
1052
1073
|
securityChecks: this._securityChecks,
|
|
1053
1074
|
autoReconnectCallback: this._handleReconnect.bind(this),
|
|
1075
|
+
_exportedSenderPromises: this._exportedSenderPromises,
|
|
1076
|
+
reconnectRetries: this._reconnectRetries,
|
|
1054
1077
|
});
|
|
1055
1078
|
}
|
|
1056
1079
|
const connection = new this._connection({
|
package/client/chats.d.ts
CHANGED
|
@@ -36,4 +36,6 @@ export interface IterParticipantsParams {
|
|
|
36
36
|
export declare function iterParticipants(client: TelegramClient, entity: EntityLike, { limit, offset, search, filter, showTotal }: IterParticipantsParams): _ParticipantsIter;
|
|
37
37
|
/** @hidden */
|
|
38
38
|
export declare function getParticipants(client: TelegramClient, entity: EntityLike, params: IterParticipantsParams): Promise<TotalList<Api.User>>;
|
|
39
|
+
/** @hidden */
|
|
40
|
+
export declare function kickParticipant(client: TelegramClient, entity: EntityLike, participant: EntityLike): Promise<Api.TypeMessage | Map<number, Api.Message> | (Api.Message | undefined)[] | undefined>;
|
|
39
41
|
export {};
|
package/client/chats.js
CHANGED
|
@@ -6,12 +6,14 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
6
6
|
exports._ParticipantsIter = void 0;
|
|
7
7
|
exports.iterParticipants = iterParticipants;
|
|
8
8
|
exports.getParticipants = getParticipants;
|
|
9
|
+
exports.kickParticipant = kickParticipant;
|
|
9
10
|
const Helpers_1 = require("../Helpers");
|
|
10
11
|
const requestIter_1 = require("../requestIter");
|
|
11
12
|
const __1 = require("../");
|
|
12
13
|
const tl_1 = require("../tl");
|
|
13
14
|
const big_integer_1 = __importDefault(require("big-integer"));
|
|
14
15
|
const inspect_1 = require("../inspect");
|
|
16
|
+
const Utils_1 = require("../Utils");
|
|
15
17
|
const _MAX_PARTICIPANTS_CHUNK_SIZE = 200;
|
|
16
18
|
const _MAX_ADMIN_LOG_CHUNK_SIZE = 100;
|
|
17
19
|
const _MAX_PROFILE_PHOTO_CHUNK_SIZE = 100;
|
|
@@ -302,3 +304,47 @@ async function getParticipants(client, entity, params) {
|
|
|
302
304
|
const it = client.iterParticipants(entity, params);
|
|
303
305
|
return (await it.collect());
|
|
304
306
|
}
|
|
307
|
+
/** @hidden */
|
|
308
|
+
async function kickParticipant(client, entity, participant) {
|
|
309
|
+
const peer = await client.getInputEntity(entity);
|
|
310
|
+
const user = await client.getInputEntity(participant);
|
|
311
|
+
let resp;
|
|
312
|
+
let request;
|
|
313
|
+
const type = __1.helpers._entityType(peer);
|
|
314
|
+
if (type === __1.helpers._EntityType.CHAT) {
|
|
315
|
+
request = new tl_1.Api.messages.DeleteChatUser({
|
|
316
|
+
chatId: (0, Helpers_1.returnBigInt)((0, Utils_1.getPeerId)(entity)),
|
|
317
|
+
userId: (0, Helpers_1.returnBigInt)((0, Utils_1.getPeerId)(participant)),
|
|
318
|
+
});
|
|
319
|
+
resp = await client.invoke(request);
|
|
320
|
+
}
|
|
321
|
+
else if (type === __1.helpers._EntityType.CHANNEL) {
|
|
322
|
+
if (user instanceof tl_1.Api.InputPeerSelf) {
|
|
323
|
+
request = new tl_1.Api.channels.LeaveChannel({
|
|
324
|
+
channel: peer,
|
|
325
|
+
});
|
|
326
|
+
resp = await client.invoke(request);
|
|
327
|
+
}
|
|
328
|
+
else {
|
|
329
|
+
request = new tl_1.Api.channels.EditBanned({
|
|
330
|
+
channel: peer,
|
|
331
|
+
participant: user,
|
|
332
|
+
bannedRights: new tl_1.Api.ChatBannedRights({
|
|
333
|
+
untilDate: 0,
|
|
334
|
+
viewMessages: true,
|
|
335
|
+
}),
|
|
336
|
+
});
|
|
337
|
+
resp = await client.invoke(request);
|
|
338
|
+
await (0, Helpers_1.sleep)(500);
|
|
339
|
+
await client.invoke(new tl_1.Api.channels.EditBanned({
|
|
340
|
+
channel: peer,
|
|
341
|
+
participant: user,
|
|
342
|
+
bannedRights: new tl_1.Api.ChatBannedRights({ untilDate: 0 }),
|
|
343
|
+
}));
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
else {
|
|
347
|
+
throw new Error("You must pass either a channel or a chat");
|
|
348
|
+
}
|
|
349
|
+
return client._getResponseMessage(request, resp, entity);
|
|
350
|
+
}
|
package/client/downloads.js
CHANGED
|
@@ -296,10 +296,10 @@ async function downloadFileV2(client, inputLocation, { outputFile = undefined, p
|
|
|
296
296
|
_d = false;
|
|
297
297
|
const chunk = _c;
|
|
298
298
|
await writer.write(chunk);
|
|
299
|
+
downloaded = downloaded.add(chunk.length);
|
|
299
300
|
if (progressCallback) {
|
|
300
301
|
await progressCallback(downloaded, (0, big_integer_1.default)(fileSize || big_integer_1.default.zero));
|
|
301
302
|
}
|
|
302
|
-
downloaded = downloaded.add(chunk.length);
|
|
303
303
|
}
|
|
304
304
|
}
|
|
305
305
|
catch (e_1_1) { e_1 = { error: e_1_1 }; }
|
package/client/messageParse.js
CHANGED
|
@@ -155,13 +155,13 @@ function _getResponseMessage(client, request, result, inputChat) {
|
|
|
155
155
|
if (schedMessage) {
|
|
156
156
|
return schedMessage;
|
|
157
157
|
}
|
|
158
|
-
client._log.warn(`No randomId in ${request} to map to. returning undefined for ${result}`);
|
|
158
|
+
client._log.warn(`No randomId in ${request} to map to. returning undefined for ${result} (Message was empty)`);
|
|
159
159
|
return undefined;
|
|
160
160
|
}
|
|
161
161
|
if (!(0, Helpers_1.isArrayLike)(randomId)) {
|
|
162
162
|
let msg = idToMessage.get(randomToId.get(randomId.toString()));
|
|
163
163
|
if (!msg) {
|
|
164
|
-
client._log.warn(`Request ${request.className} had missing message mapping ${result.className}`);
|
|
164
|
+
client._log.warn(`Request ${request.className} had missing message mapping ${result.className} (Message was empty)`);
|
|
165
165
|
}
|
|
166
166
|
return msg;
|
|
167
167
|
}
|
|
@@ -181,7 +181,7 @@ function _getResponseMessage(client, request, result, inputChat) {
|
|
|
181
181
|
final.push(tmp2);
|
|
182
182
|
}
|
|
183
183
|
if (warned) {
|
|
184
|
-
client._log.warn(`Request ${request.className} had missing message mapping ${result.className}`);
|
|
184
|
+
client._log.warn(`Request ${request.className} had missing message mapping ${result.className} (Message was empty)`);
|
|
185
185
|
}
|
|
186
186
|
const finalToReturn = [];
|
|
187
187
|
for (const rnd of randomId) {
|
package/client/messages.js
CHANGED
|
@@ -791,7 +791,7 @@ async function getCommentData(client, entity, message) {
|
|
|
791
791
|
peer: entity,
|
|
792
792
|
msgId: __1.utils.getMessageId(message),
|
|
793
793
|
}));
|
|
794
|
-
const relevantMessage = result.messages
|
|
794
|
+
const relevantMessage = result.messages.reduce((p, c) => (p && p.id < c.id ? p : c));
|
|
795
795
|
let chat;
|
|
796
796
|
for (const c of result.chats) {
|
|
797
797
|
if (relevantMessage.peerId instanceof tl_1.Api.PeerChannel &&
|
|
@@ -37,11 +37,16 @@ export interface TelegramClientParams {
|
|
|
37
37
|
*/
|
|
38
38
|
requestRetries?: number;
|
|
39
39
|
/**
|
|
40
|
-
* How many times the
|
|
40
|
+
* How many times the connection should retry, either on the initial connection or when Telegram disconnects us.<br/>
|
|
41
41
|
* May be set to a negative or undefined value for infinite retries, but this is not recommended, since the program can get stuck in an infinite loop.<br/>
|
|
42
42
|
* defaults to 5
|
|
43
43
|
*/
|
|
44
44
|
connectionRetries?: number;
|
|
45
|
+
/**
|
|
46
|
+
* How many times to reconnect before giving up. This happens after the initial connection is finished<br/>
|
|
47
|
+
* defaults to infinity
|
|
48
|
+
*/
|
|
49
|
+
reconnectRetries?: number;
|
|
45
50
|
/**
|
|
46
51
|
* Experimental proxy to be used for the connection. (only supports MTProxies)
|
|
47
52
|
*/
|
|
@@ -126,6 +131,8 @@ export declare abstract class TelegramBaseClient {
|
|
|
126
131
|
/** @hidden */
|
|
127
132
|
_connectionRetries: number;
|
|
128
133
|
/** @hidden */
|
|
134
|
+
_reconnectRetries: number;
|
|
135
|
+
/** @hidden */
|
|
129
136
|
_retryDelay: number;
|
|
130
137
|
/** @hidden */
|
|
131
138
|
_timeout: number;
|
|
@@ -162,7 +169,7 @@ export declare abstract class TelegramBaseClient {
|
|
|
162
169
|
/** @hidden */
|
|
163
170
|
_ALBUMS: Map<string, [Timeout, Api.TypeUpdate[]]>;
|
|
164
171
|
/** @hidden */
|
|
165
|
-
|
|
172
|
+
_exportedSenderPromises: Map<number, Promise<MTProtoSender>>;
|
|
166
173
|
/** @hidden */
|
|
167
174
|
private _exportedSenderReleaseTimeouts;
|
|
168
175
|
/** @hidden */
|
|
@@ -48,7 +48,6 @@ const clientParamsDefault = {
|
|
|
48
48
|
};
|
|
49
49
|
class TelegramBaseClient {
|
|
50
50
|
constructor(session, apiId, apiHash, clientParams) {
|
|
51
|
-
var _a;
|
|
52
51
|
/** The current gramJS version. */
|
|
53
52
|
this.__version__ = __1.version;
|
|
54
53
|
/** @hidden */
|
|
@@ -82,6 +81,7 @@ class TelegramBaseClient {
|
|
|
82
81
|
this._requestRetries = clientParams.requestRetries;
|
|
83
82
|
this._downloadRetries = clientParams.downloadRetries;
|
|
84
83
|
this._connectionRetries = clientParams.connectionRetries;
|
|
84
|
+
this._reconnectRetries = clientParams.reconnectRetries;
|
|
85
85
|
this._retryDelay = clientParams.retryDelay || 0;
|
|
86
86
|
this._timeout = clientParams.timeout;
|
|
87
87
|
this._autoReconnect = clientParams.autoReconnect;
|
|
@@ -94,7 +94,7 @@ class TelegramBaseClient {
|
|
|
94
94
|
}
|
|
95
95
|
this._connection = clientParams.connection;
|
|
96
96
|
let initProxy;
|
|
97
|
-
if (
|
|
97
|
+
if (this._proxy && "MTProxy" in this._proxy) {
|
|
98
98
|
this._connection = TCPMTProxy_1.ConnectionTCPMTProxyAbridged;
|
|
99
99
|
initProxy = new tl_1.Api.InputClientProxy({
|
|
100
100
|
address: this._proxy.ip,
|
|
@@ -118,9 +118,6 @@ class TelegramBaseClient {
|
|
|
118
118
|
this._selfInputPeer = undefined;
|
|
119
119
|
this.useWSS = clientParams.useWSS;
|
|
120
120
|
this._securityChecks = !!clientParams.securityChecks;
|
|
121
|
-
if (this.useWSS && this._proxy) {
|
|
122
|
-
throw new Error("Cannot use SSL with proxies. You need to disable the useWSS client param in TelegramClient");
|
|
123
|
-
}
|
|
124
121
|
this._entityCache = new entityCache_1.EntityCache();
|
|
125
122
|
// These will be set later
|
|
126
123
|
this._config = undefined;
|
|
@@ -295,7 +292,14 @@ class TelegramBaseClient {
|
|
|
295
292
|
}
|
|
296
293
|
this._exportedSenderReleaseTimeouts.set(dcId, setTimeout(() => {
|
|
297
294
|
this._exportedSenderReleaseTimeouts.delete(dcId);
|
|
298
|
-
sender.
|
|
295
|
+
if (sender._pendingState.values().length) {
|
|
296
|
+
console.log("sender already has some hanging states. reconnecting");
|
|
297
|
+
sender._reconnect();
|
|
298
|
+
this._borrowExportedSender(dcId, false, sender);
|
|
299
|
+
}
|
|
300
|
+
else {
|
|
301
|
+
sender.disconnect();
|
|
302
|
+
}
|
|
299
303
|
}, EXPORTED_SENDER_RELEASE_TIMEOUT));
|
|
300
304
|
return sender;
|
|
301
305
|
}
|
|
@@ -313,6 +317,8 @@ class TelegramBaseClient {
|
|
|
313
317
|
onConnectionBreak: this._cleanupExportedSender.bind(this),
|
|
314
318
|
client: this,
|
|
315
319
|
securityChecks: this._securityChecks,
|
|
320
|
+
_exportedSenderPromises: this._exportedSenderPromises,
|
|
321
|
+
reconnectRetries: this._reconnectRetries,
|
|
316
322
|
});
|
|
317
323
|
}
|
|
318
324
|
/** @hidden */
|
package/client/uploads.js
CHANGED
|
@@ -59,6 +59,7 @@ const LARGE_FILE_THRESHOLD = 10 * 1024 * 1024;
|
|
|
59
59
|
const UPLOAD_TIMEOUT = 15 * 1000;
|
|
60
60
|
const DISCONNECT_SLEEP = 1000;
|
|
61
61
|
const BUFFER_SIZE_2GB = 2 ** 31;
|
|
62
|
+
const BUFFER_SIZE_20MB = 20 * 1024 * 1024;
|
|
62
63
|
async function getFileBuffer(file, fileSize, maxBufferSize) {
|
|
63
64
|
const options = {};
|
|
64
65
|
if (fileSize > maxBufferSize && file instanceof CustomFile) {
|
|
@@ -78,7 +79,7 @@ async function uploadFile(client, fileParams) {
|
|
|
78
79
|
const isLarge = size > LARGE_FILE_THRESHOLD;
|
|
79
80
|
const partSize = (0, Utils_1.getAppropriatedPartSize)((0, big_integer_1.default)(size)) * KB_TO_BYTES;
|
|
80
81
|
const partCount = Math.floor((size + partSize - 1) / partSize);
|
|
81
|
-
const buffer = await getFileBuffer(file, size, fileParams.maxBufferSize ||
|
|
82
|
+
const buffer = await getFileBuffer(file, size, fileParams.maxBufferSize || BUFFER_SIZE_20MB - 1);
|
|
82
83
|
// Make sure a new sender can be created before starting upload
|
|
83
84
|
await client.getSender(client.session.dcId);
|
|
84
85
|
if (!workers || !size) {
|
|
@@ -98,7 +99,14 @@ async function uploadFile(client, fileParams) {
|
|
|
98
99
|
end = partCount;
|
|
99
100
|
}
|
|
100
101
|
for (let j = i; j < end; j++) {
|
|
101
|
-
|
|
102
|
+
let endPart = (j + 1) * partSize;
|
|
103
|
+
if (endPart > size) {
|
|
104
|
+
endPart = size;
|
|
105
|
+
}
|
|
106
|
+
if (endPart == j * partSize) {
|
|
107
|
+
break;
|
|
108
|
+
}
|
|
109
|
+
const bytes = await buffer.slice(j * partSize, endPart);
|
|
102
110
|
// eslint-disable-next-line no-loop-func
|
|
103
111
|
sendingParts.push((async (jMemo, bytesMemo) => {
|
|
104
112
|
while (true) {
|
package/client/users.js
CHANGED
|
@@ -39,6 +39,9 @@ async function invoke(client, request, dcId, otherSender) {
|
|
|
39
39
|
if (sender == undefined) {
|
|
40
40
|
throw new Error("Cannot send requests while disconnected. You need to call .connect()");
|
|
41
41
|
}
|
|
42
|
+
if (sender.userDisconnected) {
|
|
43
|
+
throw new Error("Cannot send requests while disconnected. Please reconnect.");
|
|
44
|
+
}
|
|
42
45
|
await client._connectedDeferred.promise;
|
|
43
46
|
await request.resolve(client, __1.utils);
|
|
44
47
|
client._lastRequest = new Date().getTime();
|
|
@@ -3,7 +3,7 @@ import type { MTProtoState } from "../network/MTProtoState";
|
|
|
3
3
|
import type { RequestState } from "../network/RequestState";
|
|
4
4
|
export declare class MessagePacker {
|
|
5
5
|
private _state;
|
|
6
|
-
|
|
6
|
+
_pendingStates: RequestState[];
|
|
7
7
|
private _queue;
|
|
8
8
|
private _ready;
|
|
9
9
|
private setReady;
|
|
@@ -62,7 +62,7 @@ class MessagePacker {
|
|
|
62
62
|
this._pendingStates.push(state);
|
|
63
63
|
state
|
|
64
64
|
.promise // Using finally causes triggering `unhandledrejection` event
|
|
65
|
-
.catch(() => { })
|
|
65
|
+
.catch((err) => { })
|
|
66
66
|
.finally(() => {
|
|
67
67
|
this._pendingStates = this._pendingStates.filter((s) => s !== state);
|
|
68
68
|
});
|
package/extensions/html.js
CHANGED
|
@@ -40,6 +40,9 @@ class HTMLToTelegramParser {
|
|
|
40
40
|
}
|
|
41
41
|
else if (name == "blockquote") {
|
|
42
42
|
EntityType = tl_1.Api.MessageEntityBlockquote;
|
|
43
|
+
if (attributes.expandable !== undefined) {
|
|
44
|
+
args.collapsed = true;
|
|
45
|
+
}
|
|
43
46
|
}
|
|
44
47
|
else if (name == "code") {
|
|
45
48
|
const pre = this._buildingEntities.get("pre");
|
package/extensions/markdown.js
CHANGED
|
@@ -39,7 +39,7 @@ class MarkdownParser {
|
|
|
39
39
|
foundIndex - tempEntities[foundDelim].offset;
|
|
40
40
|
entities.push(tempEntities[foundDelim]);
|
|
41
41
|
}
|
|
42
|
-
message = message.replace(foundDelim, "");
|
|
42
|
+
message = message.toString().replace(foundDelim, "");
|
|
43
43
|
i = foundIndex;
|
|
44
44
|
}
|
|
45
45
|
return [message, entities];
|
package/extensions/markdownv2.js
CHANGED
|
@@ -13,7 +13,7 @@ class MarkdownV2Parser {
|
|
|
13
13
|
// italic
|
|
14
14
|
message = message.replace(/-(.*?)-/g, "<i>$1</i>");
|
|
15
15
|
// pre
|
|
16
|
-
message = message.replace(/```(
|
|
16
|
+
message = message.replace(/```([\s\S]*?)```/g, "<pre>$1</pre>");
|
|
17
17
|
// code
|
|
18
18
|
message = message.replace(/`(.*?)`/g, "<code>$1</code>");
|
|
19
19
|
// Spoiler
|
|
@@ -22,6 +22,7 @@ class MarkdownV2Parser {
|
|
|
22
22
|
message = message.replace(/(?<!\!)\[([^\]]+)\]\(([^)]+)\)/g, '<a href="$2">$1</a>');
|
|
23
23
|
// Emoji
|
|
24
24
|
message = message.replace(/!\[([^\]]+)\]\(tg:\/\/emoji\?id=(\d+)\)/g, '<tg-emoji emoji-id="$2">$1</tg-emoji>');
|
|
25
|
+
//
|
|
25
26
|
return html_1.HTMLParser.parse(message);
|
|
26
27
|
}
|
|
27
28
|
static unparse(text, entities) {
|
|
@@ -19,9 +19,11 @@ import { RequestState } from "./RequestState";
|
|
|
19
19
|
import { Connection, UpdateConnectionState } from "./";
|
|
20
20
|
import type { TelegramClient } from "..";
|
|
21
21
|
import { CancellablePromise } from "real-cancellable-promise";
|
|
22
|
+
import { PendingState } from "../extensions/PendingState";
|
|
22
23
|
interface DEFAULT_OPTIONS {
|
|
23
24
|
logger: any;
|
|
24
25
|
retries: number;
|
|
26
|
+
reconnectRetries: number;
|
|
25
27
|
delay: number;
|
|
26
28
|
autoReconnect: boolean;
|
|
27
29
|
connectTimeout: any;
|
|
@@ -34,10 +36,12 @@ interface DEFAULT_OPTIONS {
|
|
|
34
36
|
client: TelegramClient;
|
|
35
37
|
onConnectionBreak?: CallableFunction;
|
|
36
38
|
securityChecks: boolean;
|
|
39
|
+
_exportedSenderPromises: Map<number, Promise<MTProtoSender>>;
|
|
37
40
|
}
|
|
38
41
|
export declare class MTProtoSender {
|
|
39
42
|
static DEFAULT_OPTIONS: {
|
|
40
43
|
logger: null;
|
|
44
|
+
reconnectRetries: number;
|
|
41
45
|
retries: number;
|
|
42
46
|
delay: number;
|
|
43
47
|
autoReconnect: boolean;
|
|
@@ -54,6 +58,8 @@ export declare class MTProtoSender {
|
|
|
54
58
|
private readonly _log;
|
|
55
59
|
private _dcId;
|
|
56
60
|
private readonly _retries;
|
|
61
|
+
private _reconnectRetries;
|
|
62
|
+
private _currentRetries;
|
|
57
63
|
private readonly _delay;
|
|
58
64
|
private _connectTimeout;
|
|
59
65
|
private _autoReconnect;
|
|
@@ -71,7 +77,7 @@ export declare class MTProtoSender {
|
|
|
71
77
|
readonly authKey: AuthKey;
|
|
72
78
|
private readonly _state;
|
|
73
79
|
private _sendQueue;
|
|
74
|
-
|
|
80
|
+
_pendingState: PendingState;
|
|
75
81
|
private readonly _pendingAck;
|
|
76
82
|
private readonly _lastAcks;
|
|
77
83
|
private readonly _handlers;
|
|
@@ -85,6 +91,7 @@ export declare class MTProtoSender {
|
|
|
85
91
|
private _cancelSend;
|
|
86
92
|
cancellableRecvLoopPromise?: CancellablePromise<any>;
|
|
87
93
|
private _finishedConnecting;
|
|
94
|
+
private _exportedSenderPromises;
|
|
88
95
|
/**
|
|
89
96
|
* @param authKey
|
|
90
97
|
* @param opts
|
package/network/MTProtoSender.js
CHANGED
|
@@ -40,6 +40,7 @@ class MTProtoSender {
|
|
|
40
40
|
* @param opts
|
|
41
41
|
*/
|
|
42
42
|
constructor(authKey, opts) {
|
|
43
|
+
this._exportedSenderPromises = new Map();
|
|
43
44
|
const args = Object.assign(Object.assign({}, MTProtoSender.DEFAULT_OPTIONS), opts);
|
|
44
45
|
this._finishedConnecting = false;
|
|
45
46
|
this._cancelSend = false;
|
|
@@ -47,6 +48,8 @@ class MTProtoSender {
|
|
|
47
48
|
this._log = args.logger;
|
|
48
49
|
this._dcId = args.dcId;
|
|
49
50
|
this._retries = args.retries;
|
|
51
|
+
this._currentRetries = 0;
|
|
52
|
+
this._reconnectRetries = args.reconnectRetries;
|
|
50
53
|
this._delay = args.delay;
|
|
51
54
|
this._autoReconnect = args.autoReconnect;
|
|
52
55
|
this._connectTimeout = args.connectTimeout;
|
|
@@ -59,6 +62,7 @@ class MTProtoSender {
|
|
|
59
62
|
this._onConnectionBreak = args.onConnectionBreak;
|
|
60
63
|
this._securityChecks = args.securityChecks;
|
|
61
64
|
this._connectMutex = new async_mutex_1.Mutex();
|
|
65
|
+
this._exportedSenderPromises = args._exportedSenderPromises;
|
|
62
66
|
/**
|
|
63
67
|
* whether we disconnected ourself or telegram did it.
|
|
64
68
|
*/
|
|
@@ -328,17 +332,6 @@ class MTProtoSender {
|
|
|
328
332
|
this._log.debug(`Encrypting ${batch.length} message(s) in ${data.length} bytes for sending`);
|
|
329
333
|
this._log.debug(`Sending ${batch.map((m) => m.request.className)}`);
|
|
330
334
|
data = await this._state.encryptMessageData(data);
|
|
331
|
-
try {
|
|
332
|
-
await this._connection.send(data);
|
|
333
|
-
}
|
|
334
|
-
catch (e) {
|
|
335
|
-
this._log.debug(`Connection closed while sending data ${e}`);
|
|
336
|
-
if (this._log.canSend(Logger_1.LogLevel.DEBUG)) {
|
|
337
|
-
console.error(e);
|
|
338
|
-
}
|
|
339
|
-
this._sendLoopHandle = undefined;
|
|
340
|
-
return;
|
|
341
|
-
}
|
|
342
335
|
for (const state of batch) {
|
|
343
336
|
if (!Array.isArray(state)) {
|
|
344
337
|
if (state.request.classType === "request") {
|
|
@@ -353,6 +346,21 @@ class MTProtoSender {
|
|
|
353
346
|
}
|
|
354
347
|
}
|
|
355
348
|
}
|
|
349
|
+
try {
|
|
350
|
+
await this._connection.send(data);
|
|
351
|
+
}
|
|
352
|
+
catch (e) {
|
|
353
|
+
/** when the server disconnects us we want to reconnect */
|
|
354
|
+
if (!this.userDisconnected) {
|
|
355
|
+
this._log.debug(`Connection closed while sending data ${e}`);
|
|
356
|
+
if (this._log.canSend(Logger_1.LogLevel.DEBUG)) {
|
|
357
|
+
console.error(e);
|
|
358
|
+
}
|
|
359
|
+
this.reconnect();
|
|
360
|
+
}
|
|
361
|
+
this._sendLoopHandle = undefined;
|
|
362
|
+
return;
|
|
363
|
+
}
|
|
356
364
|
this._log.debug("Encrypted messages put in a queue to be sent");
|
|
357
365
|
}
|
|
358
366
|
this._sendLoopHandle = undefined;
|
|
@@ -366,6 +374,13 @@ class MTProtoSender {
|
|
|
366
374
|
body = await this._connection.recv();
|
|
367
375
|
}
|
|
368
376
|
catch (e) {
|
|
377
|
+
if (this._currentRetries > this._reconnectRetries) {
|
|
378
|
+
for (const state of this._pendingState.values()) {
|
|
379
|
+
state.reject("Maximum reconnection retries reached. Aborting!");
|
|
380
|
+
}
|
|
381
|
+
this.userDisconnected = true;
|
|
382
|
+
return;
|
|
383
|
+
}
|
|
369
384
|
/** when the server disconnects us we want to reconnect */
|
|
370
385
|
if (!this.userDisconnected) {
|
|
371
386
|
this._log.warn("Connection closed while receiving data");
|
|
@@ -443,6 +458,7 @@ class MTProtoSender {
|
|
|
443
458
|
}
|
|
444
459
|
}
|
|
445
460
|
}
|
|
461
|
+
this._currentRetries = 0;
|
|
446
462
|
}
|
|
447
463
|
this._recvLoopHandle = undefined;
|
|
448
464
|
}
|
|
@@ -518,7 +534,6 @@ class MTProtoSender {
|
|
|
518
534
|
* @private
|
|
519
535
|
*/
|
|
520
536
|
_handleRPCResult(message) {
|
|
521
|
-
var _a;
|
|
522
537
|
const result = message.obj;
|
|
523
538
|
const state = this._pendingState.getAndDelete(result.reqMsgId);
|
|
524
539
|
this._log.debug(`Handling RPC result for message ${result.reqMsgId}`);
|
|
@@ -553,7 +568,7 @@ class MTProtoSender {
|
|
|
553
568
|
try {
|
|
554
569
|
const reader = new extensions_1.BinaryReader(result.body);
|
|
555
570
|
const read = state.request.readResult(reader);
|
|
556
|
-
this._log.debug(`Handling RPC result ${
|
|
571
|
+
this._log.debug(`Handling RPC result ${read === null || read === void 0 ? void 0 : read.className}`);
|
|
557
572
|
state.resolve(read);
|
|
558
573
|
}
|
|
559
574
|
catch (err) {
|
|
@@ -756,6 +771,21 @@ class MTProtoSender {
|
|
|
756
771
|
reconnect() {
|
|
757
772
|
if (this._userConnected && !this.isReconnecting) {
|
|
758
773
|
this.isReconnecting = true;
|
|
774
|
+
this._currentRetries++;
|
|
775
|
+
if (this._isMainSender) {
|
|
776
|
+
this._log.debug("Reconnecting all senders");
|
|
777
|
+
for (const promise of this._exportedSenderPromises.values()) {
|
|
778
|
+
promise
|
|
779
|
+
.then((sender) => {
|
|
780
|
+
if (sender && !sender._isMainSender) {
|
|
781
|
+
sender.reconnect();
|
|
782
|
+
}
|
|
783
|
+
})
|
|
784
|
+
.catch((error) => {
|
|
785
|
+
this._log.warn("Error getting sender to reconnect to");
|
|
786
|
+
});
|
|
787
|
+
}
|
|
788
|
+
}
|
|
759
789
|
// we want to wait a second between each reconnect try to not flood the server with reconnects
|
|
760
790
|
// in case of internal server issues.
|
|
761
791
|
(0, Helpers_1.sleep)(1000).then(() => {
|
|
@@ -765,7 +795,6 @@ class MTProtoSender {
|
|
|
765
795
|
}
|
|
766
796
|
}
|
|
767
797
|
async _reconnect() {
|
|
768
|
-
this._log.debug("Closing current connection...");
|
|
769
798
|
try {
|
|
770
799
|
this._log.warn("[Reconnect] Closing current connection...");
|
|
771
800
|
await this._disconnect();
|
|
@@ -779,6 +808,12 @@ class MTProtoSender {
|
|
|
779
808
|
console.error(err);
|
|
780
809
|
}
|
|
781
810
|
}
|
|
811
|
+
this._log.debug(`Adding ${this._sendQueue._pendingStates.length} old request to resend`);
|
|
812
|
+
for (let i = 0; i < this._sendQueue._pendingStates.length; i++) {
|
|
813
|
+
if (this._sendQueue._pendingStates[i].msgId != undefined) {
|
|
814
|
+
this._pendingState.set(this._sendQueue._pendingStates[i].msgId, this._sendQueue._pendingStates[i]);
|
|
815
|
+
}
|
|
816
|
+
}
|
|
782
817
|
this._sendQueue.clear();
|
|
783
818
|
this._state.reset();
|
|
784
819
|
const connection = this._connection;
|
|
@@ -805,6 +840,7 @@ class MTProtoSender {
|
|
|
805
840
|
exports.MTProtoSender = MTProtoSender;
|
|
806
841
|
MTProtoSender.DEFAULT_OPTIONS = {
|
|
807
842
|
logger: null,
|
|
843
|
+
reconnectRetries: Infinity,
|
|
808
844
|
retries: Infinity,
|
|
809
845
|
delay: 2000,
|
|
810
846
|
autoReconnect: true,
|