Skip to content

Commit 24ded9e

Browse files
committed
Merge branch 'master' into stable
2 parents 7000431 + f5e666a commit 24ded9e

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

62 files changed

+1443
-1001
lines changed

CHANGELOG.md

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,36 @@
1+
# 6.0.4
2+
3+
SMP server:
4+
- better performance/memory: fewer map updates on re-subscriptions (#1297), split and reduce STM transactions (#1294)
5+
- send DELD when subscribed queue is deleted (#1312)
6+
- add created/updated/used date to queues to manage expiration (#1306)
7+
8+
XFTP server: truncate file creation time to 1 hour (#1310)
9+
10+
Servers:
11+
- bind control port only to 127.0.0.1 for better security in case of firewall misconfiguration (#1280)
12+
- reduce memory used for period stats (#1298)
13+
14+
Agent: process last notification from list (#1307)
15+
- report receive file error with redirected file ID, when redirect is present (#1304)
16+
- special error when deleted user record is not in database (#1303)
17+
- fix race when sending a message to the deleted connection (#1296)
18+
- support for multiple messages in a single notification
19+
20+
Ntf server:
21+
- only use SOCKS proxy for servers without public address (#1314)
22+
23+
# 6.0.3
24+
25+
Agent:
26+
- fix possible stuck queue rotation (#1290).
27+
28+
SMP server:
29+
- batch END responses when subscribed client switches to reduce server and client traffic.
30+
- reduce STM transactions for better performance.
31+
- add stats for END events and for SUB/DEL event batches.
32+
- remove "expensive" stats to save memory.
33+
134
# 6.0.2
235

336
SMP agent:

apps/ntf-server/Main.hs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ logCfg = LogConfig {lc_file = Nothing, lc_stderr = True}
1515

1616
main :: IO ()
1717
main = do
18-
setLogLevel LogDebug -- change to LogError in production
18+
setLogLevel LogInfo
1919
cfgPath <- getEnvPath "NTF_SERVER_CFG_PATH" defaultCfgPath
2020
logPath <- getEnvPath "NTF_SERVER_LOG_PATH" defaultLogPath
2121
withGlobalLogging logCfg $ ntfServerCLI cfgPath logPath

package.yaml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
name: simplexmq
2-
version: 6.0.2.0
2+
version: 6.0.4.0
33
synopsis: SimpleXMQ message broker
44
description: |
55
This package includes <./docs/Simplex-Messaging-Server.html server>,
@@ -47,6 +47,7 @@ dependencies:
4747
- direct-sqlcipher == 2.3.*
4848
- directory == 1.3.*
4949
- filepath == 1.4.*
50+
- hashable == 1.4.*
5051
- hourglass == 0.2.*
5152
- http-types == 0.12.*
5253
- http2 >= 4.2.2 && < 4.3
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# iOS notifications stability
2+
3+
## Problem
4+
5+
iOS notifications may fail to deliver for several reasons, but there are two important reasons that we could address:
6+
- when notification server is not subscribed to SMP server(s), the notifications can be dropped - it can happen because either notification server restarts or becuase SMP server restarted and some messages are received before notification server resubscribed. We lose approximately 3% of notifications because of this reason.
7+
- when user device is offline or has low power condition, Apple does not deliver notification, but puts them to storage. If while the notification is in storage a new one arrives it would overwrite the previous notification. If it was the message to the same message queue, the client will download messages anyway, up to a limit, but if the message was to another queue, it will not be delivered until the app is opened. Apple delivers about 88% of notifications that should be delivered (not accounting for uninstalled apps), the rest is replaced with the newer notifications.
8+
9+
## Solution
10+
11+
The first problem can be solved by preserving notifications for a limited time (say 1 hour) in case there is no subscription to notification from notification server. At the very least, they can be preserved in SMP server memory but can also be stored to a file on restart, similar to messages, and be delivered when notification server resubscribes. It is sufficient to store one notification per messaging queue.
12+
13+
The second problem is both more damaging and more complex to solve. The solution could be to always deliver several last notifications to different queues in one packet (Apple allows up to ~4-5kb notification size, and we are sending packets of fixed size 512 bytes, so we could fit up to 8-10 of them in each notification).
14+
15+
Every time a client receives such batch of notifications if can:
16+
- check if that notification was already received in the previous batch.
17+
- if it was received, it would be ignored, otherwise it would be processed.
18+
- process them one by one, started from the most recent one while the time allows.
File renamed without changes.
File renamed without changes.

simplexmq.cabal

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ cabal-version: 1.12
55
-- see: https://github.com/sol/hpack
66

77
name: simplexmq
8-
version: 6.0.2.0
8+
version: 6.0.4.0
99
synopsis: SimpleXMQ message broker
1010
description: This package includes <./docs/Simplex-Messaging-Server.html server>,
1111
<./docs/Simplex-Messaging-Client.html client> and
@@ -236,6 +236,7 @@ library
236236
, direct-sqlcipher ==2.3.*
237237
, directory ==1.3.*
238238
, filepath ==1.4.*
239+
, hashable ==1.4.*
239240
, hourglass ==0.2.*
240241
, http-types ==0.12.*
241242
, http2 >=4.2.2 && <4.3
@@ -310,6 +311,7 @@ executable ntf-server
310311
, direct-sqlcipher ==2.3.*
311312
, directory ==1.3.*
312313
, filepath ==1.4.*
314+
, hashable ==1.4.*
313315
, hourglass ==0.2.*
314316
, http-types ==0.12.*
315317
, http2 >=4.2.2 && <4.3
@@ -389,6 +391,7 @@ executable smp-server
389391
, directory ==1.3.*
390392
, file-embed
391393
, filepath ==1.4.*
394+
, hashable ==1.4.*
392395
, hourglass ==0.2.*
393396
, http-types ==0.12.*
394397
, http2 >=4.2.2 && <4.3
@@ -467,6 +470,7 @@ executable xftp
467470
, direct-sqlcipher ==2.3.*
468471
, directory ==1.3.*
469472
, filepath ==1.4.*
473+
, hashable ==1.4.*
470474
, hourglass ==0.2.*
471475
, http-types ==0.12.*
472476
, http2 >=4.2.2 && <4.3
@@ -542,6 +546,7 @@ executable xftp-server
542546
, direct-sqlcipher ==2.3.*
543547
, directory ==1.3.*
544548
, filepath ==1.4.*
549+
, hashable ==1.4.*
545550
, hourglass ==0.2.*
546551
, http-types ==0.12.*
547552
, http2 >=4.2.2 && <4.3
@@ -653,6 +658,7 @@ test-suite simplexmq-test
653658
, directory ==1.3.*
654659
, filepath ==1.4.*
655660
, generic-random ==1.5.*
661+
, hashable ==1.4.*
656662
, hourglass ==0.2.*
657663
, hspec ==2.11.*
658664
, hspec-core ==2.11.*

src/Simplex/FileTransfer/Agent.hs

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ import Data.List (foldl', partition, sortOn)
4545
import qualified Data.List.NonEmpty as L
4646
import Data.Map.Strict (Map)
4747
import qualified Data.Map.Strict as M
48-
import Data.Maybe (mapMaybe)
48+
import Data.Maybe (fromMaybe, mapMaybe)
4949
import qualified Data.Set as S
5050
import Data.Text (Text)
5151
import Data.Time.Clock (getCurrentTime)
@@ -74,7 +74,7 @@ import qualified Simplex.Messaging.Crypto.File as CF
7474
import qualified Simplex.Messaging.Crypto.Lazy as LC
7575
import Simplex.Messaging.Encoding
7676
import Simplex.Messaging.Encoding.String (strDecode, strEncode)
77-
import Simplex.Messaging.Protocol (EntityId, ProtocolServer, ProtocolType (..), XFTPServer)
77+
import Simplex.Messaging.Protocol (ProtocolServer, ProtocolType (..), XFTPServer)
7878
import qualified Simplex.Messaging.TMap as TM
7979
import Simplex.Messaging.Util (catchAll_, liftError, tshow, unlessM, whenM)
8080
import System.FilePath (takeFileName, (</>))
@@ -190,8 +190,9 @@ runXFTPRcvWorker c srv Worker {doWork} = do
190190
runXFTPOperation :: AgentConfig -> AM ()
191191
runXFTPOperation AgentConfig {rcvFilesTTL, reconnectInterval = ri, xftpConsecutiveRetries} =
192192
withWork c doWork (\db -> getNextRcvChunkToDownload db srv rcvFilesTTL) $ \case
193-
(RcvFileChunk {rcvFileId, rcvFileEntityId, fileTmpPath, replicas = []}, _) -> rcvWorkerInternalError c rcvFileId rcvFileEntityId (Just fileTmpPath) (INTERNAL "chunk has no replicas")
194-
(fc@RcvFileChunk {userId, rcvFileId, rcvFileEntityId, digest, fileTmpPath, replicas = replica@RcvFileChunkReplica {rcvChunkReplicaId, server, delay} : _}, approvedRelays) -> do
193+
(RcvFileChunk {rcvFileId, rcvFileEntityId, fileTmpPath, replicas = []}, _, redirectEntityId_) ->
194+
rcvWorkerInternalError c rcvFileId rcvFileEntityId redirectEntityId_ (Just fileTmpPath) (INTERNAL "chunk has no replicas")
195+
(fc@RcvFileChunk {userId, rcvFileId, rcvFileEntityId, digest, fileTmpPath, replicas = replica@RcvFileChunkReplica {rcvChunkReplicaId, server, delay} : _}, approvedRelays, redirectEntityId_) -> do
195196
let ri' = maybe ri (\d -> ri {initialInterval = d, increaseAfter = 0}) delay
196197
withRetryIntervalLimit xftpConsecutiveRetries ri' $ \delay' loop -> do
197198
liftIO $ waitWhileSuspended c
@@ -202,7 +203,7 @@ runXFTPRcvWorker c srv Worker {doWork} = do
202203
where
203204
retryLoop loop e replicaDelay = do
204205
flip catchAgentError (\_ -> pure ()) $ do
205-
when (serverHostError e) $ notify c rcvFileEntityId $ RFWARN e
206+
when (serverHostError e) $ notify c (fromMaybe rcvFileEntityId redirectEntityId_) (RFWARN e)
206207
liftIO $ closeXFTPServerClient c userId server digest
207208
withStore' c $ \db -> updateRcvChunkReplicaDelay db rcvChunkReplicaId replicaDelay
208209
liftIO $ assertAgentForeground c
@@ -211,7 +212,7 @@ runXFTPRcvWorker c srv Worker {doWork} = do
211212
atomically . incXFTPServerStat c userId srv $ case e of
212213
XFTP _ XFTP.AUTH -> downloadAuthErrs
213214
_ -> downloadErrs
214-
rcvWorkerInternalError c rcvFileId rcvFileEntityId (Just fileTmpPath) e
215+
rcvWorkerInternalError c rcvFileId rcvFileEntityId redirectEntityId_ (Just fileTmpPath) e
215216
downloadFileChunk :: RcvFileChunk -> RcvFileChunkReplica -> Bool -> AM ()
216217
downloadFileChunk RcvFileChunk {userId, rcvFileId, rcvFileEntityId, rcvChunkId, chunkNo, chunkSize, digest, fileTmpPath} replica approvedRelays = do
217218
unlessM ((approvedRelays ||) <$> ipAddressProtected') $ throwE $ FILE NOT_APPROVED
@@ -262,11 +263,11 @@ retryOnError name loop done e = do
262263
then loop
263264
else done
264265

265-
rcvWorkerInternalError :: AgentClient -> DBRcvFileId -> RcvFileId -> Maybe FilePath -> AgentErrorType -> AM ()
266-
rcvWorkerInternalError c rcvFileId rcvFileEntityId tmpPath err = do
266+
rcvWorkerInternalError :: AgentClient -> DBRcvFileId -> RcvFileId -> Maybe RcvFileId -> Maybe FilePath -> AgentErrorType -> AM ()
267+
rcvWorkerInternalError c rcvFileId rcvFileEntityId redirectEntityId_ tmpPath err = do
267268
lift $ forM_ tmpPath (removePath <=< toFSFilePath)
268269
withStore' c $ \db -> updateRcvFileError db rcvFileId (show err)
269-
notify c rcvFileEntityId $ RFERR err
270+
notify c (fromMaybe rcvFileEntityId redirectEntityId_) (RFERR err)
270271

271272
runXFTPRcvLocalWorker :: AgentClient -> Worker -> AM ()
272273
runXFTPRcvLocalWorker c Worker {doWork} = do
@@ -279,8 +280,8 @@ runXFTPRcvLocalWorker c Worker {doWork} = do
279280
runXFTPOperation :: AgentConfig -> AM ()
280281
runXFTPOperation AgentConfig {rcvFilesTTL} =
281282
withWork c doWork (`getNextRcvFileToDecrypt` rcvFilesTTL) $
282-
\f@RcvFile {rcvFileId, rcvFileEntityId, tmpPath} ->
283-
decryptFile f `catchAgentError` rcvWorkerInternalError c rcvFileId rcvFileEntityId tmpPath
283+
\f@RcvFile {rcvFileId, rcvFileEntityId, tmpPath, redirect} ->
284+
decryptFile f `catchAgentError` rcvWorkerInternalError c rcvFileId rcvFileEntityId (redirectEntityId <$> redirect) tmpPath
284285
decryptFile :: RcvFile -> AM ()
285286
decryptFile RcvFile {rcvFileId, rcvFileEntityId, size, digest, key, nonce, tmpPath, saveFile, status, chunks, redirect} = do
286287
let CryptoFile savePath cfArgs = saveFile
@@ -346,7 +347,7 @@ xftpDeleteRcvFiles' c rcvFileEntityIds = do
346347
batchFiles :: (DB.Connection -> DBRcvFileId -> IO a) -> [RcvFile] -> AM' [Either AgentErrorType a]
347348
batchFiles f rcvFiles = withStoreBatch' c $ \db -> map (\RcvFile {rcvFileId} -> f db rcvFileId) rcvFiles
348349

349-
notify :: forall m e. (MonadIO m, AEntityI e) => AgentClient -> EntityId -> AEvent e -> m ()
350+
notify :: forall m e. (MonadIO m, AEntityI e) => AgentClient -> AEntityId -> AEvent e -> m ()
350351
notify c entId cmd = atomically $ writeTBQueue (subQ c) ("", entId, AEvt (sAEntity @e) cmd)
351352

352353
xftpSendFile' :: AgentClient -> UserId -> CryptoFile -> Int -> AM SndFileId

src/Simplex/FileTransfer/Client.hs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ import Simplex.Messaging.Protocol
5050
ProtocolServer (..),
5151
RecipientId,
5252
SenderId,
53+
pattern NoEntity,
5354
)
5455
import Simplex.Messaging.Transport (ALPN, HandshakeError (..), THandleAuth (..), THandleParams (..), TransportError (..), TransportPeer (..), supportedParameters)
5556
import Simplex.Messaging.Transport.Client (TransportClientConfig, TransportHost, alpn)
@@ -222,7 +223,7 @@ createXFTPChunk ::
222223
Maybe BasicAuth ->
223224
ExceptT XFTPClientError IO (SenderId, NonEmpty RecipientId)
224225
createXFTPChunk c spKey file rcps auth_ =
225-
sendXFTPCommand c spKey "" (FNEW file rcps auth_) Nothing >>= \case
226+
sendXFTPCommand c spKey NoEntity (FNEW file rcps auth_) Nothing >>= \case
226227
(FRSndIds sId rIds, body) -> noFile body (sId, rIds)
227228
(r, _) -> throwE $ unexpectedResponse r
228229

@@ -278,7 +279,7 @@ pingXFTP :: XFTPClient -> ExceptT XFTPClientError IO ()
278279
pingXFTP c@XFTPClient {thParams} = do
279280
t <-
280281
liftEither . first PCETransportError $
281-
xftpEncodeTransmission thParams ("", "", FileCmd SFRecipient PING)
282+
xftpEncodeTransmission thParams ("", NoEntity, FileCmd SFRecipient PING)
282283
(r, _) <- sendXFTPTransmission c t Nothing
283284
case r of
284285
FRPong -> pure ()

0 commit comments

Comments
 (0)