From 1d214b38e31ea516b3878fc676372b1e16c694f5 Mon Sep 17 00:00:00 2001 From: morethanwords Date: Mon, 26 Oct 2020 02:09:42 +0200 Subject: [PATCH] Maybe fixed network disconnect Fix audio waveform Fix video preview resolution in reply Fix USA country on auth page --- src/components/audio.ts | 20 +- src/components/chat/replyContainer.ts | 28 +- .../sidebarRight/tabs/sharedMedia.ts | 4 + src/countries.ts | 1 + src/lib/appManagers/appPhotosManager.ts | 12 +- src/lib/mtproto/apiManager.ts | 9 +- src/lib/mtproto/dcConfigurator.ts | 1 + src/lib/mtproto/networker.ts | 412 +++++++++--------- src/lib/mtproto/timeManager.ts | 18 +- src/lib/mtproto/tl_utils.ts | 97 ++--- src/lib/mtproto/transports/websocket.ts | 41 +- src/scss/partials/_chatBubble.scss | 6 +- src/scss/partials/_leftSidebar.scss | 2 + 13 files changed, 337 insertions(+), 314 deletions(-) diff --git a/src/components/audio.ts b/src/components/audio.ts index 361011f5..05628922 100644 --- a/src/components/audio.ts +++ b/src/components/audio.ts @@ -34,13 +34,17 @@ export function decodeWaveform(waveform: Uint8Array | number[]) { return new Uint8Array([]); } - var dataView = new DataView(waveform.buffer); - var result = new Uint8Array(valueCount); - for(var i = 0; i < valueCount; i++) { - var byteIndex = i * 5 / 8 | 0; - var bitShift = i * 5 % 8; - var value = dataView.getUint16(byteIndex, true); - result[i] = (value >> bitShift) & 0b00011111; + try { + var dataView = new DataView(waveform.buffer); + var result = new Uint8Array(valueCount); + for(var i = 0; i < valueCount; i++) { + var byteIndex = i * 5 / 8 | 0; + var bitShift = i * 5 % 8; + var value = dataView.getUint16(byteIndex, true); + result[i] = (value >> bitShift) & 0b00011111; + } + } catch(err) { + return new Uint8Array([]); } /* var byteIndex = (valueCount - 1) / 8 | 0; @@ -82,7 +86,7 @@ function wrapVoiceMessage(doc: MyDocument, audioEl: AudioElement, mid: number) { audioEl.append(svg, timeDiv); let waveform = (doc.attributes.find(attribute => attribute._ == 'documentAttributeAudio') as DocumentAttribute.documentAttributeAudio).waveform || new Uint8Array([]); - waveform = decodeWaveform(waveform.slice()); + waveform = decodeWaveform(waveform.slice(0, 63)); //console.log('decoded waveform:', waveform); diff --git a/src/components/chat/replyContainer.ts b/src/components/chat/replyContainer.ts index 7b21ecbe..67a505b8 100644 --- a/src/components/chat/replyContainer.ts +++ b/src/components/chat/replyContainer.ts @@ -31,11 +31,13 @@ export default class ReplyContainer extends DivAndCaption<(title: string, subtit //console.log('wrap reply', media); - if(media.photo || (media.document && ['video', 'sticker'].indexOf(media.document.type) !== -1)) { + if(media.photo || (media.document && ['video', 'sticker', 'gif'].indexOf(media.document.type) !== -1)) { + let good = false; const replyMedia = document.createElement('div'); replyMedia.classList.add(this.className + '-media'); if(media.document?.type == 'sticker') { + good = true; wrapSticker({ doc: media.document, div: replyMedia, @@ -48,22 +50,30 @@ export default class ReplyContainer extends DivAndCaption<(title: string, subtit } else { const photo = media.photo || media.document; - if(photo._ == 'document' || !photo.downloaded) { + const cacheContext = appPhotosManager.getCacheContext(photo); + + if(!cacheContext.downloaded) { const sizes = photo.sizes || photo.thumbs; if(sizes && sizes[0].bytes) { - appPhotosManager.setAttachmentPreview(sizes[0].bytes, replyMedia, false, true); + good = true; + renderImageFromUrl(replyMedia, appPhotosManager.getPreviewURLFromThumb(sizes[0])); } } const size = appPhotosManager.choosePhotoSize(photo, 32, 32/* mediaSizes.active.regular.width, mediaSizes.active.regular.height */); - appPhotosManager.preloadPhoto(photo, size) - .then(() => { - renderImageFromUrl(replyMedia, photo._ == 'photo' ? photo.url : appPhotosManager.getDocumentCachedThumb(photo.id).url); - }); + if(size._ != 'photoSizeEmpty') { + good = true; + appPhotosManager.preloadPhoto(photo, size) + .then(() => { + renderImageFromUrl(replyMedia, photo._ == 'photo' ? photo.url : appPhotosManager.getDocumentCachedThumb(photo.id).url); + }); + } } - this.content.prepend(this.mediaEl = replyMedia); - this.container.classList.add('is-media'); + if(good) { + this.content.prepend(this.mediaEl = replyMedia); + this.container.classList.add('is-media'); + } } } else { subtitle = subtitle ? RichTextProcessor.wrapEmojiText(subtitle) : ''; diff --git a/src/components/sidebarRight/tabs/sharedMedia.ts b/src/components/sidebarRight/tabs/sharedMedia.ts index 57980304..f9b070f4 100644 --- a/src/components/sidebarRight/tabs/sharedMedia.ts +++ b/src/components/sidebarRight/tabs/sharedMedia.ts @@ -202,6 +202,8 @@ export default class AppSharedMediaTab implements SliderTab { } public renderNewMessages(mids: number[]) { + if(this.init) return; // * not inited yet + mids = mids.slice().reverse(); // ! because it will be ascend sorted array for(const sharedMediaType of this.sharedMediaTypes) { const filtered = this.filterMessagesByType(mids, sharedMediaType); @@ -218,6 +220,8 @@ export default class AppSharedMediaTab implements SliderTab { } public deleteDeletedMessages(mids: number[]) { + if(this.init) return; // * not inited yet + for(const mid of mids) { for(const sharedMediaType of this.sharedMediaTypes) { if(!this.historiesStorage[this.peerID] || !this.historiesStorage[this.peerID][sharedMediaType]) continue; diff --git a/src/countries.ts b/src/countries.ts index 2c6372ee..962debf1 100644 --- a/src/countries.ts +++ b/src/countries.ts @@ -10,6 +10,7 @@ export type Country = { const Countries: Country[] = [{"phoneCode":"7 840","code":"AB","name":"Abkhazia","pattern":"","emoji":""},{"phoneCode":"93","code":"AF","name":"Afghanistan","pattern":"93 XXX XXX XXX","emoji":"๐Ÿ‡ฆ๐Ÿ‡ซ"},{"phoneCode":"358 18","code":"AX","name":"Aland Islands","pattern":"","emoji":"๐Ÿ‡ฆ๐Ÿ‡ฝ"},{"phoneCode":"355","code":"AL","name":"Albania","pattern":"355 XX XXX XXXX","emoji":"๐Ÿ‡ฆ๐Ÿ‡ฑ"},{"phoneCode":"213","code":"DZ","name":"Algeria","pattern":"213 XXX XX XX XX","emoji":"๐Ÿ‡ฉ๐Ÿ‡ฟ"},{"phoneCode":"1 684","code":"AS","name":"American Samoa","pattern":"1684 XXX XXXX","emoji":"๐Ÿ‡ฆ๐Ÿ‡ธ"},{"phoneCode":"376","code":"AD","name":"Andorra","pattern":"376 XX XX XX","emoji":"๐Ÿ‡ฆ๐Ÿ‡ฉ"},{"phoneCode":"244","code":"AO","name":"Angola","pattern":"244 XXX XXX XXX","emoji":"๐Ÿ‡ฆ๐Ÿ‡ด"},{"phoneCode":"1 264","code":"AI","name":"Anguilla","pattern":"1264 XXX XXXX","emoji":"๐Ÿ‡ฆ๐Ÿ‡ฎ"},{"phoneCode":"1 268","code":"AG","name":"Antigua & Barbuda","pattern":"1268 XXX XXXX","emoji":"๐Ÿ‡ฆ๐Ÿ‡ฌ"},{"phoneCode":"54","code":"AR","name":"Argentina","pattern":"","emoji":"๐Ÿ‡ฆ๐Ÿ‡ท"},{"phoneCode":"374","code":"AM","name":"Armenia","pattern":"374 XX XXX XXX","emoji":"๐Ÿ‡ฆ๐Ÿ‡ฒ"},{"phoneCode":"297","code":"AW","name":"Aruba","pattern":"297 XXX XXXX","emoji":"๐Ÿ‡ฆ๐Ÿ‡ผ"},{"phoneCode":"247","code":"SH","name":"Ascension","pattern":"290 XX XXX","emoji":"๐Ÿ‡ธ๐Ÿ‡ญ"},{"phoneCode":"61","code":"AU","name":"Australia","pattern":"61 XXX XXX XXX","emoji":"๐Ÿ‡ฆ๐Ÿ‡บ"},{"phoneCode":"672","code":"AU","name":"Australian External Territories","pattern":"61 XXX XXX XXX","emoji":"๐Ÿ‡ฆ๐Ÿ‡บ"},{"phoneCode":"43","code":"AT","name":"Austria","pattern":"","emoji":"๐Ÿ‡ฆ๐Ÿ‡น"},{"phoneCode":"994","code":"AZ","name":"Azerbaijan","pattern":"994 XX XXX XX XX","emoji":"๐Ÿ‡ฆ๐Ÿ‡ฟ"},{"phoneCode":"1 242","code":"BS","name":"Bahamas","pattern":"1242 XXX XXXX","emoji":"๐Ÿ‡ง๐Ÿ‡ธ"},{"phoneCode":"973","code":"BH","name":"Bahrain","pattern":"973 XXXX XXXX","emoji":"๐Ÿ‡ง๐Ÿ‡ญ"},{"phoneCode":"880","code":"BD","name":"Bangladesh","pattern":"","emoji":"๐Ÿ‡ง๐Ÿ‡ฉ"},{"phoneCode":"1 246","code":"BB","name":"Barbados","pattern":"1246 XXX XXXX","emoji":"๐Ÿ‡ง๐Ÿ‡ง"},{"phoneCode":"1 268","code":"AG","name":"Barbuda","pattern":"1268 XXX XXXX","emoji":"๐Ÿ‡ฆ๐Ÿ‡ฌ"},{"phoneCode":"375","code":"BY","name":"Belarus","pattern":"375 XX XXX XXXX","emoji":"๐Ÿ‡ง๐Ÿ‡พ"},{"phoneCode":"32","code":"BE","name":"Belgium","pattern":"32 XXX XX XX XX","emoji":"๐Ÿ‡ง๐Ÿ‡ช"},{"phoneCode":"501","code":"BZ","name":"Belize","pattern":"","emoji":"๐Ÿ‡ง๐Ÿ‡ฟ"},{"phoneCode":"229","code":"BJ","name":"Benin","pattern":"229 XX XXX XXX","emoji":"๐Ÿ‡ง๐Ÿ‡ฏ"},{"phoneCode":"1 441","code":"BM","name":"Bermuda","pattern":"1441 XXX XXXX","emoji":"๐Ÿ‡ง๐Ÿ‡ฒ"},{"phoneCode":"975","code":"BT","name":"Bhutan","pattern":"","emoji":"๐Ÿ‡ง๐Ÿ‡น"},{"phoneCode":"591","code":"BO","name":"Bolivia","pattern":"591 X XXX XXXX","emoji":"๐Ÿ‡ง๐Ÿ‡ด"},{"phoneCode":"599 7","code":"BQ","name":"Caribbean Netherlands","pattern":"","emoji":"๐Ÿ‡ง๐Ÿ‡ถ"},{"phoneCode":"387","code":"BA","name":"Bosnia & Herzegovina","pattern":"","emoji":"๐Ÿ‡ง๐Ÿ‡ฆ"},{"phoneCode":"267","code":"BW","name":"Botswana","pattern":"267 XX XXX XXX","emoji":"๐Ÿ‡ง๐Ÿ‡ผ"},{"phoneCode":"55","code":"BR","name":"Brazil","pattern":"55 XX XXXXX XXXX","emoji":"๐Ÿ‡ง๐Ÿ‡ท"},{"phoneCode":"246","code":"IO","name":"British Indian Ocean Territory","pattern":"246 XXX XXXX","emoji":"๐Ÿ‡ฎ๐Ÿ‡ด"},{"phoneCode":"1 284","code":"VG","name":"British Virgin Islands","pattern":"1284 XXX XXXX","emoji":"๐Ÿ‡ป๐Ÿ‡ฌ"},{"phoneCode":"673","code":"BN","name":"Brunei","pattern":"673 XXX XXXX","emoji":"๐Ÿ‡ง๐Ÿ‡ณ"},{"phoneCode":"359","code":"BG","name":"Bulgaria","pattern":"","emoji":"๐Ÿ‡ง๐Ÿ‡ฌ"},{"phoneCode":"226","code":"BF","name":"Burkina Faso","pattern":"226 XX XX XX XX","emoji":"๐Ÿ‡ง๐Ÿ‡ซ"},{"phoneCode":"95","code":"MM","name":"Myanmar (Burma)","pattern":"","emoji":"๐Ÿ‡ฒ๐Ÿ‡ฒ"},{"phoneCode":"257","code":"BI","name":"Burundi","pattern":"257 XX XX XXXX","emoji":"๐Ÿ‡ง๐Ÿ‡ฎ"},{"phoneCode":"855","code":"KH","name":"Cambodia","pattern":"","emoji":"๐Ÿ‡ฐ๐Ÿ‡ญ"},{"phoneCode":"237","code":"CM","name":"Cameroon","pattern":"237 XXXX XXXX","emoji":"๐Ÿ‡จ๐Ÿ‡ฒ"},{"phoneCode":"1","code":"CA","name":"Canada","pattern":"1 XXX XXX XXXX","emoji":"๐Ÿ‡จ๐Ÿ‡ฆ"},{"phoneCode":"238","code":"CV","name":"Cape Verde","pattern":"238 XXX XXXX","emoji":"๐Ÿ‡จ๐Ÿ‡ป"},{"phoneCode":"1 345","code":"KY","name":"Cayman Islands","pattern":"1345 XXX XXXX","emoji":"๐Ÿ‡ฐ๐Ÿ‡พ"},{"phoneCode":"236","code":"CF","name":"Central African Republic","pattern":"236 XX XX XX XX","emoji":"๐Ÿ‡จ๐Ÿ‡ซ"},{"phoneCode":"235","code":"TD","name":"Chad","pattern":"235 XX XX XX XX","emoji":"๐Ÿ‡น๐Ÿ‡ฉ"},{"phoneCode":"56","code":"CL","name":"Chile","pattern":"56 X XXXX XXXX","emoji":"๐Ÿ‡จ๐Ÿ‡ฑ"},{"phoneCode":"86","code":"CN","name":"China","pattern":"86 XXX XXXX XXXX","emoji":"๐Ÿ‡จ๐Ÿ‡ณ"},{"phoneCode":"61","code":"CX","name":"Christmas Island","pattern":"","emoji":"๐Ÿ‡จ๐Ÿ‡ฝ"},{"phoneCode":"61","code":"CC","name":"Cocos (Keeling) Islands","pattern":"","emoji":"๐Ÿ‡จ๐Ÿ‡จ"},{"phoneCode":"57","code":"CO","name":"Colombia","pattern":"57 XXX XXX XXXX","emoji":"๐Ÿ‡จ๐Ÿ‡ด"},{"phoneCode":"269","code":"KM","name":"Comoros","pattern":"269 XXX XXXX","emoji":"๐Ÿ‡ฐ๐Ÿ‡ฒ"},{"phoneCode":"242","code":"CG","name":"Congo - Brazzaville","pattern":"242 XX XXX XXXX","emoji":"๐Ÿ‡จ๐Ÿ‡ฌ"},{"phoneCode":"243","code":"CD","name":"Congo - Kinshasa","pattern":"243 XX XXX XXXX","emoji":"๐Ÿ‡จ๐Ÿ‡ฉ"},{"phoneCode":"682","code":"CK","name":"Cook Islands","pattern":"","emoji":"๐Ÿ‡จ๐Ÿ‡ฐ"},{"phoneCode":"506","code":"CR","name":"Costa Rica","pattern":"","emoji":"๐Ÿ‡จ๐Ÿ‡ท"},{"phoneCode":"225","code":"CI","name":"Cote dโ€™Ivoire","pattern":"225 XX XXX XXX","emoji":"๐Ÿ‡จ๐Ÿ‡ฎ"},{"phoneCode":"385","code":"HR","name":"Croatia","pattern":"","emoji":"๐Ÿ‡ญ๐Ÿ‡ท"},{"phoneCode":"53","code":"CU","name":"Cuba","pattern":"53 XXXX XXXX","emoji":"๐Ÿ‡จ๐Ÿ‡บ"},{"phoneCode":"599 9","code":"CW","name":"Curacao","pattern":"","emoji":"๐Ÿ‡จ๐Ÿ‡ผ"},{"phoneCode":"357","code":"CY","name":"Cyprus","pattern":"357 XXXX XXXX","emoji":"๐Ÿ‡จ๐Ÿ‡พ"},{"phoneCode":"420","code":"CZ","name":"Czech Republic","pattern":"","emoji":"๐Ÿ‡จ๐Ÿ‡ฟ"},{"phoneCode":"45","code":"DK","name":"Denmark","pattern":"45 XXXX XXXX","emoji":"๐Ÿ‡ฉ๐Ÿ‡ฐ"},{"phoneCode":"246","code":"DG","name":"Diego Garcia","pattern":"","emoji":"๐Ÿ‡ฉ๐Ÿ‡ฌ"},{"phoneCode":"253","code":"DJ","name":"Djibouti","pattern":"253 XX XX XX XX","emoji":"๐Ÿ‡ฉ๐Ÿ‡ฏ"},{"phoneCode":"1 767","code":"DM","name":"Dominica","pattern":"1767 XXX XXXX","emoji":"๐Ÿ‡ฉ๐Ÿ‡ฒ"},{"phoneCode":"1 809 and 1 829","code":"DO","name":"Dominican Republic","pattern":"1 XXX XXX XXXX","emoji":"๐Ÿ‡ฉ๐Ÿ‡ด"},{"phoneCode":"670","code":"TL","name":"Timor-Leste","pattern":"","emoji":"๐Ÿ‡น๐Ÿ‡ฑ"},{"phoneCode":"593","code":"EC","name":"Ecuador","pattern":"","emoji":"๐Ÿ‡ช๐Ÿ‡จ"},{"phoneCode":"20","code":"EG","name":"Egypt","pattern":"20 XX XXX XXXX","emoji":"๐Ÿ‡ช๐Ÿ‡ฌ"},{"phoneCode":"503","code":"SV","name":"El Salvador","pattern":"503 XXXX XXXX","emoji":"๐Ÿ‡ธ๐Ÿ‡ป"},{"phoneCode":"240","code":"GQ","name":"Equatorial Guinea","pattern":"240 XXX XXX XXX","emoji":"๐Ÿ‡ฌ๐Ÿ‡ถ"},{"phoneCode":"291","code":"ER","name":"Eritrea","pattern":"291 X XXX XXX","emoji":"๐Ÿ‡ช๐Ÿ‡ท"},{"phoneCode":"372","code":"EE","name":"Estonia","pattern":"","emoji":"๐Ÿ‡ช๐Ÿ‡ช"},{"phoneCode":"251","code":"ET","name":"Ethiopia","pattern":"251 XX XXX XXXX","emoji":"๐Ÿ‡ช๐Ÿ‡น"},{"phoneCode":"500","code":"FK","name":"Falkland Islands","pattern":"","emoji":"๐Ÿ‡ซ๐Ÿ‡ฐ"},{"phoneCode":"298","code":"FO","name":"Faroe Islands","pattern":"298 XXX XXX","emoji":"๐Ÿ‡ซ๐Ÿ‡ด"},{"phoneCode":"679","code":"FJ","name":"Fiji","pattern":"","emoji":"๐Ÿ‡ซ๐Ÿ‡ฏ"},{"phoneCode":"358","code":"FI","name":"Finland","pattern":"","emoji":"๐Ÿ‡ซ๐Ÿ‡ฎ"},{"phoneCode":"33","code":"FR","name":"France","pattern":"33 X XX XX XX XX","emoji":"๐Ÿ‡ซ๐Ÿ‡ท"},{"phoneCode":"594","code":"GF","name":"French Guiana","pattern":"","emoji":"๐Ÿ‡ฌ๐Ÿ‡ซ"},{"phoneCode":"689","code":"PF","name":"French Polynesia","pattern":"","emoji":"๐Ÿ‡ต๐Ÿ‡ซ"},{"phoneCode":"241","code":"GA","name":"Gabon","pattern":"241 X XX XX XX","emoji":"๐Ÿ‡ฌ๐Ÿ‡ฆ"},{"phoneCode":"220","code":"GM","name":"Gambia","pattern":"220 XXX XXXX","emoji":"๐Ÿ‡ฌ๐Ÿ‡ฒ"},{"phoneCode":"995","code":"GE","name":"Georgia","pattern":"","emoji":"๐Ÿ‡ฌ๐Ÿ‡ช"},{"phoneCode":"49","code":"DE","name":"Germany","pattern":"49 XXX XXXXXXXX","emoji":"๐Ÿ‡ฉ๐Ÿ‡ช"},{"phoneCode":"233","code":"GH","name":"Ghana","pattern":"","emoji":"๐Ÿ‡ฌ๐Ÿ‡ญ"},{"phoneCode":"350","code":"GI","name":"Gibraltar","pattern":"350 XXXX XXXX","emoji":"๐Ÿ‡ฌ๐Ÿ‡ฎ"},{"phoneCode":"30","code":"GR","name":"Greece","pattern":"30 XX XXXX XXXX","emoji":"๐Ÿ‡ฌ๐Ÿ‡ท"},{"phoneCode":"299","code":"GL","name":"Greenland","pattern":"299 XXX XXX","emoji":"๐Ÿ‡ฌ๐Ÿ‡ฑ"},{"phoneCode":"1 473","code":"GD","name":"Grenada","pattern":"1473 XXX XXXX","emoji":"๐Ÿ‡ฌ๐Ÿ‡ฉ"},{"phoneCode":"590","code":"GP","name":"Guadeloupe","pattern":"","emoji":"๐Ÿ‡ฌ๐Ÿ‡ต"},{"phoneCode":"1 671","code":"GU","name":"Guam","pattern":"1671 XXX XXXX","emoji":"๐Ÿ‡ฌ๐Ÿ‡บ"},{"phoneCode":"502","code":"GT","name":"Guatemala","pattern":"502 X XXX XXXX","emoji":"๐Ÿ‡ฌ๐Ÿ‡น"},{"phoneCode":"44","code":"GG","name":"Guernsey","pattern":"","emoji":"๐Ÿ‡ฌ๐Ÿ‡ฌ"},{"phoneCode":"224","code":"GN","name":"Guinea","pattern":"224 XXX XXX XXX","emoji":"๐Ÿ‡ฌ๐Ÿ‡ณ"},{"phoneCode":"245","code":"GW","name":"Guinea-Bissau","pattern":"245 XXX XXXX","emoji":"๐Ÿ‡ฌ๐Ÿ‡ผ"},{"phoneCode":"592","code":"GY","name":"Guyana","pattern":"","emoji":"๐Ÿ‡ฌ๐Ÿ‡พ"},{"phoneCode":"509","code":"HT","name":"Haiti","pattern":"","emoji":"๐Ÿ‡ญ๐Ÿ‡น"},{"phoneCode":"504","code":"HN","name":"Honduras","pattern":"504 XXXX XXXX","emoji":"๐Ÿ‡ญ๐Ÿ‡ณ"},{"phoneCode":"852","code":"HK","name":"Hong Kong SAR China","pattern":"","emoji":"๐Ÿ‡ญ๐Ÿ‡ฐ"},{"phoneCode":"36","code":"HU","name":"Hungary","pattern":"36 XX XXX XXXX","emoji":"๐Ÿ‡ญ๐Ÿ‡บ"},{"phoneCode":"354","code":"IS","name":"Iceland","pattern":"354 XXX XXXX","emoji":"๐Ÿ‡ฎ๐Ÿ‡ธ"},{"phoneCode":"91","code":"IN","name":"India","pattern":"91 XXXXX XXXXX","emoji":"๐Ÿ‡ฎ๐Ÿ‡ณ"},{"phoneCode":"62","code":"ID","name":"Indonesia","pattern":"","emoji":"๐Ÿ‡ฎ๐Ÿ‡ฉ"},{"phoneCode":"98","code":"IR","name":"Iran","pattern":"98 XXX XXX XXXX","emoji":"๐Ÿ‡ฎ๐Ÿ‡ท"},{"phoneCode":"964","code":"IQ","name":"Iraq","pattern":"964 XXX XXX XXXX","emoji":"๐Ÿ‡ฎ๐Ÿ‡ถ"},{"phoneCode":"353","code":"IE","name":"Ireland","pattern":"353 XX XXX XXXX","emoji":"๐Ÿ‡ฎ๐Ÿ‡ช"},{"phoneCode":"972","code":"IL","name":"Israel","pattern":"972 XX XXX XXXX","emoji":"๐Ÿ‡ฎ๐Ÿ‡ฑ"},{"phoneCode":"39","code":"IT","name":"Italy","pattern":"39 XXX XXX XXXX","emoji":"๐Ÿ‡ฎ๐Ÿ‡น"},{"phoneCode":"1 876","code":"JM","name":"Jamaica","pattern":"1876 XXX XXXX","emoji":"๐Ÿ‡ฏ๐Ÿ‡ฒ"},{"phoneCode":"47 79","code":"SJ","name":"Svalbard & Jan Mayen","pattern":"","emoji":"๐Ÿ‡ธ๐Ÿ‡ฏ"},{"phoneCode":"81","code":"JP","name":"Japan","pattern":"81 XX XXXX XXXX","emoji":"๐Ÿ‡ฏ๐Ÿ‡ต"},{"phoneCode":"44","code":"JE","name":"Jersey","pattern":"","emoji":"๐Ÿ‡ฏ๐Ÿ‡ช"},{"phoneCode":"962","code":"JO","name":"Jordan","pattern":"962 X XXXX XXXX","emoji":"๐Ÿ‡ฏ๐Ÿ‡ด"},{"phoneCode":"7 7","code":"KZ","name":"Kazakhstan","pattern":"7 XXX XXX XX XX","emoji":"๐Ÿ‡ฐ๐Ÿ‡ฟ"},{"phoneCode":"254","code":"KE","name":"Kenya","pattern":"254 XXX XXX XXX","emoji":"๐Ÿ‡ฐ๐Ÿ‡ช"},{"phoneCode":"686","code":"KI","name":"Kiribati","pattern":"","emoji":"๐Ÿ‡ฐ๐Ÿ‡ฎ"},{"phoneCode":"850","code":"KP","name":"North Korea","pattern":"","emoji":"๐Ÿ‡ฐ๐Ÿ‡ต"},{"phoneCode":"82","code":"KR","name":"South Korea","pattern":"","emoji":"๐Ÿ‡ฐ๐Ÿ‡ท"},{"phoneCode":"965","code":"KW","name":"Kuwait","pattern":"965 XXXX XXXX","emoji":"๐Ÿ‡ฐ๐Ÿ‡ผ"},{"phoneCode":"996","code":"KG","name":"Kyrgyzstan","pattern":"","emoji":"๐Ÿ‡ฐ๐Ÿ‡ฌ"},{"phoneCode":"856","code":"LA","name":"Laos","pattern":"","emoji":"๐Ÿ‡ฑ๐Ÿ‡ฆ"},{"phoneCode":"371","code":"LV","name":"Latvia","pattern":"371 XXX XXXXX","emoji":"๐Ÿ‡ฑ๐Ÿ‡ป"},{"phoneCode":"961","code":"LB","name":"Lebanon","pattern":"","emoji":"๐Ÿ‡ฑ๐Ÿ‡ง"},{"phoneCode":"266","code":"LS","name":"Lesotho","pattern":"266 XX XXX XXX","emoji":"๐Ÿ‡ฑ๐Ÿ‡ธ"},{"phoneCode":"231","code":"LR","name":"Liberia","pattern":"","emoji":"๐Ÿ‡ฑ๐Ÿ‡ท"},{"phoneCode":"218","code":"LY","name":"Libya","pattern":"218 XX XXX XXXX","emoji":"๐Ÿ‡ฑ๐Ÿ‡พ"},{"phoneCode":"423","code":"LI","name":"Liechtenstein","pattern":"","emoji":"๐Ÿ‡ฑ๐Ÿ‡ฎ"},{"phoneCode":"370","code":"LT","name":"Lithuania","pattern":"370 XXX XXXXX","emoji":"๐Ÿ‡ฑ๐Ÿ‡น"},{"phoneCode":"352","code":"LU","name":"Luxembourg","pattern":"","emoji":"๐Ÿ‡ฑ๐Ÿ‡บ"},{"phoneCode":"853","code":"MO","name":"Macau SAR China","pattern":"","emoji":"๐Ÿ‡ฒ๐Ÿ‡ด"},{"phoneCode":"389","code":"MK","name":"Macedonia","pattern":"","emoji":"๐Ÿ‡ฒ๐Ÿ‡ฐ"},{"phoneCode":"261","code":"MG","name":"Madagascar","pattern":"261 XX XX XXX XX","emoji":"๐Ÿ‡ฒ๐Ÿ‡ฌ"},{"phoneCode":"265","code":"MW","name":"Malawi","pattern":"","emoji":"๐Ÿ‡ฒ๐Ÿ‡ผ"},{"phoneCode":"60","code":"MM","name":"Malaysia","pattern":"","emoji":"๐Ÿ‡ฒ๐Ÿ‡ฒ"},{"phoneCode":"960","code":"MV","name":"Maldives","pattern":"","emoji":"๐Ÿ‡ฒ๐Ÿ‡ป"},{"phoneCode":"223","code":"ML","name":"Mali","pattern":"223 XXXX XXXX","emoji":"๐Ÿ‡ฒ๐Ÿ‡ฑ"},{"phoneCode":"356","code":"MT","name":"Malta","pattern":"356 XX XX XX XX","emoji":"๐Ÿ‡ฒ๐Ÿ‡น"},{"phoneCode":"692","code":"MH","name":"Marshall Islands","pattern":"","emoji":"๐Ÿ‡ฒ๐Ÿ‡ญ"},{"phoneCode":"596","code":"MQ","name":"Martinique","pattern":"","emoji":"๐Ÿ‡ฒ๐Ÿ‡ถ"},{"phoneCode":"222","code":"MR","name":"Mauritania","pattern":"222 XXXX XXXX","emoji":"๐Ÿ‡ฒ๐Ÿ‡ท"},{"phoneCode":"230","code":"MU","name":"Mauritius","pattern":"","emoji":"๐Ÿ‡ฒ๐Ÿ‡บ"},{"phoneCode":"262","code":"YT","name":"Mayotte","pattern":"","emoji":"๐Ÿ‡พ๐Ÿ‡น"},{"phoneCode":"52","code":"MX","name":"Mexico","pattern":"","emoji":"๐Ÿ‡ฒ๐Ÿ‡ฝ"},{"phoneCode":"691","code":"FM","name":"Micronesia","pattern":"","emoji":"๐Ÿ‡ซ๐Ÿ‡ฒ"},{"phoneCode":"373","code":"MD","name":"Moldova","pattern":"373 XX XXX XXX","emoji":"๐Ÿ‡ฒ๐Ÿ‡ฉ"},{"phoneCode":"377","code":"MC","name":"Monaco","pattern":"377 XXXX XXXX","emoji":"๐Ÿ‡ฒ๐Ÿ‡จ"},{"phoneCode":"976","code":"MN","name":"Mongolia","pattern":"","emoji":"๐Ÿ‡ฒ๐Ÿ‡ณ"},{"phoneCode":"382","code":"ME","name":"Montenegro","pattern":"","emoji":"๐Ÿ‡ฒ๐Ÿ‡ช"},{"phoneCode":"1 664","code":"MS","name":"Montserrat","pattern":"1664 XXX XXXX","emoji":"๐Ÿ‡ฒ๐Ÿ‡ธ"},{"phoneCode":"212","code":"MA","name":"Morocco","pattern":"212 XX XXX XXXX","emoji":"๐Ÿ‡ฒ๐Ÿ‡ฆ"},{"phoneCode":"258","code":"MZ","name":"Mozambique","pattern":"258 XX XXX XXXX","emoji":"๐Ÿ‡ฒ๐Ÿ‡ฟ"},{"phoneCode":"264","code":"NA","name":"Namibia","pattern":"264 XX XXX XXXX","emoji":"๐Ÿ‡ณ๐Ÿ‡ฆ"},{"phoneCode":"674","code":"NR","name":"Nauru","pattern":"","emoji":"๐Ÿ‡ณ๐Ÿ‡ท"},{"phoneCode":"977","code":"NP","name":"Nepal","pattern":"","emoji":"๐Ÿ‡ณ๐Ÿ‡ต"},{"phoneCode":"31","code":"NL","name":"Netherlands","pattern":"31 X XX XX XX XX","emoji":"๐Ÿ‡ณ๐Ÿ‡ฑ"},{"phoneCode":"687","code":"NC","name":"New Caledonia","pattern":"","emoji":"๐Ÿ‡ณ๐Ÿ‡จ"},{"phoneCode":"64","code":"NZ","name":"New Zealand","pattern":"","emoji":"๐Ÿ‡ณ๐Ÿ‡ฟ"},{"phoneCode":"505","code":"NI","name":"Nicaragua","pattern":"505 XXXX XXXX","emoji":"๐Ÿ‡ณ๐Ÿ‡ฎ"},{"phoneCode":"227","code":"NE","name":"Niger","pattern":"227 XX XX XX XX","emoji":"๐Ÿ‡ณ๐Ÿ‡ช"},{"phoneCode":"234","code":"NG","name":"Nigeria","pattern":"","emoji":"๐Ÿ‡ณ๐Ÿ‡ฌ"},{"phoneCode":"683","code":"NU","name":"Niue","pattern":"","emoji":"๐Ÿ‡ณ๐Ÿ‡บ"},{"phoneCode":"672","code":"NF","name":"Norfolk Island","pattern":"","emoji":"๐Ÿ‡ณ๐Ÿ‡ซ"},{"phoneCode":"1 670","code":"MP","name":"Northern Mariana Islands","pattern":"1670 XXX XXXX","emoji":"๐Ÿ‡ฒ๐Ÿ‡ต"},{"phoneCode":"47","code":"NO","name":"Norway","pattern":"47 XXXX XXXX","emoji":"๐Ÿ‡ณ๐Ÿ‡ด"},{"phoneCode":"968","code":"OM","name":"Oman","pattern":"968 XXXX XXXX","emoji":"๐Ÿ‡ด๐Ÿ‡ฒ"},{"phoneCode":"92","code":"PK","name":"Pakistan","pattern":"92 XXX XXX XXXX","emoji":"๐Ÿ‡ต๐Ÿ‡ฐ"},{"phoneCode":"680","code":"PW","name":"Palau","pattern":"","emoji":"๐Ÿ‡ต๐Ÿ‡ผ"},{"phoneCode":"970","code":"PS","name":"Palestinian Territories","pattern":"970 XXX XX XXXX","emoji":"๐Ÿ‡ต๐Ÿ‡ธ"},{"phoneCode":"507","code":"PA","name":"Panama","pattern":"507 XXXX XXXX","emoji":"๐Ÿ‡ต๐Ÿ‡ฆ"},{"phoneCode":"675","code":"PG","name":"Papua New Guinea","pattern":"","emoji":"๐Ÿ‡ต๐Ÿ‡ฌ"},{"phoneCode":"595","code":"PY","name":"Paraguay","pattern":"595 XXX XXX XXX","emoji":"๐Ÿ‡ต๐Ÿ‡พ"},{"phoneCode":"51","code":"PE","name":"Peru","pattern":"51 XXX XXX XXX","emoji":"๐Ÿ‡ต๐Ÿ‡ช"},{"phoneCode":"63","code":"PH","name":"Philippines","pattern":"63 XXX XXX XXXX","emoji":"๐Ÿ‡ต๐Ÿ‡ญ"},{"phoneCode":"64","code":"PN","name":"Pitcairn Islands","pattern":"","emoji":"๐Ÿ‡ต๐Ÿ‡ณ"},{"phoneCode":"48","code":"PL","name":"Poland","pattern":"48 XXX XXX XXX","emoji":"๐Ÿ‡ต๐Ÿ‡ฑ"},{"phoneCode":"351","code":"PT","name":"Portugal","pattern":"351 X XXXX XXXX","emoji":"๐Ÿ‡ต๐Ÿ‡น"},{"phoneCode":"1 787 and 1 939","code":"PR","name":"Puerto Rico","pattern":"1 XXX XXX XXXX","emoji":"๐Ÿ‡ต๐Ÿ‡ท"},{"phoneCode":"974","code":"QA","name":"Qatar","pattern":"","emoji":"๐Ÿ‡ถ๐Ÿ‡ฆ"},{"phoneCode":"262","code":"RE","name":"Reunion","pattern":"262 XXX XXX XXX","emoji":"๐Ÿ‡ท๐Ÿ‡ช"},{"phoneCode":"40","code":"RO","name":"Romania","pattern":"40 XXX XXX XXX","emoji":"๐Ÿ‡ท๐Ÿ‡ด"},{"phoneCode":"7","code":"RU","name":"Russia","pattern":"7 XXX XXX XX XX","emoji":"๐Ÿ‡ท๐Ÿ‡บ"},{"phoneCode":"250","code":"RW","name":"Rwanda","pattern":"250 XXX XXX XXX","emoji":"๐Ÿ‡ท๐Ÿ‡ผ"},{"phoneCode":"590","code":"BL","name":"St. Barthelemy","pattern":"","emoji":"๐Ÿ‡ง๐Ÿ‡ฑ"},{"phoneCode":"290","code":"SH","name":"St. Helena","pattern":"290 XX XXX","emoji":"๐Ÿ‡ธ๐Ÿ‡ญ"},{"phoneCode":"1 869","code":"KN","name":"St. Kitts & Nevis","pattern":"1869 XXX XXXX","emoji":"๐Ÿ‡ฐ๐Ÿ‡ณ"},{"phoneCode":"1 758","code":"LC","name":"St. Lucia","pattern":"1758 XXX XXXX","emoji":"๐Ÿ‡ฑ๐Ÿ‡จ"},{"phoneCode":"590","code":"MF","name":"St. Martin (France)","pattern":"","emoji":"๐Ÿ‡ฒ๐Ÿ‡ซ"},{"phoneCode":"508","code":"PM","name":"St. Pierre and Miquelon","pattern":"","emoji":"๐Ÿ‡ต๐Ÿ‡ฒ"},{"phoneCode":"1 784","code":"VC","name":"St. Vincent and the Grenadines","pattern":"1784 XXX XXXX","emoji":"๐Ÿ‡ป๐Ÿ‡จ"},{"phoneCode":"685","code":"WS","name":"Samoa","pattern":"","emoji":"๐Ÿ‡ผ๐Ÿ‡ธ"},{"phoneCode":"378","code":"SM","name":"San Marino","pattern":"378 XXX XXX XXXX","emoji":"๐Ÿ‡ธ๐Ÿ‡ฒ"},{"phoneCode":"239","code":"ST","name":"Sรฃo Tome & Principe","pattern":"239 XX XXXXX","emoji":"๐Ÿ‡ธ๐Ÿ‡น"},{"phoneCode":"966","code":"SA","name":"Saudi Arabia","pattern":"","emoji":"๐Ÿ‡ธ๐Ÿ‡ฆ"},{"phoneCode":"221","code":"SN","name":"Senegal","pattern":"221 XX XXX XXXX","emoji":"๐Ÿ‡ธ๐Ÿ‡ณ"},{"phoneCode":"381","code":"RS","name":"Serbia","pattern":"381 XX XXX XXXX","emoji":"๐Ÿ‡ท๐Ÿ‡ธ"},{"phoneCode":"248","code":"SC","name":"Seychelles","pattern":"248 X XX XX XX","emoji":"๐Ÿ‡ธ๐Ÿ‡จ"},{"phoneCode":"232","code":"SL","name":"Sierra Leone","pattern":"232 XX XXX XXX","emoji":"๐Ÿ‡ธ๐Ÿ‡ฑ"},{"phoneCode":"65","code":"SG","name":"Singapore","pattern":"65 XXXX XXXX","emoji":"๐Ÿ‡ธ๐Ÿ‡ฌ"},{"phoneCode":"599 3","code":"BQ","name":"Sint Eustatius","pattern":"","emoji":"๐Ÿ‡ง๐Ÿ‡ถ"},{"phoneCode":"1 721","code":"SX","name":"Sint Maarten","pattern":"1721 XXX XXXX","emoji":"๐Ÿ‡ธ๐Ÿ‡ฝ"},{"phoneCode":"421","code":"SK","name":"Slovakia","pattern":"","emoji":"๐Ÿ‡ธ๐Ÿ‡ฐ"},{"phoneCode":"386","code":"SI","name":"Slovenia","pattern":"","emoji":"๐Ÿ‡ธ๐Ÿ‡ฎ"},{"phoneCode":"677","code":"SB","name":"Solomon Islands","pattern":"","emoji":"๐Ÿ‡ธ๐Ÿ‡ง"},{"phoneCode":"252","code":"SO","name":"Somalia","pattern":"252 XX XXX XXX","emoji":"๐Ÿ‡ธ๐Ÿ‡ด"},{"phoneCode":"27","code":"ZA","name":"South Africa","pattern":"27 XX XXX XXXX","emoji":"๐Ÿ‡ฟ๐Ÿ‡ฆ"},{"phoneCode":"500","code":"GS","name":"South Georgia & South Sandwich Islands","pattern":"","emoji":"๐Ÿ‡ฌ๐Ÿ‡ธ"},{"phoneCode":"995 34","code":"","name":"South Ossetia","pattern":"","emoji":""},{"phoneCode":"211","code":"SS","name":"South Sudan","pattern":"211 XX XXX XXXX","emoji":"๐Ÿ‡ธ๐Ÿ‡ธ"},{"phoneCode":"34","code":"ES","name":"Spain","pattern":"34 XXX XXX XXX","emoji":"๐Ÿ‡ช๐Ÿ‡ธ"},{"phoneCode":"94","code":"LK","name":"Sri Lanka","pattern":"94 XX XXX XXXX","emoji":"๐Ÿ‡ฑ๐Ÿ‡ฐ"},{"phoneCode":"249","code":"SD","name":"Sudan","pattern":"249 XX XXX XXXX","emoji":"๐Ÿ‡ธ๐Ÿ‡ฉ"},{"phoneCode":"597","code":"SR","name":"Suriname","pattern":"597 XXX XXXX","emoji":"๐Ÿ‡ธ๐Ÿ‡ท"},{"phoneCode":"47 79","code":"SJ","name":"Svalbard","pattern":"","emoji":"๐Ÿ‡ธ๐Ÿ‡ฏ"},{"phoneCode":"268","code":"SZ","name":"Swaziland","pattern":"268 XXXX XXXX","emoji":"๐Ÿ‡ธ๐Ÿ‡ฟ"},{"phoneCode":"46","code":"SE","name":"Sweden","pattern":"46 XX XXX XXXX","emoji":"๐Ÿ‡ธ๐Ÿ‡ช"},{"phoneCode":"41","code":"CH","name":"Switzerland","pattern":"41 XX XXX XXXX","emoji":"๐Ÿ‡จ๐Ÿ‡ญ"},{"phoneCode":"963","code":"SY","name":"Syria","pattern":"","emoji":"๐Ÿ‡ธ๐Ÿ‡พ"},{"phoneCode":"886","code":"TW","name":"Taiwan","pattern":"","emoji":"๐Ÿ‡น๐Ÿ‡ผ"},{"phoneCode":"992","code":"TJ","name":"Tajikistan","pattern":"","emoji":"๐Ÿ‡น๐Ÿ‡ฏ"},{"phoneCode":"255","code":"TZ","name":"Tanzania","pattern":"255 XX XXX XXXX","emoji":"๐Ÿ‡น๐Ÿ‡ฟ"},{"phoneCode":"66","code":"TH","name":"Thailand","pattern":"66 X XXXX XXXX","emoji":"๐Ÿ‡น๐Ÿ‡ญ"},{"phoneCode":"228","code":"TG","name":"Togo","pattern":"228 XX XXX XXX","emoji":"๐Ÿ‡น๐Ÿ‡ฌ"},{"phoneCode":"690","code":"TK","name":"Tokelau","pattern":"","emoji":"๐Ÿ‡น๐Ÿ‡ฐ"},{"phoneCode":"676","code":"TO","name":"Tonga","pattern":"","emoji":"๐Ÿ‡น๐Ÿ‡ด"},{"phoneCode":"1 868","code":"TT","name":"Trinidad & Tobago","pattern":"1868 XXX XXXX","emoji":"๐Ÿ‡น๐Ÿ‡น"},{"phoneCode":"216","code":"TN","name":"Tunisia","pattern":"216 XX XXX XXX","emoji":"๐Ÿ‡น๐Ÿ‡ณ"},{"phoneCode":"90","code":"TR","name":"Turkey","pattern":"90 XXX XXX XXXX","emoji":"๐Ÿ‡น๐Ÿ‡ท"},{"phoneCode":"993","code":"TM","name":"Turkmenistan","pattern":"993 XX XXXXXX","emoji":"๐Ÿ‡น๐Ÿ‡ฒ"},{"phoneCode":"1 649","code":"TC","name":"Turks & Caicos Islands","pattern":"1649 XXX XXXX","emoji":"๐Ÿ‡น๐Ÿ‡จ"},{"phoneCode":"688","code":"TV","name":"Tuvalu","pattern":"","emoji":"๐Ÿ‡น๐Ÿ‡ป"},{"phoneCode":"256","code":"UG","name":"Uganda","pattern":"256 XX XXX XXXX","emoji":"๐Ÿ‡บ๐Ÿ‡ฌ"},{"phoneCode":"380","code":"UA","name":"Ukraine","pattern":"380 XX XXX XX XX","emoji":"๐Ÿ‡บ๐Ÿ‡ฆ"},{"phoneCode":"971","code":"AE","name":"United Arab Emirates","pattern":"971 XX XXX XXXX","emoji":"๐Ÿ‡ฆ๐Ÿ‡ช"},{"phoneCode":"44","code":"GB","name":"United Kingdom","pattern":"44 XXXX XXXXXX","emoji":"๐Ÿ‡ฌ๐Ÿ‡ง"},{"phoneCode":"1","code":"US","name":"United States","pattern":"1 XXX XXX XXXX","emoji":"๐Ÿ‡บ๐Ÿ‡ธ"},{"phoneCode":"598","code":"UY","name":"Uruguay","pattern":"598 XXXX XXXX","emoji":"๐Ÿ‡บ๐Ÿ‡พ"},{"phoneCode":"1 340","code":"VI","name":"U.S. Virgin Islands","pattern":"1340 XXX XXXX","emoji":"๐Ÿ‡ป๐Ÿ‡ฎ"},{"phoneCode":"998","code":"UZ","name":"Uzbekistan","pattern":"998 XX XXXXXXX","emoji":"๐Ÿ‡บ๐Ÿ‡ฟ"},{"phoneCode":"678","code":"VU","name":"Vanuatu","pattern":"","emoji":"๐Ÿ‡ป๐Ÿ‡บ"},{"phoneCode":"58","code":"VE","name":"Venezuela","pattern":"58 XXX XXX XXXX","emoji":"๐Ÿ‡ป๐Ÿ‡ช"},{"phoneCode":"39 06 698","code":"VA","name":"Vatican City","pattern":"","emoji":"๐Ÿ‡ป๐Ÿ‡ฆ"},{"phoneCode":"84","code":"VN","name":"Vietnam","pattern":"","emoji":"๐Ÿ‡ป๐Ÿ‡ณ"},{"phoneCode":"681","code":"WF","name":"Wallis & Futuna","pattern":"","emoji":"๐Ÿ‡ผ๐Ÿ‡ซ"},{"phoneCode":"967","code":"YE","name":"Yemen","pattern":"967 XXX XXX XXX","emoji":"๐Ÿ‡พ๐Ÿ‡ช"},{"phoneCode":"260","code":"ZM","name":"Zambia","pattern":"260 XX XXX XXXX","emoji":"๐Ÿ‡ฟ๐Ÿ‡ฒ"},{"phoneCode":"255","code":"","name":"Zanzibar","pattern":"","emoji":""},{"phoneCode":"263","code":"ZW","name":"Zimbabwe","pattern":"263 XX XXX XXXX","emoji":"๐Ÿ‡ฟ๐Ÿ‡ผ"}]; const PhoneCodesMain: {[phoneCode: string]: Country} = { + '1': Countries.find(c => c.name == 'United States'), '44': Countries.find(c => c.name == 'United Kingdom'), '61': Countries.find(c => c.name == 'Australia'), '64': Countries.find(c => c.name == 'New Zealand'), diff --git a/src/lib/appManagers/appPhotosManager.ts b/src/lib/appManagers/appPhotosManager.ts index a61c3455..5af6739b 100644 --- a/src/lib/appManagers/appPhotosManager.ts +++ b/src/lib/appManagers/appPhotosManager.ts @@ -15,15 +15,17 @@ export type MyPhoto = Photo.photo; // TIMES = 2 DUE TO SIDEBAR AND CHAT //let TEST_FILE_REFERENCE = "5440692274120994569", TEST_FILE_REFERENCE_TIMES = 2; +type DocumentCacheThumb = { + downloaded: number, + url: string +}; + export class AppPhotosManager { private photos: { [id: string]: MyPhoto } = {}; private documentThumbsCache: { - [docID: string]: { - downloaded: number, - url: string - } + [docID: string]: DocumentCacheThumb } = {}; public windowW = 0; public windowH = 0; @@ -294,7 +296,7 @@ export class AppPhotosManager { return download; } - public getCacheContext(photo: any) { + public getCacheContext(photo: any): DocumentCacheThumb { return photo._ == 'document' ? this.getDocumentCachedThumb(photo.id) : photo; } diff --git a/src/lib/mtproto/apiManager.ts b/src/lib/mtproto/apiManager.ts index ed5bcb9b..99cab370 100644 --- a/src/lib/mtproto/apiManager.ts +++ b/src/lib/mtproto/apiManager.ts @@ -48,6 +48,8 @@ export class ApiManager { private log: ReturnType = logger('API'); private afterMessageTempIDs: {[tempID: string]: string} = {}; + + //private lol = false; constructor() { //MtpSingleInstanceService.start(); @@ -193,6 +195,11 @@ export class ApiManager { public invokeApi(method: T, params: MethodDeclMap[T]['req'] = {}, options: InvokeApiOptions = {}): CancellablePromise { ///////this.log('Invoke api', method, params, options); + /* if(!this.lol) { + networkerFactory.updatesProcessor({_: 'new_session_created'}, true); + this.lol = true; + } */ + const deferred = deferredPromise(); const afterMessageIDTemp = options.afterMessageID; @@ -211,7 +218,7 @@ export class ApiManager { const interval = MOUNT_CLASS_TO.setInterval(() => { this.log.error('Request is still processing:', method, params, options, 'time:', (Date.now() - startTime) / 1000); //this.cachedUploadNetworkers[2].requestMessageStatus(); - }, 30e3); + }, 5e3); } const rejectPromise = (error: ApiError) => { diff --git a/src/lib/mtproto/dcConfigurator.ts b/src/lib/mtproto/dcConfigurator.ts index c880ce38..4caec670 100644 --- a/src/lib/mtproto/dcConfigurator.ts +++ b/src/lib/mtproto/dcConfigurator.ts @@ -47,6 +47,7 @@ export class DcConfigurator { const subdomain = this.sslSubdomains[dcID - 1]; const path = Modes.test ? 'apiws_test' : 'apiws'; const chosenServer = 'wss://' + subdomain + '.web.telegram.org/' + path; + const suffix = connectionType == 'upload' ? '-U' : connectionType == 'download' ? '-D' : ''; return new Socket(dcID, chosenServer, connectionType != 'client' ? '-U' : ''); }; diff --git a/src/lib/mtproto/networker.ts b/src/lib/mtproto/networker.ts index 3d972f66..4b6106ef 100644 --- a/src/lib/mtproto/networker.ts +++ b/src/lib/mtproto/networker.ts @@ -30,10 +30,10 @@ import Socket from './transports/websocket'; //console.error('networker included!', new Error().stack); export type MTMessageOptions = InvokeApiOptions & Partial<{ - noResponse: true, + noResponse: true, // http_wait longPoll: true, - notContentRelated: true, + notContentRelated: true, // ACK noSchedule: true, messageID: string, }>; @@ -114,13 +114,15 @@ export default class MTPNetworker { //console.trace('Create', dcID, options); + const suffix = this.options.fileUpload ? '-U' : this.options.fileDownload ? '-D' : ''; this.upload = this.options.fileUpload || this.options.fileDownload; - //this.log = logger('NET-' + dcID + (this.upload ? '-U' : ''), this.upload && this.dcID == 2 ? LogLevels.debug | LogLevels.warn | LogLevels.log | LogLevels.error : LogLevels.error); - this.log = logger('NET-' + dcID + (this.upload ? '-U' : ''), LogLevels.log | LogLevels.error); + //this.log = logger('NET-' + dcID + suffix, this.upload && this.dcID == 1 ? LogLevels.debug | LogLevels.warn | LogLevels.log | LogLevels.error : LogLevels.error); + this.log = logger('NET-' + dcID + suffix, LogLevels.log | LogLevels.error); this.log('constructor'/* , this.authKey, this.authKeyID, this.serverSalt */); - /* // Test resend after bad_server_salt - if(this.dcID == 1 && this.upload) { + // Test resend after bad_server_salt + /* if(this.dcID == 1 && this.upload) { + timeManager.applyServerTime((Date.now() / 1000 - 86400) | 0); this.serverSalt[0] = 0; } */ @@ -134,14 +136,14 @@ export default class MTPNetworker { /// #if MTPROTO_HTTP_UPLOAD if(this.transport instanceof HTTP) { - /* this.longPollInt = */setInterval(this.checkLongPoll.bind(this), 10000); + /* this.longPollInt = */setInterval(this.checkLongPoll, 10000); this.checkLongPoll(); } else { (this.transport as Socket).networker = this; } /// #elif MTPROTO_HTTP //if(this.transport instanceof HTTP) { - /* this.longPollInt = */setInterval(this.checkLongPoll.bind(this), 10000); + /* this.longPollInt = */setInterval(this.checkLongPoll, 10000); this.checkLongPoll(); /// #else //} else { @@ -161,6 +163,7 @@ export default class MTPNetworker { if(!sentMessage) { return false; } + if(sentMessage.container) { const newInner: string[] = []; sentMessage.inner.forEach((innerSentMessageID) => { @@ -168,15 +171,16 @@ export default class MTPNetworker { if(innerSentMessage) { newInner.push(innerSentMessage.msg_id); } - }) + }); + sentMessage.inner = newInner; } sentMessage.msg_id = timeManager.generateID(); - sentMessage.seq_no = this.generateSeqNo( - sentMessage.notContentRelated || - sentMessage.container - ); + sentMessage.seq_no = this.generateSeqNo(sentMessage.notContentRelated || sentMessage.container); + + this.log('updateSentMessage', sentMessage.msg_id, sentMessageID); + this.sentMessages[sentMessage.msg_id] = sentMessage; delete this.sentMessages[sentMessageID]; @@ -234,19 +238,19 @@ export default class MTPNetworker { } public wrapApiCall(method: string, params: any = {}, options: InvokeApiOptions = {}) { - let serializer = new TLSerialization(options); + const serializer = new TLSerialization(options); if(!this.connectionInited) { // this will call once for each new session ///////this.log('Wrap api call !this.connectionInited'); - let invokeWithLayer = Schema.API.methods.find(m => m.method == 'invokeWithLayer'); + const invokeWithLayer = Schema.API.methods.find(m => m.method == 'invokeWithLayer'); if(!invokeWithLayer) throw new Error('no invokeWithLayer!'); serializer.storeInt(+invokeWithLayer.id >>> 0, 'invokeWithLayer'); // @ts-ignore serializer.storeInt(Schema.layer, 'layer'); - let initConnection = Schema.API.methods.find(m => m.method == 'initConnection'); + const initConnection = Schema.API.methods.find(m => m.method == 'initConnection'); if(!initConnection) throw new Error('no initConnection!'); serializer.storeInt(+initConnection.id >>> 0, 'initConnection'); @@ -272,7 +276,7 @@ export default class MTPNetworker { } if(options.afterMessageID) { - let invokeAfterMsg = Schema.API.methods.find(m => m.method == 'invokeAfterMsg'); + const invokeAfterMsg = Schema.API.methods.find(m => m.method == 'invokeAfterMsg'); if(!invokeAfterMsg) throw new Error('no invokeAfterMsg!'); this.log('Api call options.afterMessageID!'); @@ -286,9 +290,9 @@ export default class MTPNetworker { this.log('api call body:', serializer.getBytes(true)); } */ - var messageID = timeManager.generateID(); - var seqNo = this.generateSeqNo(); - var message = { + const messageID = timeManager.generateID(); + const seqNo = this.generateSeqNo(); + const message = { msg_id: messageID, seq_no: seqNo, body: serializer.getBytes(true), @@ -305,7 +309,7 @@ export default class MTPNetworker { } /// #if MTPROTO_HTTP || MTPROTO_HTTP_UPLOAD - public checkLongPoll() { + public checkLongPoll = () => { const isClean = this.cleanupSent(); //this.log.error('Check lp', this.longPollPending, this.dcID, isClean, this); if((this.longPollPending && Date.now() < this.longPollPending) || @@ -326,10 +330,10 @@ export default class MTPNetworker { this.sendLongPoll(); }); - } + }; public sendLongPoll() { - let maxWait = 25000; + const maxWait = 25000; this.longPollPending = Date.now() + maxWait; //this.log('Set lp', this.longPollPending, tsNow()) @@ -343,7 +347,7 @@ export default class MTPNetworker { longPoll: true }).then(() => { this.longPollPending = 0; - setTimeout(this.checkLongPoll.bind(this), 0); + setTimeout(this.checkLongPoll, 0); }, (error: ErrorEvent) => { this.log('Long-poll failed', error); }); @@ -356,29 +360,26 @@ export default class MTPNetworker { clearTimeout(this.checkConnectionTimeout); this.checkConnectionTimeout = 0; - var serializer = new TLSerialization({mtproto: true}); - var pingID = [nextRandomInt(0xFFFFFFFF), nextRandomInt(0xFFFFFFFF)]; + const serializer = new TLSerialization({mtproto: true}); + const pingID = [nextRandomInt(0xFFFFFFFF), nextRandomInt(0xFFFFFFFF)]; serializer.storeMethod('ping', { ping_id: pingID }); - var pingMessage = { + const pingMessage = { msg_id: timeManager.generateID(), seq_no: this.generateSeqNo(true), body: serializer.getBytes() }; - - var self = this; - this.sendEncryptedRequest(pingMessage, { - timeout: 15000 - }).then((result) => { + + this.sendEncryptedRequest(pingMessage).then((result) => { /* delete $rootScope.offlineConnecting */ - self.toggleOffline(false); + this.toggleOffline(false); }, () => { - this.log('Delay ', self.checkConnectionPeriod * 1000); - self.checkConnectionTimeout = setTimeout(self.checkConnection.bind(self), self.checkConnectionPeriod * 1000 | 0); - self.checkConnectionPeriod = Math.min(60, self.checkConnectionPeriod * 1.5); + this.log('Delay ', this.checkConnectionPeriod * 1000); + this.checkConnectionTimeout = setTimeout(this.checkConnection, this.checkConnectionPeriod * 1000 | 0); + this.checkConnectionPeriod = Math.min(60, this.checkConnectionPeriod * 1.5); /* setTimeout(function() { delete $rootScope.offlineConnecting }, 1000); */ @@ -404,7 +405,7 @@ export default class MTPNetworker { this.checkConnectionPeriod = 0; } - this.checkConnectionTimeout = setTimeout(this.checkConnection.bind(this), this.checkConnectionPeriod * 1000 | 0); + this.checkConnectionTimeout = setTimeout(this.checkConnection, this.checkConnectionPeriod * 1000 | 0); this.checkConnectionPeriod = Math.min(30, (1 + this.checkConnectionPeriod) * 1.5); document.body.addEventListener('online', this.checkConnection, false); @@ -430,14 +431,14 @@ export default class MTPNetworker { // this.log('parse for', message) this.parseResponse(result).then((response) => { if(Modes.debug) { - this.log('Server response', this.dcID, response); + this.log('Server response', response); } this.processMessage(response.response, response.messageID, response.sessionID); noResponseMsgs.forEach((msgID) => { if(this.sentMessages[msgID]) { - var deferred = this.sentMessages[msgID].deferred; + const deferred = this.sentMessages[msgID].deferred; delete this.sentMessages[msgID]; deferred.resolve(); } @@ -462,7 +463,7 @@ export default class MTPNetworker { noResponseMsgs.forEach((msgID) => { if(this.sentMessages[msgID]) { - var deferred = this.sentMessages[msgID].deferred; + const deferred = this.sentMessages[msgID].deferred; delete this.sentMessages[msgID]; delete this.pendingMessages[msgID]; deferred.reject(); @@ -504,14 +505,14 @@ export default class MTPNetworker { const value = delay ? Date.now() + delay : 0; const sentMessage = this.sentMessages[messageID]; if(sentMessage.container) { - for(let i = 0, length = sentMessage.inner.length; i < length; i++) { - this.pendingMessages[sentMessage.inner[i]] = value; + for(const innerMsgID of sentMessage.inner) { + this.pendingMessages[innerMsgID] = value; } } else { this.pendingMessages[messageID] = value; } - this.log('Resend due', messageID, this.pendingMessages); + this.log('Resend', messageID, sentMessage, this.pendingMessages); this.scheduleRequest(delay); } @@ -527,11 +528,11 @@ export default class MTPNetworker { }; public getAesKeyIv(msgKey: Uint8Array | number[], isOut: boolean): Promise<[Uint8Array, Uint8Array]> { - var authKey = this.authKeyUint8; - var x = isOut ? 0 : 8; - var sha2aText = new Uint8Array(52); - var sha2bText = new Uint8Array(52); - var promises: Array> = []; + const authKey = this.authKeyUint8; + const x = isOut ? 0 : 8; + const sha2aText = new Uint8Array(52); + const sha2bText = new Uint8Array(52); + const promises: Array> = []; sha2aText.set(msgKey, 0); sha2aText.set(authKey.subarray(x, x + 36), 16); @@ -542,10 +543,10 @@ export default class MTPNetworker { promises.push(CryptoWorker.sha256Hash(sha2bText)); return Promise.all(promises).then((results) => { - var aesKey = new Uint8Array(32); - var aesIv = new Uint8Array(32); - var sha2a = new Uint8Array(results[0]); - var sha2b = new Uint8Array(results[1]); + const aesKey = new Uint8Array(32); + const aesIv = new Uint8Array(32); + const sha2a = new Uint8Array(results[0]); + const sha2b = new Uint8Array(results[1]); aesKey.set(sha2a.subarray(0, 8)); aesKey.set(sha2b.subarray(8, 24), 8); @@ -559,7 +560,7 @@ export default class MTPNetworker { }); } - public performScheduledRequest() { + public performScheduledRequest = () => { // this.log('scheduled', this.dcID, this.iii) /// #if MTPROTO_HTTP || MTPROTO_HTTP_UPLOAD @@ -604,24 +605,23 @@ export default class MTPNetworker { }; } - var message: MTPNetworker['sentMessages'][keyof MTPNetworker['sentMessages']]; - var messages: typeof message[] = []; + let message: MTPNetworker['sentMessages'][keyof MTPNetworker['sentMessages']]; + const messages: typeof message[] = []; - var messagesByteLen = 0; - var currentTime = Date.now(); - var hasApiCall = false; - var hasHttpWait = false; - var lengthOverflow = false; - var singlesCount = 0; - var self = this; - - for(let messageID in this.pendingMessages) { - let value = this.pendingMessages[messageID]; + const currentTime = Date.now(); + let messagesByteLen = 0; + let hasApiCall = false; + let hasHttpWait = false; + let lengthOverflow = false; + let singlesCount = 0; + + for(const messageID in this.pendingMessages) { + const value = this.pendingMessages[messageID]; if(!value || value >= currentTime) { if(message = this.sentMessages[messageID]) { //this.log('performScheduledRequest message:', message); - var messageByteLength = (/* message.body.byteLength || */message.body.length) + 32; + const messageByteLength = (/* message.body.byteLength || */message.body.length) + 32; if(!message.notContentRelated && lengthOverflow) { continue; // maybe break here @@ -653,7 +653,7 @@ export default class MTPNetworker { // this.log(message, messageID) } - delete self.pendingMessages[messageID]; + delete this.pendingMessages[messageID]; } } @@ -662,7 +662,7 @@ export default class MTPNetworker { /// #endif /// #if MTPROTO_HTTP || MTPROTO_HTTP_UPLOAD if(hasApiCall && !hasHttpWait) { - var serializer = new TLSerialization({mtproto: true}); + const serializer = new TLSerialization({mtproto: true}); serializer.storeMethod('http_wait', { max_delay: 500, wait_after: 150, @@ -682,10 +682,10 @@ export default class MTPNetworker { return; } - var noResponseMsgs: Array = []; + const noResponseMsgs: Array = []; if(messages.length > 1) { - var container = new TLSerialization({ + const container = new TLSerialization({ mtproto: true, startMaxLength: messagesByteLen + 64 }); @@ -693,7 +693,7 @@ export default class MTPNetworker { container.storeInt(0x73f1f8dc, 'CONTAINER[id]'); container.storeInt(messages.length, 'CONTAINER[count]'); - var innerMessages: string[] = []; + const innerMessages: string[] = []; messages.forEach((message, i) => { container.storeLong(message.msg_id, 'CONTAINER[' + i + '][msg_id]'); innerMessages.push(message.msg_id); @@ -705,7 +705,7 @@ export default class MTPNetworker { } }); - var containerSentMessage: MTMessage = { + const containerSentMessage: MTMessage = { msg_id: timeManager.generateID(), seq_no: this.generateSeqNo(true), container: true, @@ -731,17 +731,19 @@ export default class MTPNetworker { this.pendingAcks = []; - let promise = this.sendEncryptedRequest(message); + const promise = this.sendEncryptedRequest(message); /// #if MTPROTO_HTTP_UPLOAD if(!(this.transport instanceof HTTP)) { if(noResponseMsgs.length) this.log.error('noResponseMsgs length!', noResponseMsgs); + this.cleanupSent(); // ! WARNING } else { this.handleSentEncryptedRequestHTTP(promise, message, noResponseMsgs); } /// #elif !MTPROTO_HTTP //if(!(this.transport instanceof HTTP)) { if(noResponseMsgs.length) this.log.error('noResponseMsgs length!', noResponseMsgs); + this.cleanupSent(); // ! WARNING //} else { /// #else this.handleSentEncryptedRequestHTTP(promise, message, noResponseMsgs); @@ -751,14 +753,14 @@ export default class MTPNetworker { if(lengthOverflow || singlesCount > 1) { this.scheduleRequest(); } - } + }; public async getEncryptedMessage(dataWithPadding: ArrayBuffer) { - let msgKey = await this.getMsgKey(dataWithPadding, true); - let keyIv = await this.getAesKeyIv(msgKey, true); + const msgKey = await this.getMsgKey(dataWithPadding, true); + const keyIv = await this.getAesKeyIv(msgKey, true); // this.log('after msg key iv') - let encryptedBytes = await CryptoWorker.aesEncrypt(dataWithPadding, keyIv[0], keyIv[1]); + const encryptedBytes = await CryptoWorker.aesEncrypt(dataWithPadding, keyIv[0], keyIv[1]); // this.log('Finish encrypt') return { @@ -775,10 +777,8 @@ export default class MTPNetworker { }); } - public sendEncryptedRequest(message: MTMessage, options: any = {}) { - const self = this; - - this.log.debug('Send encrypted', message, options, this.authKeyID); + public sendEncryptedRequest(message: MTMessage) { + this.log.debug('Send encrypted', message, this.authKeyID); // console.trace() const data = new TLSerialization({ startMaxLength: message.body.length + 2048 @@ -813,7 +813,7 @@ export default class MTPNetworker { const request = new TLSerialization({ startMaxLength: encryptedResult.bytes.length + 256 }); - request.storeIntBytes(self.authKeyID, 64, 'auth_key_id'); + request.storeIntBytes(this.authKeyID, 64, 'auth_key_id'); request.storeIntBytes(encryptedResult.msgKey, 128, 'msg_key'); request.storeRawBytes(encryptedResult.bytes, 'encrypted_data'); @@ -826,9 +826,9 @@ export default class MTPNetworker { transport: this.transport }; - if(message.fileUpload) { + /* if(message.fileUpload) { this.log('Send encrypted: requestData length:', requestData.length, requestData.length % 16, paddingLength % 16, paddingLength, data.offset); - } + } */ const promise = this.transport.send(requestData); /// #if !MTPROTO_HTTP && !MTPROTO_HTTP_UPLOAD @@ -858,19 +858,19 @@ export default class MTPNetworker { public parseResponse(responseBuffer: Uint8Array) { this.log.debug('Start parsing response'/* , responseBuffer */); - let self = this; - let deserializer = new TLDeserialization(responseBuffer); + const deserializer = new TLDeserialization(responseBuffer); - let authKeyID = deserializer.fetchIntBytes(64, true, 'auth_key_id'); + const authKeyID = deserializer.fetchIntBytes(64, true, 'auth_key_id'); if(!bytesCmp(authKeyID, this.authKeyID)) { throw new Error('[MT] Invalid server auth_key_id: ' + authKeyID.hex); } - let msgKey = deserializer.fetchIntBytes(128, true, 'msg_key'); - let encryptedData = deserializer.fetchRawBytes(responseBuffer.byteLength - deserializer.getOffset(), true, 'encrypted_data'); + + const msgKey = deserializer.fetchIntBytes(128, true, 'msg_key'); + const encryptedData = deserializer.fetchRawBytes(responseBuffer.byteLength - deserializer.getOffset(), true, 'encrypted_data'); - return self.getDecryptedMessage(msgKey, encryptedData).then((dataWithPadding) => { + return this.getDecryptedMessage(msgKey, encryptedData).then((dataWithPadding) => { // this.log('after decrypt') - return self.getMsgKey(dataWithPadding, false).then((calcMsgKey) => { + return this.getMsgKey(dataWithPadding, false).then((calcMsgKey) => { if(!bytesCmp(msgKey, calcMsgKey)) { this.log.warn('[MT] msg_keys', msgKey, calcMsgKey); this.updateSession(); // fix 28.01.2020 @@ -880,103 +880,103 @@ export default class MTPNetworker { let deserializer = new TLDeserialization(dataWithPadding, {mtproto: true}); - /* let salt = */deserializer.fetchIntBytes(64, false, 'salt'); // need - let sessionID = deserializer.fetchIntBytes(64, false, 'session_id'); - let messageID = deserializer.fetchLong('message_id'); + /* const salt = */deserializer.fetchIntBytes(64, false, 'salt'); // need + const sessionID = deserializer.fetchIntBytes(64, false, 'session_id'); + const messageID = deserializer.fetchLong('message_id'); - if(!bytesCmp(sessionID, self.sessionID) && - (!self.prevSessionID || !bytesCmp(sessionID, self.prevSessionID))) { - this.log.warn('Sessions', sessionID, self.sessionID, self.prevSessionID, dataWithPadding); + if(!bytesCmp(sessionID, this.sessionID) && + (!this.prevSessionID || !bytesCmp(sessionID, this.prevSessionID))) { + this.log.warn('Sessions', sessionID, this.sessionID, this.prevSessionID, dataWithPadding); //this.updateSession(); //this.sessionID = sessionID; throw new Error('[MT] Invalid server session_id: ' + bytesToHex(sessionID)); } - let seqNo = deserializer.fetchInt('seq_no'); + const seqNo = deserializer.fetchInt('seq_no'); - let totalLength = dataWithPadding.byteLength; + const totalLength = dataWithPadding.byteLength; - let messageBodyLength = deserializer.fetchInt('message_data[length]'); + const messageBodyLength = deserializer.fetchInt('message_data[length]'); let offset = deserializer.getOffset(); if((messageBodyLength % 4) || messageBodyLength > totalLength - offset) { throw new Error('[MT] Invalid body length: ' + messageBodyLength); } - let messageBody = deserializer.fetchRawBytes(messageBodyLength, true, 'message_data'); + const messageBody = deserializer.fetchRawBytes(messageBodyLength, true, 'message_data'); offset = deserializer.getOffset(); - let paddingLength = totalLength - offset; + const paddingLength = totalLength - offset; if(paddingLength < 12 || paddingLength > 1024) { throw new Error('[MT] Invalid padding length: ' + paddingLength); } //let buffer = bytesToArrayBuffer(messageBody); - deserializer = new TLDeserialization(/* buffer */messageBody, {mtproto: true}); - // ะบะพัั‚ั‹ะปัŒ - deserializer.override = { - mt_message: (function(this: TLDeserialization, result: any, field: string) { - result.msg_id = this.fetchLong(field + '[msg_id]'); - result.seqno = this.fetchInt(field + '[seqno]'); - result.bytes = this.fetchInt(field + '[bytes]'); - - var offset = this.getOffset(); - - //self.log('mt_message!!!!!', result, field); - - try { - result.body = this.fetchObject('Object', field + '[body]'); - } catch(e) { - self.log.error('parse error', e.message, e.stack); - result.body = { - _: 'parse_error', - error: e - }; - } - if(this.offset != offset + result.bytes) { - // console.warn(dT(), 'set offset', this.offset, offset, result.bytes) - // this.log(result) - this.offset = offset + result.bytes; - } - // this.log('override message', result) - }).bind(deserializer), - mt_rpc_result: (function(this: TLDeserialization, result: any, field: any) { - result.req_msg_id = this.fetchLong(field + '[req_msg_id]'); - - var sentMessage = self.sentMessages[result.req_msg_id]; - var type = sentMessage && sentMessage.resultType || 'Object'; + deserializer = new TLDeserialization(/* buffer */messageBody, { + mtproto: true, + override: { + mt_message: (result: any, field: string) => { + result.msg_id = deserializer.fetchLong(field + '[msg_id]'); + result.seqno = deserializer.fetchInt(field + '[seqno]'); + result.bytes = deserializer.fetchInt(field + '[bytes]'); + + const offset = deserializer.getOffset(); + + //self.log('mt_message!!!!!', result, field); + + try { + result.body = deserializer.fetchObject('Object', field + '[body]'); + } catch(e) { + this.log.error('parse error', e.message, e.stack); + result.body = { + _: 'parse_error', + error: e + }; + } - if(result.req_msg_id && !sentMessage) { - // console.warn(dT(), 'Result for unknown message', result); - return; + if(deserializer.offset != offset + result.bytes) { + // console.warn(dT(), 'set offset', this.offset, offset, result.bytes) + // this.log(result) + deserializer.offset = offset + result.bytes; + } + // this.log('override message', result) + }, + mt_rpc_result: (result: any, field: any) => { + result.req_msg_id = deserializer.fetchLong(field + '[req_msg_id]'); + + const sentMessage = this.sentMessages[result.req_msg_id]; + const type = sentMessage && sentMessage.resultType || 'Object'; + + if(result.req_msg_id && !sentMessage) { + // console.warn(dT(), 'Result for unknown message', result); + return; + } + + result.result = deserializer.fetchObject(type, field + '[result]'); + // self.log(dT(), 'override rpc_result', sentMessage, type, result); } + } + }); - result.result = this.fetchObject(type, field + '[result]'); - // self.log(dT(), 'override rpc_result', sentMessage, type, result); - }).bind(deserializer) - }; - - var response = deserializer.fetchObject('', 'INPUT'); - + const response = deserializer.fetchObject('', 'INPUT'); return { - response: response, - messageID: messageID, - sessionID: sessionID, - seqNo: seqNo + response, + messageID, + sessionID, + seqNo }; }); }); } public applyServerSalt(newServerSalt: string) { - var serverSalt = longToBytes(newServerSalt); + const serverSalt = longToBytes(newServerSalt); AppStorage.set({ ['dc' + this.dcID + '_server_salt']: bytesToHex(serverSalt) }); this.serverSalt = serverSalt; - return true; } public scheduleRequest(delay = 0) { @@ -1007,9 +1007,9 @@ export default class MTPNetworker { clearTimeout(this.nextReqTimeout); this.nextReqTimeout = 0; if(delay > 0) { - this.nextReqTimeout = self.setTimeout(this.performScheduledRequest.bind(this), delay || 0); + this.nextReqTimeout = self.setTimeout(this.performScheduledRequest, delay || 0); } else { - setTimeout(this.performScheduledRequest.bind(this), 0); + setTimeout(this.performScheduledRequest, 0); } this.nextReq = nextReq; @@ -1039,8 +1039,8 @@ export default class MTPNetworker { // this.log('clean notContentRelated', msgID) delete this.sentMessages[msgID]; } else if(message.container) { - for(let i = 0; i < message.inner.length; i++) { - if(this.sentMessages[message.inner[i]] !== undefined) { + for(const innerMsgID of message.inner) { + if(this.sentMessages[innerMsgID] !== undefined) { // this.log('clean failed, found', msgID, message.inner[i], this.sentMessages[message.inner[i]].seq_no) notEmpty = true; return; @@ -1057,7 +1057,7 @@ export default class MTPNetworker { } public processMessageAck(messageID: string) { - var sentMessage = this.sentMessages[messageID]; + const sentMessage = this.sentMessages[messageID]; if(sentMessage && !sentMessage.acked) { delete sentMessage.body; sentMessage.acked = true; @@ -1069,7 +1069,7 @@ export default class MTPNetworker { } public processError(rawError: {error_message: string, error_code: number}) { - var matches = (rawError.error_message || '').match(/^([A-Z_0-9]+\b)(: (.+))?/) || []; + const matches = (rawError.error_message || '').match(/^([A-Z_0-9]+\b)(: (.+))?/) || []; rawError.error_code = rawError.error_code; return { @@ -1084,7 +1084,7 @@ export default class MTPNetworker { * ั‚ะพะปัŒะบะพ ะดะปั ัะพะบะตั‚ะฐ, ะฒะพะทะผะพะถะฝะพ ัั‚ะพ ะฑัƒะดะตั‚ ะฝะตะฟั€ะฐะฒะธะปัŒะฝะพ ั€ะฐะฑะพั‚ะฐั‚ัŒ, ะฝะพ ะฒ ั‚ะตัั‚ะต ัั€ะฐะฑะพั‚ะฐะปะพ ะฟั€ะฐะฒะธะปัŒะฝะพ */ public resend() { - for(let id in this.sentMessages) { + for(const id in this.sentMessages) { const msg = this.sentMessages[id]; if(msg.body) { this.pushResend(id); @@ -1092,7 +1092,7 @@ export default class MTPNetworker { } } - public requestMessageStatus() { + /* public requestMessageStatus() { const ids: string[] = []; for(const id in this.sentMessages) { const message = this.sentMessages[id]; @@ -1109,11 +1109,11 @@ export default class MTPNetworker { }).then(res => { this.log('status', res); }); - } + } */ // * https://core.telegram.org/mtproto/service_messages_about_messages#notice-of-ignored-error-message public processMessage(message: any, messageID: string, sessionID: Uint8Array | number[]) { - var msgidInt = parseInt(messageID/* .toString(10) */.substr(0, -10), 10); + const msgidInt = parseInt(messageID.substr(0, -10), 10); if(msgidInt % 2) { this.log.warn('[MT] Server even message id: ', messageID, message); return; @@ -1122,27 +1122,27 @@ export default class MTPNetworker { this.log.debug('process message', message, messageID, sessionID); switch(message._) { - case 'msg_container': - var len = message.messages.length; - for(var i = 0; i < len; i++) { - this.processMessage(message.messages[i], message.messages[i].msg_id, sessionID); + case 'msg_container': { + for(const innerMessage of message.messages) { + this.processMessage(innerMessage, innerMessage.msg_id, sessionID); } + break; + } - case 'bad_server_salt': + case 'bad_server_salt': { this.log('Bad server salt', message); - var sentMessage = this.sentMessages[message.bad_msg_id]; - if(!sentMessage || sentMessage.seq_no != message.bad_msg_seqno) { - this.log(message.bad_msg_id, message.bad_msg_seqno); - throw new Error('[MT] Bad server salt for invalid message'); - } this.applyServerSalt(message.new_server_salt); - this.pushResend(message.bad_msg_id); + + if(this.sentMessages[message.bad_msg_id]) { + this.pushResend(message.bad_msg_id); + } + this.ackMessage(messageID); - /* // simulate disconnect - try { + // simulate disconnect + /* try { this.log('networker state:', this); // @ts-ignore this.transport.ws.close(1000); @@ -1151,19 +1151,14 @@ export default class MTPNetworker { } */ break; + } - case 'bad_msg_notification': - var sentMessage = this.sentMessages[message.bad_msg_id]; - this.log.error('Bad msg notification', message, sentMessage); - if(!sentMessage || sentMessage.seq_no != message.bad_msg_seqno) { - this.log(message.bad_msg_id, message.bad_msg_seqno); - throw new Error('[MT] Bad msg notification for invalid message'); - } - + case 'bad_msg_notification': { + this.log.error('Bad msg notification', message); + if(message.error_code == 16 || message.error_code == 17) { - if(timeManager.applyServerTime( - bigStringInt(messageID).shiftRight(32).toString(10) - )) { + const changedOffset = timeManager.applyServerTime(bigStringInt(messageID).shiftRight(32).toString(10)); + if(message.error_code == 17 || changedOffset) { this.log('Update session'); this.updateSession(); } @@ -1172,22 +1167,28 @@ export default class MTPNetworker { if(badMessage) this.pushResend(badMessage.msg_id); // fix 23.01.2020 this.ackMessage(messageID); } + break; + } - case 'message': + case 'message': { if(this.lastServerMessages.indexOf(messageID) != -1) { // console.warn('[MT] Server same messageID: ', messageID) this.ackMessage(messageID); return; } + this.lastServerMessages.push(messageID); if(this.lastServerMessages.length > 100) { this.lastServerMessages.shift(); } + this.processMessage(message.body, message.msg_id, sessionID); break; + } + - case 'new_session_created': + case 'new_session_created': { this.ackMessage(messageID); this.log.debug('new_session_created', message); @@ -1202,12 +1203,15 @@ export default class MTPNetworker { } }); break; - - case 'msgs_ack': - for(var i = 0; i < message.msg_ids.length; i++) { - this.processMessageAck(message.msg_ids[i]); + } + + case 'msgs_ack': { + for(const msgID of message.msg_ids) { + this.processMessageAck(msgID); } + break; + } case 'msg_detailed_info': if(!this.sentMessages[message.msg_id]) { @@ -1221,34 +1225,34 @@ export default class MTPNetworker { this.reqResendMessage(message.answer_msg_id); break; - case 'msgs_state_info': + case 'msgs_state_info': { this.ackMessage(message.answer_msg_id); if(this.lastResendReq && this.lastResendReq.req_msg_id == message.req_msg_id && this.pendingResends.length ) { - var badMsgID, pos; - for(let i = 0; i < this.lastResendReq.resend_msg_ids.length; i++) { - badMsgID = this.lastResendReq.resend_msg_ids[i]; - pos = this.pendingResends.indexOf(badMsgID); + for(const badMsgID of this.lastResendReq.resend_msg_ids) { + const pos = this.pendingResends.indexOf(badMsgID); if(pos != -1) { this.pendingResends.splice(pos, 1); } } } + break; - - case 'rpc_result': + } + + case 'rpc_result': { this.ackMessage(messageID); - var sentMessageID = message.req_msg_id; - var sentMessage = this.sentMessages[sentMessageID]; + const sentMessageID = message.req_msg_id; + const sentMessage = this.sentMessages[sentMessageID]; this.processMessageAck(sentMessageID); if(sentMessage) { - var deferred = sentMessage.deferred; + const deferred = sentMessage.deferred; if(message.result._ == 'rpc_error') { - var error = this.processError(message.result); + const error = this.processError(message.result); this.log('Rpc error', error); if(deferred) { deferred.reject(error); @@ -1258,7 +1262,7 @@ export default class MTPNetworker { if(Modes.debug) { this.log.debug('Rpc response', message.result); } else { - var dRes = message.result._; + let dRes = message.result._; if(!dRes) { if(message.result.length > 5) { dRes = '[..' + message.result.length + '..]'; @@ -1266,6 +1270,7 @@ export default class MTPNetworker { dRes = message.result; } } + this.log.debug('Rpc response', dRes, sentMessage); } @@ -1281,6 +1286,7 @@ export default class MTPNetworker { delete this.sentMessages[sentMessageID]; } break; + } default: this.ackMessage(messageID); diff --git a/src/lib/mtproto/timeManager.ts b/src/lib/mtproto/timeManager.ts index ff0d2ba7..8a9a45aa 100644 --- a/src/lib/mtproto/timeManager.ts +++ b/src/lib/mtproto/timeManager.ts @@ -14,12 +14,12 @@ export class TimeManager { } public generateID(): string { - var timeTicks = Date.now(), + const timeTicks = Date.now(), timeSec = Math.floor(timeTicks / 1000) + this.timeOffset, timeMSec = timeTicks % 1000, random = nextRandomInt(0xFFFF); - var messageID = [timeSec, (timeMSec << 21) | (random << 3) | 4]; + let messageID = [timeSec, (timeMSec << 21) | (random << 3) | 4]; if(this.lastMessageID[0] > messageID[0] || this.lastMessageID[0] == messageID[0] && this.lastMessageID[1] >= messageID[1]) { messageID = [this.lastMessageID[0], this.lastMessageID[1] + 4]; @@ -27,21 +27,25 @@ export class TimeManager { this.lastMessageID = messageID; - // console.log('generated msg id', messageID, timeOffset) + const ret = longFromInts(messageID[0], messageID[1]); - return longFromInts(messageID[0], messageID[1]); + //console.log('[TimeManager]: Generated msg id', messageID, this.timeOffset, ret); + + return ret } public applyServerTime(serverTime: number, localTime?: number) { - var newTimeOffset = serverTime - Math.floor((localTime || Date.now()) / 1000); - var changed = Math.abs(this.timeOffset - newTimeOffset) > 10; + localTime = (localTime || Date.now()) / 1000 | 0; + const newTimeOffset = serverTime - localTime; + const changed = Math.abs(this.timeOffset - newTimeOffset) > 10; AppStorage.set({ server_time_offset: newTimeOffset }); this.lastMessageID = [0, 0]; this.timeOffset = newTimeOffset; - //console.log(dT(), 'Apply server time', serverTime, localTime, newTimeOffset, changed); + + //console.log('[TimeManager]: Apply server time', serverTime, localTime, newTimeOffset, changed); return changed; } diff --git a/src/lib/mtproto/tl_utils.ts b/src/lib/mtproto/tl_utils.ts index 1b73d9c0..dd3eb1ed 100644 --- a/src/lib/mtproto/tl_utils.ts +++ b/src/lib/mtproto/tl_utils.ts @@ -396,7 +396,7 @@ class TLSerialization { class TLDeserialization { public offset = 0; // in bytes - public override: any; + public override: {[key: string]: (result: any, field: string) => void}; public buffer: ArrayBuffer; //public intView: Uint32Array; @@ -616,13 +616,13 @@ class TLDeserialization { if(type.substr(0, 6) == 'Vector' || type.substr(0, 6) == 'vector') { if(type.charAt(0) == 'V') { - var constructor = this.readInt(field + '[id]'); - var constructorCmp = constructor; + const constructor = this.readInt(field + '[id]'); + const constructorCmp = constructor; if(constructorCmp == gzipPacked) { // Gzip packed - var compressed = this.fetchBytes(field + '[packed_string]'); - var uncompressed = gzipUncompress(compressed); - var newDeserializer = new TLDeserialization(uncompressed); + const compressed = this.fetchBytes(field + '[packed_string]'); + const uncompressed = gzipUncompress(compressed); + const newDeserializer = new TLDeserialization(uncompressed); return newDeserializer.fetchObject(type, field); } @@ -632,11 +632,11 @@ class TLDeserialization { } } - var len = this.readInt(field + '[count]'); - var result: any = []; + const len = this.readInt(field + '[count]'); + const result: any = []; if(len > 0) { - var itemType = type.substr(7, type.length - 8); // for "Vector" - for(var i = 0; i < len; i++) { + const itemType = type.substr(7, type.length - 8); // for "Vector" + for(let i = 0; i < len; i++) { result.push(this.fetchObject(itemType, field + '[' + i + ']')); } } @@ -644,62 +644,49 @@ class TLDeserialization { return result; } - var schema = this.mtproto ? Schema.MTProto : Schema.API; - var predicate = false; - var constructorData: any = false; + const schema = this.mtproto ? Schema.MTProto : Schema.API; + let constructorData: MTProtoConstructor = null; + let fallback = false; if(type.charAt(0) == '%') { - var checkType = type.substr(1); - for(var i = 0; i < schema.constructors.length; i++) { - if(schema.constructors[i].type == checkType) { - constructorData = schema.constructors[i]; - break; - } - } - + const checkType = type.substr(1); + constructorData = schema.constructors.find(c => c.type == checkType); if(!constructorData) { throw new Error('Constructor not found for type: ' + type); } } else if(type.charAt(0) >= 97 && type.charAt(0) <= 122) { - for(var i = 0; i < schema.constructors.length; i++) { - if(schema.constructors[i].predicate == type) { - constructorData = schema.constructors[i]; - break; - } - } - + constructorData = schema.constructors.find(c => c.predicate == type); if(!constructorData) { throw new Error('Constructor not found for predicate: ' + type); } } else { - var constructor = this.readInt(field + '[id]'); - var constructorCmp = constructor; + const constructor = this.readInt(field + '[id]'); + const constructorCmp = constructor; if(constructorCmp == gzipPacked) { // Gzip packed - var compressed = this.fetchBytes(field + '[packed_string]'); - var uncompressed = gzipUncompress(compressed); - var newDeserializer = new TLDeserialization(uncompressed); + const compressed = this.fetchBytes(field + '[packed_string]'); + const uncompressed = gzipUncompress(compressed); + const newDeserializer = new TLDeserialization(uncompressed); return newDeserializer.fetchObject(type, field); } - var index = schema.constructorsIndex; + let index = schema.constructorsIndex; if(!index) { schema.constructorsIndex = index = {}; - for(var i = 0; i < schema.constructors.length; i++) { + for(let i = 0, len = schema.constructors.length; i < len; i++) { index[schema.constructors[i].id] = i; } } - var i = index[constructorCmp]; + const i = index[constructorCmp]; if(i) { constructorData = schema.constructors[i]; } - var fallback = false; if(!constructorData && this.mtproto) { - var schemaFallback = Schema.API; - for(i = 0; i < schemaFallback.constructors.length; i++) { + const schemaFallback = Schema.API; + for(let i = 0, len = schemaFallback.constructors.length; i < len; i++) { if(+schemaFallback.constructors[i].id == constructorCmp) { constructorData = schemaFallback.constructors[i]; @@ -715,33 +702,27 @@ class TLDeserialization { } } - predicate = constructorData.predicate; - - var result: any = {'_': predicate}; - var overrideKey = (this.mtproto ? 'mt_' : '') + predicate; - var self = this; + const predicate = constructorData.predicate; + const result: any = {'_': predicate}; + const overrideKey = (this.mtproto ? 'mt_' : '') + predicate; if(this.override[overrideKey]) { - this.override[overrideKey].apply(this, [result, field + '[' + predicate + ']']); + this.override[overrideKey](result, field + '[' + predicate + ']'); } else { - var i: number, param; - var type, isCond; - var condType, fieldBit; - var value; - var len: number = constructorData.params.length; - for(i = 0; i < len; i++) { - param = constructorData.params[i]; - type = param.type; + for(let i = 0, len = constructorData.params.length; i < len; i++) { + const param = constructorData.params[i]; + let type = param.type; if(type == '#' && result.pFlags === undefined) { result.pFlags = {}; } - if(isCond = (type.indexOf('?') !== -1)) { - condType = type.split('?'); - fieldBit = condType[0].split('.'); + const isCond = (type.indexOf('?') !== -1); + if(isCond) { + const condType = type.split('?'); + const fieldBit = condType[0].split('.'); - if(!(result[fieldBit[0]] & (1 << fieldBit[1]))) { + if(!(result[fieldBit[0]] & (1 << +fieldBit[1]))) { //console.log('fetchObject bad', constructorData, result[fieldBit[0]], fieldBit); continue; } @@ -751,7 +732,7 @@ class TLDeserialization { type = condType[1]; } - value = self.fetchObject(type, field + '[' + predicate + '][' + param.name + ']'); + const value = this.fetchObject(type, field + '[' + predicate + '][' + param.name + ']'); if(isCond && type === 'true') { result.pFlags[param.name] = value; diff --git a/src/lib/mtproto/transports/websocket.ts b/src/lib/mtproto/transports/websocket.ts index 4928ab4d..83084d93 100644 --- a/src/lib/mtproto/transports/websocket.ts +++ b/src/lib/mtproto/transports/websocket.ts @@ -67,6 +67,11 @@ export default class Socket extends MTTransport { this.connected = true; this.releasePending(); + + if(this.networker && this.lastCloseTime) { + this.networker.cleanupSent(); + this.networker.resend(); + } //}, 3e3); }; @@ -75,37 +80,29 @@ export default class Socket extends MTTransport { }; handleClose = (event: CloseEvent) => { - this.log('closed', event, this.pending); + this.log('closed', event, this.pending, this.ws.bufferedAmount); this.connected = false; const time = Date.now(); const diff = time - this.lastCloseTime; - let needTimeout = !isNaN(diff) && diff < CONNECTION_RETRY_TIMEOUT ? CONNECTION_RETRY_TIMEOUT - diff : 0; - - //this.pending.length = 0; - /* if(this.networker) { - this.networker.resend(); - this.networker.cleanupSent(); - } */ + const needTimeout = !isNaN(diff) && diff < CONNECTION_RETRY_TIMEOUT ? CONNECTION_RETRY_TIMEOUT - diff : 0; this.log('will try to reconnect after timeout:', needTimeout / 1000); setTimeout(() => { this.log('trying to reconnect...'); this.lastCloseTime = Date.now(); - this.connect(); - - for(let pending of this.pending) { + + for(const pending of this.pending) { if(pending.bodySent) { pending.bodySent = false; } } - + if(this.networker) { - this.ws.addEventListener('open', () => { - this.networker.resend(); - this.networker.cleanupSent(); - }, {once: true}); + this.pending } + + this.connect(); }, needTimeout); }; @@ -126,7 +123,7 @@ export default class Socket extends MTTransport { } //console.log('got hex:', data.hex); - let pending = this.pending.shift(); + const pending = this.pending.shift(); if(!pending) { return this.log.debug('no pending for res:', data.hex); } @@ -177,9 +174,13 @@ export default class Socket extends MTTransport { this.log.error('bufferedAmount:', this.ws.bufferedAmount); } */ - //setTimeout(() => { - this.ws.send(enc); - //}, 500); + if(this.ws.readyState !== this.ws.OPEN) { + this.log.error('ws is closed?'); + this.connected = false; + break; + } + + this.ws.send(enc); if(!pending.resolve) { // remove if no response needed this.pending.splice(i--, 1); diff --git a/src/scss/partials/_chatBubble.scss b/src/scss/partials/_chatBubble.scss index 4ce1a013..5acc8200 100644 --- a/src/scss/partials/_chatBubble.scss +++ b/src/scss/partials/_chatBubble.scss @@ -159,11 +159,11 @@ $bubble-margin: .25rem; &-select-checkbox { z-index: 2; position: absolute; - /* left: 0; - bottom: .75rem; // * by avatar */ left: 0; + bottom: .75rem; // * by avatar + /* left: 0; top: 50%; - transform: translateY(-50%); + transform: translateY(-50%); */ display: flex; [type="checkbox"] { diff --git a/src/scss/partials/_leftSidebar.scss b/src/scss/partials/_leftSidebar.scss index 0c49b330..5511c321 100644 --- a/src/scss/partials/_leftSidebar.scss +++ b/src/scss/partials/_leftSidebar.scss @@ -45,6 +45,8 @@ z-index: 1; background-color: #fff; border-bottom: 1px solid #dadce0; + position: relative; + box-shadow: 0px 1px 5px -1px rgba(0, 0, 0, .16); .scrollable { position: relative;