Merge branch 'master' into lp/custom-user-picker-sheet

This commit is contained in:
Levitating Pineapple
2024-09-30 22:47:40 +03:00
20 changed files with 343 additions and 132 deletions
+2 -2
View File
@@ -72,7 +72,7 @@ You must:
Messages not following these rules will be deleted, the right to send messages may be revoked, and the access to the new members to the group may be temporarily restricted, to prevent re-joining under a different name - our imperfect group moderation does not have a better solution at the moment.
You can join an English-speaking users group if you want to ask any questions: [#SimpleX users group](https://simplex.chat/contact#/?v=1-4&smp=smp%3A%2F%2FPQUV2eL0t7OStZOoAsPEV2QYWt4-xilbakvGUGOItUo%3D%40smp6.simplex.im%2Fos8FftfoV8zjb2T89fUEjJtF7y64p5av%23%2F%3Fv%3D1-2%26dh%3DMCowBQYDK2VuAyEAQqMgh0fw2lPhjn3PDIEfAKA_E0-gf8Hr8zzhYnDivRs%253D%26srv%3Dbylepyau3ty4czmn77q4fglvperknl4bi2eb2fdy2bh4jxtf32kf73yd.onion&data=%7B%22type%22%3A%22group%22%2C%22groupLinkId%22%3A%22lBPiveK2mjfUH43SN77R0w%3D%3D%22%7D)
You can join an English-speaking users group if you want to ask any questions: [#SimpleX users group](https://simplex.chat/contact#/?v=2-4&smp=smp%3A%2F%2FPQUV2eL0t7OStZOoAsPEV2QYWt4-xilbakvGUGOItUo%3D%40smp6.simplex.im%2Fos8FftfoV8zjb2T89fUEjJtF7y64p5av%23%2F%3Fv%3D1-2%26dh%3DMCowBQYDK2VuAyEAQqMgh0fw2lPhjn3PDIEfAKA_E0-gf8Hr8zzhYnDivRs%253D%26srv%3Dbylepyau3ty4czmn77q4fglvperknl4bi2eb2fdy2bh4jxtf32kf73yd.onion&data=%7B%22type%22%3A%22group%22%2C%22groupLinkId%22%3A%22lBPiveK2mjfUH43SN77R0w%3D%3D%22%7D)
There is also a group [#simplex-devs](https://simplex.chat/contact#/?v=1-4&smp=smp%3A%2F%2FPQUV2eL0t7OStZOoAsPEV2QYWt4-xilbakvGUGOItUo%3D%40smp6.simplex.im%2FvYCRjIflKNMGYlfTkuHe4B40qSlQ0439%23%2F%3Fv%3D1-2%26dh%3DMCowBQYDK2VuAyEAHNdcqNbzXZhyMoSBjT2R0-Eb1EPaLyUg3KZjn-kmM1w%253D%26srv%3Dbylepyau3ty4czmn77q4fglvperknl4bi2eb2fdy2bh4jxtf32kf73yd.onion&data=%7B%22type%22%3A%22group%22%2C%22groupLinkId%22%3A%22PD20tcXjw7IpkkMCfR6HLA%3D%3D%22%7D) for developers who build on SimpleX platform:
@@ -83,7 +83,7 @@ There is also a group [#simplex-devs](https://simplex.chat/contact#/?v=1-4&smp=s
There are groups in other languages, that we have the apps interface translated into. These groups are for testing, and asking questions to other SimpleX Chat users:
[\#SimpleX-DE](https://simplex.chat/contact#/?v=1-2&smp=smp%3A%2F%2FPQUV2eL0t7OStZOoAsPEV2QYWt4-xilbakvGUGOItUo%3D%40smp6.simplex.im%2FkIEl7OQzcp-J6aDmjdlQbRJwqkcZE7XR%23%2F%3Fv%3D1-2%26dh%3DMCowBQYDK2VuAyEAR16PCu02MobRmKAsjzhDWMZcWP9hS8l5AUZi-Gs8z18%253D%26srv%3Dbylepyau3ty4czmn77q4fglvperknl4bi2eb2fdy2bh4jxtf32kf73yd.onion&data=%7B%22type%22%3A%22group%22%2C%22groupLinkId%22%3A%22puYPMCQt11yPUvgmI5jCiw%3D%3D%22%7D) (German-speaking), [\#SimpleX-ES](https://simplex.chat/contact#/?v=1-2&smp=smp%3A%2F%2FPQUV2eL0t7OStZOoAsPEV2QYWt4-xilbakvGUGOItUo%3D%40smp6.simplex.im%2FaJ8O1O8A8GbeoaHTo_V8dcefaCl7ouPb%23%2F%3Fv%3D1-2%26dh%3DMCowBQYDK2VuAyEA034qWTA3sWcTsi6aWhNf9BA34vKVCFaEBdP2R66z6Ao%253D%26srv%3Dbylepyau3ty4czmn77q4fglvperknl4bi2eb2fdy2bh4jxtf32kf73yd.onion&data=%7B%22type%22%3A%22group%22%2C%22groupLinkId%22%3A%22wiZ1v_wNjLPlT-nCSB-bRA%3D%3D%22%7D) (Spanish-speaking), [\#SimpleX-FR](https://simplex.chat/contact#/?v=1-2&smp=smp%3A%2F%2Fhpq7_4gGJiilmz5Rf-CswuU5kZGkm_zOIooSw6yALRg%3D%40smp5.simplex.im%2FvIHQDxTor53nwnWWTy5cHNwQQAdWN5Hw%23%2F%3Fv%3D1-2%26dh%3DMCowBQYDK2VuAyEAPdgK1eBnETmgiqEQufbUkydKBJafoRx4iRrtrC2NAGc%253D%26srv%3Djjbyvoemxysm7qxap7m5d5m35jzv5qq6gnlv7s4rsn7tdwwmuqciwpid.onion&data=%7B%22type%22%3A%22group%22%2C%22groupLinkId%22%3A%221FyUryBPza-1ZFFE80Ekbg%3D%3D%22%7D) (French-speaking), [\#SimpleX-RU](https://simplex.chat/contact#/?v=1-2&smp=smp%3A%2F%2FPQUV2eL0t7OStZOoAsPEV2QYWt4-xilbakvGUGOItUo%3D%40smp6.simplex.im%2FXZyt3hJmWsycpN7Dqve_wbrAqb6myk1R%23%2F%3Fv%3D1-2%26dh%3DMCowBQYDK2VuAyEAMFVIoytozTEa_QXOgoZFq_oe0IwZBYKvW50trSFXzXo%253D%26srv%3Dbylepyau3ty4czmn77q4fglvperknl4bi2eb2fdy2bh4jxtf32kf73yd.onion&data=%7B%22type%22%3A%22group%22%2C%22groupLinkId%22%3A%22xz05ngjA3pNIxLZ32a8Vxg%3D%3D%22%7D) (Russian-speaking), [\#SimpleX-IT](https://simplex.chat/contact#/?v=1-2&smp=smp%3A%2F%2Fu2dS9sG8nMNURyZwqASV4yROM28Er0luVTx5X1CsMrU%3D%40smp4.simplex.im%2F0weR-ZgDUl7ruOtI_8TZwEsnJP6UiImA%23%2F%3Fv%3D1-2%26dh%3DMCowBQYDK2VuAyEAq4PSThO9Fvb5ydF48wB0yNbpzCbuQJCW3vZ9BGUfcxk%253D%26srv%3Do5vmywmrnaxalvz6wi3zicyftgio6psuvyniis6gco6bp6ekl4cqj4id.onion&data=%7B%22type%22%3A%22group%22%2C%22groupLinkId%22%3A%22e-iceLA0SctC62eARgYDWg%3D%3D%22%7D) (Italian-speaking).
[\#SimpleX-DE](https://simplex.chat/contact#/?v=1-4&smp=smp%3A%2F%2FPQUV2eL0t7OStZOoAsPEV2QYWt4-xilbakvGUGOItUo%3D%40smp6.simplex.im%2FmfiivxDKWFuowXrQOp11jsY8TuP__rBL%23%2F%3Fv%3D1-2%26dh%3DMCowBQYDK2VuAyEAiz3pKNwvKudckFYMUfgoT0s96B0jfZ7ALHAu7rtE9HQ%253D%26srv%3Dbylepyau3ty4czmn77q4fglvperknl4bi2eb2fdy2bh4jxtf32kf73yd.onion&data=%7B%22type%22%3A%22group%22%2C%22groupLinkId%22%3A%22jZeJpXGrRXQJU_-MSJ_v2A%3D%3D%22%7D) (German-speaking), [\#SimpleX-ES](https://simplex.chat/contact#/?v=2-4&smp=smp%3A%2F%2Fhpq7_4gGJiilmz5Rf-CswuU5kZGkm_zOIooSw6yALRg%3D%40smp5.simplex.im%2FJ5ES83pJimY2BRklS8fvy_iQwIU37xra%23%2F%3Fv%3D1-2%26dh%3DMCowBQYDK2VuAyEA0F0STP6UqN_12_k2cjjTrIjFgBGeWhOAmbY1qlk3pnM%253D%26srv%3Djjbyvoemxysm7qxap7m5d5m35jzv5qq6gnlv7s4rsn7tdwwmuqciwpid.onion&data=%7B%22type%22%3A%22group%22%2C%22groupLinkId%22%3A%22VmUU0fqmYdCRmVCyvStvHA%3D%3D%22%7D) (Spanish-speaking), [\#SimpleX-FR](https://simplex.chat/contact#/?v=2-7&smp=smp%3A%2F%2FPQUV2eL0t7OStZOoAsPEV2QYWt4-xilbakvGUGOItUo%3D%40smp6.simplex.im%2FxCHBE_6PBRMqNEpm4UQDHXb9cz-mN7dd%23%2F%3Fv%3D1-3%26dh%3DMCowBQYDK2VuAyEAetqlcM7zTCRw-iatnwCrvpJSto7lq5Yv6AsBMWv7GSM%253D%26srv%3Dbylepyau3ty4czmn77q4fglvperknl4bi2eb2fdy2bh4jxtf32kf73yd.onion&data=%7B%22type%22%3A%22group%22%2C%22groupLinkId%22%3A%22foO5Xw4hhjOa_x7zET7otw%3D%3D%22%7D) (French-speaking), [\#SimpleX-RU](https://simplex.chat/contact#/?v=2-4&smp=smp%3A%2F%2Fhpq7_4gGJiilmz5Rf-CswuU5kZGkm_zOIooSw6yALRg%3D%40smp5.simplex.im%2FVXQTB0J2lLjYkgjWByhl6-1qmb5fgZHh%23%2F%3Fv%3D1-2%26dh%3DMCowBQYDK2VuAyEAI6JaEWezfSwvcoTEkk6au-gkjrXR2ew2OqZYMYBvayk%253D%26srv%3Djjbyvoemxysm7qxap7m5d5m35jzv5qq6gnlv7s4rsn7tdwwmuqciwpid.onion&data=%7B%22type%22%3A%22group%22%2C%22groupLinkId%22%3A%22ORH9OEe8Duissh-hslfeVg%3D%3D%22%7D) (Russian-speaking), [\#SimpleX-IT](https://simplex.chat/contact#/?v=2-7&smp=smp%3A%2F%2Fhpq7_4gGJiilmz5Rf-CswuU5kZGkm_zOIooSw6yALRg%3D%40smp5.simplex.im%2FqpHu0psOUdYfc11yQCzSyq5JhijrBzZT%23%2F%3Fv%3D1-3%26dh%3DMCowBQYDK2VuAyEACZ_7fbwlM45wl6cGif8cY47oPQ_AMdP0ATqOYLA6zHY%253D%26srv%3Djjbyvoemxysm7qxap7m5d5m35jzv5qq6gnlv7s4rsn7tdwwmuqciwpid.onion&data=%7B%22type%22%3A%22group%22%2C%22groupLinkId%22%3A%229uRQRTir3ealdcSfB0zsrw%3D%3D%22%7D) (Italian-speaking).
You can join either by opening these links in the app or by opening them in a desktop browser and scanning the QR code.
+20 -20
View File
@@ -218,12 +218,12 @@
D741547A29AF90B00022400A /* PushKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D741547929AF90B00022400A /* PushKit.framework */; };
D77B92DC2952372200A5A1CC /* SwiftyGif in Frameworks */ = {isa = PBXBuildFile; productRef = D77B92DB2952372200A5A1CC /* SwiftyGif */; };
D7F0E33929964E7E0068AF69 /* LZString in Frameworks */ = {isa = PBXBuildFile; productRef = D7F0E33829964E7E0068AF69 /* LZString */; };
E51B923B2CAB2B8800C212F2 /* libHSsimplex-chat-6.1.0.5-HWShuJBYoppEOt1hLB8GPU.a in Frameworks */ = {isa = PBXBuildFile; fileRef = E51B92362CAB2B8800C212F2 /* libHSsimplex-chat-6.1.0.5-HWShuJBYoppEOt1hLB8GPU.a */; };
E51B923C2CAB2B8800C212F2 /* libgmp.a in Frameworks */ = {isa = PBXBuildFile; fileRef = E51B92372CAB2B8800C212F2 /* libgmp.a */; };
E51B923D2CAB2B8800C212F2 /* libffi.a in Frameworks */ = {isa = PBXBuildFile; fileRef = E51B92382CAB2B8800C212F2 /* libffi.a */; };
E51B923E2CAB2B8800C212F2 /* libHSsimplex-chat-6.1.0.5-HWShuJBYoppEOt1hLB8GPU-ghc9.6.3.a in Frameworks */ = {isa = PBXBuildFile; fileRef = E51B92392CAB2B8800C212F2 /* libHSsimplex-chat-6.1.0.5-HWShuJBYoppEOt1hLB8GPU-ghc9.6.3.a */; };
E51B923F2CAB2B8800C212F2 /* libgmpxx.a in Frameworks */ = {isa = PBXBuildFile; fileRef = E51B923A2CAB2B8800C212F2 /* libgmpxx.a */; };
E51CC1E62C62085600DB91FE /* OneHandUICard.swift in Sources */ = {isa = PBXBuildFile; fileRef = E51CC1E52C62085600DB91FE /* OneHandUICard.swift */; };
E5D826852CA5F56100A9B74D /* libHSsimplex-chat-6.1.0.4-5C0H3SCWHuhICcJbTCMAKi-ghc9.6.3.a in Frameworks */ = {isa = PBXBuildFile; fileRef = E5D826802CA5F56100A9B74D /* libHSsimplex-chat-6.1.0.4-5C0H3SCWHuhICcJbTCMAKi-ghc9.6.3.a */; };
E5D826862CA5F56100A9B74D /* libffi.a in Frameworks */ = {isa = PBXBuildFile; fileRef = E5D826812CA5F56100A9B74D /* libffi.a */; };
E5D826872CA5F56100A9B74D /* libgmp.a in Frameworks */ = {isa = PBXBuildFile; fileRef = E5D826822CA5F56100A9B74D /* libgmp.a */; };
E5D826882CA5F56100A9B74D /* libgmpxx.a in Frameworks */ = {isa = PBXBuildFile; fileRef = E5D826832CA5F56100A9B74D /* libgmpxx.a */; };
E5D826892CA5F56100A9B74D /* libHSsimplex-chat-6.1.0.4-5C0H3SCWHuhICcJbTCMAKi.a in Frameworks */ = {isa = PBXBuildFile; fileRef = E5D826842CA5F56100A9B74D /* libHSsimplex-chat-6.1.0.4-5C0H3SCWHuhICcJbTCMAKi.a */; };
E5DCF8DB2C56FAC1007928CC /* SimpleXChat.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5CE2BA682845308900EC33A6 /* SimpleXChat.framework */; };
E5DCF9712C590272007928CC /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = E5DCF96F2C590272007928CC /* Localizable.strings */; };
E5DCF9842C5902CE007928CC /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = E5DCF9822C5902CE007928CC /* Localizable.strings */; };
@@ -559,12 +559,12 @@
D741547729AF89AF0022400A /* StoreKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = StoreKit.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS16.1.sdk/System/Library/Frameworks/StoreKit.framework; sourceTree = DEVELOPER_DIR; };
D741547929AF90B00022400A /* PushKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = PushKit.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS16.1.sdk/System/Library/Frameworks/PushKit.framework; sourceTree = DEVELOPER_DIR; };
D7AA2C3429A936B400737B40 /* MediaEncryption.playground */ = {isa = PBXFileReference; lastKnownFileType = file.playground; name = MediaEncryption.playground; path = Shared/MediaEncryption.playground; sourceTree = SOURCE_ROOT; xcLanguageSpecificationIdentifier = xcode.lang.swift; };
E51B92362CAB2B8800C212F2 /* libHSsimplex-chat-6.1.0.5-HWShuJBYoppEOt1hLB8GPU.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-6.1.0.5-HWShuJBYoppEOt1hLB8GPU.a"; sourceTree = "<group>"; };
E51B92372CAB2B8800C212F2 /* libgmp.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmp.a; sourceTree = "<group>"; };
E51B92382CAB2B8800C212F2 /* libffi.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libffi.a; sourceTree = "<group>"; };
E51B92392CAB2B8800C212F2 /* libHSsimplex-chat-6.1.0.5-HWShuJBYoppEOt1hLB8GPU-ghc9.6.3.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-6.1.0.5-HWShuJBYoppEOt1hLB8GPU-ghc9.6.3.a"; sourceTree = "<group>"; };
E51B923A2CAB2B8800C212F2 /* libgmpxx.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmpxx.a; sourceTree = "<group>"; };
E51CC1E52C62085600DB91FE /* OneHandUICard.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OneHandUICard.swift; sourceTree = "<group>"; };
E5D826802CA5F56100A9B74D /* libHSsimplex-chat-6.1.0.4-5C0H3SCWHuhICcJbTCMAKi-ghc9.6.3.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-6.1.0.4-5C0H3SCWHuhICcJbTCMAKi-ghc9.6.3.a"; sourceTree = "<group>"; };
E5D826812CA5F56100A9B74D /* libffi.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libffi.a; sourceTree = "<group>"; };
E5D826822CA5F56100A9B74D /* libgmp.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmp.a; sourceTree = "<group>"; };
E5D826832CA5F56100A9B74D /* libgmpxx.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmpxx.a; sourceTree = "<group>"; };
E5D826842CA5F56100A9B74D /* libHSsimplex-chat-6.1.0.4-5C0H3SCWHuhICcJbTCMAKi.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-6.1.0.4-5C0H3SCWHuhICcJbTCMAKi.a"; sourceTree = "<group>"; };
E5DCF9702C590272007928CC /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Localizable.strings; sourceTree = "<group>"; };
E5DCF9722C590274007928CC /* bg */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = bg; path = bg.lproj/Localizable.strings; sourceTree = "<group>"; };
E5DCF9732C590275007928CC /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hans"; path = "zh-Hans.lproj/Localizable.strings"; sourceTree = "<group>"; };
@@ -655,14 +655,14 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
E5D826852CA5F56100A9B74D /* libHSsimplex-chat-6.1.0.4-5C0H3SCWHuhICcJbTCMAKi-ghc9.6.3.a in Frameworks */,
E51B923B2CAB2B8800C212F2 /* libHSsimplex-chat-6.1.0.5-HWShuJBYoppEOt1hLB8GPU.a in Frameworks */,
E51B923D2CAB2B8800C212F2 /* libffi.a in Frameworks */,
E51B923C2CAB2B8800C212F2 /* libgmp.a in Frameworks */,
5CE2BA93284534B000EC33A6 /* libiconv.tbd in Frameworks */,
E5D826892CA5F56100A9B74D /* libHSsimplex-chat-6.1.0.4-5C0H3SCWHuhICcJbTCMAKi.a in Frameworks */,
E51B923F2CAB2B8800C212F2 /* libgmpxx.a in Frameworks */,
5CE2BA94284534BB00EC33A6 /* libz.tbd in Frameworks */,
E5D826862CA5F56100A9B74D /* libffi.a in Frameworks */,
E5D826872CA5F56100A9B74D /* libgmp.a in Frameworks */,
CE38A29C2C3FCD72005ED185 /* SwiftyGif in Frameworks */,
E5D826882CA5F56100A9B74D /* libgmpxx.a in Frameworks */,
E51B923E2CAB2B8800C212F2 /* libHSsimplex-chat-6.1.0.5-HWShuJBYoppEOt1hLB8GPU-ghc9.6.3.a in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -739,11 +739,11 @@
5C764E5C279C70B7000C6508 /* Libraries */ = {
isa = PBXGroup;
children = (
E5D826812CA5F56100A9B74D /* libffi.a */,
E5D826822CA5F56100A9B74D /* libgmp.a */,
E5D826832CA5F56100A9B74D /* libgmpxx.a */,
E5D826802CA5F56100A9B74D /* libHSsimplex-chat-6.1.0.4-5C0H3SCWHuhICcJbTCMAKi-ghc9.6.3.a */,
E5D826842CA5F56100A9B74D /* libHSsimplex-chat-6.1.0.4-5C0H3SCWHuhICcJbTCMAKi.a */,
E51B92382CAB2B8800C212F2 /* libffi.a */,
E51B92372CAB2B8800C212F2 /* libgmp.a */,
E51B923A2CAB2B8800C212F2 /* libgmpxx.a */,
E51B92392CAB2B8800C212F2 /* libHSsimplex-chat-6.1.0.5-HWShuJBYoppEOt1hLB8GPU-ghc9.6.3.a */,
E51B92362CAB2B8800C212F2 /* libHSsimplex-chat-6.1.0.5-HWShuJBYoppEOt1hLB8GPU.a */,
);
path = Libraries;
sourceTree = "<group>";
+1
View File
@@ -1353,6 +1353,7 @@ public struct NetCfg: Codable, Equatable {
public var sessionMode = TransportSessionMode.user
public var smpProxyMode: SMPProxyMode = .unknown
public var smpProxyFallback: SMPProxyFallback = .allowProtected
var smpWebPort = false
public var tcpConnectTimeout: Int // microseconds
public var tcpTimeout: Int // microseconds
public var tcpTimeoutPerKb: Int // microseconds
@@ -737,7 +737,11 @@ fun WebRTCView(callCommand: SnapshotStateList<WCallCommand>, onResponse: (WVAPIM
}
} catch (e: Exception) {
Log.e(TAG, "Error initializing WebView: ${e.stackTraceToString()}")
AlertManager.shared.showAlertMsg(generalGetString(MR.strings.error), generalGetString(MR.strings.error_initializing_web_view).format(e.stackTraceToString()))
if (e.stackTraceToString().contains("/lib64")) {
AlertManager.shared.showAlertMsg(generalGetString(MR.strings.error), generalGetString(MR.strings.error_initializing_web_view_wrong_arch).format(e.stackTraceToString()))
} else {
AlertManager.shared.showAlertMsg(generalGetString(MR.strings.error), generalGetString(MR.strings.error_initializing_web_view).format(e.stackTraceToString()))
}
return@AndroidView View(androidAppContext)
}
}
@@ -3653,6 +3653,7 @@ data class NetCfg(
val sessionMode: TransportSessionMode = TransportSessionMode.User,
val smpProxyMode: SMPProxyMode = SMPProxyMode.Unknown,
val smpProxyFallback: SMPProxyFallback = SMPProxyFallback.AllowProtected,
val smpWebPort: Boolean = false,
val tcpConnectTimeout: Long, // microseconds
val tcpTimeout: Long, // microseconds
val tcpTimeoutPerKb: Long, // microseconds
@@ -17,7 +17,7 @@ data class Call(
val callUUID: String?,
val callState: CallState,
val initialCallType: CallMediaType,
val localMediaSources: CallMediaSources = CallMediaSources(mic = true, camera = initialCallType == CallMediaType.Video && appPlatform.isAndroid),
val localMediaSources: CallMediaSources = CallMediaSources(mic = true, camera = initialCallType == CallMediaType.Video),
val localCapabilities: CallCapabilities? = null,
val peerMediaSources: CallMediaSources = CallMediaSources(),
val sharedKey: String? = null,
@@ -12,6 +12,7 @@ import androidx.compose.material.*
import androidx.compose.runtime.*
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.ui.*
import androidx.compose.ui.draw.clip
import androidx.compose.ui.draw.drawWithCache
import androidx.compose.ui.graphics.*
import androidx.compose.ui.layout.layoutId
@@ -779,30 +780,16 @@ fun ChatInfoToolbar(
if (chatInfo is ChatInfo.Direct && chatInfo.contact.mergedPreferences.calls.enabled.forUser) {
if (activeCall == null) {
barButtons.add {
if (appPlatform.isAndroid) {
IconButton({
showMenu.value = false
startCall(CallMediaType.Audio)
}, enabled = chatInfo.contact.ready && chatInfo.contact.active
) {
Icon(
painterResource(MR.images.ic_call_500),
stringResource(MR.strings.icon_descr_audio_call).capitalize(Locale.current),
tint = if (chatInfo.contact.ready && chatInfo.contact.active) MaterialTheme.colors.primary else MaterialTheme.colors.secondary
)
}
} else {
IconButton({
showMenu.value = false
startCall(CallMediaType.Video)
}, enabled = chatInfo.contact.ready && chatInfo.contact.active
) {
Icon(
painterResource(MR.images.ic_videocam),
stringResource(MR.strings.icon_descr_video_call).capitalize(Locale.current),
tint = if (chatInfo.contact.ready && chatInfo.contact.active) MaterialTheme.colors.primary else MaterialTheme.colors.secondary
)
}
IconButton({
showMenu.value = false
startCall(CallMediaType.Audio)
}, enabled = chatInfo.contact.ready && chatInfo.contact.active
) {
Icon(
painterResource(MR.images.ic_call_500),
stringResource(MR.strings.icon_descr_audio_call).capitalize(Locale.current),
tint = if (chatInfo.contact.ready && chatInfo.contact.active) MaterialTheme.colors.primary else MaterialTheme.colors.secondary
)
}
}
} else if (activeCall?.contact?.id == chatInfo.id && appPlatform.isDesktop) {
@@ -836,17 +823,10 @@ fun ChatInfoToolbar(
}
if (chatInfo.contact.ready && chatInfo.contact.active && activeCall == null) {
menuItems.add {
if (appPlatform.isAndroid) {
ItemAction(stringResource(MR.strings.icon_descr_video_call).capitalize(Locale.current), painterResource(MR.images.ic_videocam), onClick = {
showMenu.value = false
startCall(CallMediaType.Video)
})
} else {
ItemAction(stringResource(MR.strings.icon_descr_audio_call).capitalize(Locale.current), painterResource(MR.images.ic_call_500), onClick = {
showMenu.value = false
startCall(CallMediaType.Audio)
})
}
ItemAction(stringResource(MR.strings.icon_descr_video_call).capitalize(Locale.current), painterResource(MR.images.ic_videocam), onClick = {
showMenu.value = false
startCall(CallMediaType.Video)
})
}
}
} else if (chatInfo is ChatInfo.Group && chatInfo.groupInfo.canAddMembers) {
@@ -1271,6 +1251,12 @@ fun BoxWithConstraintsScope.ChatItemsList(
}
}
FloatingButtons(chatModel.chatItems, unreadCount, remoteHostId, chatInfo, searchValue, markRead, setFloatingButton, listState)
FloatingDate(
Modifier.padding(top = 10.dp).align(Alignment.TopCenter),
listState,
)
LaunchedEffect(Unit) {
snapshotFlow { listState.isScrollInProgress }
.collect {
@@ -1497,6 +1483,108 @@ private fun TopEndFloatingButton(
}
}
@Composable
private fun FloatingDate(
modifier: Modifier,
listState: LazyListState,
) {
var nearBottomIndex by remember { mutableStateOf(-1) }
var isNearBottom by remember { mutableStateOf(true) }
val lastVisibleItemDate = remember {
derivedStateOf {
if (listState.layoutInfo.visibleItemsInfo.lastIndex >= 0 && listState.firstVisibleItemIndex >= 0) {
val lastVisibleChatItemIndex = chatModel.chatItems.value.lastIndex - listState.firstVisibleItemIndex - listState.layoutInfo.visibleItemsInfo.lastIndex
val item = chatModel.chatItems.value.getOrNull(lastVisibleChatItemIndex)
val timeZone = TimeZone.currentSystemDefault()
item?.meta?.itemTs?.toLocalDateTime(timeZone)?.date?.atStartOfDayIn(timeZone)
} else {
null
}
}
}
val showDate = remember { mutableStateOf(false) }
LaunchedEffect(Unit) {
launch {
snapshotFlow { chatModel.chatId.value }
.distinctUntilChanged()
.collect {
showDate.value = false
isNearBottom = true
nearBottomIndex = -1
}
}
}
LaunchedEffect(Unit) {
snapshotFlow { listState.layoutInfo.visibleItemsInfo }
.collect { visibleItemsInfo ->
if (visibleItemsInfo.find { it.index == 0 } != null) {
var elapsedOffset = 0
for (it in visibleItemsInfo) {
if (elapsedOffset >= listState.layoutInfo.viewportSize.height / 2.5) {
nearBottomIndex = it.index
break;
}
elapsedOffset += it.size
}
}
isNearBottom = if (nearBottomIndex == -1) true else (visibleItemsInfo.firstOrNull()?.index ?: 0) <= nearBottomIndex
}
}
fun setDateVisibility(isVisible: Boolean) {
if (isVisible) {
val now = Clock.System.now()
val date = lastVisibleItemDate.value
if (!isNearBottom && !showDate.value && date != null && getTimestampDateText(date) != getTimestampDateText(now)) {
showDate.value = true
}
} else if (showDate.value) {
showDate.value = false
}
}
LaunchedEffect(Unit) {
var hideDateWhenNotScrolling: Job = Job()
snapshotFlow { listState.firstVisibleItemScrollOffset }
.collect {
setDateVisibility(true)
hideDateWhenNotScrolling.cancel()
hideDateWhenNotScrolling = launch {
delay(1000)
setDateVisibility(false)
}
}
}
AnimatedVisibility(
modifier = modifier,
visible = showDate.value,
enter = fadeIn(tween(durationMillis = 350)),
exit = fadeOut(tween(durationMillis = 350))
) {
val date = lastVisibleItemDate.value
Column {
Text(
text = if (date != null) getTimestampDateText(date) else "",
Modifier
.background(
color = MaterialTheme.colors.secondaryVariant,
RoundedCornerShape(25.dp)
)
.padding(vertical = 4.dp, horizontal = 8.dp)
.clip(RoundedCornerShape(25.dp)),
fontSize = 14.sp,
fontWeight = FontWeight.Medium,
textAlign = TextAlign.Center,
color = MaterialTheme.colors.secondary
)
}
}
}
@Composable
private fun DownloadFilesButton(
forwardConfirmation: ForwardConfirmation.FilesNotAccepted,
@@ -1560,7 +1648,7 @@ private fun ButtonRow(horizontalArrangement: Arrangement.Horizontal, content: @C
private fun DateSeparator(date: Instant) {
Text(
text = getTimestampDateText(date),
Modifier.padding(DEFAULT_PADDING).fillMaxWidth(),
Modifier.padding(vertical = DEFAULT_PADDING_HALF + 4.dp, horizontal = DEFAULT_PADDING_HALF).fillMaxWidth(),
fontSize = 14.sp,
fontWeight = FontWeight.Medium,
textAlign = TextAlign.Center,
@@ -125,9 +125,9 @@ fun reserveSpaceForMeta(
showViaProxy: Boolean = false,
showTimestamp: Boolean
): String {
val iconSpace = " "
val whiteSpace = " "
var res = iconSpace
val iconSpace = " \u00A0\u00A0\u00A0"
val whiteSpace = "\u00A0"
var res = if (showTimestamp) "" else iconSpace
var space: String? = null
fun appendSpace() {
@@ -989,6 +989,7 @@
<string name="audio_device_wired_headphones">Headphones</string>
<string name="audio_device_bluetooth">Bluetooth</string>
<string name="error_initializing_web_view">Error initializing WebView. Update your system to the new version. Please contact developers.\nError: %s</string>
<string name="error_initializing_web_view_wrong_arch">Error initializing WebView. Make sure you have WebView installed and it\'s supported architecture is arm64.\nError: %s</string>
<!-- SimpleXInfo -->
<string name="next_generation_of_private_messaging">The next generation\nof private messaging</string>
@@ -76,6 +76,8 @@ const processCommand = (function () {
iceCandidatePoolSize: 10,
encodedInsertableStreams,
iceTransportPolicy: relay ? "relay" : "all",
// needed for Android WebView >= 69 && <= 72 where default was "plan-b" which is incompatible with transceivers
sdpSemantics: "unified-plan",
},
iceCandidates: {
delay: 750,
@@ -186,6 +188,7 @@ const processCommand = (function () {
localStream,
localScreenStream,
remoteStream,
remoteTracks: new Map(),
remoteScreenStream,
peerMediaSources: {
mic: false,
@@ -201,7 +204,12 @@ const processCommand = (function () {
localOrPeerMediaSourcesChanged(call);
await setupMediaStreams(call);
let connectionTimeout = setTimeout(connectionHandler, answerTimeout);
pc.addEventListener("connectionstatechange", connectionStateChange);
if (pc.connectionState) {
pc.addEventListener("connectionstatechange", connectionStateChange);
}
else {
pc.addEventListener("iceconnectionstatechange", connectionStateChange);
}
return call;
async function connectionStateChange() {
// "failed" means the second party did not answer in time (15 sec timeout in Chrome WebView)
@@ -210,26 +218,38 @@ const processCommand = (function () {
connectionHandler();
}
async function connectionHandler() {
var _a;
sendMessageToNative({
resp: {
type: "connection",
state: {
connectionState: pc.connectionState,
connectionState: (_a = pc.connectionState) !== null && _a !== void 0 ? _a : (pc.iceConnectionState != "completed" && pc.iceConnectionState != "checking"
? pc.iceConnectionState
: pc.iceConnectionState == "completed"
? "connected"
: "connecting") /* webView 69-70 doesn't have connectionState yet */,
iceConnectionState: pc.iceConnectionState,
iceGatheringState: pc.iceGatheringState,
signalingState: pc.signalingState,
},
},
});
if (pc.connectionState == "disconnected" || pc.connectionState == "failed") {
if (pc.connectionState == "disconnected" ||
pc.connectionState == "failed" ||
(!pc.connectionState && (pc.iceConnectionState == "disconnected" || pc.iceConnectionState == "failed"))) {
clearConnectionTimeout();
pc.removeEventListener("connectionstatechange", connectionStateChange);
if (pc.connectionState) {
pc.removeEventListener("connectionstatechange", connectionStateChange);
}
else {
pc.removeEventListener("iceconnectionstatechange", connectionStateChange);
}
if (activeCall) {
setTimeout(() => sendMessageToNative({ resp: { type: "ended" } }), 0);
}
endCall();
}
else if (pc.connectionState == "connected") {
else if (pc.connectionState == "connected" || (!pc.connectionState && pc.iceConnectionState == "connected")) {
clearConnectionTimeout();
const stats = (await pc.getStats());
for (const stat of stats.values()) {
@@ -276,7 +296,7 @@ const processCommand = (function () {
endCall();
let localStream = null;
try {
localStream = await getLocalMediaStream(true, command.media == CallMediaType.Video && !isDesktop, VideoCamera.User);
localStream = await getLocalMediaStream(true, command.media == CallMediaType.Video, VideoCamera.User);
const videos = getVideoElements();
if (videos) {
videos.local.srcObject = localStream;
@@ -305,7 +325,7 @@ const processCommand = (function () {
if (activeCall)
endCall();
inactiveCallMediaSources.mic = true;
inactiveCallMediaSources.camera = command.media == CallMediaType.Video && !isDesktop;
inactiveCallMediaSources.camera = command.media == CallMediaType.Video;
inactiveCallMediaSourcesChanged(inactiveCallMediaSources);
const { media, iceServers, relay } = command;
const encryption = supportsInsertableStreams(useWorker);
@@ -354,7 +374,7 @@ const processCommand = (function () {
activeCall = await initializeCall(getCallConfig(!!aesKey, iceServers, relay), media, aesKey);
const pc = activeCall.connection;
// console.log("offer remoteIceCandidates", JSON.stringify(remoteIceCandidates))
await pc.setRemoteDescription(new RTCSessionDescription(offer));
await pc.setRemoteDescription(new RTCSessionDescription(!webView69Or70() ? offer : adaptSdpToOldWebView(offer)));
// setting up local stream only after setRemoteDescription in order to have transceivers set
await setupLocalStream(false, activeCall);
setupEncryptionForLocalStream(activeCall);
@@ -396,7 +416,7 @@ const processCommand = (function () {
const answer = parse(command.answer);
const remoteIceCandidates = parse(command.iceCandidates);
// console.log("answer remoteIceCandidates", JSON.stringify(remoteIceCandidates))
await pc.setRemoteDescription(new RTCSessionDescription(answer));
await pc.setRemoteDescription(new RTCSessionDescription(!webView69Or70() ? answer : adaptSdpToOldWebView(answer)));
adaptToOldVersion(pc.getTransceivers()[2].currentDirection == "sendonly", activeCall);
addIceCandidates(pc, remoteIceCandidates);
addIceCandidates(pc, afterCallInitializedCandidates);
@@ -548,14 +568,6 @@ const processCommand = (function () {
call.worker = new Worker(URL.createObjectURL(new Blob([workerCode], { type: "text/javascript" })));
call.worker.onerror = ({ error, filename, lineno, message }) => console.log({ error, filename, lineno, message });
// call.worker.onmessage = ({data}) => console.log(JSON.stringify({message: data}))
call.worker.onmessage = ({ data }) => {
console.log(JSON.stringify({ message: data }));
const transceiverMid = data.transceiverMid;
const mute = data.mute;
if (transceiverMid && mute != undefined) {
onMediaMuteUnmute(transceiverMid, mute);
}
};
}
}
}
@@ -661,12 +673,7 @@ const processCommand = (function () {
}
setupMuteUnmuteListener(event.transceiver, track);
const mediaSource = mediaSourceFromTransceiverMid(event.transceiver.mid);
if (mediaSource == CallMediaSource.ScreenAudio || mediaSource == CallMediaSource.ScreenVideo) {
call.remoteScreenStream.addTrack(track);
}
else {
call.remoteStream.addTrack(track);
}
call.remoteTracks.set(mediaSource, track);
console.log(`ontrack success`);
}
catch (e) {
@@ -946,6 +953,7 @@ const processCommand = (function () {
});
}
if (inboundStatsId) {
// even though MSDN site says `packetsReceived` is available in WebView 80+, in reality it's available even in 69
const packets = (_a = stats.get(inboundStatsId)) === null || _a === void 0 ? void 0 : _a.packetsReceived;
if (packets <= lastPacketsReceived) {
mutedSeconds++;
@@ -1023,10 +1031,26 @@ const processCommand = (function () {
if (!mute)
videos.remoteScreen.play().catch((e) => console.log(e));
}
if (!mute)
addRemoteTracksWhenUnmuted(source, activeCall);
localOrPeerMediaSourcesChanged(activeCall);
// Make sure that remote camera and remote screen video in their places and shown/hidden based on layout type currently in use
changeLayout(activeCall.layout);
}
/*
When new remote tracks are coming, they don't get added to remote streams. They are stored in a map and once any of them "unmuted",
that track is added to the stream. Such workaround needed because Safari doesn't play one stream
if another one is not playing too, eg. no audio if only audio is playing while video track is present too but muted.
But we have possibility to have only one currently active track, even no active track at all.
*/
function addRemoteTracksWhenUnmuted(source, call) {
const track = call.remoteTracks.get(source);
if (track) {
const stream = source == CallMediaSource.Mic || source == CallMediaSource.Camera ? call.remoteStream : call.remoteScreenStream;
stream.addTrack(track);
call.remoteTracks.delete(source);
}
}
async function getLocalMediaStream(mic, camera, facingMode) {
if (!mic && !camera)
return new MediaStream();
@@ -1136,7 +1160,7 @@ const processCommand = (function () {
if (peerHasOldVersion) {
console.log("The peer has an old version.", "Tracks size:", activeCall.remoteStream.getAudioTracks().length, activeCall.remoteStream.getVideoTracks().length);
onMediaMuteUnmute("0", false);
if (activeCall.remoteStream.getVideoTracks().length > 0) {
if (activeCall.remoteStream.getVideoTracks().length > 0 || activeCall.remoteTracks.get(CallMediaSource.Camera)) {
onMediaMuteUnmute("1", false);
}
if (activeCall.localMediaSources.camera && !activeCall.peerMediaSources.camera) {
@@ -1152,6 +1176,22 @@ const processCommand = (function () {
}
}
}
function webView69Or70() {
return !isDesktop && (navigator.userAgent.includes("Chrome/69.") || navigator.userAgent.includes("Chrome/70."));
}
// Adding `a=extmap-allow-mixed` causes exception on old WebViews
// https://groups.google.com/a/chromium.org/g/blink-dev/c/7z3uvp0-ZAc/m/8Z7qpp71BgAJ
function adaptSdpToOldWebView(desc) {
var _a;
const res = [];
(_a = desc.sdp) === null || _a === void 0 ? void 0 : _a.split("\n").forEach((line) => {
// Chrome has a bug related to SDP parser in old web view versions
if (!line.includes("a=extmap-allow-mixed")) {
res.push(line);
}
});
return { sdp: res.join("\n"), type: desc.type };
}
return processCommand;
})();
function toggleRemoteVideoFitFill() {
@@ -1 +1 @@
var LZString=function(){function o(o,r){if(!t[o]){t[o]={};for(var n=0;n<o.length;n++)t[o][o.charAt(n)]=n}return t[o][r]}var r=String.fromCharCode,n="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",e="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-$",t={},i={compressToBase64:function(o){if(null==o)return"";var r=i._compress(o,6,function(o){return n.charAt(o)});switch(r.length%4){default:case 0:return r;case 1:return r+"===";case 2:return r+"==";case 3:return r+"="}},decompressFromBase64:function(r){return null==r?"":""==r?null:i._decompress(r.length,32,function(e){return o(n,r.charAt(e))})},compressToUTF16:function(o){return null==o?"":i._compress(o,15,function(o){return r(o+32)})+" "},decompressFromUTF16:function(o){return null==o?"":""==o?null:i._decompress(o.length,16384,function(r){return o.charCodeAt(r)-32})},compressToUint8Array:function(o){for(var r=i.compress(o),n=new Uint8Array(2*r.length),e=0,t=r.length;t>e;e++){var s=r.charCodeAt(e);n[2*e]=s>>>8,n[2*e+1]=s%256}return n},decompressFromUint8Array:function(o){if(null===o||void 0===o)return i.decompress(o);for(var n=new Array(o.length/2),e=0,t=n.length;t>e;e++)n[e]=256*o[2*e]+o[2*e+1];var s=[];return n.forEach(function(o){s.push(r(o))}),i.decompress(s.join(""))},compressToEncodedURIComponent:function(o){return null==o?"":i._compress(o,6,function(o){return e.charAt(o)})},decompressFromEncodedURIComponent:function(r){return null==r?"":""==r?null:(r=r.replace(/ /g,"+"),i._decompress(r.length,32,function(n){return o(e,r.charAt(n))}))},compress:function(o){return i._compress(o,16,function(o){return r(o)})},_compress:function(o,r,n){if(null==o)return"";var e,t,i,s={},p={},u="",c="",a="",l=2,f=3,h=2,d=[],m=0,v=0;for(i=0;i<o.length;i+=1)if(u=o.charAt(i),Object.prototype.hasOwnProperty.call(s,u)||(s[u]=f++,p[u]=!0),c=a+u,Object.prototype.hasOwnProperty.call(s,c))a=c;else{if(Object.prototype.hasOwnProperty.call(p,a)){if(a.charCodeAt(0)<256){for(e=0;h>e;e++)m<<=1,v==r-1?(v=0,d.push(n(m)),m=0):v++;for(t=a.charCodeAt(0),e=0;8>e;e++)m=m<<1|1&t,v==r-1?(v=0,d.push(n(m)),m=0):v++,t>>=1}else{for(t=1,e=0;h>e;e++)m=m<<1|t,v==r-1?(v=0,d.push(n(m)),m=0):v++,t=0;for(t=a.charCodeAt(0),e=0;16>e;e++)m=m<<1|1&t,v==r-1?(v=0,d.push(n(m)),m=0):v++,t>>=1}l--,0==l&&(l=Math.pow(2,h),h++),delete p[a]}else for(t=s[a],e=0;h>e;e++)m=m<<1|1&t,v==r-1?(v=0,d.push(n(m)),m=0):v++,t>>=1;l--,0==l&&(l=Math.pow(2,h),h++),s[c]=f++,a=String(u)}if(""!==a){if(Object.prototype.hasOwnProperty.call(p,a)){if(a.charCodeAt(0)<256){for(e=0;h>e;e++)m<<=1,v==r-1?(v=0,d.push(n(m)),m=0):v++;for(t=a.charCodeAt(0),e=0;8>e;e++)m=m<<1|1&t,v==r-1?(v=0,d.push(n(m)),m=0):v++,t>>=1}else{for(t=1,e=0;h>e;e++)m=m<<1|t,v==r-1?(v=0,d.push(n(m)),m=0):v++,t=0;for(t=a.charCodeAt(0),e=0;16>e;e++)m=m<<1|1&t,v==r-1?(v=0,d.push(n(m)),m=0):v++,t>>=1}l--,0==l&&(l=Math.pow(2,h),h++),delete p[a]}else for(t=s[a],e=0;h>e;e++)m=m<<1|1&t,v==r-1?(v=0,d.push(n(m)),m=0):v++,t>>=1;l--,0==l&&(l=Math.pow(2,h),h++)}for(t=2,e=0;h>e;e++)m=m<<1|1&t,v==r-1?(v=0,d.push(n(m)),m=0):v++,t>>=1;for(;;){if(m<<=1,v==r-1){d.push(n(m));break}v++}return d.join("")},decompress:function(o){return null==o?"":""==o?null:i._decompress(o.length,32768,function(r){return o.charCodeAt(r)})},_decompress:function(o,n,e){var t,i,s,p,u,c,a,l,f=[],h=4,d=4,m=3,v="",w=[],A={val:e(0),position:n,index:1};for(i=0;3>i;i+=1)f[i]=i;for(p=0,c=Math.pow(2,2),a=1;a!=c;)u=A.val&A.position,A.position>>=1,0==A.position&&(A.position=n,A.val=e(A.index++)),p|=(u>0?1:0)*a,a<<=1;switch(t=p){case 0:for(p=0,c=Math.pow(2,8),a=1;a!=c;)u=A.val&A.position,A.position>>=1,0==A.position&&(A.position=n,A.val=e(A.index++)),p|=(u>0?1:0)*a,a<<=1;l=r(p);break;case 1:for(p=0,c=Math.pow(2,16),a=1;a!=c;)u=A.val&A.position,A.position>>=1,0==A.position&&(A.position=n,A.val=e(A.index++)),p|=(u>0?1:0)*a,a<<=1;l=r(p);break;case 2:return""}for(f[3]=l,s=l,w.push(l);;){if(A.index>o)return"";for(p=0,c=Math.pow(2,m),a=1;a!=c;)u=A.val&A.position,A.position>>=1,0==A.position&&(A.position=n,A.val=e(A.index++)),p|=(u>0?1:0)*a,a<<=1;switch(l=p){case 0:for(p=0,c=Math.pow(2,8),a=1;a!=c;)u=A.val&A.position,A.position>>=1,0==A.position&&(A.position=n,A.val=e(A.index++)),p|=(u>0?1:0)*a,a<<=1;f[d++]=r(p),l=d-1,h--;break;case 1:for(p=0,c=Math.pow(2,16),a=1;a!=c;)u=A.val&A.position,A.position>>=1,0==A.position&&(A.position=n,A.val=e(A.index++)),p|=(u>0?1:0)*a,a<<=1;f[d++]=r(p),l=d-1,h--;break;case 2:return w.join("")}if(0==h&&(h=Math.pow(2,m),m++),f[l])v=f[l];else{if(l!==d)return null;v=s+s.charAt(0)}w.push(v),f[d++]=s+v.charAt(0),h--,s=v,0==h&&(h=Math.pow(2,m),m++)}}};return i}();"function"==typeof define&&define.amd?define(function(){return LZString}):"undefined"!=typeof module&&null!=module&&(module.exports=LZString);
var LZString=function(){var r=String.fromCharCode,o="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",n="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-$",e={};function t(r,o){if(!e[r]){e[r]={};for(var n=0;n<r.length;n++)e[r][r.charAt(n)]=n}return e[r][o]}var i={compressToBase64:function(r){if(null==r)return"";var n=i._compress(r,6,function(r){return o.charAt(r)});switch(n.length%4){default:case 0:return n;case 1:return n+"===";case 2:return n+"==";case 3:return n+"="}},decompressFromBase64:function(r){return null==r?"":""==r?null:i._decompress(r.length,32,function(n){return t(o,r.charAt(n))})},compressToUTF16:function(o){return null==o?"":i._compress(o,15,function(o){return r(o+32)})+" "},decompressFromUTF16:function(r){return null==r?"":""==r?null:i._decompress(r.length,16384,function(o){return r.charCodeAt(o)-32})},compressToUint8Array:function(r){for(var o=i.compress(r),n=new Uint8Array(2*o.length),e=0,t=o.length;e<t;e++){var s=o.charCodeAt(e);n[2*e]=s>>>8,n[2*e+1]=s%256}return n},decompressFromUint8Array:function(o){if(null==o)return i.decompress(o);for(var n=new Array(o.length/2),e=0,t=n.length;e<t;e++)n[e]=256*o[2*e]+o[2*e+1];var s=[];return n.forEach(function(o){s.push(r(o))}),i.decompress(s.join(""))},compressToEncodedURIComponent:function(r){return null==r?"":i._compress(r,6,function(r){return n.charAt(r)})},decompressFromEncodedURIComponent:function(r){return null==r?"":""==r?null:(r=r.replace(/ /g,"+"),i._decompress(r.length,32,function(o){return t(n,r.charAt(o))}))},compress:function(o){return i._compress(o,16,function(o){return r(o)})},_compress:function(r,o,n){if(null==r)return"";var e,t,i,s={},u={},a="",p="",c="",l=2,f=3,h=2,d=[],m=0,v=0;for(i=0;i<r.length;i+=1)if(a=r.charAt(i),Object.prototype.hasOwnProperty.call(s,a)||(s[a]=f++,u[a]=!0),p=c+a,Object.prototype.hasOwnProperty.call(s,p))c=p;else{if(Object.prototype.hasOwnProperty.call(u,c)){if(c.charCodeAt(0)<256){for(e=0;e<h;e++)m<<=1,v==o-1?(v=0,d.push(n(m)),m=0):v++;for(t=c.charCodeAt(0),e=0;e<8;e++)m=m<<1|1&t,v==o-1?(v=0,d.push(n(m)),m=0):v++,t>>=1}else{for(t=1,e=0;e<h;e++)m=m<<1|t,v==o-1?(v=0,d.push(n(m)),m=0):v++,t=0;for(t=c.charCodeAt(0),e=0;e<16;e++)m=m<<1|1&t,v==o-1?(v=0,d.push(n(m)),m=0):v++,t>>=1}0==--l&&(l=Math.pow(2,h),h++),delete u[c]}else for(t=s[c],e=0;e<h;e++)m=m<<1|1&t,v==o-1?(v=0,d.push(n(m)),m=0):v++,t>>=1;0==--l&&(l=Math.pow(2,h),h++),s[p]=f++,c=String(a)}if(""!==c){if(Object.prototype.hasOwnProperty.call(u,c)){if(c.charCodeAt(0)<256){for(e=0;e<h;e++)m<<=1,v==o-1?(v=0,d.push(n(m)),m=0):v++;for(t=c.charCodeAt(0),e=0;e<8;e++)m=m<<1|1&t,v==o-1?(v=0,d.push(n(m)),m=0):v++,t>>=1}else{for(t=1,e=0;e<h;e++)m=m<<1|t,v==o-1?(v=0,d.push(n(m)),m=0):v++,t=0;for(t=c.charCodeAt(0),e=0;e<16;e++)m=m<<1|1&t,v==o-1?(v=0,d.push(n(m)),m=0):v++,t>>=1}0==--l&&(l=Math.pow(2,h),h++),delete u[c]}else for(t=s[c],e=0;e<h;e++)m=m<<1|1&t,v==o-1?(v=0,d.push(n(m)),m=0):v++,t>>=1;0==--l&&(l=Math.pow(2,h),h++)}for(t=2,e=0;e<h;e++)m=m<<1|1&t,v==o-1?(v=0,d.push(n(m)),m=0):v++,t>>=1;for(;;){if(m<<=1,v==o-1){d.push(n(m));break}v++}return d.join("")},decompress:function(r){return null==r?"":""==r?null:i._decompress(r.length,32768,function(o){return r.charCodeAt(o)})},_decompress:function(o,n,e){var t,i,s,u,a,p,c,l=[],f=4,h=4,d=3,m="",v=[],g={val:e(0),position:n,index:1};for(t=0;t<3;t+=1)l[t]=t;for(s=0,a=Math.pow(2,2),p=1;p!=a;)u=g.val&g.position,g.position>>=1,0==g.position&&(g.position=n,g.val=e(g.index++)),s|=(u>0?1:0)*p,p<<=1;switch(s){case 0:for(s=0,a=Math.pow(2,8),p=1;p!=a;)u=g.val&g.position,g.position>>=1,0==g.position&&(g.position=n,g.val=e(g.index++)),s|=(u>0?1:0)*p,p<<=1;c=r(s);break;case 1:for(s=0,a=Math.pow(2,16),p=1;p!=a;)u=g.val&g.position,g.position>>=1,0==g.position&&(g.position=n,g.val=e(g.index++)),s|=(u>0?1:0)*p,p<<=1;c=r(s);break;case 2:return""}for(l[3]=c,i=c,v.push(c);;){if(g.index>o)return"";for(s=0,a=Math.pow(2,d),p=1;p!=a;)u=g.val&g.position,g.position>>=1,0==g.position&&(g.position=n,g.val=e(g.index++)),s|=(u>0?1:0)*p,p<<=1;switch(c=s){case 0:for(s=0,a=Math.pow(2,8),p=1;p!=a;)u=g.val&g.position,g.position>>=1,0==g.position&&(g.position=n,g.val=e(g.index++)),s|=(u>0?1:0)*p,p<<=1;l[h++]=r(s),c=h-1,f--;break;case 1:for(s=0,a=Math.pow(2,16),p=1;p!=a;)u=g.val&g.position,g.position>>=1,0==g.position&&(g.position=n,g.val=e(g.index++)),s|=(u>0?1:0)*p,p<<=1;l[h++]=r(s),c=h-1,f--;break;case 2:return v.join("")}if(0==f&&(f=Math.pow(2,d),d++),l[c])m=l[c];else{if(c!==h)return null;m=i+i.charAt(0)}v.push(m),l[h++]=i+m.charAt(0),i=m,0==--f&&(f=Math.pow(2,d),d++)}}};return i}();"function"==typeof define&&define.amd?define(function(){return LZString}):"undefined"!=typeof module&&null!=module?module.exports=LZString:"undefined"!=typeof angular&&null!=angular&&angular.module("LZString",[]).factory("LZString",function(){return LZString});
+15 -1
View File
@@ -12,7 +12,7 @@ constraints: zip +disable-bzip2 +disable-zstd
source-repository-package
type: git
location: https://github.com/simplex-chat/simplexmq.git
tag: 03168b9fbfd8a507a5374ff3375609e705225e29
tag: da79d544cf990fb0638ae5434407d6a30724fb87
source-repository-package
type: git
@@ -49,3 +49,17 @@ source-repository-package
type: git
location: https://github.com/simplex-chat/zip.git
tag: bd421c6b19cc4c465cd7af1f6f26169fb8ee1ebc
-- waiting for published warp-tls-3.4.7
source-repository-package
type: git
location: https://github.com/yesodweb/wai.git
tag: ec5e017d896a78e787a5acea62b37a4e677dec2e
subdir: warp-tls
-- backported fork due http-5.0
source-repository-package
type: git
location: https://github.com/simplex-chat/wai.git
tag: 2f6e5aa5f05ba9140ac99e195ee647b4f7d926b0
subdir: warp
+1 -1
View File
@@ -1,5 +1,5 @@
name: simplex-chat
version: 6.1.0.4
version: 6.1.0.5
#synopsis:
#description:
homepage: https://github.com/simplex-chat/simplex-chat#readme
+2 -2
View File
@@ -27,7 +27,7 @@
"author": "SimpleX Chat",
"license": "AGPL-3.0-or-later",
"devDependencies": {
"@types/lz-string": "^1.3.34",
"@types/lz-string": "1.3.34",
"husky": "^7.0.4",
"isomorphic-webcrypto": "^2.3.8",
"lint-staged": "^12.4.1",
@@ -38,6 +38,6 @@
"**/*": "prettier --write --ignore-unknown"
},
"dependencies": {
"lz-string": "^1.4.4"
"lz-string": "1.5.0"
}
}
+74 -24
View File
@@ -248,7 +248,10 @@ interface Call {
localCamera: VideoCamera
localStream: MediaStream
localScreenStream: MediaStream
// has no tracks in the beggining, see addRemoteTracksWhenUnmuted
remoteStream: MediaStream
remoteTracks: Map<CallMediaSource, MediaStreamTrack>
// has no tracks in the beggining too
remoteScreenStream: MediaStream
peerMediaSources: CallMediaSources
aesKey?: string
@@ -308,8 +311,12 @@ const processCommand = (function () {
encodedInsertableStreams: boolean
}
type RTCConfigurationWithSdpSemantics = RTCConfiguration & {
sdpSemantics: string
}
interface CallConfig {
peerConnectionConfig: RTCConfigurationWithEncryption
peerConnectionConfig: RTCConfigurationWithEncryption & RTCConfigurationWithSdpSemantics
iceCandidates: {
delay: number
extrasInterval: number
@@ -331,6 +338,8 @@ const processCommand = (function () {
iceCandidatePoolSize: 10,
encodedInsertableStreams,
iceTransportPolicy: relay ? "relay" : "all",
// needed for Android WebView >= 69 && <= 72 where default was "plan-b" which is incompatible with transceivers
sdpSemantics: "unified-plan",
},
iceCandidates: {
delay: 750,
@@ -439,6 +448,7 @@ const processCommand = (function () {
localStream,
localScreenStream,
remoteStream,
remoteTracks: new Map(),
remoteScreenStream,
peerMediaSources: {
mic: false,
@@ -454,7 +464,11 @@ const processCommand = (function () {
localOrPeerMediaSourcesChanged(call)
await setupMediaStreams(call)
let connectionTimeout: number | undefined = setTimeout(connectionHandler, answerTimeout)
pc.addEventListener("connectionstatechange", connectionStateChange)
if (pc.connectionState) {
pc.addEventListener("connectionstatechange", connectionStateChange)
} else {
pc.addEventListener("iceconnectionstatechange", connectionStateChange)
}
return call
async function connectionStateChange() {
@@ -468,21 +482,35 @@ const processCommand = (function () {
resp: {
type: "connection",
state: {
connectionState: pc.connectionState,
connectionState:
pc.connectionState ??
(pc.iceConnectionState != "completed" && pc.iceConnectionState != "checking"
? pc.iceConnectionState
: pc.iceConnectionState == "completed"
? "connected"
: "connecting") /* webView 69-70 doesn't have connectionState yet */,
iceConnectionState: pc.iceConnectionState,
iceGatheringState: pc.iceGatheringState,
signalingState: pc.signalingState,
},
},
})
if (pc.connectionState == "disconnected" || pc.connectionState == "failed") {
if (
pc.connectionState == "disconnected" ||
pc.connectionState == "failed" ||
(!pc.connectionState && (pc.iceConnectionState == "disconnected" || pc.iceConnectionState == "failed"))
) {
clearConnectionTimeout()
pc.removeEventListener("connectionstatechange", connectionStateChange)
if (pc.connectionState) {
pc.removeEventListener("connectionstatechange", connectionStateChange)
} else {
pc.removeEventListener("iceconnectionstatechange", connectionStateChange)
}
if (activeCall) {
setTimeout(() => sendMessageToNative({resp: {type: "ended"}}), 0)
}
endCall()
} else if (pc.connectionState == "connected") {
} else if (pc.connectionState == "connected" || (!pc.connectionState && pc.iceConnectionState == "connected")) {
clearConnectionTimeout()
const stats = (await pc.getStats()) as Map<string, any>
for (const stat of stats.values()) {
@@ -532,7 +560,7 @@ const processCommand = (function () {
let localStream: MediaStream | null = null
try {
localStream = await getLocalMediaStream(true, command.media == CallMediaType.Video && !isDesktop, VideoCamera.User)
localStream = await getLocalMediaStream(true, command.media == CallMediaType.Video, VideoCamera.User)
const videos = getVideoElements()
if (videos) {
videos.local.srcObject = localStream
@@ -560,7 +588,7 @@ const processCommand = (function () {
if (activeCall) endCall()
inactiveCallMediaSources.mic = true
inactiveCallMediaSources.camera = command.media == CallMediaType.Video && !isDesktop
inactiveCallMediaSources.camera = command.media == CallMediaType.Video
inactiveCallMediaSourcesChanged(inactiveCallMediaSources)
const {media, iceServers, relay} = command
@@ -609,7 +637,7 @@ const processCommand = (function () {
activeCall = await initializeCall(getCallConfig(!!aesKey, iceServers, relay), media, aesKey)
const pc = activeCall.connection
// console.log("offer remoteIceCandidates", JSON.stringify(remoteIceCandidates))
await pc.setRemoteDescription(new RTCSessionDescription(offer))
await pc.setRemoteDescription(new RTCSessionDescription(!webView69Or70() ? offer : adaptSdpToOldWebView(offer)))
// setting up local stream only after setRemoteDescription in order to have transceivers set
await setupLocalStream(false, activeCall)
setupEncryptionForLocalStream(activeCall)
@@ -650,7 +678,7 @@ const processCommand = (function () {
const remoteIceCandidates: RTCIceCandidateInit[] = parse(command.iceCandidates)
// console.log("answer remoteIceCandidates", JSON.stringify(remoteIceCandidates))
await pc.setRemoteDescription(new RTCSessionDescription(answer))
await pc.setRemoteDescription(new RTCSessionDescription(!webView69Or70() ? answer : adaptSdpToOldWebView(answer)))
adaptToOldVersion(pc.getTransceivers()[2].currentDirection == "sendonly", activeCall!)
addIceCandidates(pc, remoteIceCandidates)
addIceCandidates(pc, afterCallInitializedCandidates)
@@ -794,14 +822,6 @@ const processCommand = (function () {
call.worker = new Worker(URL.createObjectURL(new Blob([workerCode], {type: "text/javascript"})))
call.worker.onerror = ({error, filename, lineno, message}: ErrorEvent) => console.log({error, filename, lineno, message})
// call.worker.onmessage = ({data}) => console.log(JSON.stringify({message: data}))
call.worker.onmessage = ({data}) => {
console.log(JSON.stringify({message: data}))
const transceiverMid: string = data.transceiverMid
const mute: boolean = data.mute
if (transceiverMid && mute != undefined) {
onMediaMuteUnmute(transceiverMid, mute)
}
}
}
}
}
@@ -927,11 +947,7 @@ const processCommand = (function () {
setupMuteUnmuteListener(event.transceiver, track)
const mediaSource = mediaSourceFromTransceiverMid(event.transceiver.mid)
if (mediaSource == CallMediaSource.ScreenAudio || mediaSource == CallMediaSource.ScreenVideo) {
call.remoteScreenStream.addTrack(track)
} else {
call.remoteStream.addTrack(track)
}
call.remoteTracks.set(mediaSource, track)
console.log(`ontrack success`)
} catch (e) {
console.log(`ontrack error: ${(e as Error).message}`)
@@ -1227,6 +1243,7 @@ const processCommand = (function () {
})
}
if (inboundStatsId) {
// even though MSDN site says `packetsReceived` is available in WebView 80+, in reality it's available even in 69
const packets = (stats as any).get(inboundStatsId)?.packetsReceived
if (packets <= lastPacketsReceived) {
mutedSeconds++
@@ -1296,11 +1313,27 @@ const processCommand = (function () {
sendMessageToNative({resp: resp})
if (!mute) videos.remoteScreen.play().catch((e) => console.log(e))
}
if (!mute) addRemoteTracksWhenUnmuted(source, activeCall)
localOrPeerMediaSourcesChanged(activeCall)
// Make sure that remote camera and remote screen video in their places and shown/hidden based on layout type currently in use
changeLayout(activeCall.layout)
}
/*
When new remote tracks are coming, they don't get added to remote streams. They are stored in a map and once any of them "unmuted",
that track is added to the stream. Such workaround needed because Safari doesn't play one stream
if another one is not playing too, eg. no audio if only audio is playing while video track is present too but muted.
But we have possibility to have only one currently active track, even no active track at all.
*/
function addRemoteTracksWhenUnmuted(source: CallMediaSource, call: Call) {
const track = call.remoteTracks.get(source)
if (track) {
const stream = source == CallMediaSource.Mic || source == CallMediaSource.Camera ? call.remoteStream : call.remoteScreenStream
stream.addTrack(track)
call.remoteTracks.delete(source)
}
}
async function getLocalMediaStream(mic: boolean, camera: boolean, facingMode: VideoCamera): Promise<MediaStream> {
if (!mic && !camera) return new MediaStream()
const constraints = callMediaConstraints(mic, camera, facingMode)
@@ -1422,7 +1455,7 @@ const processCommand = (function () {
activeCall.remoteStream.getVideoTracks().length
)
onMediaMuteUnmute("0", false)
if (activeCall.remoteStream.getVideoTracks().length > 0) {
if (activeCall.remoteStream.getVideoTracks().length > 0 || activeCall.remoteTracks.get(CallMediaSource.Camera)) {
onMediaMuteUnmute("1", false)
}
if (activeCall.localMediaSources.camera && !activeCall.peerMediaSources.camera) {
@@ -1439,6 +1472,23 @@ const processCommand = (function () {
}
}
function webView69Or70(): boolean {
return !isDesktop && (navigator.userAgent.includes("Chrome/69.") || navigator.userAgent.includes("Chrome/70."))
}
// Adding `a=extmap-allow-mixed` causes exception on old WebViews
// https://groups.google.com/a/chromium.org/g/blink-dev/c/7z3uvp0-ZAc/m/8Z7qpp71BgAJ
function adaptSdpToOldWebView(desc: RTCSessionDescriptionInit): RTCSessionDescriptionInit {
const res: string[] = []
desc.sdp?.split("\n").forEach((line) => {
// Chrome has a bug related to SDP parser in old web view versions
if (!line.includes("a=extmap-allow-mixed")) {
res.push(line)
}
})
return {sdp: res.join("\n"), type: desc.type}
}
return processCommand
})()
+3 -1
View File
@@ -1,5 +1,5 @@
{
"https://github.com/simplex-chat/simplexmq.git"."03168b9fbfd8a507a5374ff3375609e705225e29" = "0g6xry0far2wppfxv99hqh3ckldglmpazib5l8vsvcmivcz5zww1";
"https://github.com/simplex-chat/simplexmq.git"."da79d544cf990fb0638ae5434407d6a30724fb87" = "11rxpcg2g781rbr5d20fw6zpv81q06w3c9bh6qh5cpnza230yvl3";
"https://github.com/simplex-chat/hs-socks.git"."a30cc7a79a08d8108316094f8f2f82a0c5e1ac51" = "0yasvnr7g91k76mjkamvzab2kvlb1g5pspjyjn2fr6v83swjhj38";
"https://github.com/simplex-chat/direct-sqlcipher.git"."f814ee68b16a9447fbb467ccc8f29bdd3546bfd9" = "1ql13f4kfwkbaq7nygkxgw84213i0zm7c1a8hwvramayxl38dq5d";
"https://github.com/simplex-chat/sqlcipher-simple.git"."a46bd361a19376c5211f1058908fc0ae6bf42446" = "1z0r78d8f0812kxbgsm735qf6xx8lvaz27k1a0b4a2m0sshpd5gl";
@@ -7,4 +7,6 @@
"https://github.com/simplex-chat/haskell-terminal.git"."f708b00009b54890172068f168bf98508ffcd495" = "0zmq7lmfsk8m340g47g5963yba7i88n4afa6z93sg9px5jv1mijj";
"https://github.com/simplex-chat/android-support.git"."9aa09f148089d6752ce563b14c2df1895718d806" = "0pbf2pf13v2kjzi397nr13f1h3jv0imvsq8rpiyy2qyx5vd50pqn";
"https://github.com/simplex-chat/zip.git"."bd421c6b19cc4c465cd7af1f6f26169fb8ee1ebc" = "1csqfjhvc8wb5h4kxxndmb6iw7b4ib9ff2n81hrizsmnf45a6gg0";
"https://github.com/yesodweb/wai.git"."ec5e017d896a78e787a5acea62b37a4e677dec2e" = "1ckcpmpjfy9jiqrb52q20lj7ln4hmq9v2jk6kpkf3m68c1m9c2bx";
"https://github.com/simplex-chat/wai.git"."2f6e5aa5f05ba9140ac99e195ee647b4f7d926b0" = "199g4rjdf1zp1fcw8nqdsyr1h36hmg424qqx03071jk7j00z7ay4";
}
+1 -1
View File
@@ -5,7 +5,7 @@ cabal-version: 1.12
-- see: https://github.com/sol/hpack
name: simplex-chat
version: 6.1.0.4
version: 6.1.0.5
category: Web, System, Services, Cryptography
homepage: https://github.com/simplex-chat/simplex-chat#readme
author: simplex.chat
+22 -12
View File
@@ -52,7 +52,7 @@ import Simplex.Messaging.Protocol (srvHostnamesSMPClientVersion)
import Simplex.Messaging.Server (runSMPServerBlocking)
import Simplex.Messaging.Server.Env.STM
import Simplex.Messaging.Transport
import Simplex.Messaging.Transport.Server (TransportServerConfig (..), defaultTransportServerConfig)
import Simplex.Messaging.Transport.Server (ServerCredentials (..), TransportServerConfig (..), defaultTransportServerConfig)
import Simplex.Messaging.Version
import Simplex.Messaging.Version.Internal
import System.Directory (createDirectoryIfMissing, removeDirectoryRecursive)
@@ -420,7 +420,7 @@ concurrentlyN_ = mapConcurrently_ id
smpServerCfg :: ServerConfig
smpServerCfg =
ServerConfig
{ transports = [(serverPort, transport @TLS)],
{ transports = [(serverPort, transport @TLS, False)],
tbqSize = 1,
-- serverTbqSize = 1,
msgQueueQuota = 16,
@@ -428,23 +428,30 @@ smpServerCfg =
msgIdBytes = 6,
storeLogFile = Nothing,
storeMsgsFile = Nothing,
storeNtfsFile = Nothing,
allowNewQueues = True,
-- server password is disabled as otherwise v1 tests fail
newQueueBasicAuth = Nothing, -- Just "server_password",
controlPortUserAuth = Nothing,
controlPortAdminAuth = Nothing,
messageExpiration = Just defaultMessageExpiration,
notificationExpiration = defaultNtfExpiration,
inactiveClientExpiration = Just defaultInactiveClientExpiration,
caCertificateFile = "tests/fixtures/tls/ca.crt",
privateKeyFile = "tests/fixtures/tls/server.key",
certificateFile = "tests/fixtures/tls/server.crt",
smpCredentials =
ServerCredentials
{ caCertificateFile = Just "tests/fixtures/tls/ca.crt",
privateKeyFile = "tests/fixtures/tls/server.key",
certificateFile = "tests/fixtures/tls/server.crt"
},
httpCredentials = Nothing,
logStatsInterval = Nothing,
logStatsStartTime = 0,
serverStatsLogFile = "tests/smp-server-stats.daily.log",
serverStatsBackupFile = Nothing,
pendingENDInterval = 500000,
ntfDeliveryInterval = 200000,
smpServerVRange = supportedServerSMPRelayVRange,
transportConfig = defaultTransportServerConfig {alpn = Just supportedSMPHandshakes},
transportConfig = defaultTransportServerConfig,
smpHandshakeTimeout = 1000000,
controlPort = Nothing,
smpAgentCfg = defaultSMPClientAgentConfig,
@@ -457,7 +464,7 @@ withSmpServer :: IO () -> IO ()
withSmpServer = withSmpServer' smpServerCfg
withSmpServer' :: ServerConfig -> IO () -> IO ()
withSmpServer' cfg = serverBracket (`runSMPServerBlocking` cfg)
withSmpServer' cfg = serverBracket (\started -> runSMPServerBlocking started cfg Nothing)
xftpTestPort :: ServiceName
xftpTestPort = "7002"
@@ -481,16 +488,19 @@ xftpServerConfig =
fileExpiration = Just defaultFileExpiration,
fileTimeout = 10000000,
inactiveClientExpiration = Just defaultInactiveClientExpiration,
caCertificateFile = "tests/fixtures/tls/ca.crt",
privateKeyFile = "tests/fixtures/tls/server.key",
certificateFile = "tests/fixtures/tls/server.crt",
xftpCredentials =
ServerCredentials
{ caCertificateFile = Just "tests/fixtures/tls/ca.crt",
privateKeyFile = "tests/fixtures/tls/server.key",
certificateFile = "tests/fixtures/tls/server.crt"
},
xftpServerVRange = supportedFileServerVRange,
logStatsInterval = Nothing,
logStatsStartTime = 0,
serverStatsLogFile = "tests/tmp/xftp-server-stats.daily.log",
serverStatsBackupFile = Nothing,
controlPort = Nothing,
transportConfig = defaultTransportServerConfig {alpn = Just supportedXFTPhandshakes},
transportConfig = defaultTransportServerConfig,
responseDelay = 0
}
@@ -502,7 +512,7 @@ withXFTPServer' cfg =
serverBracket
( \started -> do
createDirectoryIfMissing False xftpServerFiles
runXFTPServerBlocking started cfg
runXFTPServerBlocking started cfg Nothing
)
serverBracket :: (TMVar Bool -> IO ()) -> IO () -> IO ()
+1 -1
View File
@@ -6419,7 +6419,7 @@ testGroupMemberInactive tmp = do
where
serverCfg' =
smpServerCfg
{ transports = [("7003", transport @TLS)],
{ transports = [("7003", transport @TLS, False)],
msgQueueQuota = 2
}
fastRetryInterval = defaultReconnectInterval {initialInterval = 50_000} -- same as in agent tests
+1 -1
View File
@@ -1689,7 +1689,7 @@ testChangePCCUserDiffSrv tmp = do
where
serverCfg' =
smpServerCfg
{ transports = [("7003", transport @TLS), ("7002", transport @TLS)],
{ transports = [("7003", transport @TLS, False), ("7002", transport @TLS, False)],
msgQueueQuota = 2
}