Compare commits

..

229 Commits

Author SHA1 Message Date
Evgeny Poberezkin bf25b116d7 Merge branch 'stable' into stable-ios 2024-01-18 20:59:49 +00:00
Evgeny Poberezkin 5236e0f201 core: 5.4.4.0 2024-01-18 20:56:45 +00:00
Evgeny Poberezkin 1eb1ed92f7 ci: disable *-armv7a tags 2024-01-17 19:27:07 +00:00
Evgeny Poberezkin c25e9e3b72 scripts: curl/wget security (#3693) 2024-01-17 15:23:43 +00:00
Evgeny Poberezkin 300223b32e core: update simplexmq 5.5.0.6 (fix race conditions) (#3691)
* core: update simplexmq (fix race conditions)

* simplexmq 5.5.0.6
2024-01-16 23:42:29 +00:00
Evgeny Poberezkin 8d7dcb550a core: update simplexmq, optimize batching, remove builder (#3685)
* core: update simplexmq (optimize batching, remove builder)

* do not use builder to batch

* refactor
2024-01-15 10:46:13 +00:00
Evgeny Poberezkin c070d69114 Merge branch 'stable' into stable-ios 2024-01-10 12:17:26 +00:00
Evgeny Poberezkin 045b195483 5.4.3: ios 188, android 169, desktop 22 2024-01-10 11:56:57 +00:00
Evgeny Poberezkin a3b91ad182 Merge branch 'stable' into stable-ios 2024-01-09 20:20:52 +00:00
Evgeny Poberezkin 53414608db core: 5.4.3.0 (simplexmq 5.5.0.5) 2024-01-09 20:20:14 +00:00
Stanislav Dmitrenko c7cf206585 android: fix call sound when the app in the background (#3660)
* android: fix call sound when the app in the background

* using previous notification channel

* Revert "using previous notification channel"

This reverts commit 19da9a9ce193c39b353f478e884a97bbbf002e77.

* prevent playing sound on call twice
2024-01-09 19:45:46 +00:00
Evgeny Poberezkin 6067ac3c93 ios: more aggressive GC in NSE 2024-01-09 19:34:54 +00:00
Evgeny Poberezkin 591df1e0f4 Merge branch 'stable' into stable-ios 2024-01-09 10:40:52 +00:00
Evgeny Poberezkin a2f190a6c6 core: update simplexmq (better batching) 2024-01-09 09:15:35 +00:00
Stanislav Dmitrenko 267178dddb android, desktop: show alerts on critical and internal errors (#3653)
* android, desktop: show alerts on critical and internal errors

* test

* don't stop chat if it's stopped already

* show notification

* restart chat or app

* Revert "test"

This reverts commit 5b78bbae5b.

* update strings

* strings2

* refactoring

* refactoring2

* refactoring3

---------

Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>
2024-01-08 18:20:52 +00:00
spaced4ndy fadce0c140 core: create new chat controller with chatActivated set to true 2024-01-08 17:34:10 +04:00
spaced4ndy 58ad97fe6d core: pause cleanup when chat is suspended (#3658) 2024-01-08 17:28:01 +04:00
Evgeny Poberezkin 3ccd9903a7 core: do not start clean up manager in background NSE (#3657)
* core: do not start clean up manager in background NSE

* update UIs

* fix test
2024-01-08 12:53:16 +00:00
Evgeny Poberezkin e294999044 ios: fix callkit calls via NSE (#3655)
* ios: fix callkit calls via NSE

* comments

* more reliable NSE start

* remove public logs, different RTS parameters for NSE

* only suspend NSE if we have chat controller, to avoid crashes if suspension attempted without controller created

* comments

* fix

* simplify
2024-01-08 10:56:01 +00:00
Evgeny Poberezkin b1156d401c Merge branch 'stable' into stable-ios 2024-01-06 11:49:37 +00:00
Evgeny Poberezkin 2bbc687f4a core: simplexmq 5.5.0.4 2024-01-06 11:48:28 +00:00
Evgeny Poberezkin bb61b9c658 core: update simplexmq (critical errors, worker restarts, subscription timeouts) 2024-01-05 20:07:19 +00:00
sh 575d899f5a build-android: fix new arrangement of nix command (#3634) 2024-01-02 14:39:23 +00:00
Evgeny Poberezkin 3411658a8d Merge branch 'stable' into stable-ios 2023-12-30 10:21:46 +00:00
Evgeny Poberezkin fdbfeb6652 Merge branch 'master-ios' into stable-ios 2023-12-28 09:18:42 +00:00
Evgeny Poberezkin 2c6b0ef917 Merge branch 'master-ghc8107' into master-ios 2023-12-27 21:03:06 +00:00
Evgeny Poberezkin 5d8dd8ffd3 Merge branch 'master-ghc8107' into master-ios 2023-12-27 14:10:02 +00:00
Evgeny Poberezkin 235b220378 Merge branch 'master-ghc8107' into master-ios 2023-12-26 21:27:34 +00:00
Evgeny Poberezkin 6a8dba25f0 Merge branch 'master-ghc8107' into master-ios 2023-12-23 19:57:49 +00:00
Evgeny Poberezkin decfbdb07b Merge branch 'master-ghc8107' into master-ios 2023-12-23 17:25:40 +00:00
Evgeny Poberezkin 9becf48db6 Merge branch 'master-ghc8107' into master-ios 2023-12-23 15:13:16 +00:00
Evgeny Poberezkin 2590fc0c80 Merge branch 'master-ghc8107' into master-ios 2023-12-21 10:00:44 +00:00
Evgeny Poberezkin cdd735930d Merge branch 'master-ghc8107' into master-ios 2023-12-21 00:45:46 +00:00
Evgeny Poberezkin 9bfc2ed16e nix: fix script 2023-12-13 20:30:25 +00:00
Evgeny Poberezkin 52c22c2f77 nix: fix direct-sqlcipher sha 2023-12-13 20:23:18 +00:00
Evgeny Poberezkin f16da09213 Merge branch 'master-ghc8107' into master-ios 2023-12-13 12:36:22 +00:00
Evgeny Poberezkin a993a26920 Merge branch 'master-ghc8107' into master-ios 2023-12-11 17:37:17 +00:00
Evgeny Poberezkin aff589becd Merge branch 'master-ghc8107' into master-ios 2023-12-11 14:57:49 +00:00
spaced4ndy 5125b27938 Merge branch 'master-ghc8107' into master-ios 2023-12-11 17:53:26 +04:00
Evgeny Poberezkin 691d318764 Merge branch 'master-ios' into stable-ios 2023-12-09 20:43:45 +00:00
Evgeny Poberezkin 28b7bad69f Merge branch 'master-ghc8107' into master-ios 2023-12-07 15:13:12 +00:00
Evgeny Poberezkin 4efd505fd3 Merge branch 'master-ghc8107' into master-ios 2023-12-04 12:32:23 +00:00
spaced4ndy bcb2e9fb9b Merge branch 'master-ghc8107' into master-ios 2023-11-30 21:11:07 +04:00
spaced4ndy 48056d7452 Merge branch 'master-ghc8107' into master-ios 2023-11-30 20:57:16 +04:00
spaced4ndy b5a99b2b14 Merge branch 'master-ghc8107' into master-ios 2023-11-27 19:17:56 +04:00
Evgeny Poberezkin 5899b8f734 Merge branch 'master-ghc8107' into master-ios 2023-11-26 20:00:03 +00:00
Evgeny Poberezkin d9428db2f5 Merge branch 'master-ios' into stable-ios 2023-11-26 13:15:13 +00:00
Evgeny Poberezkin 9e9a6ac64e Merge branch 'master' into master-ios 2023-11-26 11:51:34 +00:00
Evgeny Poberezkin 1bbaffe0a6 Merge branch 'master-ghc8107' into master-ios 2023-11-24 20:02:30 +00:00
Evgeny Poberezkin 57eea0947f Merge branch 'master' into master-ios 2023-11-23 16:23:30 +00:00
Evgeny Poberezkin 006ab7c46a Merge branch 'master-ghc8107' into master-ios 2023-11-21 21:15:39 +00:00
spaced4ndy 45026b6bf5 Merge branch 'master-ghc8107' into master-ios 2023-11-21 19:42:06 +04:00
Evgeny Poberezkin 12f38028f3 Merge branch 'master-ghc8107' into master-ios 2023-11-21 00:01:53 +00:00
Evgeny Poberezkin 4fecfe825a update hpack 2023-11-20 14:34:25 +00:00
Evgeny Poberezkin fad4cbf7e5 Merge branch 'master-ghc8107' into master-ios 2023-11-20 14:30:44 +00:00
Evgeny Poberezkin b6b23d6ddd Merge branch 'master-ghc8107' into master-ios 2023-11-20 13:25:10 +00:00
spaced4ndy 9ecd5ff1b2 Merge branch 'master-ghc8107' into master-ios 2023-11-20 14:07:45 +04:00
Evgeny Poberezkin 0297cc43d0 Merge branch 'master-ghc8107' into master-ios 2023-11-20 00:07:33 +00:00
Evgeny Poberezkin 20dcfbbffe Merge branch 'master-ghc8107' into master-ios 2023-11-17 11:48:16 +00:00
Evgeny Poberezkin 909ff6516b Merge branch 'master-ghc8107' into master-ios 2023-11-16 18:55:39 +00:00
Evgeny Poberezkin bfb6dfb2c5 Merge branch 'master-ghc8107' into master-ios 2023-11-11 13:57:13 +00:00
Evgeny Poberezkin 2f1c7400e9 Merge branch 'master-ghc8107' into master-ios 2023-11-11 09:52:27 +00:00
Evgeny Poberezkin 168a31c9d7 Merge branch 'master-ghc8107' into master-ios 2023-11-10 21:22:56 +00:00
Evgeny Poberezkin 8e33b92f39 Merge branch 'master-ghc8107' into master-ios 2023-11-10 21:08:36 +00:00
Evgeny Poberezkin 3c35dcb4f2 Merge branch 'master-ghc8107' into master-ios 2023-11-06 11:27:10 +00:00
spaced4ndy 552dc9ab64 Merge branch 'master-ghc8107' into master-ios 2023-11-06 11:42:23 +04:00
Evgeny Poberezkin 916e14e44c Merge branch 'master-ghc8107' into master-ios 2023-11-04 13:39:57 +00:00
spaced4ndy c27e7fb68d Merge branch 'master-ghc8107' into master-ios 2023-10-30 21:00:55 +04:00
Evgeny Poberezkin c84d96b534 Merge branch 'master-ghc8107' into master-ios 2023-10-29 18:27:26 +00:00
spaced4ndy e2a6ff28fb Merge branch 'master-ghc8107' into master-ios 2023-10-25 10:47:53 +04:00
spaced4ndy aaab15175d Merge branch 'master-ghc8107' into master-ios 2023-10-24 18:14:10 +04:00
spaced4ndy 64b4d6c6f6 Merge branch 'master-ghc8107' into master-ios 2023-10-24 17:41:36 +04:00
Evgeny Poberezkin 567ba1974e Merge branch 'master-ghc8107' into master-ios 2023-10-22 15:35:27 +01:00
Evgeny Poberezkin 64f429f4d2 Merge branch 'master-ghc8107' into master-ios 2023-10-18 22:44:49 +01:00
spaced4ndy b30b1d67d5 Merge branch 'master-ghc8107' into master-ios 2023-10-16 20:05:35 +04:00
spaced4ndy 48e7418c3a Merge branch 'master-ghc8107' into master-ios 2023-10-16 19:28:31 +04:00
Evgeny Poberezkin e0d71dd784 Merge branch 'master-ghc8107' into master-ios 2023-10-15 18:53:52 +01:00
Evgeny Poberezkin a4e07cbbb3 Merge branch 'master-ghc8107' into master-ios 2023-10-11 21:58:42 +01:00
Evgeny Poberezkin b4a72fafaa Merge branch 'master-ghc8107' into master-ios 2023-10-11 21:27:37 +01:00
spaced4ndy a5c81d8c77 Merge branch 'master-ghc8107' into master-ios 2023-10-11 13:22:10 +04:00
Evgeny Poberezkin 3309a3fe4f Merge branch 'stable' into stable-ios 2023-10-09 19:57:27 +01:00
Evgeny Poberezkin bae6a53ec8 Merge branch 'master-ghc8107' into master-ios 2023-10-09 17:32:16 +01:00
Evgeny Poberezkin 4d4dc44302 Merge branch 'stable' into stable-ios 2023-10-09 14:36:32 +01:00
Evgeny Poberezkin 373da2b528 Merge branch 'master-ghc8107' into master-ios 2023-10-09 14:05:41 +01:00
Evgeny Poberezkin 5246445400 Merge branch 'stable-android' into stable-ios 2023-10-08 17:32:06 +01:00
Evgeny Poberezkin d19d2d58a3 Merge branch 'master-ghc8107' into master-ios 2023-10-08 08:41:36 +01:00
Evgeny Poberezkin 48158a9db1 Merge branch 'master-ghc8107' into master-ios 2023-10-07 21:10:44 +01:00
Evgeny Poberezkin 25972f8f6c Merge branch 'master-ghc8107' into master-ios 2023-10-02 23:05:10 +01:00
Evgeny Poberezkin 8ac12a58c6 Merge branch 'master-ghc8107' into master-ios 2023-10-01 13:22:14 +01:00
Evgeny Poberezkin 4de3d6a8f4 Merge branch 'master-ghc8107' into master-ios 2023-10-01 11:20:19 +01:00
Evgeny Poberezkin 39bbea1e18 Merge branch 'stable-android' into stable-ios 2023-10-01 11:04:46 +01:00
Evgeny Poberezkin f7478f5699 Merge branch 'master-ghc8107' into master-ios 2023-09-29 13:15:50 +01:00
Evgeny Poberezkin dce29e91d4 Merge branch 'master-ghc8107' into master-ios 2023-09-27 22:10:30 +01:00
spaced4ndy 760ab4a45c Merge branch 'master-ghc8107' into master-ios 2023-09-27 20:38:19 +04:00
Evgeny Poberezkin 9c99e4fae2 Merge branch 'master-ghc8107' into master-ios 2023-09-27 16:07:08 +01:00
spaced4ndy c931f52631 Merge branch 'master-ghc8107' into master-ios 2023-09-25 17:44:12 +04:00
spaced4ndy 2d8739dec2 Merge branch 'master-ghc8107' into master-ios 2023-09-25 17:07:43 +04:00
Evgeny Poberezkin 87aff89d5e Merge branch 'master-ghc8107' into master-ios 2023-09-22 17:23:28 +01:00
Evgeny Poberezkin ff182c97ee Merge branch 'master-ghc8107' into master-ios 2023-09-22 14:15:01 +01:00
Evgeny Poberezkin 9f117a30db Merge branch 'master-android' into master-ios 2023-09-21 17:05:05 +01:00
Evgeny Poberezkin 2cab235888 Merge branch 'master-android' into master-ios 2023-09-21 12:06:35 +01:00
Evgeny Poberezkin d4201071e0 Merge branch 'master-android' into master-ios 2023-09-20 14:56:57 +01:00
Evgeny Poberezkin c0e666770b Merge branch 'master-android' into master-ios 2023-09-18 21:58:07 +01:00
Evgeny Poberezkin 016f3c9670 Merge branch 'master' into master-ios 2023-09-18 21:30:32 +01:00
spaced4ndy 49116233a8 Merge branch 'master' into master-ios 2023-09-18 14:12:37 +04:00
Evgeny Poberezkin 51621ba11d Merge branch 'stable' into stable-ios 2023-09-17 23:21:46 +01:00
Evgeny Poberezkin e54419e4f0 Merge branch 'master' into master-ios 2023-09-17 22:41:16 +01:00
spaced4ndy d6c6da6edf Merge branch 'master' into master-ios 2023-09-12 18:14:58 +04:00
spaced4ndy e5828f4495 Merge branch 'master' into master-ios 2023-09-11 18:39:29 +04:00
Evgeny Poberezkin 5e23bbecf1 Merge branch 'master' into master-ios 2023-09-10 21:13:18 +01:00
Evgeny Poberezkin 17c734dcb9 Merge branch 'master' into master-ios 2023-09-07 20:19:20 +01:00
Evgeny Poberezkin 85adf2951e Merge branch 'master' into master-ios 2023-09-07 13:45:06 +01:00
Evgeny Poberezkin a250a8e6ca Merge branch 'master' into master-ios 2023-09-06 20:22:00 +01:00
Evgeny Poberezkin 38e10d843b Merge branch 'master' into master-ios 2023-09-06 19:54:48 +01:00
Evgeny Poberezkin 9153cb93de Merge branch 'master' into master-ios 2023-09-05 21:07:22 +01:00
Evgeny Poberezkin f978198fe6 Merge branch 'master' into master-ios 2023-09-04 23:20:27 +01:00
Evgeny Poberezkin 7b434d9f97 Merge branch 'master' into master-ios 2023-09-04 18:29:53 +01:00
Evgeny Poberezkin aaf6dd57c7 Merge branch 'master' into master-ios 2023-09-02 23:34:35 +01:00
Evgeny Poberezkin dc2272ac6e Merge branch 'master' into master-ios 2023-09-01 22:27:15 +01:00
Evgeny Poberezkin 4c172ac680 Merge branch 'master' into master-ios 2023-09-01 20:40:14 +01:00
Evgeny Poberezkin 096bd9ea72 Merge branch 'master' into master-ios 2023-08-26 18:37:12 +01:00
Evgeny Poberezkin f8b757ddf9 Merge branch 'master' into master-ios 2023-08-25 14:11:13 +01:00
Evgeny Poberezkin 62a4fd2c7c Merge branch 'master' into master-ios 2023-08-25 11:32:07 +01:00
Evgeny Poberezkin d6dba0e26a Merge branch 'master' into master-ios 2023-08-24 20:43:20 +01:00
Evgeny Poberezkin 20ebccdbf2 Merge branch 'master' into master-ios 2023-08-22 16:14:32 +01:00
Evgeny Poberezkin 2ac6c2dec9 Merge branch 'master' into master-ios 2023-08-18 21:36:18 +01:00
Evgeny Poberezkin 2babe6d548 Merge branch 'master' into master-ios 2023-08-17 23:16:40 +01:00
spaced4ndy 0a3f2444d9 Merge branch 'master' into master-ios 2023-08-16 10:44:15 +04:00
Evgeny Poberezkin ebfa9e699b Merge branch 'master' into master-ios 2023-08-12 22:00:40 +01:00
Evgeny Poberezkin 2cf07ae0a7 Merge branch 'master' into master-ios 2023-08-12 18:16:16 +01:00
Evgeny Poberezkin 5199cb9e82 Merge branch 'master' into master-ios 2023-08-12 15:26:18 +01:00
Evgeny Poberezkin c42b8373b0 Merge branch 'stable' into stable-ios 2023-08-12 14:33:39 +01:00
spaced4ndy 4bf43c3cde Merge branch 'master' into master-ios 2023-08-08 19:05:23 +04:00
Evgeny Poberezkin fe8c98d69a Merge branch 'stable' into stable-ios 2023-08-06 22:14:33 +01:00
Evgeny Poberezkin b2523e07f8 Merge branch 'master' into master-ios 2023-08-05 15:16:34 +01:00
spaced4ndy deb4fae07c Merge branch 'master' into master-ios 2023-08-03 18:28:23 +04:00
Evgeny Poberezkin 1f4e99f291 Merge branch 'master' into master-ios 2023-08-02 16:23:36 +01:00
Evgeny Poberezkin 439900dbdb Merge branch 'stable' into stable-ios 2023-08-02 16:22:58 +01:00
Evgeny Poberezkin 0f2ac69562 Merge branch 'master' into master-ios 2023-07-31 16:13:41 +01:00
spaced4ndy 8704a23c6f Merge branch 'stable' into stable-ios 2023-07-31 17:00:48 +04:00
spaced4ndy 2ee528c81c Merge branch 'stable' into stable-ios 2023-07-31 15:27:17 +04:00
spaced4ndy 5e1e6aed6b Merge branch 'stable' into stable-ios 2023-07-31 14:21:30 +04:00
spaced4ndy 96128dbf33 Merge branch 'stable' into stable-ios 2023-07-31 12:19:19 +04:00
spaced4ndy 4c3bab1402 Merge branch 'master' into master-ios 2023-07-28 11:10:08 +04:00
spaced4ndy 281f6d0bf9 Merge branch 'master' into master-ios 2023-07-26 15:03:26 +04:00
Evgeny Poberezkin 065bd27b36 Merge branch 'stable' into stable-ios 2023-07-22 16:27:13 +01:00
Evgeny Poberezkin 46043acb85 Merge branch 'stable' into stable-ios 2023-07-22 15:30:21 +01:00
Evgeny Poberezkin e956690390 Merge branch 'stable' into stable-ios 2023-07-22 13:30:47 +01:00
Evgeny Poberezkin 1022124f69 Merge branch 'stable' into master-ios 2023-07-21 23:31:58 +01:00
Evgeny Poberezkin 5803274950 Merge branch 'master' into master-ios 2023-07-20 18:20:12 +01:00
spaced4ndy 444c5e2fc4 Merge branch 'master' into master-ios 2023-07-20 18:44:13 +04:00
Evgeny Poberezkin 1038305802 Merge branch 'master' into master-ios 2023-07-17 14:45:16 +01:00
Evgeny Poberezkin f9530c70fc Merge branch 'master' into master-ios 2023-07-17 13:34:22 +01:00
Evgeny Poberezkin 5e0b2a8706 Merge branch 'master' into master-ios 2023-07-13 23:48:55 +01:00
spaced4ndy 7e9990d710 Merge branch 'master' into master-ios 2023-07-11 20:57:44 +04:00
spaced4ndy 27244da82a Merge branch 'master' into master-ios 2023-07-10 17:40:43 +04:00
Evgeny Poberezkin d89c6ae672 Merge branch 'master' into master-ios 2023-07-09 23:25:16 +01:00
spaced4ndy 121e0ede6c Merge branch 'master' into master-ios 2023-07-05 19:45:23 +04:00
Evgeny Poberezkin ae7a71c4a4 Merge branch 'master' into master-ios 2023-07-05 09:10:43 +01:00
spaced4ndy 8df46c8630 Merge branch 'master' into master-ios 2023-07-03 20:16:45 +04:00
spaced4ndy 55a17a564e Merge branch 'master' into master-ios 2023-06-28 16:49:43 +04:00
spaced4ndy e0956b656c Merge branch 'master' into master-ios 2023-06-28 16:13:45 +04:00
spaced4ndy ca0192abfc Merge branch 'master' into master-ios 2023-06-26 21:48:51 +04:00
Evgeny Poberezkin 3eec371c3f Merge branch 'master' into master-ios 2023-06-24 17:40:05 +01:00
spaced4ndy 1c21afddff Merge branch 'master' into master-ios 2023-06-20 10:19:40 +04:00
spaced4ndy 94b3adb515 Merge branch 'master' into master-ios 2023-06-19 16:07:45 +04:00
spaced4ndy 4c7784c9dc Merge branch 'master' into master-ios 2023-06-16 19:06:31 +04:00
spaced4ndy 99b39fda91 Merge branch 'master' into master-ios 2023-06-12 13:47:27 +04:00
spaced4ndy c16bd3f7b1 Merge branch 'master' into master-ios 2023-06-09 17:31:57 +04:00
spaced4ndy 1c49ba9eaf Merge branch 'master' into master-ios 2023-05-29 15:22:06 +04:00
Evgeny Poberezkin b83fb77b9e Merge branch 'master' into master-ios 2023-05-27 19:36:22 +01:00
spaced4ndy 5cac9c4594 Merge branch 'master' into master-ios 2023-05-26 17:36:58 +04:00
spaced4ndy d17623d20b Merge branch 'master' into master-ios 2023-05-26 14:06:07 +04:00
spaced4ndy 3b452ae4af Merge branch 'master' into master-ios 2023-05-26 14:04:05 +04:00
spaced4ndy 08ba0b2755 Merge branch 'master' into master-ios 2023-05-25 20:55:25 +04:00
spaced4ndy abd362f10a Merge branch 'master' into master-ios 2023-05-24 16:17:05 +04:00
spaced4ndy 31b47746e5 Merge branch 'master' into master-ios 2023-05-23 19:12:25 +04:00
spaced4ndy 76ce8bec1d Merge branch 'master' into master-ios 2023-05-23 18:40:52 +04:00
spaced4ndy eeb2fee659 Merge branch 'master' into master-ios 2023-05-23 15:55:11 +04:00
spaced4ndy d034cb08f9 Merge branch 'master' into master-ios 2023-05-23 13:51:52 +04:00
Evgeny Poberezkin 9d9761ad98 Merge branch 'master' into master-ios 2023-05-20 23:09:20 +01:00
spaced4ndy ffdd598a9c Merge branch 'master' into master-ios 2023-05-19 17:00:44 +04:00
Evgeny Poberezkin e4649c4776 Merge branch 'master' into master-ios 2023-05-19 13:53:30 +01:00
Evgeny Poberezkin 3e9df58955 Merge branch 'master' into master-ios 2023-05-18 17:13:13 +01:00
spaced4ndy b014bfcdb4 Merge branch 'master' into master-ios 2023-05-17 16:14:18 +04:00
Evgeny Poberezkin b8b4ef39e9 Merge branch 'master' into master-ios 2023-05-17 00:23:36 +01:00
spaced4ndy 2a9f98e43f Merge branch 'master' into master-ios 2023-05-16 15:06:01 +04:00
spaced4ndy 6e0ec89fdc Merge branch 'master' into master-ios 2023-05-15 21:23:22 +04:00
Evgeny Poberezkin 080ab90e26 Merge branch 'master' into master-ios 2023-05-15 13:28:27 +01:00
spaced4ndy a6d1f7d449 Merge branch 'master' into master-ios 2023-05-11 16:00:32 +04:00
Evgeny Poberezkin 19c94e59e6 Merge branch 'master' into master-ios 2023-05-09 09:34:05 +01:00
spaced4ndy 1bb4672815 Merge branch 'master' into master-ios 2023-05-09 11:00:46 +04:00
spaced4ndy 371db95950 Merge branch 'master' into master-ios 2023-05-05 15:55:54 +04:00
Evgeny Poberezkin 672c807e47 Merge branch 'master' into master-ios 2023-05-04 13:28:20 +01:00
spaced4ndy 512394b8a6 Merge branch 'master' into master-ios 2023-05-03 20:26:46 +04:00
spaced4ndy 7d3c188cd2 Merge branch 'master' into master-ios 2023-05-03 15:31:03 +04:00
spaced4ndy 2fe765b0bc Merge branch 'master' into master-ios 2023-05-02 10:25:26 +04:00
Evgeny Poberezkin 40cf101148 Merge branch 'master' into master-ios 2023-05-01 11:34:16 +01:00
spaced4ndy 680903a763 Merge branch 'master' into master-ios 2023-04-26 14:35:44 +04:00
spaced4ndy 6b6eff6b52 Merge branch 'master' into master-ios 2023-04-21 13:48:21 +04:00
spaced4ndy e949b4fc3c Merge branch 'master' into master-ios 2023-04-20 20:28:49 +04:00
Evgeny Poberezkin 6790362036 Merge branch 'master' into master-ios 2023-04-20 14:19:27 +01:00
spaced4ndy 623b84d3e1 Merge branch 'master' into master-ios 2023-04-19 15:21:51 +04:00
Evgeny Poberezkin 101ab76a33 Merge branch 'master' into master-ios 2023-04-18 21:04:45 +01:00
spaced4ndy c1909b91d0 Merge branch 'master' into master-ios 2023-04-18 19:49:26 +04:00
spaced4ndy cb9cf6229c Merge branch 'master' into master-ios 2023-04-18 13:49:47 +04:00
spaced4ndy 1561268c5e Merge branch 'master' into master-ios 2023-04-18 12:49:17 +04:00
Evgeny Poberezkin 80368f97ef Merge branch 'master' into master-ios 2023-04-17 10:18:27 +01:00
Evgeny Poberezkin 7ec6f2b421 Merge branch 'master' into master-ios 2023-04-16 18:31:05 +01:00
Evgeny Poberezkin d3a1aec7ad Merge branch 'master' into master-ios 2023-04-16 15:04:35 +01:00
spaced4ndy 990f96a19f Merge branch 'master' into master-ios 2023-04-14 18:06:36 +04:00
spaced4ndy 330c9afc1b Merge branch 'master' into master-ios 2023-04-14 15:55:38 +04:00
spaced4ndy 93922a592c Merge branch 'master' into master-ios 2023-04-13 20:49:23 +04:00
Evgeny Poberezkin a9b08e5c2f Merge branch 'master' into master-ios 2023-04-07 23:23:26 +01:00
Evgeny Poberezkin c677baaa22 Merge branch 'master' into master-ios 2023-04-06 23:16:48 +01:00
Evgeny Poberezkin 5448573d0b Merge branch 'master' into master-ios 2023-04-06 22:49:53 +01:00
Evgeny Poberezkin 1a1b5aade5 Merge branch 'master' into master-ios 2023-04-06 21:07:07 +01:00
Evgeny Poberezkin bd9a60af5a Merge branch 'master' into master-ios 2023-04-05 22:00:08 +01:00
Evgeny Poberezkin 617e12a3d4 Merge branch 'master' into master-ios 2023-04-04 18:43:42 +01:00
spaced4ndy 8c625faa5e Merge branch 'master' into master-ios 2023-03-31 19:20:03 +04:00
spaced4ndy cab7201b72 Merge branch 'master' into master-ios 2023-03-31 17:36:32 +04:00
spaced4ndy c2fd1d5d29 Merge branch 'master' into master-ios 2023-03-30 19:45:49 +04:00
spaced4ndy 5b541e296b Merge branch 'master' into master-ios 2023-03-30 18:42:13 +04:00
Evgeny Poberezkin daaecf11ec Merge branch 'master' into master-ios 2023-03-29 20:46:34 +01:00
spaced4ndy 9c4df591a7 Merge branch 'master' into master-ios 2023-03-29 19:17:15 +04:00
Evgeny Poberezkin c339e8290b Merge branch 'master' into master-ios 2023-03-28 19:26:26 +01:00
spaced4ndy ac606336ed Merge branch 'master' into master-ios 2023-03-28 19:29:30 +04:00
Evgeny Poberezkin f79e6fddec Merge branch 'master' into master-ios 2023-03-27 23:22:16 +01:00
Evgeny Poberezkin 2aab931589 nix: revert changes from 05c4a6c (support for ARMv7a and Android 8+) 2023-03-27 20:48:49 +01:00
58 changed files with 745 additions and 523 deletions
+1
View File
@@ -9,6 +9,7 @@ on:
tags:
- "v*"
- "!*-fdroid"
- "!*-armv7a"
pull_request:
jobs:
+3 -3
View File
@@ -16,13 +16,13 @@ private var nseSubscribers: [UUID:NSESubscriber] = [:]
private let SUSPENDING_TIMEOUT: TimeInterval = 2
// timeout should be larger than SUSPENDING_TIMEOUT
func waitNSESuspended(timeout: TimeInterval, dispatchQueue: DispatchQueue = DispatchQueue.main, suspended: @escaping (Bool) -> Void) {
func waitNSESuspended(timeout: TimeInterval, suspended: @escaping (Bool) -> Void) {
if timeout <= SUSPENDING_TIMEOUT {
logger.warning("waitNSESuspended: small timeout \(timeout), using \(SUSPENDING_TIMEOUT + 1)")
}
var state = nseStateGroupDefault.get()
if case .suspended = state {
dispatchQueue.async { suspended(true) }
DispatchQueue.main.async { suspended(true) }
return
}
let id = UUID()
@@ -45,7 +45,7 @@ func waitNSESuspended(timeout: TimeInterval, dispatchQueue: DispatchQueue = Disp
logger.debug("waitNSESuspended notifySuspended: calling suspended(\(ok))")
suspendedCalled = true
nseSubscribers.removeValue(forKey: id)
dispatchQueue.async { suspended(ok) }
DispatchQueue.main.async { suspended(ok) }
}
}
+2 -2
View File
@@ -211,7 +211,7 @@ func apiDeleteUser(_ userId: Int64, _ delSMPQueues: Bool, viewPwd: String?) asyn
}
func apiStartChat() throws -> Bool {
let r = chatSendCmdSync(.startChat(subscribe: true, expire: true, xftp: true))
let r = chatSendCmdSync(.startChat(mainApp: true))
switch r {
case .chatStarted: return true
case .chatRunning: return false
@@ -403,7 +403,7 @@ func apiGetNtfToken() -> (DeviceToken?, NtfTknStatus?, NotificationsMode) {
case let .ntfToken(token, status, ntfMode): return (token, status, ntfMode)
case .chatCmdError(_, .errorAgent(.CMD(.PROHIBITED))): return (nil, nil, .off)
default:
logger.debug("apiGetNtfToken response: \(String(describing: r), privacy: .public)")
logger.debug("apiGetNtfToken response: \(String(describing: r))")
return (nil, nil, .off)
}
}
+19 -4
View File
@@ -19,11 +19,13 @@ let terminationTimeout: Int = 3 // seconds
let activationDelay: TimeInterval = 1.5
let nseSuspendTimeout: TimeInterval = 5
private func _suspendChat(timeout: Int) {
// this is a redundant check to prevent logical errors, like the one fixed in this PR
let state = AppChatState.shared.value
if !state.canSuspend {
logger.error("_suspendChat called, current state: \(state.rawValue, privacy: .public)")
logger.error("_suspendChat called, current state: \(state.rawValue)")
} else if ChatModel.ok {
AppChatState.shared.set(.suspending)
apiSuspendChat(timeoutMicroseconds: timeout * 1000000)
@@ -134,20 +136,33 @@ func initChatAndMigrate(refreshInvitations: Bool = true) {
}
}
func startChatAndActivate(dispatchQueue: DispatchQueue = DispatchQueue.main, _ completion: @escaping () -> Void) {
func startChatForCall() {
logger.debug("DEBUGGING: startChatForCall")
if ChatModel.shared.chatRunning == true {
ChatReceiver.shared.start()
logger.debug("DEBUGGING: startChatForCall: after ChatReceiver.shared.start")
}
if .active != AppChatState.shared.value {
logger.debug("DEBUGGING: startChatForCall: before activateChat")
activateChat()
logger.debug("DEBUGGING: startChatForCall: after activateChat")
}
}
func startChatAndActivate(_ completion: @escaping () -> Void) {
logger.debug("DEBUGGING: startChatAndActivate")
if ChatModel.shared.chatRunning == true {
ChatReceiver.shared.start()
logger.debug("DEBUGGING: startChatAndActivate: after ChatReceiver.shared.start")
}
if .active == AppChatState.shared.value {
if case .active = AppChatState.shared.value {
completion()
} else if nseStateGroupDefault.get().inactive {
activate()
} else {
// setting app state to "activating" to notify NSE that it should suspend
setAppState(.activating)
waitNSESuspended(timeout: 10, dispatchQueue: dispatchQueue) { ok in
waitNSESuspended(timeout: nseSuspendTimeout) { ok in
if !ok {
// if for some reason NSE failed to suspend,
// e.g., it crashed previously without setting its state to "suspended",
+3 -3
View File
@@ -98,12 +98,12 @@ struct SimpleXApp: App {
if legacyDatabase, case .documents = dbContainerGroupDefault.get() {
dbContainerGroupDefault.set(.documents)
setMigrationState(.offer)
logger.debug("SimpleXApp init: using legacy DB in documents folder: \(getAppDatabasePath(), privacy: .public)*.db")
logger.debug("SimpleXApp init: using legacy DB in documents folder: \(getAppDatabasePath())*.db")
} else {
dbContainerGroupDefault.set(.group)
setMigrationState(.ready)
logger.debug("SimpleXApp init: using DB in app group container: \(getAppDatabasePath(), privacy: .public)*.db")
logger.debug("SimpleXApp init: legacy DB\(legacyDatabase ? "" : " not", privacy: .public) present")
logger.debug("SimpleXApp init: using DB in app group container: \(getAppDatabasePath())*.db")
logger.debug("SimpleXApp init: legacy DB\(legacyDatabase ? "" : " not") present")
}
}
@@ -38,13 +38,13 @@ struct ActiveCallView: View {
}
}
.onAppear {
logger.debug("ActiveCallView: appear client is nil \(client == nil), scenePhase \(String(describing: scenePhase), privacy: .public), canConnectCall \(canConnectCall)")
logger.debug("ActiveCallView: appear client is nil \(client == nil), scenePhase \(String(describing: scenePhase)), canConnectCall \(canConnectCall)")
AppDelegate.keepScreenOn(true)
createWebRTCClient()
dismissAllSheets()
}
.onChange(of: canConnectCall) { _ in
logger.debug("ActiveCallView: canConnectCall changed to \(canConnectCall, privacy: .public)")
logger.debug("ActiveCallView: canConnectCall changed to \(canConnectCall)")
createWebRTCClient()
}
.onDisappear {
+41 -29
View File
@@ -130,7 +130,7 @@ class CallController: NSObject, CXProviderDelegate, PKPushRegistryDelegate, Obse
// The delay allows to accept the second call before suspending a chat
// see `.onChange(of: scenePhase)` in SimpleXApp
DispatchQueue.main.asyncAfter(deadline: .now() + 3) { [weak self] in
logger.debug("CallController: shouldSuspendChat \(String(describing: self?.shouldSuspendChat), privacy: .public)")
logger.debug("CallController: shouldSuspendChat \(String(describing: self?.shouldSuspendChat))")
if ChatModel.shared.activeCall == nil && self?.shouldSuspendChat == true {
self?.shouldSuspendChat = false
suspendChat()
@@ -142,45 +142,57 @@ class CallController: NSObject, CXProviderDelegate, PKPushRegistryDelegate, Obse
@objc(pushRegistry:didUpdatePushCredentials:forType:)
func pushRegistry(_ registry: PKPushRegistry, didUpdate pushCredentials: PKPushCredentials, for type: PKPushType) {
logger.debug("CallController: didUpdate push credentials for type \(type.rawValue, privacy: .public)")
logger.debug("CallController: didUpdate push credentials for type \(type.rawValue)")
}
func pushRegistry(_ registry: PKPushRegistry, didReceiveIncomingPushWith payload: PKPushPayload, for type: PKPushType, completion: @escaping () -> Void) {
logger.debug("CallController: did receive push with type \(type.rawValue, privacy: .public)")
logger.debug("CallController: did receive push with type \(type.rawValue)")
if type != .voIP {
completion()
return
}
logger.debug("CallController: initializing chat")
if (!ChatModel.shared.chatInitialized) {
initChatAndMigrate(refreshInvitations: false)
if AppChatState.shared.value == .stopped {
self.reportExpiredCall(payload: payload, completion)
return
}
startChatAndActivate(dispatchQueue: DispatchQueue.global()) {
self.shouldSuspendChat = true
// There are no invitations in the model, as it was processed by NSE
_ = try? justRefreshCallInvitations()
// logger.debug("CallController justRefreshCallInvitations: \(String(describing: m.callInvitations))")
// Extract the call information from the push notification payload
let m = ChatModel.shared
if let contactId = payload.dictionaryPayload["contactId"] as? String,
let invitation = m.callInvitations[contactId] {
if (!ChatModel.shared.chatInitialized) {
logger.debug("CallController: initializing chat")
do {
try initializeChat(start: true, refreshInvitations: false)
} catch let error {
logger.error("CallController: initializing chat error: \(error)")
self.reportExpiredCall(payload: payload, completion)
return
}
}
logger.debug("CallController: initialized chat")
startChatForCall()
logger.debug("CallController: started chat")
self.shouldSuspendChat = true
// There are no invitations in the model, as it was processed by NSE
_ = try? justRefreshCallInvitations()
logger.debug("CallController: updated call invitations chat")
// logger.debug("CallController justRefreshCallInvitations: \(String(describing: m.callInvitations))")
// Extract the call information from the push notification payload
let m = ChatModel.shared
if let contactId = payload.dictionaryPayload["contactId"] as? String,
let invitation = m.callInvitations[contactId] {
let update = self.cxCallUpdate(invitation: invitation)
if let uuid = invitation.callkitUUID {
logger.debug("CallController: report pushkit call via CallKit")
let update = self.cxCallUpdate(invitation: invitation)
if let uuid = invitation.callkitUUID {
logger.debug("CallController: report pushkit call via CallKit")
let update = self.cxCallUpdate(invitation: invitation)
self.provider.reportNewIncomingCall(with: uuid, update: update) { error in
if error != nil {
m.callInvitations.removeValue(forKey: contactId)
}
// Tell PushKit that the notification is handled.
completion()
self.provider.reportNewIncomingCall(with: uuid, update: update) { error in
if error != nil {
m.callInvitations.removeValue(forKey: contactId)
}
} else {
self.reportExpiredCall(update: update, completion)
// Tell PushKit that the notification is handled.
completion()
}
} else {
self.reportExpiredCall(payload: payload, completion)
self.reportExpiredCall(update: update, completion)
}
} else {
self.reportExpiredCall(payload: payload, completion)
}
}
@@ -211,7 +223,7 @@ class CallController: NSObject, CXProviderDelegate, PKPushRegistryDelegate, Obse
}
func reportNewIncomingCall(invitation: RcvCallInvitation, completion: @escaping (Error?) -> Void) {
logger.debug("CallController.reportNewIncomingCall, UUID=\(String(describing: invitation.callkitUUID), privacy: .public)")
logger.debug("CallController.reportNewIncomingCall, UUID=\(String(describing: invitation.callkitUUID))")
if CallController.useCallKit(), let uuid = invitation.callkitUUID {
if invitation.callTs.timeIntervalSinceNow >= -180 {
let update = cxCallUpdate(invitation: invitation)
@@ -351,7 +363,7 @@ class CallController: NSObject, CXProviderDelegate, PKPushRegistryDelegate, Obse
private func requestTransaction(with action: CXAction, onSuccess: @escaping () -> Void = {}) {
controller.request(CXTransaction(action: action)) { error in
if let error = error {
logger.error("CallController.requestTransaction error requesting transaction: \(error.localizedDescription, privacy: .public)")
logger.error("CallController.requestTransaction error requesting transaction: \(error.localizedDescription)")
} else {
logger.debug("CallController.requestTransaction requested transaction successfully")
onSuccess()
+100 -46
View File
@@ -16,9 +16,11 @@ let logger = Logger()
let appSuspendingDelay: UInt64 = 2_500_000_000
let nseSuspendDelay: TimeInterval = 2
typealias SuspendSchedule = (delay: TimeInterval, timeout: Int)
let nseSuspendTimeout: Int = 5
let nseSuspendSchedule: SuspendSchedule = (2, 4)
let fastNSESuspendSchedule: SuspendSchedule = (1, 1)
typealias NtfStream = ConcurrentQueue<NSENotification>
@@ -32,7 +34,7 @@ actor PendingNtfs {
private var ntfStreams: [String: NtfStream] = [:]
func createStream(_ id: String) async {
logger.debug("NotificationService PendingNtfs.createStream: \(id, privacy: .public)")
logger.debug("NotificationService PendingNtfs.createStream: \(id)")
if ntfStreams[id] == nil {
ntfStreams[id] = ConcurrentQueue()
logger.debug("NotificationService PendingNtfs.createStream: created ConcurrentQueue")
@@ -40,14 +42,14 @@ actor PendingNtfs {
}
func readStream(_ id: String, for nse: NotificationService, ntfInfo: NtfMessages) async {
logger.debug("NotificationService PendingNtfs.readStream: \(id, privacy: .public) \(ntfInfo.ntfMessages.count, privacy: .public)")
logger.debug("NotificationService PendingNtfs.readStream: \(id) \(ntfInfo.ntfMessages.count)")
if !ntfInfo.user.showNotifications {
nse.setBestAttemptNtf(.empty)
}
if let s = ntfStreams[id] {
logger.debug("NotificationService PendingNtfs.readStream: has stream")
var expected = Set(ntfInfo.ntfMessages.map { $0.msgId })
logger.debug("NotificationService PendingNtfs.readStream: expecting: \(expected, privacy: .public)")
logger.debug("NotificationService PendingNtfs.readStream: expecting: \(expected)")
var readCancelled = false
var dequeued: DequeueElement<NSENotification>?
nse.cancelRead = {
@@ -66,7 +68,7 @@ actor PendingNtfs {
} else if case let .msgInfo(info) = ntf {
let found = expected.remove(info.msgId)
if found != nil {
logger.debug("NotificationService PendingNtfs.readStream: msgInfo, last: \(expected.isEmpty, privacy: .public)")
logger.debug("NotificationService PendingNtfs.readStream: msgInfo, last: \(expected.isEmpty)")
if expected.isEmpty { break }
} else if let msgTs = ntfInfo.msgTs, info.msgTs > msgTs {
logger.debug("NotificationService PendingNtfs.readStream: unexpected msgInfo")
@@ -88,7 +90,7 @@ actor PendingNtfs {
}
func writeStream(_ id: String, _ ntf: NSENotification) async {
logger.debug("NotificationService PendingNtfs.writeStream: \(id, privacy: .public)")
logger.debug("NotificationService PendingNtfs.writeStream: \(id)")
if let s = ntfStreams[id] {
logger.debug("NotificationService PendingNtfs.writeStream: writing ntf")
s.enqueue(ntf)
@@ -208,7 +210,7 @@ class NotificationService: UNNotificationServiceExtension {
self.contentHandler = contentHandler
registerGroupDefaults()
let appState = appStateGroupDefault.get()
logger.debug("NotificationService: app is \(appState.rawValue, privacy: .public)")
logger.debug("NotificationService: app is \(appState.rawValue)")
switch appState {
case .stopped:
setBadgeCount()
@@ -238,7 +240,7 @@ class NotificationService: UNNotificationServiceExtension {
}
}
}
logger.debug("NotificationService: app state is now \(state.rawValue, privacy: .public)")
logger.debug("NotificationService: app state is now \(state.rawValue)")
if state.inactive {
receiveNtfMessages(request, contentHandler)
} else {
@@ -267,7 +269,7 @@ class NotificationService: UNNotificationServiceExtension {
let dbStatus = startChat()
if case .ok = dbStatus,
let ntfInfo = apiGetNtfMessage(nonce: nonce, encNtfInfo: encNtfInfo) {
logger.debug("NotificationService: receiveNtfMessages: apiGetNtfMessage \(String(describing: ntfInfo.ntfMessages.count), privacy: .public)")
logger.debug("NotificationService: receiveNtfMessages: apiGetNtfMessage \(String(describing: ntfInfo.ntfMessages.count))")
if let connEntity = ntfInfo.connEntity_ {
setBestAttemptNtf(
ntfInfo.ntfsEnabled
@@ -279,7 +281,7 @@ class NotificationService: UNNotificationServiceExtension {
NtfStreamSemaphores.shared.waitForStream(id)
if receiveEntityId != nil {
Task {
logger.debug("NotificationService: receiveNtfMessages: in Task, connEntity id \(id, privacy: .public)")
logger.debug("NotificationService: receiveNtfMessages: in Task, connEntity id \(id)")
await PendingNtfs.shared.createStream(id)
await PendingNtfs.shared.readStream(id, for: self, ntfInfo: ntfInfo)
deliverBestAttemptNtf()
@@ -297,7 +299,7 @@ class NotificationService: UNNotificationServiceExtension {
override func serviceExtensionTimeWillExpire() {
logger.debug("DEBUGGING: NotificationService.serviceExtensionTimeWillExpire")
deliverBestAttemptNtf()
deliverBestAttemptNtf(urgent: true)
}
func setBadgeCount() {
@@ -319,7 +321,7 @@ class NotificationService: UNNotificationServiceExtension {
}
}
private func deliverBestAttemptNtf() {
private func deliverBestAttemptNtf(urgent: Bool = false) {
logger.debug("NotificationService.deliverBestAttemptNtf")
if let cancel = cancelRead {
cancelRead = nil
@@ -329,20 +331,55 @@ class NotificationService: UNNotificationServiceExtension {
receiveEntityId = nil
NtfStreamSemaphores.shared.signalStreamReady(id)
}
let suspend: Bool
if let t = threadId {
threadId = nil
if NSEThreads.shared.endThread(t) {
logger.debug("NotificationService.deliverBestAttemptNtf: will suspend")
// suspension is delayed to allow chat core finalise any processing
// (e.g., send delivery receipts)
DispatchQueue.global().asyncAfter(deadline: .now() + nseSuspendDelay) {
if NSEThreads.shared.noThreads {
logger.debug("NotificationService.deliverBestAttemptNtf: suspending...")
suspendChat(nseSuspendTimeout)
suspend = NSEThreads.shared.endThread(t) && NSEThreads.shared.noThreads
} else {
suspend = false
}
deliverCallkitOrNotification(urgent: urgent, suspend: suspend)
}
private func deliverCallkitOrNotification(urgent: Bool, suspend: Bool = false) {
if case .callkit = bestAttemptNtf {
logger.debug("NotificationService.deliverCallkitOrNotification: will suspend, callkit")
if urgent {
// suspending NSE even though there may be other notifications
// to allow the app to process callkit call
suspendChat(0)
deliverNotification()
} else {
// suspending NSE with delay and delivering after the suspension
// because pushkit notification must be processed without delay
// to avoid app termination
DispatchQueue.global().asyncAfter(deadline: .now() + fastNSESuspendSchedule.delay) {
suspendChat(fastNSESuspendSchedule.timeout)
DispatchQueue.global().asyncAfter(deadline: .now() + Double(fastNSESuspendSchedule.timeout)) {
self.deliverNotification()
}
}
}
} else {
if suspend {
logger.debug("NotificationService.deliverCallkitOrNotification: will suspend")
if urgent {
suspendChat(0)
} else {
// suspension is delayed to allow chat core finalise any processing
// (e.g., send delivery receipts)
DispatchQueue.global().asyncAfter(deadline: .now() + nseSuspendSchedule.delay) {
if NSEThreads.shared.noThreads {
suspendChat(nseSuspendSchedule.timeout)
}
}
}
}
deliverNotification()
}
}
private func deliverNotification() {
if let handler = contentHandler, let ntf = bestAttemptNtf {
contentHandler = nil
bestAttemptNtf = nil
@@ -357,17 +394,14 @@ class NotificationService: UNNotificationServiceExtension {
switch ntf {
case let .nse(content): deliver(content)
case let .callkit(invitation):
logger.debug("NotificationService reportNewIncomingVoIPPushPayload for \(invitation.contact.id)")
CXProvider.reportNewIncomingVoIPPushPayload([
"displayName": invitation.contact.displayName,
"contactId": invitation.contact.id,
"media": invitation.callType.media.rawValue
]) { error in
if error == nil {
deliver(nil)
} else {
logger.debug("NotificationService reportNewIncomingVoIPPushPayload success to CallController for \(invitation.contact.id)")
deliver(createCallInvitationNtf(invitation))
}
logger.debug("reportNewIncomingVoIPPushPayload result: \(error)")
deliver(error == nil ? nil : createCallInvitationNtf(invitation))
}
case .empty: deliver(nil) // used to mute notifications that did not unsubscribe yet
case .msgInfo: deliver(nil) // unreachable, the best attempt is never set to msgInfo
@@ -402,14 +436,14 @@ var appSubscriber: AppSubscriber = appStateSubscriber { state in
logger.debug("NotificationService: appSubscriber")
if state.running && NSEChatState.shared.value.canSuspend {
logger.debug("NotificationService: appSubscriber app state \(state.rawValue), suspending")
suspendChat(nseSuspendTimeout)
suspendChat(fastNSESuspendSchedule.timeout)
}
}
func appStateSubscriber(onState: @escaping (AppState) -> Void) -> AppSubscriber {
appMessageSubscriber { msg in
if case let .state(state) = msg {
logger.debug("NotificationService: appStateSubscriber \(state.rawValue, privacy: .public)")
logger.debug("NotificationService: appStateSubscriber \(state.rawValue)")
onState(state)
}
}
@@ -425,24 +459,33 @@ let xftpConfig: XFTPFileConfig? = getXFTPCfg()
// Subsequent calls to didReceive will be waiting on semaphore and won't start chat again, as it will be .active
func startChat() -> DBMigrationResult? {
logger.debug("NotificationService: startChat")
if case .active = NSEChatState.shared.value { return .ok }
// only skip creating if there is chat controller
if case .active = NSEChatState.shared.value, hasChatCtrl() { return .ok }
startLock.wait()
defer { startLock.signal() }
return switch NSEChatState.shared.value {
case .created: doStartChat()
case .starting: .ok // it should never get to this branch, as it would be waiting for start on startLock
case .active: .ok
case .suspending: activateChat()
case .suspended: activateChat()
if hasChatCtrl() {
return switch NSEChatState.shared.value {
case .created: doStartChat()
case .starting: .ok // it should never get to this branch, as it would be waiting for start on startLock
case .active: .ok
case .suspending: activateChat()
case .suspended: activateChat()
}
} else {
// Ignore state in preference if there is no chat controller.
// State in preference may have failed to update e.g. because of a crash.
NSEChatState.shared.set(.created)
return doStartChat()
}
}
func doStartChat() -> DBMigrationResult? {
logger.debug("NotificationService: doStartChat")
hs_init(0, nil)
haskell_init_nse()
let (_, dbStatus) = chatMigrateInit(confirmMigrations: defaultMigrationConfirmation(), backgroundMode: true)
logger.debug("NotificationService: doStartChat \(String(describing: dbStatus))")
if dbStatus != .ok {
resetChatCtrl()
NSEChatState.shared.set(.created)
@@ -477,7 +520,7 @@ func doStartChat() -> DBMigrationResult? {
return .ok
}
} catch {
logger.error("NotificationService startChat error: \(responseError(error), privacy: .public)")
logger.error("NotificationService startChat error: \(responseError(error))")
}
} else {
logger.debug("NotificationService: no active user")
@@ -504,8 +547,10 @@ func suspendChat(_ timeout: Int) {
logger.debug("NotificationService: suspendChat")
let state = NSEChatState.shared.value
if !state.canSuspend {
logger.error("NotificationService suspendChat called, current state: \(state.rawValue, privacy: .public)")
} else {
logger.error("NotificationService suspendChat called, current state: \(state.rawValue)")
} else if hasChatCtrl() {
// only suspend if we have chat controller to avoid crashes when suspension is
// attempted when chat controller was not created
suspendLock.wait()
defer { suspendLock.signal() }
@@ -571,7 +616,7 @@ private let isInChina = SKStorefront().countryCode == "CHN"
private func useCallKit() -> Bool { !isInChina && callKitEnabledGroupDefault.get() }
func receivedMsgNtf(_ res: ChatResponse) async -> (String, NSENotification)? {
logger.debug("NotificationService receivedMsgNtf: \(res.responseType, privacy: .public)")
logger.debug("NotificationService receivedMsgNtf: \(res.responseType)")
switch res {
case let .contactConnected(user, contact, _):
return (contact.id, .nse(createContactConnectedNtf(user, contact)))
@@ -613,6 +658,9 @@ func receivedMsgNtf(_ res: ChatResponse) async -> (String, NSENotification)? {
case .chatSuspended:
chatSuspended()
return nil
case let .chatError(_, err):
logger.error("NotificationService receivedMsgNtf error: \(String(describing: err))")
return nil
default:
logger.debug("NotificationService receivedMsgNtf ignored event: \(res.responseType)")
return nil
@@ -627,17 +675,22 @@ func updateNetCfg() {
try setNetworkConfig(networkConfig)
networkConfig = newNetConfig
} catch {
logger.error("NotificationService apply changed network config error: \(responseError(error), privacy: .public)")
logger.error("NotificationService apply changed network config error: \(responseError(error))")
}
}
}
func apiGetActiveUser() -> User? {
let r = sendSimpleXCmd(.showActiveUser)
logger.debug("apiGetActiveUser sendSimpleXCmd response: \(String(describing: r))")
logger.debug("apiGetActiveUser sendSimpleXCmd response: \(r.responseType)")
switch r {
case let .activeUser(user): return user
case .chatCmdError(_, .error(.noActiveUser)): return nil
case .chatCmdError(_, .error(.noActiveUser)):
logger.debug("apiGetActiveUser sendSimpleXCmd no active user")
return nil
case let .chatCmdError(_, err):
logger.debug("apiGetActiveUser sendSimpleXCmd error: \(String(describing: err))")
return nil
default:
logger.error("NotificationService apiGetActiveUser unexpected response: \(String(describing: r))")
return nil
@@ -645,7 +698,7 @@ func apiGetActiveUser() -> User? {
}
func apiStartChat() throws -> Bool {
let r = sendSimpleXCmd(.startChat(subscribe: false, expire: false, xftp: false))
let r = sendSimpleXCmd(.startChat(mainApp: false))
switch r {
case .chatStarted: return true
case .chatRunning: return false
@@ -699,11 +752,12 @@ func apiGetNtfMessage(nonce: String, encNtfInfo: String) -> NtfMessages? {
}
let r = sendSimpleXCmd(.apiGetNtfMessage(nonce: nonce, encNtfInfo: encNtfInfo))
if case let .ntfMessages(user, connEntity_, msgTs, ntfMessages) = r, let user = user {
logger.debug("apiGetNtfMessage response ntfMessages: \(ntfMessages.count)")
return NtfMessages(user: user, connEntity_: connEntity_, msgTs: msgTs, ntfMessages: ntfMessages)
} else if case let .chatCmdError(_, error) = r {
logger.debug("apiGetNtfMessage error response: \(String.init(describing: error))")
} else {
logger.debug("apiGetNtfMessage ignored response: \(r.responseType, privacy: .public) \(String.init(describing: r), privacy: .private)")
logger.debug("apiGetNtfMessage ignored response: \(r.responseType) \(String.init(describing: r))")
}
return nil
}
+32 -32
View File
@@ -30,6 +30,11 @@
5C116CDC27AABE0400E66D01 /* ContactRequestView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C116CDB27AABE0400E66D01 /* ContactRequestView.swift */; };
5C13730B28156D2700F43030 /* ContactConnectionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C13730A28156D2700F43030 /* ContactConnectionView.swift */; };
5C1A4C1E27A715B700EAD5AD /* ChatItemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C1A4C1D27A715B700EAD5AD /* ChatItemView.swift */; };
5C245F232B4EAA5E001CC39F /* libgmpxx.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C245F1E2B4EAA5E001CC39F /* libgmpxx.a */; };
5C245F242B4EAA5E001CC39F /* libHSsimplex-chat-5.4.3.0-BrNBQIZf2Ju9TtaZoeJyIH-ghc9.6.3.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C245F1F2B4EAA5E001CC39F /* libHSsimplex-chat-5.4.3.0-BrNBQIZf2Ju9TtaZoeJyIH-ghc9.6.3.a */; };
5C245F252B4EAA5E001CC39F /* libgmp.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C245F202B4EAA5E001CC39F /* libgmp.a */; };
5C245F262B4EAA5E001CC39F /* libHSsimplex-chat-5.4.3.0-BrNBQIZf2Ju9TtaZoeJyIH.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C245F212B4EAA5E001CC39F /* libHSsimplex-chat-5.4.3.0-BrNBQIZf2Ju9TtaZoeJyIH.a */; };
5C245F272B4EAA5E001CC39F /* libffi.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C245F222B4EAA5E001CC39F /* libffi.a */; };
5C2E260727A2941F00F70299 /* SimpleXAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C2E260627A2941F00F70299 /* SimpleXAPI.swift */; };
5C2E260B27A30CFA00F70299 /* ChatListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C2E260A27A30CFA00F70299 /* ChatListView.swift */; };
5C2E260F27A30FDC00F70299 /* ChatView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C2E260E27A30FDC00F70299 /* ChatView.swift */; };
@@ -43,11 +48,6 @@
5C3F1D562842B68D00EC8A82 /* IntegrityErrorItemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C3F1D552842B68D00EC8A82 /* IntegrityErrorItemView.swift */; };
5C3F1D58284363C400EC8A82 /* PrivacySettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C3F1D57284363C400EC8A82 /* PrivacySettings.swift */; };
5C4B3B0A285FB130003915F2 /* DatabaseView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C4B3B09285FB130003915F2 /* DatabaseView.swift */; };
5C4E80DA2B3CCD090080FAE2 /* libgmp.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C4E80D52B3CCD090080FAE2 /* libgmp.a */; };
5C4E80DB2B3CCD090080FAE2 /* libffi.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C4E80D62B3CCD090080FAE2 /* libffi.a */; };
5C4E80DC2B3CCD090080FAE2 /* libHSsimplex-chat-5.4.2.1-FP1oxJSttEYhorN1FRfI5.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C4E80D72B3CCD090080FAE2 /* libHSsimplex-chat-5.4.2.1-FP1oxJSttEYhorN1FRfI5.a */; };
5C4E80DD2B3CCD090080FAE2 /* libHSsimplex-chat-5.4.2.1-FP1oxJSttEYhorN1FRfI5-ghc9.6.3.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C4E80D82B3CCD090080FAE2 /* libHSsimplex-chat-5.4.2.1-FP1oxJSttEYhorN1FRfI5-ghc9.6.3.a */; };
5C4E80DE2B3CCD090080FAE2 /* libgmpxx.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C4E80D92B3CCD090080FAE2 /* libgmpxx.a */; };
5C5346A827B59A6A004DF848 /* ChatHelp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C5346A727B59A6A004DF848 /* ChatHelp.swift */; };
5C55A91F283AD0E400C4E99E /* CallManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C55A91E283AD0E400C4E99E /* CallManager.swift */; };
5C55A921283CCCB700C4E99E /* IncomingCallView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C55A920283CCCB700C4E99E /* IncomingCallView.swift */; };
@@ -285,6 +285,11 @@
5C13730A28156D2700F43030 /* ContactConnectionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContactConnectionView.swift; sourceTree = "<group>"; };
5C13730C2815740A00F43030 /* DebugJSON.playground */ = {isa = PBXFileReference; lastKnownFileType = file.playground; path = DebugJSON.playground; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.swift; };
5C1A4C1D27A715B700EAD5AD /* ChatItemView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatItemView.swift; sourceTree = "<group>"; };
5C245F1E2B4EAA5E001CC39F /* libgmpxx.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmpxx.a; sourceTree = "<group>"; };
5C245F1F2B4EAA5E001CC39F /* libHSsimplex-chat-5.4.3.0-BrNBQIZf2Ju9TtaZoeJyIH-ghc9.6.3.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-5.4.3.0-BrNBQIZf2Ju9TtaZoeJyIH-ghc9.6.3.a"; sourceTree = "<group>"; };
5C245F202B4EAA5E001CC39F /* libgmp.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmp.a; sourceTree = "<group>"; };
5C245F212B4EAA5E001CC39F /* libHSsimplex-chat-5.4.3.0-BrNBQIZf2Ju9TtaZoeJyIH.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-5.4.3.0-BrNBQIZf2Ju9TtaZoeJyIH.a"; sourceTree = "<group>"; };
5C245F222B4EAA5E001CC39F /* libffi.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libffi.a; sourceTree = "<group>"; };
5C2E260627A2941F00F70299 /* SimpleXAPI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SimpleXAPI.swift; sourceTree = "<group>"; };
5C2E260A27A30CFA00F70299 /* ChatListView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatListView.swift; sourceTree = "<group>"; };
5C2E260E27A30FDC00F70299 /* ChatView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatView.swift; sourceTree = "<group>"; };
@@ -299,11 +304,6 @@
5C3F1D57284363C400EC8A82 /* PrivacySettings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PrivacySettings.swift; sourceTree = "<group>"; };
5C422A7C27A9A6FA0097A1E1 /* SimpleX (iOS).entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = "SimpleX (iOS).entitlements"; sourceTree = "<group>"; };
5C4B3B09285FB130003915F2 /* DatabaseView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DatabaseView.swift; sourceTree = "<group>"; };
5C4E80D52B3CCD090080FAE2 /* libgmp.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmp.a; sourceTree = "<group>"; };
5C4E80D62B3CCD090080FAE2 /* libffi.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libffi.a; sourceTree = "<group>"; };
5C4E80D72B3CCD090080FAE2 /* libHSsimplex-chat-5.4.2.1-FP1oxJSttEYhorN1FRfI5.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-5.4.2.1-FP1oxJSttEYhorN1FRfI5.a"; sourceTree = "<group>"; };
5C4E80D82B3CCD090080FAE2 /* libHSsimplex-chat-5.4.2.1-FP1oxJSttEYhorN1FRfI5-ghc9.6.3.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-5.4.2.1-FP1oxJSttEYhorN1FRfI5-ghc9.6.3.a"; sourceTree = "<group>"; };
5C4E80D92B3CCD090080FAE2 /* libgmpxx.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmpxx.a; sourceTree = "<group>"; };
5C5346A727B59A6A004DF848 /* ChatHelp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatHelp.swift; sourceTree = "<group>"; };
5C55A91E283AD0E400C4E99E /* CallManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CallManager.swift; sourceTree = "<group>"; };
5C55A920283CCCB700C4E99E /* IncomingCallView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IncomingCallView.swift; sourceTree = "<group>"; };
@@ -529,13 +529,13 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
5C4E80DD2B3CCD090080FAE2 /* libHSsimplex-chat-5.4.2.1-FP1oxJSttEYhorN1FRfI5-ghc9.6.3.a in Frameworks */,
5C245F232B4EAA5E001CC39F /* libgmpxx.a in Frameworks */,
5C245F262B4EAA5E001CC39F /* libHSsimplex-chat-5.4.3.0-BrNBQIZf2Ju9TtaZoeJyIH.a in Frameworks */,
5C245F252B4EAA5E001CC39F /* libgmp.a in Frameworks */,
5CE2BA93284534B000EC33A6 /* libiconv.tbd in Frameworks */,
5C4E80DA2B3CCD090080FAE2 /* libgmp.a in Frameworks */,
5C4E80DC2B3CCD090080FAE2 /* libHSsimplex-chat-5.4.2.1-FP1oxJSttEYhorN1FRfI5.a in Frameworks */,
5C245F272B4EAA5E001CC39F /* libffi.a in Frameworks */,
5CE2BA94284534BB00EC33A6 /* libz.tbd in Frameworks */,
5C4E80DB2B3CCD090080FAE2 /* libffi.a in Frameworks */,
5C4E80DE2B3CCD090080FAE2 /* libgmpxx.a in Frameworks */,
5C245F242B4EAA5E001CC39F /* libHSsimplex-chat-5.4.3.0-BrNBQIZf2Ju9TtaZoeJyIH-ghc9.6.3.a in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -597,11 +597,11 @@
5C764E5C279C70B7000C6508 /* Libraries */ = {
isa = PBXGroup;
children = (
5C4E80D62B3CCD090080FAE2 /* libffi.a */,
5C4E80D52B3CCD090080FAE2 /* libgmp.a */,
5C4E80D92B3CCD090080FAE2 /* libgmpxx.a */,
5C4E80D82B3CCD090080FAE2 /* libHSsimplex-chat-5.4.2.1-FP1oxJSttEYhorN1FRfI5-ghc9.6.3.a */,
5C4E80D72B3CCD090080FAE2 /* libHSsimplex-chat-5.4.2.1-FP1oxJSttEYhorN1FRfI5.a */,
5C245F222B4EAA5E001CC39F /* libffi.a */,
5C245F202B4EAA5E001CC39F /* libgmp.a */,
5C245F1E2B4EAA5E001CC39F /* libgmpxx.a */,
5C245F1F2B4EAA5E001CC39F /* libHSsimplex-chat-5.4.3.0-BrNBQIZf2Ju9TtaZoeJyIH-ghc9.6.3.a */,
5C245F212B4EAA5E001CC39F /* libHSsimplex-chat-5.4.3.0-BrNBQIZf2Ju9TtaZoeJyIH.a */,
);
path = Libraries;
sourceTree = "<group>";
@@ -1528,7 +1528,7 @@
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = "SimpleX (iOS).entitlements";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 186;
CURRENT_PROJECT_VERSION = 188;
DEVELOPMENT_TEAM = 5NN7GUYB6T;
ENABLE_BITCODE = NO;
ENABLE_PREVIEWS = YES;
@@ -1550,7 +1550,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
MARKETING_VERSION = 5.4.2;
MARKETING_VERSION = 5.4.3;
PRODUCT_BUNDLE_IDENTIFIER = chat.simplex.app;
PRODUCT_NAME = SimpleX;
SDKROOT = iphoneos;
@@ -1571,7 +1571,7 @@
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = "SimpleX (iOS).entitlements";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 186;
CURRENT_PROJECT_VERSION = 188;
DEVELOPMENT_TEAM = 5NN7GUYB6T;
ENABLE_BITCODE = NO;
ENABLE_PREVIEWS = YES;
@@ -1593,7 +1593,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
MARKETING_VERSION = 5.4.2;
MARKETING_VERSION = 5.4.3;
PRODUCT_BUNDLE_IDENTIFIER = chat.simplex.app;
PRODUCT_NAME = SimpleX;
SDKROOT = iphoneos;
@@ -1652,7 +1652,7 @@
CODE_SIGN_ENTITLEMENTS = "SimpleX NSE/SimpleX NSE.entitlements";
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 186;
CURRENT_PROJECT_VERSION = 188;
DEVELOPMENT_TEAM = 5NN7GUYB6T;
ENABLE_BITCODE = NO;
GENERATE_INFOPLIST_FILE = YES;
@@ -1665,7 +1665,7 @@
"@executable_path/Frameworks",
"@executable_path/../../Frameworks",
);
MARKETING_VERSION = 5.4.2;
MARKETING_VERSION = 5.4.3;
PRODUCT_BUNDLE_IDENTIFIER = "chat.simplex.app.SimpleX-NSE";
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
@@ -1684,7 +1684,7 @@
CODE_SIGN_ENTITLEMENTS = "SimpleX NSE/SimpleX NSE.entitlements";
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 186;
CURRENT_PROJECT_VERSION = 188;
DEVELOPMENT_TEAM = 5NN7GUYB6T;
ENABLE_BITCODE = NO;
GENERATE_INFOPLIST_FILE = YES;
@@ -1697,7 +1697,7 @@
"@executable_path/Frameworks",
"@executable_path/../../Frameworks",
);
MARKETING_VERSION = 5.4.2;
MARKETING_VERSION = 5.4.3;
PRODUCT_BUNDLE_IDENTIFIER = "chat.simplex.app.SimpleX-NSE";
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
@@ -1716,7 +1716,7 @@
APPLICATION_EXTENSION_API_ONLY = YES;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 186;
CURRENT_PROJECT_VERSION = 188;
DEFINES_MODULE = YES;
DEVELOPMENT_TEAM = 5NN7GUYB6T;
DYLIB_COMPATIBILITY_VERSION = 1;
@@ -1740,7 +1740,7 @@
"$(inherited)",
"$(PROJECT_DIR)/Libraries/sim",
);
MARKETING_VERSION = 5.4.2;
MARKETING_VERSION = 5.4.3;
PRODUCT_BUNDLE_IDENTIFIER = chat.simplex.SimpleXChat;
PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
SDKROOT = iphoneos;
@@ -1762,7 +1762,7 @@
APPLICATION_EXTENSION_API_ONLY = YES;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 186;
CURRENT_PROJECT_VERSION = 188;
DEFINES_MODULE = YES;
DEVELOPMENT_TEAM = 5NN7GUYB6T;
DYLIB_COMPATIBILITY_VERSION = 1;
@@ -1786,7 +1786,7 @@
"$(inherited)",
"$(PROJECT_DIR)/Libraries/sim",
);
MARKETING_VERSION = 5.4.2;
MARKETING_VERSION = 5.4.3;
PRODUCT_BUNDLE_IDENTIFIER = chat.simplex.SimpleXChat;
PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
SDKROOT = iphoneos;
@@ -41,7 +41,7 @@
</Testables>
</TestAction>
<LaunchAction
buildConfiguration = "Release"
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
@@ -2,7 +2,7 @@
<Scheme
LastUpgradeVersion = "1400"
wasCreatedForAppExtension = "YES"
version = "2.0">
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
@@ -47,16 +47,14 @@
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = ""
selectedLauncherIdentifier = "Xcode.IDEFoundation.Launcher.PosixSpawn"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
askForAppToLaunch = "Yes"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES"
launchAutomaticallySubstyle = "2">
allowLocationSimulation = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
+5 -1
View File
@@ -12,7 +12,11 @@ private var chatController: chat_ctrl?
private var migrationResult: (Bool, DBMigrationResult)?
public func getChatCtrl(_ useKey: String? = nil) -> chat_ctrl {
public func hasChatCtrl() -> Bool {
chatController != nil
}
public func getChatCtrl() -> chat_ctrl {
if let controller = chatController { return controller }
fatalError("chat controller not initialized")
}
+2 -2
View File
@@ -25,7 +25,7 @@ public enum ChatCommand {
case apiMuteUser(userId: Int64)
case apiUnmuteUser(userId: Int64)
case apiDeleteUser(userId: Int64, delSMPQueues: Bool, viewPwd: String?)
case startChat(subscribe: Bool, expire: Bool, xftp: Bool)
case startChat(mainApp: Bool)
case apiStopChat
case apiActivateChat(restoreChat: Bool)
case apiSuspendChat(timeoutMicroseconds: Int)
@@ -154,7 +154,7 @@ public enum ChatCommand {
case let .apiMuteUser(userId): return "/_mute user \(userId)"
case let .apiUnmuteUser(userId): return "/_unmute user \(userId)"
case let .apiDeleteUser(userId, delSMPQueues, viewPwd): return "/_delete user \(userId) del_smp=\(onOff(delSMPQueues))\(maybePwd(viewPwd))"
case let .startChat(subscribe, expire, xftp): return "/_start subscribe=\(onOff(subscribe)) expire=\(onOff(expire)) xftp=\(onOff(xftp))"
case let .startChat(mainApp): return "/_start main=\(onOff(mainApp))"
case .apiStopChat: return "/_stop"
case let .apiActivateChat(restore): return "/_app activate restore=\(onOff(restore))"
case let .apiSuspendChat(timeoutMicroseconds): return "/_app suspend \(timeoutMicroseconds)"
+16
View File
@@ -23,3 +23,19 @@ void haskell_init(void) {
char **pargv = argv;
hs_init_with_rtsopts(&argc, &pargv);
}
void haskell_init_nse(void) {
int argc = 7;
char *argv[] = {
"simplex",
"+RTS", // requires `hs_init_with_rtsopts`
"-A1m", // chunk size for new allocations
"-H1m", // initial heap size
"-F0.5", // heap growth triggering GC
"-Fd1", // memory return
"-c", // compacting garbage collector
0
};
char **pargv = argv;
hs_init_with_rtsopts(&argc, &pargv);
}
+2
View File
@@ -11,4 +11,6 @@
void haskell_init(void);
void haskell_init_nse(void);
#endif /* hs_init_h */
@@ -164,13 +164,14 @@ class SimplexApp: Application(), LifecycleEventObserver {
androidAppContext = this
APPLICATION_ID = BuildConfig.APPLICATION_ID
ntfManager = object : chat.simplex.common.platform.NtfManager() {
override fun notifyCallInvitation(invitation: RcvCallInvitation) = NtfManager.notifyCallInvitation(invitation)
override fun notifyCallInvitation(invitation: RcvCallInvitation): Boolean = NtfManager.notifyCallInvitation(invitation)
override fun hasNotificationsForChat(chatId: String): Boolean = NtfManager.hasNotificationsForChat(chatId)
override fun cancelNotificationsForChat(chatId: String) = NtfManager.cancelNotificationsForChat(chatId)
override fun displayNotification(user: UserLike, chatId: String, displayName: String, msgText: String, image: String?, actions: List<Pair<NotificationAction, () -> Unit>>) = NtfManager.displayNotification(user, chatId, displayName, msgText, image, actions.map { it.first })
override fun androidCreateNtfChannelsMaybeShowAlert() = NtfManager.createNtfChannelsMaybeShowAlert()
override fun cancelCallNotification() = NtfManager.cancelCallNotification()
override fun cancelAllNotifications() = NtfManager.cancelAllNotifications()
override fun showMessage(title: String, text: String) = NtfManager.showMessage(title, text)
}
platform = object : PlatformInterface {
override suspend fun androidServiceStart() {
@@ -30,7 +30,7 @@ object NtfManager {
const val ShowChatsAction: String = "chat.simplex.app.SHOW_CHATS"
// DO NOT change notification channel settings / names
const val CallChannel: String = "chat.simplex.app.CALL_NOTIFICATION_1"
const val CallChannel: String = "chat.simplex.app.CALL_NOTIFICATION_2"
const val AcceptCallAction: String = "chat.simplex.app.ACCEPT_CALL"
const val RejectCallAction: String = "chat.simplex.app.REJECT_CALL"
const val CallNotificationId: Int = -1
@@ -59,7 +59,7 @@ object NtfManager {
.setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
.setUsage(AudioAttributes.USAGE_NOTIFICATION_RINGTONE)
.build()
val soundUri = Uri.parse(ContentResolver.SCHEME_ANDROID_RESOURCE + "://" + context.packageName + "/" + R.raw.ring_once)
val soundUri = Uri.parse(ContentResolver.SCHEME_ANDROID_RESOURCE + "://" + context.packageName + "/raw/ring_once")
Log.d(TAG, "callNotificationChannel sound: $soundUri")
callChannel.setSound(soundUri, attrs)
callChannel.enableVibration(true)
@@ -140,7 +140,7 @@ object NtfManager {
}
}
fun notifyCallInvitation(invitation: RcvCallInvitation) {
fun notifyCallInvitation(invitation: RcvCallInvitation): Boolean {
val keyguardManager = getKeyguardManager(context)
Log.d(
TAG,
@@ -149,7 +149,7 @@ object NtfManager {
"callOnLockScreen ${appPreferences.callOnLockScreen.get()}, " +
"onForeground ${isAppOnForeground}"
)
if (isAppOnForeground) return
if (isAppOnForeground) return false
val contactId = invitation.contact.id
Log.d(TAG, "notifyCallInvitation $contactId")
val image = invitation.contact.image
@@ -163,7 +163,7 @@ object NtfManager {
.setFullScreenIntent(fullScreenPendingIntent, true)
.setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
} else {
val soundUri = Uri.parse(ContentResolver.SCHEME_ANDROID_RESOURCE + "://" + context.packageName + "/" + R.raw.ring_once)
val soundUri = Uri.parse(ContentResolver.SCHEME_ANDROID_RESOURCE + "://" + context.packageName + "/raw/ring_once")
val fullScreenPendingIntent = PendingIntent.getActivity(context, 0, Intent(), PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE)
NotificationCompat.Builder(context, CallChannel)
.setContentIntent(chatPendingIntent(OpenChatAction, invitation.user.userId, invitation.contact.id))
@@ -206,6 +206,39 @@ object NtfManager {
notify(CallNotificationId, notification)
}
}
return true
}
fun showMessage(title: String, text: String) {
val builder = NotificationCompat.Builder(context, MessageChannel)
.setContentTitle(title)
.setContentText(text)
.setPriority(NotificationCompat.PRIORITY_HIGH)
.setGroup(MessageGroup)
.setGroupAlertBehavior(NotificationCompat.GROUP_ALERT_CHILDREN)
.setSmallIcon(R.drawable.ntf_icon)
.setLargeIcon(null)
.setColor(0x88FFFF)
.setAutoCancel(true)
.setVibrate(null)
.setContentIntent(chatPendingIntent(ShowChatsAction, null, null))
.setSilent(false)
val summary = NotificationCompat.Builder(context, MessageChannel)
.setSmallIcon(R.drawable.ntf_icon)
.setColor(0x88FFFF)
.setGroup(MessageGroup)
.setGroupAlertBehavior(NotificationCompat.GROUP_ALERT_CHILDREN)
.setGroupSummary(true)
.setContentIntent(chatPendingIntent(ShowChatsAction, null))
.build()
with(NotificationManagerCompat.from(context)) {
if (ActivityCompat.checkSelfPermission(SimplexApp.context, android.Manifest.permission.POST_NOTIFICATIONS) == PackageManager.PERMISSION_GRANTED) {
notify("MESSAGE".hashCode(), builder.build())
notify(0, summary)
}
}
}
fun cancelCallNotification() {
@@ -248,6 +281,7 @@ object NtfManager {
manager.createNotificationChannel(callNotificationChannel(CallChannel, generalGetString(MR.strings.ntf_channel_calls)))
// Remove old channels since they can't be edited
manager.deleteNotificationChannel("chat.simplex.app.CALL_NOTIFICATION")
manager.deleteNotificationChannel("chat.simplex.app.CALL_NOTIFICATION_1")
manager.deleteNotificationChannel("chat.simplex.app.LOCK_SCREEN_CALL_NOTIFICATION")
}
@@ -0,0 +1,7 @@
package chat.simplex.common.views.database
import chat.simplex.common.views.usersettings.restartApp
actual fun restartChatOrApp() {
restartApp()
}
@@ -28,7 +28,7 @@ actual fun SettingsSectionApp(
}
private fun restartApp() {
fun restartApp() {
ProcessPhoenix.triggerRebirth(androidAppContext)
shutdownApp()
}
@@ -122,6 +122,9 @@ object ChatModel {
val remoteHostPairing = mutableStateOf<Pair<RemoteHostInfo?, RemoteHostSessionState>?>(null)
val remoteCtrlSession = mutableStateOf<RemoteCtrlSession?>(null)
val processedCriticalError: ProcessedErrors<AgentErrorType.CRITICAL> = ProcessedErrors(60_000)
val processedInternalError: ProcessedErrors<AgentErrorType.INTERNAL> = ProcessedErrors(20_000)
fun getUser(userId: Long): User? = if (currentUser.value?.userId == userId) {
currentUser.value
} else {
@@ -108,6 +108,7 @@ class AppPreferences {
val chatArchiveTime = mkDatePreference(SHARED_PREFS_CHAT_ARCHIVE_TIME, null)
val chatLastStart = mkDatePreference(SHARED_PREFS_CHAT_LAST_START, null)
val developerTools = mkBoolPreference(SHARED_PREFS_DEVELOPER_TOOLS, false)
val showInternalErrors = mkBoolPreference(SHARED_PREFS_SHOW_INTERNAL_ERRORS, false)
val terminalAlwaysVisible = mkBoolPreference(SHARED_PREFS_TERMINAL_ALWAYS_VISIBLE, false)
val networkUseSocksProxy = mkBoolPreference(SHARED_PREFS_NETWORK_USE_SOCKS_PROXY, false)
val networkProxyHostPort = mkStrPreference(SHARED_PREFS_NETWORK_PROXY_HOST_PORT, "localhost:9050")
@@ -276,6 +277,7 @@ class AppPreferences {
private const val SHARED_PREFS_ONBOARDING_STAGE = "OnboardingStage"
private const val SHARED_PREFS_CHAT_LAST_START = "ChatLastStart"
private const val SHARED_PREFS_DEVELOPER_TOOLS = "DeveloperTools"
private const val SHARED_PREFS_SHOW_INTERNAL_ERRORS = "ShowInternalErrors"
private const val SHARED_PREFS_TERMINAL_ALWAYS_VISIBLE = "TerminalAlwaysVisible"
private const val SHARED_PREFS_NETWORK_USE_SOCKS_PROXY = "NetworkUseSocksProxy"
private const val SHARED_PREFS_NETWORK_PROXY_HOST_PORT = "NetworkProxyHostPort"
@@ -583,7 +585,7 @@ object ChatController {
}
suspend fun apiStartChat(): Boolean {
val r = sendCmd(null, CC.StartChat(expire = true))
val r = sendCmd(null, CC.StartChat(mainApp = true))
when (r) {
is CR.ChatStarted -> return true
is CR.ChatRunning -> return false
@@ -1920,6 +1922,14 @@ object ChatController {
}
}
}
is CR.ChatCmdError -> when {
r.chatError is ChatError.ChatErrorAgent && r.chatError.agentError is AgentErrorType.CRITICAL -> {
chatModel.processedCriticalError.newError(r.chatError.agentError, r.chatError.agentError.offerRestart)
}
r.chatError is ChatError.ChatErrorAgent && r.chatError.agentError is AgentErrorType.INTERNAL && appPrefs.showInternalErrors.get() -> {
chatModel.processedInternalError.newError(r.chatError.agentError, false)
}
}
else ->
Log.d(TAG , "unsupported event: ${r.responseType}")
}
@@ -2161,7 +2171,7 @@ sealed class CC {
class ApiMuteUser(val userId: Long): CC()
class ApiUnmuteUser(val userId: Long): CC()
class ApiDeleteUser(val userId: Long, val delSMPQueues: Boolean, val viewPwd: String?): CC()
class StartChat(val expire: Boolean): CC()
class StartChat(val mainApp: Boolean): CC()
class ApiStopChat: CC()
class SetTempFolder(val tempFolder: String): CC()
class SetFilesFolder(val filesFolder: String): CC()
@@ -2288,7 +2298,7 @@ sealed class CC {
is ApiMuteUser -> "/_mute user $userId"
is ApiUnmuteUser -> "/_unmute user $userId"
is ApiDeleteUser -> "/_delete user $userId del_smp=${onOff(delSMPQueues)}${maybePwd(viewPwd)}"
is StartChat -> "/_start subscribe=on expire=${onOff(expire)} xftp=on"
is StartChat -> "/_start main=${onOff(mainApp)}"
is ApiStopChat -> "/_stop"
is SetTempFolder -> "/_temp_folder $tempFolder"
is SetFilesFolder -> "/_files_folder $filesFolder"
@@ -4710,6 +4720,7 @@ sealed class AgentErrorType {
is AGENT -> "AGENT ${agentErr.string}"
is INTERNAL -> "INTERNAL $internalErr"
is INACTIVE -> "INACTIVE"
is CRITICAL -> "CRITICAL $offerRestart $criticalErr"
}
@Serializable @SerialName("CMD") class CMD(val cmdErr: CommandErrorType): AgentErrorType()
@Serializable @SerialName("CONN") class CONN(val connErr: ConnectionErrorType): AgentErrorType()
@@ -4721,6 +4732,7 @@ sealed class AgentErrorType {
@Serializable @SerialName("AGENT") class AGENT(val agentErr: SMPAgentError): AgentErrorType()
@Serializable @SerialName("INTERNAL") class INTERNAL(val internalErr: String): AgentErrorType()
@Serializable @SerialName("INACTIVE") object INACTIVE: AgentErrorType()
@Serializable @SerialName("CRITICAL") data class CRITICAL(val offerRestart: Boolean, val criticalErr: String): AgentErrorType()
}
@Serializable
@@ -93,12 +93,13 @@ abstract class NtfManager {
}
}
abstract fun notifyCallInvitation(invitation: RcvCallInvitation)
abstract fun notifyCallInvitation(invitation: RcvCallInvitation): Boolean
abstract fun hasNotificationsForChat(chatId: String): Boolean
abstract fun cancelNotificationsForChat(chatId: String)
abstract fun displayNotification(user: UserLike, chatId: String, displayName: String, msgText: String, image: String? = null, actions: List<Pair<NotificationAction, () -> Unit>> = emptyList())
abstract fun cancelCallNotification()
abstract fun cancelAllNotifications()
abstract fun showMessage(title: String, text: String)
// Android only
abstract fun androidCreateNtfChannelsMaybeShowAlert()
@@ -13,8 +13,8 @@ class CallManager(val chatModel: ChatModel) {
callInvitations[invitation.contact.id] = invitation
if (invitation.user.showNotifications) {
if (Clock.System.now() - invitation.callTs <= 3.minutes) {
invitation.sentNotification = ntfManager.notifyCallInvitation(invitation)
activeCallInvitation.value = invitation
ntfManager.notifyCallInvitation(invitation)
} else {
val contact = invitation.contact
ntfManager.displayNotification(user = invitation.user, chatId = contact.id, displayName = contact.displayName, msgText = invitation.callTypeText)
@@ -15,11 +15,10 @@ import dev.icerock.moko.resources.compose.painterResource
import dev.icerock.moko.resources.compose.stringResource
import androidx.compose.ui.unit.dp
import chat.simplex.common.model.*
import chat.simplex.common.platform.*
import chat.simplex.common.ui.theme.*
import chat.simplex.common.views.helpers.ProfileImage
import chat.simplex.common.views.usersettings.ProfilePreview
import chat.simplex.common.platform.ntfManager
import chat.simplex.common.platform.SoundPlayer
import chat.simplex.res.MR
import kotlinx.datetime.Clock
@@ -27,7 +26,11 @@ import kotlinx.datetime.Clock
fun IncomingCallAlertView(invitation: RcvCallInvitation, chatModel: ChatModel) {
val cm = chatModel.callManager
val scope = rememberCoroutineScope()
LaunchedEffect(true) { SoundPlayer.start(scope, sound = !chatModel.showCallView.value) }
LaunchedEffect(Unit) {
if (chatModel.activeCallInvitation.value?.sentNotification == false || appPlatform.isDesktop) {
SoundPlayer.start(scope, sound = !chatModel.showCallView.value)
}
}
DisposableEffect(true) { onDispose { SoundPlayer.stop() } }
IncomingCallAlertLayout(
invitation,
@@ -112,6 +112,9 @@ sealed class WCallResponse {
CallMediaType.Video -> MR.strings.incoming_video_call
CallMediaType.Audio -> MR.strings.incoming_audio_call
})
// Shows whether notification was shown or not to prevent playing sound twice in both notification and in-app
var sentNotification: Boolean = false
}
@Serializable data class CallCapabilities(val encryption: Boolean)
@Serializable data class ConnectionInfo(private val localCandidate: RTCIceCandidate?, private val remoteCandidate: RTCIceCandidate?) {
@@ -4,7 +4,6 @@ import SectionBottomSpacer
import SectionDividerSpaced
import SectionTextFooter
import SectionItemView
import SectionSpacer
import SectionView
import androidx.compose.desktop.ui.tooling.preview.Preview
import androidx.compose.foundation.layout.*
@@ -367,7 +366,7 @@ fun chatArchiveTitle(chatArchiveTime: Instant, chatLastStart: Instant): String {
return stringResource(if (chatArchiveTime < chatLastStart) MR.strings.old_database_archive else MR.strings.new_database_archive)
}
private fun startChat(m: ChatModel, chatLastStart: MutableState<Instant?>, chatDbChanged: MutableState<Boolean>) {
fun startChat(m: ChatModel, chatLastStart: MutableState<Instant?>, chatDbChanged: MutableState<Boolean>) {
withApi {
try {
if (chatDbChanged.value) {
@@ -407,6 +406,8 @@ private fun stopChatAlert(m: ChatModel) {
)
}
expect fun restartChatOrApp()
private fun exportProhibitedAlert() {
AlertManager.shared.showAlertMsg(
title = generalGetString(MR.strings.set_password_to_export),
@@ -414,7 +415,7 @@ private fun exportProhibitedAlert() {
)
}
private fun authStopChat(m: ChatModel) {
fun authStopChat(m: ChatModel, onStop: (() -> Unit)? = null) {
if (m.controller.appPrefs.performLA.get()) {
authenticate(
generalGetString(MR.strings.auth_stop_chat),
@@ -422,7 +423,7 @@ private fun authStopChat(m: ChatModel) {
completed = { laResult ->
when (laResult) {
LAResult.Success, is LAResult.Unavailable -> {
stopChat(m)
stopChat(m, onStop)
}
is LAResult.Error -> {
m.chatRunning.value = true
@@ -434,15 +435,16 @@ private fun authStopChat(m: ChatModel) {
}
)
} else {
stopChat(m)
stopChat(m, onStop)
}
}
private fun stopChat(m: ChatModel) {
private fun stopChat(m: ChatModel, onStop: (() -> Unit)? = null) {
withApi {
try {
stopChatAsync(m)
platform.androidChatStopped()
onStop?.invoke()
} catch (e: Error) {
m.chatRunning.value = true
AlertManager.shared.showAlertMsg(generalGetString(MR.strings.error_stopping_chat), e.toString())
@@ -0,0 +1,64 @@
package chat.simplex.common.views.helpers
import chat.simplex.common.model.AgentErrorType
import chat.simplex.common.platform.Log
import chat.simplex.common.platform.TAG
import chat.simplex.common.platform.ntfManager
import chat.simplex.common.views.database.restartChatOrApp
import chat.simplex.res.MR
import kotlinx.coroutines.Job
import kotlinx.coroutines.delay
class ProcessedErrors <T: AgentErrorType>(val interval: Long) {
private var lastShownTimestamp: Long = -1
private var lastShownOfferRestart: Boolean = false
private var timer: Job = Job()
fun newError(error: T, offerRestart: Boolean) {
timer.cancel()
timer = withBGApi {
val delayBeforeNext = (lastShownTimestamp + interval) - System.currentTimeMillis()
if ((lastShownOfferRestart || !offerRestart) && delayBeforeNext >= 0) {
delay(delayBeforeNext)
}
lastShownTimestamp = System.currentTimeMillis()
lastShownOfferRestart = offerRestart
AlertManager.shared.hideAllAlerts()
showMessage(error, offerRestart)
}
}
private fun showMessage(error: T, offerRestart: Boolean) {
when (error) {
is AgentErrorType.CRITICAL -> {
val title = generalGetString(MR.strings.agent_critical_error_title)
val text = generalGetString(MR.strings.agent_critical_error_desc).format(error.criticalErr)
try {
ntfManager.showMessage(title, text)
} catch (e: Throwable) {
Log.e(TAG, e.stackTraceToString())
}
if (offerRestart) {
AlertManager.shared.showAlertDialog(
title = title,
text = text,
confirmText = generalGetString(MR.strings.restart_chat_button),
onConfirm = {
withApi { restartChatOrApp() }
})
} else {
AlertManager.shared.showAlertMsg(
title = title,
text = text,
)
}
}
is AgentErrorType.INTERNAL -> {
AlertManager.shared.showAlertMsg(
title = generalGetString(MR.strings.agent_internal_error_title),
text = generalGetString(MR.strings.agent_internal_error_desc).format(error.internalErr),
)
}
}
}
}
@@ -10,10 +10,11 @@ import androidx.compose.foundation.verticalScroll
import androidx.compose.runtime.*
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalUriHandler
import chat.simplex.common.model.*
import dev.icerock.moko.resources.compose.painterResource
import dev.icerock.moko.resources.compose.stringResource
import chat.simplex.common.model.ChatModel
import chat.simplex.common.platform.appPlatform
import chat.simplex.common.platform.appPreferences
import chat.simplex.common.views.TerminalView
import chat.simplex.common.views.helpers.*
import chat.simplex.res.MR
@@ -44,6 +45,7 @@ fun DeveloperView(
m.controller.appPrefs.terminalAlwaysVisible.set(false)
}
}
SettingsPreferenceItem(painterResource(MR.images.ic_report), stringResource(MR.strings.show_internal_errors), appPreferences.showInternalErrors)
}
}
SectionTextFooter(
@@ -662,6 +662,7 @@
<string name="hide_dev_options">Hide:</string>
<string name="show_developer_options">Show developer options</string>
<string name="developer_options">Database IDs and Transport isolation option.</string>
<string name="show_internal_errors">Show internal errors</string>
<string name="shutdown_alert_question">Shutdown?</string>
<string name="shutdown_alert_desc">Notifications will stop working until you re-launch the app</string>
@@ -1724,4 +1725,11 @@
<string name="connect_plan_you_are_already_joining_the_group_via_this_link">You are already joining the group via this link.</string>
<string name="connect_plan_you_are_already_in_group_vName">You are already in group %1$s.</string>
<string name="connect_plan_connect_via_link">Connect via link?</string>
<!-- Errors -->
<string name="agent_critical_error_title">Critical error</string>
<string name="agent_critical_error_desc">Please report it to the developers: \n%s\n\nIt is recommended to restart the app.</string>
<string name="agent_internal_error_title">Internal error</string>
<string name="agent_internal_error_desc">Please report it to the developers: \n%s</string>
<string name="restart_chat_button">Restart chat</string>
</resources>
@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 -960 960 960" width="24"><path d="M479.895-284Q494-284 504-293.895q10-9.894 10-24Q514-332 504.105-342q-9.894-10-24-10Q466-352 456-342.105q-10 9.894-10 24Q446-304 455.895-294q9.894 10 24 10ZM451.5-425H509v-261h-57.5v261ZM332-124.5 124.5-332.176V-628l207.676-207.5H628l207.5 207.676V-332L627.824-124.5H332Zm24.222-57.5h248.243L778-356.222v-248.243L604.242-778H356L182-604.242V-356l174.222 174ZM480-480Z"/></svg>

After

Width:  |  Height:  |  Size: 472 B

@@ -16,8 +16,8 @@ import javax.imageio.ImageIO
object NtfManager {
private val prevNtfs = arrayListOf<Pair<ChatId, Slice>>()
fun notifyCallInvitation(invitation: RcvCallInvitation) {
if (simplexWindowState.windowFocused.value) return
fun notifyCallInvitation(invitation: RcvCallInvitation): Boolean {
if (simplexWindowState.windowFocused.value) return false
val contactId = invitation.contact.id
Log.d(TAG, "notifyCallInvitation $contactId")
val image = invitation.contact.image
@@ -45,6 +45,11 @@ object NtfManager {
displayNotificationViaLib(contactId, title, text, prepareIconPath(largeIcon), actions) {
ntfManager.openChatAction(invitation.user.userId, contactId)
}
return true
}
fun showMessage(title: String, text: String) {
displayNotificationViaLib("MESSAGE", title, text, null, emptyList()) {}
}
fun hasNotificationsForChat(chatId: ChatId) = false//prevNtfs.any { it.first == chatId }
@@ -16,13 +16,14 @@ val defaultLocale: Locale = Locale.getDefault()
fun initApp() {
ntfManager = object : NtfManager() {
override fun notifyCallInvitation(invitation: RcvCallInvitation) = chat.simplex.common.model.NtfManager.notifyCallInvitation(invitation)
override fun notifyCallInvitation(invitation: RcvCallInvitation): Boolean = chat.simplex.common.model.NtfManager.notifyCallInvitation(invitation)
override fun hasNotificationsForChat(chatId: String): Boolean = chat.simplex.common.model.NtfManager.hasNotificationsForChat(chatId)
override fun cancelNotificationsForChat(chatId: String) = chat.simplex.common.model.NtfManager.cancelNotificationsForChat(chatId)
override fun displayNotification(user: UserLike, chatId: String, displayName: String, msgText: String, image: String?, actions: List<Pair<NotificationAction, () -> Unit>>) = chat.simplex.common.model.NtfManager.displayNotification(user, chatId, displayName, msgText, image, actions)
override fun androidCreateNtfChannelsMaybeShowAlert() {}
override fun cancelCallNotification() {}
override fun cancelAllNotifications() = chat.simplex.common.model.NtfManager.cancelAllNotifications()
override fun showMessage(title: String, text: String) = chat.simplex.common.model.NtfManager.showMessage(title, text)
}
applyAppLocale()
withBGApi {
@@ -0,0 +1,23 @@
package chat.simplex.common.views.database
import androidx.compose.runtime.mutableStateOf
import chat.simplex.common.platform.chatModel
import chat.simplex.common.views.helpers.withApi
import kotlinx.coroutines.delay
import kotlinx.datetime.Instant
actual fun restartChatOrApp() {
if (chatModel.chatRunning.value == false) {
chatModel.chatDbChanged.value = true
startChat(chatModel, mutableStateOf(Instant.DISTANT_PAST), chatModel.chatDbChanged)
} else {
authStopChat(chatModel) {
withApi {
// adding delay in order to prevent locked database by previous initialization
delay(1000)
chatModel.chatDbChanged.value = true
startChat(chatModel, mutableStateOf(Instant.DISTANT_PAST), chatModel.chatDbChanged)
}
}
}
}
+4 -4
View File
@@ -25,11 +25,11 @@ android.nonTransitiveRClass=true
android.enableJetifier=true
kotlin.mpp.androidSourceSetLayoutVersion=2
android.version_name=5.4.2
android.version_code=166
android.version_name=5.4.3
android.version_code=169
desktop.version_name=5.4.2
desktop.version_code=20
desktop.version_name=5.4.3
desktop.version_code=22
kotlin.version=1.8.20
gradle.plugin.version=7.4.2
+1 -1
View File
@@ -14,7 +14,7 @@ constraints: zip +disable-bzip2 +disable-zstd
source-repository-package
type: git
location: https://github.com/simplex-chat/simplexmq.git
tag: d0588bd0ac23a459cbfc9a4789633014e91ffa19
tag: f6ed4640d407f8879273d104a3e69069806dcb7c
source-repository-package
type: git
Generated
+92 -150
View File
@@ -51,11 +51,11 @@
"cabal-34": {
"flake": false,
"locked": {
"lastModified": 1645834128,
"narHash": "sha256-wG3d+dOt14z8+ydz4SL7pwGfe7SiimxcD/LOuPCV6xM=",
"lastModified": 1640353650,
"narHash": "sha256-N1t6M3/wqj90AEdRkeC8i923gQYUpzSr8b40qVOZ1Rk=",
"owner": "haskell",
"repo": "cabal",
"rev": "5ff598c67f53f7c4f48e31d722ba37172230c462",
"rev": "942639c18c0cd8ec53e0a6f8d120091af35312cd",
"type": "github"
},
"original": {
@@ -68,11 +68,11 @@
"cabal-36": {
"flake": false,
"locked": {
"lastModified": 1669081697,
"narHash": "sha256-I5or+V7LZvMxfbYgZATU4awzkicBwwok4mVoje+sGmU=",
"lastModified": 1641652457,
"narHash": "sha256-BlFPKP4C4HRUJeAbdembX1Rms1LD380q9s0qVDeoAak=",
"owner": "haskell",
"repo": "cabal",
"rev": "8fd619e33d34924a94e691c5fea2c42f0fc7f144",
"rev": "f27667f8ec360c475027dcaee0138c937477b070",
"type": "github"
},
"original": {
@@ -159,16 +159,15 @@
"flake-compat": {
"flake": false,
"locked": {
"lastModified": 1672831974,
"narHash": "sha256-z9k3MfslLjWQfnjBtEtJZdq3H7kyi2kQtUThfTgdRk0=",
"lastModified": 1635892615,
"narHash": "sha256-harGbMZr4hzat2BWBU+Y5OYXlu+fVz7E4WeQzHi5o8A=",
"owner": "input-output-hk",
"repo": "flake-compat",
"rev": "45f2638735f8cdc40fe302742b79f248d23eb368",
"rev": "eca47d3377946315596da653862d341ee5341318",
"type": "github"
},
"original": {
"owner": "input-output-hk",
"ref": "hkm/gitlab-fix",
"repo": "flake-compat",
"type": "github"
}
@@ -191,11 +190,11 @@
},
"flake-utils": {
"locked": {
"lastModified": 1676283394,
"narHash": "sha256-XX2f9c3iySLCw54rJ/CZs+ZK6IQy7GXNY4nSOyu2QG4=",
"lastModified": 1667395993,
"narHash": "sha256-nuEHfE/LcWyuSWnS8t12N1wc105Qtau+/OdUAjtQ0rA=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "3db36a8b464d0c4532ba1c7dda728f4576d6d073",
"rev": "5aed5285a952e0b949eb3ba02c12fa4fcfef535f",
"type": "github"
},
"original": {
@@ -206,11 +205,11 @@
},
"flake-utils_2": {
"locked": {
"lastModified": 1667395993,
"narHash": "sha256-nuEHfE/LcWyuSWnS8t12N1wc105Qtau+/OdUAjtQ0rA=",
"lastModified": 1644229661,
"narHash": "sha256-1YdnJAsNy69bpcjuoKdOYQX0YxZBiCYZo4Twxerqv7k=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "5aed5285a952e0b949eb3ba02c12fa4fcfef535f",
"rev": "3cecb5b042f7f209c56ffd8371b2711a290ec797",
"type": "github"
},
"original": {
@@ -249,6 +248,21 @@
"type": "github"
}
},
"flake-utils_5": {
"locked": {
"lastModified": 1653893745,
"narHash": "sha256-0jntwV3Z8//YwuOjzhV2sgJJPt+HY6KhU7VZUL0fKZQ=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "1ed9fb1935d260de5fe1c2f7ee0ebaae17ed2fa1",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "flake-utils",
"type": "github"
}
},
"ghc-8.6.5-iohk": {
"flake": false,
"locked": {
@@ -316,7 +330,6 @@
],
"hpc-coveralls": "hpc-coveralls",
"hydra": "hydra",
"iserv-proxy": "iserv-proxy",
"nixpkgs": [
"nixpkgs"
],
@@ -324,23 +337,21 @@
"nixpkgs-2105": "nixpkgs-2105",
"nixpkgs-2111": "nixpkgs-2111",
"nixpkgs-2205": "nixpkgs-2205",
"nixpkgs-2211": "nixpkgs-2211",
"nixpkgs-unstable": "nixpkgs-unstable",
"old-ghc-nix": "old-ghc-nix",
"stackage": "stackage",
"tullia": "tullia"
},
"locked": {
"lastModified": 1677975916,
"narHash": "sha256-dbe8lEEPyfzjdRwpePClv7J9p9lQg7BwbBqAMCw4RLw=",
"owner": "input-output-hk",
"lastModified": 1672501055,
"narHash": "sha256-Wy6KqoYqQOP1rBvfHUvM3ex8HIdBA4kwnvZj2qQ1VLU=",
"owner": "simplex-chat",
"repo": "haskell.nix",
"rev": "ab5efd87ce3fd8ade38a01d97693d29a4f1ae7e4",
"rev": "dc719cd6dc318923c4a524d005c13f474c00d3d3",
"type": "github"
},
"original": {
"owner": "input-output-hk",
"ref": "armv7a",
"owner": "simplex-chat",
"repo": "haskell.nix",
"type": "github"
}
@@ -372,11 +383,11 @@
]
},
"locked": {
"lastModified": 1671755331,
"narHash": "sha256-hXsgJj0Cy0ZiCiYdW2OdBz5WmFyOMKuw4zyxKpgUKm4=",
"lastModified": 1646878427,
"narHash": "sha256-KtbrofMtN8GlM7D+n90kixr7QpSlVmdN+vK5CA/aRzc=",
"owner": "NixOS",
"repo": "hydra",
"rev": "f48f00ee6d5727ae3e488cbf9ce157460853fea8",
"rev": "28b682b85b7efc5cf7974065792a1f22203a5927",
"type": "github"
},
"original": {
@@ -384,46 +395,6 @@
"type": "indirect"
}
},
"incl": {
"inputs": {
"nixlib": [
"haskellNix",
"tullia",
"std",
"nixpkgs"
]
},
"locked": {
"lastModified": 1669263024,
"narHash": "sha256-E/+23NKtxAqYG/0ydYgxlgarKnxmDbg6rCMWnOBqn9Q=",
"owner": "divnix",
"repo": "incl",
"rev": "ce7bebaee048e4cd7ebdb4cee7885e00c4e2abca",
"type": "github"
},
"original": {
"owner": "divnix",
"repo": "incl",
"type": "github"
}
},
"iserv-proxy": {
"flake": false,
"locked": {
"lastModified": 1670983692,
"narHash": "sha256-avLo34JnI9HNyOuauK5R69usJm+GfW3MlyGlYxZhTgY=",
"ref": "hkm/remote-iserv",
"rev": "50d0abb3317ac439a4e7495b185a64af9b7b9300",
"revCount": 10,
"type": "git",
"url": "https://gitlab.haskell.org/hamishmack/iserv-proxy.git"
},
"original": {
"ref": "hkm/remote-iserv",
"type": "git",
"url": "https://gitlab.haskell.org/hamishmack/iserv-proxy.git"
}
},
"lowdown-src": {
"flake": false,
"locked": {
@@ -440,14 +411,25 @@
"type": "github"
}
},
"mdbook-kroki-preprocessor": {
"flake": false,
"locked": {
"lastModified": 1661755005,
"narHash": "sha256-1TJuUzfyMycWlOQH67LR63/ll2GDZz25I3JfScy/Jnw=",
"owner": "JoelCourtney",
"repo": "mdbook-kroki-preprocessor",
"rev": "93adb5716d035829efed27f65f2f0833a7d3e76f",
"type": "github"
},
"original": {
"owner": "JoelCourtney",
"repo": "mdbook-kroki-preprocessor",
"type": "github"
}
},
"n2c": {
"inputs": {
"flake-utils": [
"haskellNix",
"tullia",
"std",
"flake-utils"
],
"flake-utils": "flake-utils_5",
"nixpkgs": [
"haskellNix",
"tullia",
@@ -476,16 +458,16 @@
"nixpkgs-regression": "nixpkgs-regression"
},
"locked": {
"lastModified": 1661606874,
"narHash": "sha256-9+rpYzI+SmxJn+EbYxjGv68Ucp22bdFUSy/4LkHkkDQ=",
"lastModified": 1643066034,
"narHash": "sha256-xEPeMcNJVOeZtoN+d+aRwolpW8mFSEQx76HTRdlhPhg=",
"owner": "NixOS",
"repo": "nix",
"rev": "11e45768b34fdafdcf019ddbd337afa16127ff0f",
"rev": "a1cd7e58606a41fcf62bf8637804cf8306f17f62",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "2.11.0",
"ref": "2.6.0",
"repo": "nix",
"type": "github"
}
@@ -581,18 +563,17 @@
},
"nixpkgs": {
"locked": {
"lastModified": 1657693803,
"narHash": "sha256-G++2CJ9u0E7NNTAi9n5G8TdDmGJXcIjkJ3NF8cetQB8=",
"lastModified": 1632864508,
"narHash": "sha256-d127FIvGR41XbVRDPVvozUPQ/uRHbHwvfyKHwEt5xFM=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "365e1b3a859281cf11b94f87231adeabbdd878a2",
"rev": "82891b5e2c2359d7e58d08849e4c89511ab94234",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixos-22.05-small",
"repo": "nixpkgs",
"type": "github"
"id": "nixpkgs",
"ref": "nixos-21.05-small",
"type": "indirect"
}
},
"nixpkgs-2003": {
@@ -645,11 +626,11 @@
},
"nixpkgs-2205": {
"locked": {
"lastModified": 1672580127,
"narHash": "sha256-3lW3xZslREhJogoOkjeZtlBtvFMyxHku7I/9IVehhT8=",
"lastModified": 1663981975,
"narHash": "sha256-TKaxWAVJR+a5JJauKZqibmaM5e/Pi5tBDx9s8fl/kSE=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "0874168639713f547c05947c76124f78441ea46c",
"rev": "309faedb8338d3ae8ad8f1043b3ccf48c9cc2970",
"type": "github"
},
"original": {
@@ -659,22 +640,6 @@
"type": "github"
}
},
"nixpkgs-2211": {
"locked": {
"lastModified": 1675730325,
"narHash": "sha256-uNvD7fzO5hNlltNQUAFBPlcEjNG5Gkbhl/ROiX+GZU4=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "b7ce17b1ebf600a72178f6302c77b6382d09323f",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixpkgs-22.11-darwin",
"repo": "nixpkgs",
"type": "github"
}
},
"nixpkgs-regression": {
"locked": {
"lastModified": 1643052045,
@@ -685,19 +650,18 @@
"type": "github"
},
"original": {
"owner": "NixOS",
"repo": "nixpkgs",
"id": "nixpkgs",
"rev": "215d4d0fd80ca5163643b03a33fde804a29cc1e2",
"type": "github"
"type": "indirect"
}
},
"nixpkgs-unstable": {
"locked": {
"lastModified": 1675758091,
"narHash": "sha256-7gFSQbSVAFUHtGCNHPF7mPc5CcqDk9M2+inlVPZSneg=",
"lastModified": 1663905476,
"narHash": "sha256-0CSwRKaYravh9v6qSlBpM0gNg0UhKT2lL7Yn6Zbx7UM=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "747927516efcb5e31ba03b7ff32f61f6d47e7d87",
"rev": "e14f9fb57315f0d4abde222364f19f88c77d2b79",
"type": "github"
},
"original": {
@@ -756,35 +720,20 @@
},
"nixpkgs_5": {
"locked": {
"lastModified": 1676726892,
"narHash": "sha256-M7OYVR6dKmzmlebIjybFf3l18S2uur8lMyWWnHQooLY=",
"owner": "angerman",
"lastModified": 1669833724,
"narHash": "sha256-/HEZNyGbnQecrgJnfE8d0WC5c1xuPSD2LUpB6YXlg4c=",
"owner": "nixos",
"repo": "nixpkgs",
"rev": "729469087592bdea58b360de59dadf6d58714c42",
"rev": "4d2b37a84fad1091b9de401eb450aae66f1a741e",
"type": "github"
},
"original": {
"owner": "angerman",
"ref": "release-22.11",
"owner": "nixos",
"ref": "22.11",
"repo": "nixpkgs",
"type": "github"
}
},
"nosys": {
"locked": {
"lastModified": 1667881534,
"narHash": "sha256-FhwJ15uPLRsvaxtt/bNuqE/ykMpNAPF0upozFKhTtXM=",
"owner": "divnix",
"repo": "nosys",
"rev": "2d0d5207f6a230e9d0f660903f8db9807b54814f",
"type": "github"
},
"original": {
"owner": "divnix",
"repo": "nosys",
"type": "github"
}
},
"old-ghc-nix": {
"flake": false,
"locked": {
@@ -813,11 +762,11 @@
"stackage": {
"flake": false,
"locked": {
"lastModified": 1677888571,
"narHash": "sha256-YkhRNOaN6QVagZo1cfykYV8KqkI8/q6r2F5+jypOma4=",
"lastModified": 1669598217,
"narHash": "sha256-UioviNyxA3fexeguXLQpgMR6uWL9Q/wulipCbET3C8w=",
"owner": "input-output-hk",
"repo": "stackage.nix",
"rev": "cb50e6fabdfb2d7e655059039012ad0623f06a27",
"rev": "8400280d894949e26354123aebc20801a2165182",
"type": "github"
},
"original": {
@@ -828,23 +777,17 @@
},
"std": {
"inputs": {
"arion": [
"haskellNix",
"tullia",
"std",
"blank"
],
"blank": "blank",
"devshell": "devshell",
"dmerge": "dmerge",
"flake-utils": "flake-utils_4",
"incl": "incl",
"makes": [
"haskellNix",
"tullia",
"std",
"blank"
],
"mdbook-kroki-preprocessor": "mdbook-kroki-preprocessor",
"microvm": [
"haskellNix",
"tullia",
@@ -854,15 +797,14 @@
"n2c": "n2c",
"nixago": "nixago",
"nixpkgs": "nixpkgs_4",
"nosys": "nosys",
"yants": "yants"
},
"locked": {
"lastModified": 1674526466,
"narHash": "sha256-tMTaS0bqLx6VJ+K+ZT6xqsXNpzvSXJTmogkraBGzymg=",
"lastModified": 1665513321,
"narHash": "sha256-D6Pacw9yf/HMs84KYuCxHXnNDL7v43gtcka5URagFqE=",
"owner": "divnix",
"repo": "std",
"rev": "516387e3d8d059b50e742a2ff1909ed3c8f82826",
"rev": "94a90eedb9cfc115b12ae8f6622d9904788559e4",
"type": "github"
},
"original": {
@@ -882,11 +824,11 @@
"std": "std"
},
"locked": {
"lastModified": 1675695930,
"narHash": "sha256-B7rEZ/DBUMlK1AcJ9ajnAPPxqXY6zW2SBX+51bZV0Ac=",
"lastModified": 1666200256,
"narHash": "sha256-cJPS8zBu30SMhxMe7I8DWutwqMuhPsEez87y9gxMKc4=",
"owner": "input-output-hk",
"repo": "tullia",
"rev": "621365f2c725608f381b3ad5b57afef389fd4c31",
"rev": "575362c2244498e8d2c97f72861510fa72e75d44",
"type": "github"
},
"original": {
@@ -920,11 +862,11 @@
]
},
"locked": {
"lastModified": 1667096281,
"narHash": "sha256-wRRec6ze0gJHmGn6m57/zhz/Kdvp9HS4Nl5fkQ+uIuA=",
"lastModified": 1660507851,
"narHash": "sha256-BKjq7JnVuUR/xDtcv6Vm9GYGKAblisXrAgybor9hT/s=",
"owner": "divnix",
"repo": "yants",
"rev": "d18f356ec25cb94dc9c275870c3a7927a10f8c3c",
"rev": "0b895ca02a8fa72bad50b454cb3e7d8a66407c96",
"type": "github"
},
"original": {
+110 -108
View File
@@ -1,7 +1,7 @@
{
description = "nix flake for simplex-chat";
inputs.nixpkgs.url = "github:angerman/nixpkgs/release-22.11";
inputs.haskellNix.url = "github:input-output-hk/haskell.nix/armv7a";
inputs.nixpkgs.url = "github:nixos/nixpkgs/22.11";
inputs.haskellNix.url = "github:simplex-chat/haskell.nix";
inputs.haskellNix.inputs.nixpkgs.follows = "nixpkgs";
inputs.hackage = {
url = "github:input-output-hk/hackage.nix";
@@ -12,23 +12,7 @@
outputs = { self, haskellNix, nixpkgs, flake-utils, ... }:
let systems = [ "x86_64-linux" "x86_64-darwin" "aarch64-linux" "aarch64-darwin" ]; in
flake-utils.lib.eachSystem systems (system:
# this android26 overlay makes the pkgsCross.{aarch64-android,armv7a-android-prebuilt} to set stdVer to 26 (Android 8).
let android26 = final: prev: {
pkgsCross = prev.pkgsCross // {
aarch64-android = import prev.path {
inherit system;
inherit (prev) overlays;
crossSystem = prev.lib.systems.examples.aarch64-android // { sdkVer = "26"; };
};
armv7a-android-prebuilt = import prev.path {
inherit system;
inherit (prev) overlays;
crossSystem = prev.lib.systems.examples.armv7a-android-prebuilt // { sdkVer = "26"; };
};
};
}; in
# `appendOverlays` with a singleton is identical to `extend`.
let pkgs = haskellNix.legacyPackages.${system}.appendOverlays [android26]; in
let pkgs = haskellNix.legacyPackages.${system}; in
let drv' = { extra-modules, pkgs', ... }: pkgs'.haskell-nix.project {
compiler-nix-name = "ghc8107";
index-state = "2023-12-12T00:00:00Z";
@@ -97,7 +81,6 @@
"x86_64-linux" =
let
androidPkgs = pkgs.pkgsCross.aarch64-android;
android32Pkgs = pkgs.pkgsCross.armv7a-android-prebuilt;
# For some reason building libiconv with nixpgks android setup produces
# LANGINFO_CODESET to be found, which is not compatible with android sdk 23;
# so we'll patch up iconv to not include that.
@@ -113,32 +96,11 @@
androidFFI = androidPkgs.libffi.overrideAttrs (old: {
dontDisableStatic = true;
hardeningDisable = [ "fortify" ];
});
android32FFI = android32Pkgs.libffi.overrideAttrs (old: {
dontDisableStatic = true;
hardeningDisable = [ "fortify" ];
postConfigure = ''
echo "#undef HAVE_MEMFD_CREATE" >> aarch64-unknown-linux-android/fficonfig.h
'';
}
);in {
"${pkgs.pkgsCross.musl64.hostPlatform.system}-static:exe:simplex-chat" = (drv pkgs.pkgsCross.musl64).simplex-chat.components.exes.simplex-chat;
"${pkgs.pkgsCross.musl32.hostPlatform.system}-static:exe:simplex-chat" = (drv pkgs.pkgsCross.musl32).simplex-chat.components.exes.simplex-chat;
# "${pkgs.pkgsCross.muslpi.hostPlatform.system}-static:exe:simplex-chat" = (drv pkgs.pkgsCross.muslpi).simplex-chat.components.exes.simplex-chat;
"${pkgs.pkgsCross.aarch64-multiplatform-musl.hostPlatform.system}-static:exe:simplex-chat" = (drv pkgs.pkgsCross.aarch64-multiplatform-musl).simplex-chat.components.exes.simplex-chat;
"armv7a-android:lib:support" = (drv android32Pkgs).android-support.components.library.override {
smallAddressSpace = true; enableShared = false;
setupBuildFlags = map (x: "--ghc-option=${x}") [ "-shared" "-o" "libsupport.so" ];
postInstall = ''
mkdir -p $out/_pkg
cp libsupport.so $out/_pkg
${pkgs.patchelf}/bin/patchelf --remove-needed libunwind.so.1 $out/_pkg/libsupport.so
(cd $out/_pkg; ${pkgs.zip}/bin/zip -r -9 $out/pkg-armv7a-android-libsupport.zip *)
rm -fR $out/_pkg
mkdir -p $out/nix-support
echo "file binary-dist \"$(echo $out/*.zip)\"" \
> $out/nix-support/hydra-build-products
'';
};
"aarch64-android:lib:support" = (drv androidPkgs).android-support.components.library.override {
smallAddressSpace = true; enableShared = false;
setupBuildFlags = map (x: "--ghc-option=${x}") [ "-shared" "-o" "libsupport.so" ];
@@ -155,70 +117,6 @@
> $out/nix-support/hydra-build-products
'';
};
"armv7a-android:lib:simplex-chat" = (drv' {
pkgs' = android32Pkgs;
extra-modules = [{
packages.direct-sqlcipher.flags.openssl = true;
packages.direct-sqlcipher.components.library.libs = pkgs.lib.mkForce [
(android32Pkgs.openssl.override { static = true; enableKTLS = false; })
];
packages.direct-sqlcipher.patches = [
./scripts/nix/direct-sqlcipher-android-log.patch
];
packages.simplexmq.components.library.libs = pkgs.lib.mkForce [
(android32Pkgs.openssl.override { static = true; enableKTLS = false; })
];
}];
}).simplex-chat.components.library.override {
smallAddressSpace = true; enableShared = false;
# for android we build a shared library, passing these arguments is a bit tricky, as
# we want only the threaded rts (HSrts_thr) and ffi to be linked, but not fed into iserv for
# template haskell cross compilation. Thus we just pass them as linker options (-optl).
setupBuildFlags = map (x: "--ghc-option=${x}") [ "-shared" "-o" "libsimplex.so" "-optl-lHSrts_thr" "-optl-lffi"];
postInstall = ''
set -x
${pkgs.tree}/bin/tree $out
mkdir -p $out/_pkg
# copy over includes, we might want those, but maybe not.
# cp -r $out/lib/*/*/include $out/_pkg/
# find the libHS...ghc-X.Y.Z.a static library; this is the
# rolled up one with all dependencies included.
cp libsimplex.so $out/_pkg
# find ./dist -name "lib*.so" -exec cp {} $out/_pkg \;
# find ./dist -name "libHS*-ghc*.a" -exec cp {} $out/_pkg \;
# find ${android32FFI}/lib -name "*.a" -exec cp {} $out/_pkg \;
# find ${android32Pkgs.gmp6.override { withStatic = true; }}/lib -name "*.a" -exec cp {} $out/_pkg \;
# find ${androidIconv}/lib -name "*.a" -exec cp {} $out/_pkg \;
# find ${android32Pkgs.stdenv.cc.libc}/lib -name "*.a" -exec cp {} $out/_pkg \;
echo ${android32Pkgs.openssl.override { enableKTLS = false; }}
find ${(android32Pkgs.openssl.override { enableKTLS = false; }).out}/lib -name "*.so" -exec cp {} $out/_pkg \;
# remove the .1 and other version suffixes from .so's. Androids linker
# doesn't play nice with them.
for lib in $out/_pkg/*.so; do
for dep in $(${pkgs.patchelf}/bin/patchelf --print-needed "$lib"); do
if [[ "''${dep##*.so}" ]]; then
echo "$lib : $dep -> ''${dep%%.so*}.so"
chmod +w "$lib"
${pkgs.patchelf}/bin/patchelf --replace-needed "$dep" "''${dep%%.so*}.so" "$lib"
fi
done
done
for lib in $out/_pkg/*.so; do
chmod +w "$lib"
${pkgs.patchelf}/bin/patchelf --remove-needed libunwind.so "$lib"
[[ "$lib" != *libsimplex.so ]] && ${pkgs.patchelf}/bin/patchelf --set-soname "$(basename -a $lib)" "$lib"
done
${pkgs.tree}/bin/tree $out/_pkg
(cd $out/_pkg; ${pkgs.zip}/bin/zip -r -9 $out/pkg-armv7a-android-libsimplex.zip *)
rm -fR $out/_pkg
mkdir -p $out/nix-support
echo "file binary-dist \"$(echo $out/*.zip)\"" \
> $out/nix-support/hydra-build-products
'';
};
"aarch64-android:lib:simplex-chat" = (drv' {
pkgs' = androidPkgs;
extra-modules = [{
@@ -283,6 +181,110 @@
> $out/nix-support/hydra-build-products
'';
};
"x86_64-android:lib:support" = (drv androidPkgs).android-support.components.library.override {
smallAddressSpace = true; enableShared = false;
setupBuildFlags = map (x: "--ghc-option=${x}") [ "-shared" "-o" "libsupport.so" ];
postInstall = ''
mkdir -p $out/_pkg
cp libsupport.so $out/_pkg
${pkgs.patchelf}/bin/patchelf --remove-needed libunwind.so.1 $out/_pkg/libsupport.so
(cd $out/_pkg; ${pkgs.zip}/bin/zip -r -9 $out/pkg-x86_64-android-libsupport.zip *)
rm -fR $out/_pkg
mkdir -p $out/nix-support
echo "file binary-dist \"$(echo $out/*.zip)\"" \
> $out/nix-support/hydra-build-products
'';
};
"x86_64-android:lib:simplex-chat" = (drv' {
pkgs' = androidPkgs;
extra-modules = [{
packages.direct-sqlcipher.flags.openssl = true;
}];
}).simplex-chat.components.library.override {
smallAddressSpace = true; enableShared = false;
# for android we build a shared library, passing these arguments is a bit tricky, as
# we want only the threaded rts (HSrts_thr) and ffi to be linked, but not fed into iserv for
# template haskell cross compilation. Thus we just pass them as linker options (-optl).
setupBuildFlags = map (x: "--ghc-option=${x}") [ "-shared" "-o" "libsimplex.so" "-optl-lHSrts_thr" "-optl-lffi"];
postInstall = ''
${pkgs.tree}/bin/tree $out
mkdir -p $out/_pkg
# copy over includes, we might want those, but maybe not.
# cp -r $out/lib/*/*/include $out/_pkg/
# find the libHS...ghc-X.Y.Z.a static library; this is the
# rolled up one with all dependencies included.
cp libsimplex.so $out/_pkg
# find ./dist -name "lib*.so" -exec cp {} $out/_pkg \;
# find ./dist -name "libHS*-ghc*.a" -exec cp {} $out/_pkg \;
# find ${androidFFI}/lib -name "*.a" -exec cp {} $out/_pkg \;
# find ${androidPkgs.gmp6.override { withStatic = true; }}/lib -name "*.a" -exec cp {} $out/_pkg \;
# find ${androidIconv}/lib -name "*.a" -exec cp {} $out/_pkg \;
# find ${androidPkgs.stdenv.cc.libc}/lib -name "*.a" -exec cp {} $out/_pkg \;
${pkgs.patchelf}/bin/patchelf --remove-needed libunwind.so.1 $out/_pkg/libsimplex.so
${pkgs.tree}/bin/tree $out/_pkg
(cd $out/_pkg; ${pkgs.zip}/bin/zip -r -9 $out/pkg-x86_64-android-libsimplex.zip *)
rm -fR $out/_pkg
mkdir -p $out/nix-support
echo "file binary-dist \"$(echo $out/*.zip)\"" \
> $out/nix-support/hydra-build-products
'';
};
"x86_64-linux:lib:support" = (drv androidPkgs).android-support.components.library.override {
smallAddressSpace = true; enableShared = false;
setupBuildFlags = map (x: "--ghc-option=${x}") [ "-shared" "-o" "libsupport.so" ];
postInstall = ''
mkdir -p $out/_pkg
cp libsupport.so $out/_pkg
${pkgs.patchelf}/bin/patchelf --remove-needed libunwind.so.1 $out/_pkg/libsupport.so
(cd $out/_pkg; ${pkgs.zip}/bin/zip -r -9 $out/pkg-x86_64-linux-libsupport.zip *)
rm -fR $out/_pkg
mkdir -p $out/nix-support
echo "file binary-dist \"$(echo $out/*.zip)\"" \
> $out/nix-support/hydra-build-products
'';
};
"x86_64-linux:lib:simplex-chat" = (drv' {
pkgs' = androidPkgs;
extra-modules = [{
packages.direct-sqlcipher.flags.openssl = true;
}];
}).simplex-chat.components.library.override {
smallAddressSpace = true; enableShared = false;
# for android we build a shared library, passing these arguments is a bit tricky, as
# we want only the threaded rts (HSrts_thr) and ffi to be linked, but not fed into iserv for
# template haskell cross compilation. Thus we just pass them as linker options (-optl).
setupBuildFlags = map (x: "--ghc-option=${x}") [ "-shared" "-o" "libsimplex.so" "-optl-lHSrts_thr" "-optl-lffi"];
postInstall = ''
${pkgs.tree}/bin/tree $out
mkdir -p $out/_pkg
# copy over includes, we might want those, but maybe not.
# cp -r $out/lib/*/*/include $out/_pkg/
# find the libHS...ghc-X.Y.Z.a static library; this is the
# rolled up one with all dependencies included.
cp libsimplex.so $out/_pkg
# find ./dist -name "lib*.so" -exec cp {} $out/_pkg \;
# find ./dist -name "libHS*-ghc*.a" -exec cp {} $out/_pkg \;
# find ${androidFFI}/lib -name "*.a" -exec cp {} $out/_pkg \;
# find ${androidPkgs.gmp6.override { withStatic = true; }}/lib -name "*.a" -exec cp {} $out/_pkg \;
# find ${androidIconv}/lib -name "*.a" -exec cp {} $out/_pkg \;
# find ${androidPkgs.stdenv.cc.libc}/lib -name "*.a" -exec cp {} $out/_pkg \;
${pkgs.patchelf}/bin/patchelf --remove-needed libunwind.so.1 $out/_pkg/libsimplex.so
${pkgs.tree}/bin/tree $out/_pkg
(cd $out/_pkg; ${pkgs.zip}/bin/zip -r -9 $out/pkg-x86_64-linux-libsimplex.zip *)
rm -fR $out/_pkg
mkdir -p $out/nix-support
echo "file binary-dist \"$(echo $out/*.zip)\"" \
> $out/nix-support/hydra-build-products
'';
};
};
# builds for iOS and iOS simulator
+2 -2
View File
@@ -1,5 +1,5 @@
name: simplex-chat
version: 5.4.2.1
version: 5.4.4.0
#synopsis:
#description:
homepage: https://github.com/simplex-chat/simplex-chat#readme
@@ -36,7 +36,7 @@ dependencies:
- network >= 3.1.2.7 && < 3.2
- network-transport == 0.5.6
- optparse-applicative >= 0.15 && < 0.17
- process >= 1.6 && < 1.6.18
- process == 1.6.*
- random >= 1.1 && < 1.3
- record-hasfield == 1.0.*
- simple-logger == 0.1.*
+5 -2
View File
@@ -108,10 +108,13 @@ build() {
if [ "$arch" = "armv7a" ] && [ -n "$tag_full" ] ; then
git checkout "${tag_version}-armv7a"
android_simplex_lib="${folder}#hydraJobs.${arch}-android:lib:simplex-chat.x86_64-linux"
android_support_lib="${folder}#hydraJobs.${arch}-android:lib:support.x86_64-linux"
else
android_simplex_lib="${folder}#hydraJobs.x86_64-linux.${arch}-android:lib:simplex-chat"
android_support_lib="${folder}#hydraJobs.x86_64-linux.${arch}-android:lib:support"
fi
android_simplex_lib="${folder}#hydraJobs.${arch}-android:lib:simplex-chat.x86_64-linux"
android_support_lib="${folder}#hydraJobs.${arch}-android:lib:support.x86_64-linux"
android_simplex_lib_output="${PWD}/result/pkg-${arch}-android-libsimplex.zip"
android_support_lib_output="${PWD}/result/pkg-${arch}-android-libsupport.zip"
+2 -2
View File
@@ -37,12 +37,12 @@ for ((i = 0 ; i < ${#arches[@]}; i++)); do
mkdir -p "$output_dir" 2> /dev/null
curl --location -o libsupport.zip $job_repo/$arch-android:lib:support.x86_64-linux/latest/download/1 && \
curl --tlsv1.2 --location -o libsupport.zip $job_repo/$arch-android:lib:support.x86_64-linux/latest/download/1 && \
unzip -o libsupport.zip && \
mv libsupport.so "$output_dir" && \
rm libsupport.zip
curl --location -o libsimplex.zip "$job_repo"/"$arch"-android:lib:simplex-chat.x86_64-linux/latest/download/1 && \
curl --tlsv1.2 --location -o libsimplex.zip "$job_repo"/"$arch"-android:lib:simplex-chat.x86_64-linux/latest/download/1 && \
unzip -o libsimplex.zip && \
mv libsimplex.so "$output_dir" && \
rm libsimplex.zip
+1 -1
View File
@@ -37,7 +37,7 @@ cp *imple*.desktop usr/share/applications/
cp $multiplatform_dir/desktop/src/jvmMain/resources/distribute/*.appdata.xml usr/share/metainfo
if [ ! -f ../appimagetool-x86_64.AppImage ]; then
wget https://github.com/AppImage/appimagetool/releases/download/continuous/appimagetool-x86_64.AppImage -O ../appimagetool-x86_64.AppImage
wget --secure-protocol=TLSv1_3 https://github.com/AppImage/appimagetool/releases/download/continuous/appimagetool-x86_64.AppImage -O ../appimagetool-x86_64.AppImage
chmod +x ../appimagetool-x86_64.AppImage
fi
../appimagetool-x86_64.AppImage .
+1 -1
View File
@@ -12,7 +12,7 @@ cd $root_dir
if [ ! -f dist-newstyle/openssl-1.1.1w/libcrypto-1_1-x64.dll ]; then
mkdir dist-newstyle 2>/dev/null || true
cd dist-newstyle
curl https://www.openssl.org/source/openssl-1.1.1w.tar.gz -o openssl.tar.gz
curl --tlsv1.2 https://www.openssl.org/source/openssl-1.1.1w.tar.gz -o openssl.tar.gz
$WINDIR\\System32\\tar.exe -xvzf openssl.tar.gz
cd openssl-1.1.1w
./Configure mingw64
+5 -5
View File
@@ -14,7 +14,7 @@ mkdir $vlc_dir || exit 0
cd /tmp
mkdir tmp 2>/dev/null || true
cd tmp
curl https://github.com/cmatomic/VLCplayer-AppImage/releases/download/3.0.11.1/VLC_media_player-3.0.11.1-x86_64.AppImage -L -o appimage
curl --tlsv1.2 https://github.com/cmatomic/VLCplayer-AppImage/releases/download/3.0.11.1/VLC_media_player-3.0.11.1-x86_64.AppImage -L -o appimage
chmod +x appimage
./appimage --appimage-extract
cp -r squashfs-root/usr/lib/* $vlc_dir
@@ -28,7 +28,7 @@ cd /tmp
(
mkdir tmp
cd tmp
curl http://archive.ubuntu.com/ubuntu/pool/universe/v/vlc/libvlc5_3.0.9.2-1_amd64.deb -o libvlc
curl --tlsv1.2 https://archive.ubuntu.com/ubuntu/pool/universe/v/vlc/libvlc5_3.0.9.2-1_amd64.deb -o libvlc
ar p libvlc data.tar.xz > data.tar.xz
tar -xvf data.tar.xz
mv usr/lib/x86_64-linux-gnu/libvlc.so{.5,}
@@ -40,7 +40,7 @@ rm -rf tmp
(
mkdir tmp
cd tmp
curl http://archive.ubuntu.com/ubuntu/pool/universe/v/vlc/libvlccore9_3.0.9.2-1_amd64.deb -o libvlccore
curl --tlsv1.2 https://archive.ubuntu.com/ubuntu/pool/universe/v/vlc/libvlccore9_3.0.9.2-1_amd64.deb -o libvlccore
ar p libvlccore data.tar.xz > data.tar.xz
tar -xvf data.tar.xz
cp usr/lib/x86_64-linux-gnu/libvlccore.so* $vlc_dir
@@ -51,7 +51,7 @@ rm -rf tmp
(
mkdir tmp
cd tmp
curl http://mirrors.edge.kernel.org/ubuntu/pool/universe/v/vlc/vlc-plugin-base_3.0.9.2-1_amd64.deb -o plugins
curl --tlsv1.2 https://mirrors.edge.kernel.org/ubuntu/pool/universe/v/vlc/vlc-plugin-base_3.0.9.2-1_amd64.deb -o plugins
ar p plugins data.tar.xz > data.tar.xz
tar -xvf data.tar.xz
find usr/lib/x86_64-linux-gnu/vlc/plugins/ -name "lib*.so*" -exec patchelf --set-rpath '$ORIGIN/../../' {} \;
@@ -63,7 +63,7 @@ rm -rf tmp
(
mkdir tmp
cd tmp
curl http://archive.ubuntu.com/ubuntu/pool/main/libi/libidn/libidn11_1.33-2.2ubuntu2_amd64.deb -o idn
curl --tlsv1.2 https://archive.ubuntu.com/ubuntu/pool/main/libi/libidn/libidn11_1.33-2.2ubuntu2_amd64.deb -o idn
ar p idn data.tar.xz > data.tar.xz
tar -xvf data.tar.xz
cp lib/x86_64-linux-gnu/lib* $vlc_dir
+1 -1
View File
@@ -23,7 +23,7 @@ mkdir -p $vlc_dir/vlc || exit 0
cd /tmp
mkdir tmp 2>/dev/null || true
cd tmp
curl https://github.com/simplex-chat/vlc/releases/download/v$vlc_version/vlc-macos-$ARCH.zip -L -o vlc
curl --tlsv1.2 https://github.com/simplex-chat/vlc/releases/download/v$vlc_version/vlc-macos-$ARCH.zip -L -o vlc
unzip -oqq vlc
install_name_tool -add_rpath "@loader_path/VLC.app/Contents/MacOS/lib" vlc-cache-gen
cd VLC.app/Contents/MacOS/lib
+1 -1
View File
@@ -13,7 +13,7 @@ mkdir -p $vlc_dir/vlc || exit 0
cd /tmp
mkdir tmp 2>/dev/null || true
cd tmp
curl https://irltoolkit.mm.fcix.net/videolan-ftp/vlc/3.0.18/win64/vlc-3.0.18-win64.zip -L -o vlc
curl --tlsv1.2 https://irltoolkit.mm.fcix.net/videolan-ftp/vlc/3.0.18/win64/vlc-3.0.18-win64.zip -L -o vlc
$WINDIR\\System32\\tar.exe -xf vlc
cd vlc-*
# Setting the same date as the date that will be on the file after extraction from JAR to make VLC cache checker happy
+1 -1
View File
@@ -35,7 +35,7 @@ for ((i = 0 ; i < ${#arches[@]}; i++)); do
output_arch="${output_arches[$i]}"
output_dir="$HOME/Downloads"
curl --location -o "$output_dir"/pkg-ios-"$arch"-swift-json.zip "$job_repo"/"$arch"-darwin-ios:lib:simplex-chat."$arch"-darwin/latest/download/1 && \
curl --tlsv1.2 --location -o "$output_dir"/pkg-ios-"$arch"-swift-json.zip "$job_repo"/"$arch"-darwin-ios:lib:simplex-chat."$arch"-darwin/latest/download/1 && \
unzip -o "$output_dir"/pkg-ios-"$output_arch"-swift-json.zip -d ~/Downloads/pkg-ios-"$output_arch"-swift-json
done
sh "$root_dir"/scripts/ios/prepare-x86_64.sh
+1 -1
View File
@@ -1,5 +1,5 @@
{
"https://github.com/simplex-chat/simplexmq.git"."d0588bd0ac23a459cbfc9a4789633014e91ffa19" = "0b17qy74capb0jyli8f3pg1xi4aawhcgpmaz2ykl9g3605png1na";
"https://github.com/simplex-chat/simplexmq.git"."f6ed4640d407f8879273d104a3e69069806dcb7c" = "072rakv697f85i8ldjl7bj7jc7vfmzphasx2i4ynwgz3kksydfp5";
"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";
+8 -8
View File
@@ -5,7 +5,7 @@ cabal-version: 1.12
-- see: https://github.com/sol/hpack
name: simplex-chat
version: 5.4.2.1
version: 5.4.4.0
category: Web, System, Services, Cryptography
homepage: https://github.com/simplex-chat/simplex-chat#readme
author: simplex.chat
@@ -192,7 +192,7 @@ library
, network >=3.1.2.7 && <3.2
, network-transport ==0.5.6
, optparse-applicative >=0.15 && <0.17
, process >=1.6 && <1.6.18
, process ==1.6.*
, random >=1.1 && <1.3
, record-hasfield ==1.0.*
, simple-logger ==0.1.*
@@ -251,7 +251,7 @@ executable simplex-bot
, network >=3.1.2.7 && <3.2
, network-transport ==0.5.6
, optparse-applicative >=0.15 && <0.17
, process >=1.6 && <1.6.18
, process ==1.6.*
, random >=1.1 && <1.3
, record-hasfield ==1.0.*
, simple-logger ==0.1.*
@@ -311,7 +311,7 @@ executable simplex-bot-advanced
, network >=3.1.2.7 && <3.2
, network-transport ==0.5.6
, optparse-applicative >=0.15 && <0.17
, process >=1.6 && <1.6.18
, process ==1.6.*
, random >=1.1 && <1.3
, record-hasfield ==1.0.*
, simple-logger ==0.1.*
@@ -373,7 +373,7 @@ executable simplex-broadcast-bot
, network >=3.1.2.7 && <3.2
, network-transport ==0.5.6
, optparse-applicative >=0.15 && <0.17
, process >=1.6 && <1.6.18
, process ==1.6.*
, random >=1.1 && <1.3
, record-hasfield ==1.0.*
, simple-logger ==0.1.*
@@ -434,7 +434,7 @@ executable simplex-chat
, network ==3.1.*
, network-transport ==0.5.6
, optparse-applicative >=0.15 && <0.17
, process >=1.6 && <1.6.18
, process ==1.6.*
, random >=1.1 && <1.3
, record-hasfield ==1.0.*
, simple-logger ==0.1.*
@@ -500,7 +500,7 @@ executable simplex-directory-service
, network >=3.1.2.7 && <3.2
, network-transport ==0.5.6
, optparse-applicative >=0.15 && <0.17
, process >=1.6 && <1.6.18
, process ==1.6.*
, random >=1.1 && <1.3
, record-hasfield ==1.0.*
, simple-logger ==0.1.*
@@ -594,7 +594,7 @@ test-suite simplex-chat-test
, network ==3.1.*
, network-transport ==0.5.6
, optparse-applicative >=0.15 && <0.17
, process >=1.6 && <1.6.18
, process ==1.6.*
, random >=1.1 && <1.3
, record-hasfield ==1.0.*
, silently ==1.2.*
+37 -26
View File
@@ -28,7 +28,6 @@ import Data.Bifunctor (bimap, first)
import Data.ByteArray (ScrubbedBytes)
import qualified Data.ByteArray as BA
import qualified Data.ByteString.Base64 as B64
import Data.ByteString.Builder (toLazyByteString)
import Data.ByteString.Char8 (ByteString)
import qualified Data.ByteString.Char8 as B
import qualified Data.ByteString.Lazy.Char8 as LB
@@ -233,6 +232,7 @@ newChatController
expireCIFlags <- newTVarIO M.empty
cleanupManagerAsync <- newTVarIO Nothing
timedItemThreads <- atomically TM.empty
chatActivated <- newTVarIO True
showLiveItems <- newTVarIO False
encryptLocalFiles <- newTVarIO False
userXFTPFileConfig <- newTVarIO $ xftpFileConfig cfg
@@ -268,6 +268,7 @@ newChatController
expireCIFlags,
cleanupManagerAsync,
timedItemThreads,
chatActivated,
showLiveItems,
encryptLocalFiles,
userXFTPFileConfig,
@@ -310,10 +311,10 @@ cfgServers = \case
SPSMP -> smp
SPXFTP -> xftp
startChatController :: forall m. ChatMonad' m => Bool -> Bool -> Bool -> m (Async ())
startChatController subConns enableExpireCIs startXFTPWorkers = do
startChatController :: forall m. ChatMonad' m => Bool -> m (Async ())
startChatController mainApp = do
asks smpAgent >>= resumeAgentClient
unless subConns $
unless mainApp $
chatWriteVar subscriptionMode SMOnlyCreate
users <- fromRight [] <$> runExceptT (withStoreCtx' (Just "startChatController, getUsers") getUsers)
restoreCalls
@@ -323,15 +324,15 @@ startChatController subConns enableExpireCIs startXFTPWorkers = do
start s users = do
a1 <- async agentSubscriber
a2 <-
if subConns
if mainApp
then Just <$> async (subscribeUsers False users)
else pure Nothing
atomically . writeTVar s $ Just (a1, a2)
when startXFTPWorkers $ do
when mainApp $ do
startXFTP
void $ forkIO $ startFilesToReceive users
startCleanupManager
when enableExpireCIs $ startExpireCIs users
startCleanupManager
startExpireCIs users
pure a1
startXFTP = do
tmp <- readTVarIO =<< asks tempDirectory
@@ -543,16 +544,17 @@ processChatCommand' vr = \case
checkDeleteChatUser user'
withChatLock "deleteUser" . procCmd $ deleteChatUser user' delSMPQueues
DeleteUser uName delSMPQueues viewPwd_ -> withUserName uName $ \userId -> APIDeleteUser userId delSMPQueues viewPwd_
StartChat subConns enableExpireCIs startXFTPWorkers -> withUser' $ \_ ->
StartChat mainApp -> withUser' $ \_ ->
asks agentAsync >>= readTVarIO >>= \case
Just _ -> pure CRChatRunning
_ -> checkStoreNotChanged $ startChatController subConns enableExpireCIs startXFTPWorkers $> CRChatStarted
_ -> checkStoreNotChanged $ startChatController mainApp $> CRChatStarted
APIStopChat -> do
ask >>= stopChatController
pure CRChatStopped
APIActivateChat restoreChat -> withUser $ \_ -> do
when restoreChat restoreCalls
withAgent foregroundAgent
chatWriteVar chatActivated True
when restoreChat $ do
users <- withStoreCtx' (Just "APIActivateChat, getUsers") getUsers
void . forkIO $ subscribeUsers True users
@@ -560,6 +562,7 @@ processChatCommand' vr = \case
setAllExpireCIFlags True
ok_
APISuspendChat t -> do
chatWriteVar chatActivated False
setAllExpireCIFlags False
stopRemoteCtrl
withAgent (`suspendAgent` t)
@@ -2480,6 +2483,7 @@ startExpireCIThread user@User {userId} = do
flip catchChatError (toView . CRChatError (Just user)) $ do
expireFlags <- asks expireCIFlags
atomically $ TM.lookup userId expireFlags >>= \b -> unless (b == Just True) retry
waitChatStartedAndActivated
ttl <- withStoreCtx' (Just "startExpireCIThread, getChatItemTTL") (`getChatItemTTL` user)
forM_ ttl $ \t -> expireChatItems user t False
liftIO $ threadDelay' interval
@@ -2973,7 +2977,7 @@ cleanupManager = do
stepDelay <- asks (cleanupManagerStepDelay . config)
forever $ do
flip catchChatError (toView . CRChatError Nothing) $ do
waitChatStarted
waitChatStartedAndActivated
users <- withStoreCtx' (Just "cleanupManager, getUsers 1") getUsers
let (us, us') = partition activeUser users
forM_ us $ cleanupUser interval stepDelay
@@ -2983,7 +2987,7 @@ cleanupManager = do
liftIO $ threadDelay' $ diffToMicroseconds interval
where
runWithoutInitialDelay cleanupInterval = flip catchChatError (toView . CRChatError Nothing) $ do
waitChatStarted
waitChatStartedAndActivated
users <- withStoreCtx' (Just "cleanupManager, getUsers 2") getUsers
let (us, us') = partition activeUser users
forM_ us $ \u -> cleanupTimedItems cleanupInterval u `catchChatError` (toView . CRChatError (Just u))
@@ -3038,7 +3042,7 @@ deleteTimedItem :: ChatMonad m => User -> (ChatRef, ChatItemId) -> UTCTime -> m
deleteTimedItem user (ChatRef cType chatId, itemId) deleteAt = do
ts <- liftIO getCurrentTime
liftIO $ threadDelay' $ diffToMicroseconds $ diffUTCTime deleteAt ts
waitChatStarted
waitChatStartedAndActivated
vr <- chatVersionRange
case cType of
CTDirect -> do
@@ -3064,8 +3068,10 @@ expireChatItems user@User {userId} ttl sync = do
let expirationDate = addUTCTime (-1 * fromIntegral ttl) currentTs
-- this is to keep group messages created during last 12 hours even if they're expired according to item_ts
createdAtCutoff = addUTCTime (-43200 :: NominalDiffTime) currentTs
waitChatStartedAndActivated
contacts <- withStoreCtx' (Just "expireChatItems, getUserContacts") (`getUserContacts` user)
loop contacts $ processContact expirationDate
waitChatStartedAndActivated
groups <- withStoreCtx' (Just "expireChatItems, getUserGroupDetails") (\db -> getUserGroupDetails db vr user Nothing Nothing)
loop groups $ processGroup expirationDate createdAtCutoff
where
@@ -3084,11 +3090,13 @@ expireChatItems user@User {userId} ttl sync = do
when (expire == Just True) $ threadDelay 100000 >> a
processContact :: UTCTime -> Contact -> m ()
processContact expirationDate ct = do
waitChatStartedAndActivated
filesInfo <- withStoreCtx' (Just "processContact, getContactExpiredFileInfo") $ \db -> getContactExpiredFileInfo db user ct expirationDate
deleteFilesAndConns user filesInfo
withStoreCtx' (Just "processContact, deleteContactExpiredCIs") $ \db -> deleteContactExpiredCIs db user ct expirationDate
processGroup :: UTCTime -> UTCTime -> GroupInfo -> m ()
processGroup expirationDate createdAtCutoff gInfo = do
waitChatStartedAndActivated
filesInfo <- withStoreCtx' (Just "processGroup, getGroupExpiredFileInfo") $ \db -> getGroupExpiredFileInfo db user gInfo expirationDate createdAtCutoff
deleteFilesAndConns user filesInfo
withStoreCtx' (Just "processGroup, deleteGroupExpiredCIs") $ \db -> deleteGroupExpiredCIs db user gInfo expirationDate createdAtCutoff
@@ -5648,8 +5656,7 @@ sendGroupMemberMessages user conn@Connection {connId} events groupId = do
processBatch batch `catchChatError` (toView . CRChatError (Just user))
where
processBatch :: MsgBatch -> m ()
processBatch (MsgBatch builder sndMsgs) = do
let batchBody = LB.toStrict $ toLazyByteString builder
processBatch (MsgBatch batchBody sndMsgs) = do
agentMsgId <- withAgent $ \a -> sendMessage a (aConnId conn) MsgFlags {notification = True} batchBody
let sndMsgDelivery = SndMsgDelivery {connId, agentMsgId}
void . withStoreBatch' $ \db -> map (\SndMessage {msgId} -> createSndMsgDelivery db sndMsgDelivery msgId) sndMsgs
@@ -5669,28 +5676,28 @@ directMessage chatMsgEvent = do
chatVRange <- chatVersionRange
let r = encodeChatMessage ChatMessage {chatVRange, msgId = Nothing, chatMsgEvent}
case r of
ECMEncoded encodedBody -> pure . LB.toStrict $ encodedBody
ECMEncoded encodedBody -> pure encodedBody
ECMLarge -> throwChatError $ CEException "large message"
deliverMessage :: ChatMonad m => Connection -> CMEventTag e -> LazyMsgBody -> MessageId -> m Int64
deliverMessage :: ChatMonad m => Connection -> CMEventTag e -> MsgBody -> MessageId -> m Int64
deliverMessage conn cmEventTag msgBody msgId = do
let msgFlags = MsgFlags {notification = hasNotification cmEventTag}
deliverMessage' conn msgFlags msgBody msgId
deliverMessage' :: ChatMonad m => Connection -> MsgFlags -> LazyMsgBody -> MessageId -> m Int64
deliverMessage' :: ChatMonad m => Connection -> MsgFlags -> MsgBody -> MessageId -> m Int64
deliverMessage' conn msgFlags msgBody msgId =
deliverMessages [(conn, msgFlags, msgBody, msgId)] >>= \case
[r] -> liftEither r
rs -> throwChatError $ CEInternalError $ "deliverMessage: expected 1 result, got " <> show (length rs)
deliverMessages :: ChatMonad' m => [(Connection, MsgFlags, LazyMsgBody, MessageId)] -> m [Either ChatError Int64]
deliverMessages :: ChatMonad' m => [(Connection, MsgFlags, MsgBody, MessageId)] -> m [Either ChatError Int64]
deliverMessages msgReqs = do
sent <- zipWith prepareBatch msgReqs <$> withAgent' (`sendMessages` aReqs)
withStoreBatch $ \db -> map (bindRight $ createDelivery db) sent
where
aReqs = map (\(conn, msgFlags, msgBody, _msgId) -> (aConnId conn, msgFlags, LB.toStrict msgBody)) msgReqs
aReqs = map (\(conn, msgFlags, msgBody, _msgId) -> (aConnId conn, msgFlags, msgBody)) msgReqs
prepareBatch req = bimap (`ChatErrorAgent` Nothing) (req,)
createDelivery :: DB.Connection -> ((Connection, MsgFlags, LazyMsgBody, MessageId), AgentMsgId) -> IO (Either ChatError Int64)
createDelivery :: DB.Connection -> ((Connection, MsgFlags, MsgBody, MessageId), AgentMsgId) -> IO (Either ChatError Int64)
createDelivery db ((Connection {connId}, _, _, msgId), agentMsgId) =
Right <$> createSndMsgDelivery db (SndMsgDelivery {connId, agentMsgId}) msgId
@@ -6114,10 +6121,14 @@ checkSameUser userId User {userId = activeUserId} = when (userId /= activeUserId
chatStarted :: ChatMonad m => m Bool
chatStarted = fmap isJust . readTVarIO =<< asks agentAsync
waitChatStarted :: ChatMonad m => m ()
waitChatStarted = do
waitChatStartedAndActivated :: ChatMonad m => m ()
waitChatStartedAndActivated = do
agentStarted <- asks agentAsync
atomically $ readTVar agentStarted >>= \a -> unless (isJust a) retry
chatActivated <- asks chatActivated
atomically $ do
started <- readTVar agentStarted
activated <- readTVar chatActivated
unless (isJust started && activated) retry
chatVersionRange :: ChatMonad' m => m VersionRange
chatVersionRange = do
@@ -6154,8 +6165,8 @@ chatCommandP =
"/_delete user " *> (APIDeleteUser <$> A.decimal <* " del_smp=" <*> onOffP <*> optional (A.space *> jsonP)),
"/delete user " *> (DeleteUser <$> displayName <*> pure True <*> optional (A.space *> pwdP)),
("/user" <|> "/u") $> ShowActiveUser,
"/_start subscribe=" *> (StartChat <$> onOffP <* " expire=" <*> onOffP <* " xftp=" <*> onOffP),
"/_start" $> StartChat True True True,
"/_start main=" *> (StartChat <$> onOffP),
"/_start" $> StartChat True,
"/_stop" $> APIStopChat,
"/_app activate restore=" *> (APIActivateChat <$> onOffP),
"/_app activate" $> APIActivateChat True,
+2 -1
View File
@@ -200,6 +200,7 @@ data ChatController = ChatController
expireCIThreads :: TMap UserId (Maybe (Async ())),
expireCIFlags :: TMap UserId Bool,
cleanupManagerAsync :: TVar (Maybe (Async ())),
chatActivated :: TVar Bool,
timedItemThreads :: TMap (ChatRef, ChatItemId) (TVar (Maybe (Weak ThreadId))),
showLiveItems :: TVar Bool,
encryptLocalFiles :: TVar Bool,
@@ -233,7 +234,7 @@ data ChatCommand
| UnmuteUser
| APIDeleteUser UserId Bool (Maybe UserPwd)
| DeleteUser UserName Bool (Maybe UserPwd)
| StartChat {subscribeConnections :: Bool, enableExpireChatItems :: Bool, startXFTPWorkers :: Bool}
| StartChat {mainApp :: Bool}
| APIStopChat
| APIActivateChat {restoreChat :: Bool}
| APISuspendChat {suspendTimeout :: Int}
+1 -1
View File
@@ -35,7 +35,7 @@ runSimplexChat :: ChatOpts -> User -> ChatController -> (User -> ChatController
runSimplexChat ChatOpts {maintenance} u cc chat
| maintenance = wait =<< async (chat u cc)
| otherwise = do
a1 <- runReaderT (startChatController True True True) cc
a1 <- runReaderT (startChatController True) cc
a2 <- async $ chat u cc
waitEither_ a1 a2
+2 -5
View File
@@ -21,7 +21,6 @@ import qualified Data.Aeson.Encoding as JE
import qualified Data.Aeson.TH as JQ
import qualified Data.Attoparsec.ByteString.Char8 as A
import qualified Data.ByteString.Base64 as B64
import qualified Data.ByteString.Lazy as L
import qualified Data.ByteString.Lazy.Char8 as LB
import Data.Char (isSpace)
import Data.Int (Int64)
@@ -763,12 +762,10 @@ checkChatType x = case testEquality (chatTypeI @c) (chatTypeI @c') of
Just Refl -> Right x
Nothing -> Left "bad chat type"
type LazyMsgBody = L.ByteString
data SndMessage = SndMessage
{ msgId :: MessageId,
sharedMsgId :: SharedMsgId,
msgBody :: LazyMsgBody
msgBody :: MsgBody
}
deriving (Show)
@@ -790,7 +787,7 @@ data RcvMessage = RcvMessage
data PendingGroupMessage = PendingGroupMessage
{ msgId :: MessageId,
cmEventTag :: ACMEventTag,
msgBody :: LazyMsgBody,
msgBody :: MsgBody,
introId_ :: Maybe Int64
}
+24 -28
View File
@@ -1,40 +1,36 @@
{-# LANGUAGE DuplicateRecordFields #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE NamedFieldPuns #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE ScopedTypeVariables #-}
module Simplex.Chat.Messages.Batch
( MsgBatch (..),
batchMessages,
)
where
module Simplex.Chat.Messages.Batch (
MsgBatch (..),
batchMessages,
) where
import Data.ByteString.Builder (Builder, charUtf8, lazyByteString)
import qualified Data.ByteString.Lazy as LB
import Data.Int (Int64)
import Data.ByteString.Char8 (ByteString)
import qualified Data.ByteString.Char8 as B
import Simplex.Chat.Controller (ChatError (..), ChatErrorType (..))
import Simplex.Chat.Messages
data MsgBatch = MsgBatch Builder [SndMessage]
data MsgBatch = MsgBatch ByteString [SndMessage]
-- | Batches [SndMessage] into batches of ByteString builders in form of JSON arrays.
-- | Batches [SndMessage] into batches of ByteStrings in form of JSON arrays.
-- Does not check if the resulting batch is a valid JSON.
-- If a single element is passed, it is returned as is (a JSON string).
-- If an element exceeds maxLen, it is returned as ChatError.
batchMessages :: Int64 -> [SndMessage] -> [Either ChatError MsgBatch]
batchMessages maxLen msgs =
let (batches, batch, _, n) = foldr addToBatch ([], [], 0, 0) msgs
in if n == 0 then batches else msgBatch batch : batches
batchMessages :: Int -> [SndMessage] -> [Either ChatError MsgBatch]
batchMessages maxLen = addBatch . foldr addToBatch ([], [], 0, 0)
where
msgBatch batch = Right (MsgBatch (encodeMessages batch) batch)
addToBatch :: SndMessage -> ([Either ChatError MsgBatch], [SndMessage], Int64, Int) -> ([Either ChatError MsgBatch], [SndMessage], Int64, Int)
addToBatch msg@SndMessage {msgBody} (batches, batch, len, n)
addToBatch :: SndMessage -> ([Either ChatError MsgBatch], [SndMessage], Int, Int) -> ([Either ChatError MsgBatch], [SndMessage], Int, Int)
addToBatch msg@SndMessage {msgBody} acc@(batches, batch, len, n)
| batchLen <= maxLen = (batches, msg : batch, len', n + 1)
| msgLen <= maxLen = (batches', [msg], msgLen, 1)
| otherwise = (errLarge msg : (if n == 0 then batches else batches'), [], 0, 0)
| msgLen <= maxLen = (addBatch acc, [msg], msgLen, 1)
| otherwise = (errLarge msg : addBatch acc, [], 0, 0)
where
msgLen = LB.length msgBody
batches' = msgBatch batch : batches
msgLen = B.length msgBody
len'
| n == 0 = msgLen
| otherwise = msgLen + len + 1 -- 1 accounts for comma
@@ -42,11 +38,11 @@ batchMessages maxLen msgs =
| n == 0 = len'
| otherwise = len' + 2 -- 2 accounts for opening and closing brackets
errLarge SndMessage {msgId} = Left $ ChatError $ CEInternalError ("large message " <> show msgId)
encodeMessages :: [SndMessage] -> Builder
encodeMessages = \case
[] -> mempty
[msg] -> encodeMsg msg
(msg : msgs) -> charUtf8 '[' <> encodeMsg msg <> mconcat [charUtf8 ',' <> encodeMsg msg' | msg' <- msgs] <> charUtf8 ']'
where
encodeMsg SndMessage {msgBody} = lazyByteString msgBody
addBatch :: ([Either ChatError MsgBatch], [SndMessage], Int, Int) -> [Either ChatError MsgBatch]
addBatch (batches, batch, _, n) = if n == 0 then batches else msgBatch batch : batches
encodeMessages :: [SndMessage] -> ByteString
encodeMessages = \case
[] -> mempty
[msg] -> body msg
msgs -> B.concat ["[", B.intercalate "," (map body msgs), "]"]
body SndMessage {msgBody} = msgBody
+5 -7
View File
@@ -29,9 +29,7 @@ import qualified Data.Attoparsec.ByteString.Char8 as A
import Data.ByteString.Char8 (ByteString)
import qualified Data.ByteString.Char8 as B
import Data.ByteString.Internal (c2w, w2c)
import qualified Data.ByteString.Lazy as L
import qualified Data.ByteString.Lazy.Char8 as LB
import Data.Int (Int64)
import Data.Maybe (fromMaybe)
import Data.String
import Data.Text (Text)
@@ -491,20 +489,20 @@ $(JQ.deriveJSON defaultJSON ''QuotedMsg)
-- this limit reserves space for metadata in forwarded messages
-- 15780 (limit used for fileChunkSize) - 161 (x.grp.msg.forward overhead) = 15619, round to 15610
maxChatMsgSize :: Int64
maxChatMsgSize :: Int
maxChatMsgSize = 15610
data EncodedChatMessage = ECMEncoded L.ByteString | ECMLarge
data EncodedChatMessage = ECMEncoded ByteString | ECMLarge
encodeChatMessage :: MsgEncodingI e => ChatMessage e -> EncodedChatMessage
encodeChatMessage msg = do
case chatToAppMessage msg of
AMJson m -> do
let body = J.encode m
if LB.length body > maxChatMsgSize
let body = LB.toStrict $ J.encode m
if B.length body > maxChatMsgSize
then ECMLarge
else ECMEncoded body
AMBinary m -> ECMEncoded . LB.fromStrict $ strEncode m
AMBinary m -> ECMEncoded $ strEncode m
parseChatMessages :: ByteString -> [Either String AChatMessage]
parseChatMessages "" = [Left "empty string"]
+1
View File
@@ -413,6 +413,7 @@ xftpServerConfig =
logStatsStartTime = 0,
serverStatsLogFile = "tests/tmp/xftp-server-stats.daily.log",
serverStatsBackupFile = Nothing,
controlPort = Nothing,
transportConfig = defaultTransportServerConfig
}
+1 -1
View File
@@ -1149,7 +1149,7 @@ testSubscribeAppNSE tmp =
alice ##> "/_app suspend 1"
alice <## "ok"
alice <## "chat suspended"
nseAlice ##> "/_start subscribe=off expire=off xftp=off"
nseAlice ##> "/_start main=off"
nseAlice <## "chat started"
nseAlice ##> "/ad"
cLink <- getContactLink nseAlice True
+8 -8
View File
@@ -7,8 +7,8 @@
module MessageBatching (batchingTests) where
import Crypto.Number.Serialize (os2ip)
import Data.ByteString.Builder (toLazyByteString)
import qualified Data.ByteString.Lazy as LB
import Data.ByteString (ByteString)
import qualified Data.ByteString as B
import Data.Either (partitionEithers)
import Data.Int (Int64)
import Data.String (IsString (..))
@@ -26,7 +26,7 @@ batchingTests = describe "message batching tests" $ do
it "image x.msg.new and x.msg.file.descr should fit into single batch" testImageFitsSingleBatch
instance IsString SndMessage where
fromString s = SndMessage {msgId, sharedMsgId = SharedMsgId "", msgBody = LB.fromStrict s'}
fromString s = SndMessage {msgId, sharedMsgId = SharedMsgId "", msgBody = s'}
where
s' = encodeUtf8 $ T.pack s
msgId = fromInteger $ os2ip s'
@@ -94,14 +94,14 @@ testImageFitsSingleBatch = do
-- 261_120 bytes (MAX_IMAGE_SIZE in UI), rounded up, example was 743
let descrRoundedSize = 800
let xMsgNewStr = LB.replicate xMsgNewRoundedSize 1
descrStr = LB.replicate descrRoundedSize 2
let xMsgNewStr = B.replicate xMsgNewRoundedSize 1
descrStr = B.replicate descrRoundedSize 2
msg s = SndMessage {msgId = 0, sharedMsgId = SharedMsgId "", msgBody = s}
batched = "[" <> xMsgNewStr <> "," <> descrStr <> "]"
runBatcherTest' maxChatMsgSize [msg xMsgNewStr, msg descrStr] [] [batched]
runBatcherTest :: Int64 -> [SndMessage] -> [ChatError] -> [LB.ByteString] -> Spec
runBatcherTest :: Int -> [SndMessage] -> [ChatError] -> [ByteString] -> Spec
runBatcherTest maxLen msgs expectedErrors expectedBatches =
it
( (show (map (\SndMessage {msgBody} -> msgBody) msgs) <> ", limit " <> show maxLen <> ": should return ")
@@ -110,10 +110,10 @@ runBatcherTest maxLen msgs expectedErrors expectedBatches =
)
(runBatcherTest' maxLen msgs expectedErrors expectedBatches)
runBatcherTest' :: Int64 -> [SndMessage] -> [ChatError] -> [LB.ByteString] -> IO ()
runBatcherTest' :: Int -> [SndMessage] -> [ChatError] -> [ByteString] -> IO ()
runBatcherTest' maxLen msgs expectedErrors expectedBatches = do
let (errors, batches) = partitionEithers $ batchMessages maxLen msgs
batchedStrs = map (\(MsgBatch builder _) -> toLazyByteString builder) batches
batchedStrs = map (\(MsgBatch batchBody _) -> batchBody) batches
testErrors errors `shouldBe` testErrors expectedErrors
batchedStrs `shouldBe` expectedBatches
where
+1 -2
View File
@@ -7,7 +7,6 @@ module ProtocolTests where
import qualified Data.Aeson as J
import Data.ByteString.Char8 (ByteString)
import qualified Data.ByteString.Lazy.Char8 as LB
import Data.Time.Clock.System (SystemTime (..), systemToUTCTime)
import Simplex.Chat.Protocol
import Simplex.Chat.Types
@@ -74,7 +73,7 @@ s ##== msg = do
let r = encodeChatMessage msg
case r of
ECMEncoded encodedBody ->
J.eitherDecodeStrict' (LB.toStrict encodedBody)
J.eitherDecodeStrict' encodedBody
`shouldBe` (J.eitherDecodeStrict' s :: Either String J.Value)
ECMLarge -> expectationFailure $ "large message"