mirror of
https://github.com/simplex-chat/simplex-chat.git
synced 2026-07-18 08:26:15 +00:00
Merge branch 'master' into f/public-groups
This commit is contained in:
@@ -652,12 +652,14 @@ processChatCommand cxt nm = \case
|
||||
_ <- createChatTag db user emoji text
|
||||
CRChatTags user <$> getUserChatTags db user
|
||||
APISetChatTags (ChatRef cType chatId scope) tagIds -> withUser $ \user -> case cType of
|
||||
CTDirect -> withFastStore' $ \db -> do
|
||||
updateDirectChatTags db chatId (maybe [] L.toList tagIds)
|
||||
CRTagsUpdated user <$> getUserChatTags db user <*> getDirectChatTags db chatId
|
||||
CTGroup | isNothing scope -> withFastStore' $ \db -> do
|
||||
updateGroupChatTags db chatId (maybe [] L.toList tagIds)
|
||||
CRTagsUpdated user <$> getUserChatTags db user <*> getGroupChatTags db chatId
|
||||
CTDirect -> withFastStore $ \db -> do
|
||||
Contact {contactId} <- getContact db cxt user chatId
|
||||
liftIO $ updateDirectChatTags db contactId (maybe [] L.toList tagIds)
|
||||
CRTagsUpdated user <$> liftIO (getUserChatTags db user) <*> liftIO (getDirectChatTags db contactId)
|
||||
CTGroup | isNothing scope -> withFastStore $ \db -> do
|
||||
GroupInfo {groupId} <- getGroupInfo db cxt user chatId
|
||||
liftIO $ updateGroupChatTags db groupId (maybe [] L.toList tagIds)
|
||||
CRTagsUpdated user <$> liftIO (getUserChatTags db user) <*> liftIO (getGroupChatTags db groupId)
|
||||
_ -> throwCmdError "not supported"
|
||||
APIDeleteChatTag tagId -> withUser $ \user -> do
|
||||
withFastStore' $ \db -> deleteChatTag db user tagId
|
||||
@@ -1694,8 +1696,11 @@ processChatCommand cxt nm = \case
|
||||
CRServerOperatorConditions <$> getServerOperators db
|
||||
APISetChatTTL userId (ChatRef cType chatId scope) newTTL_ ->
|
||||
withUserId userId $ \user -> checkStoreNotChanged $ withChatLock "setChatTTL" $ do
|
||||
(oldTTL_, globalTTL, ttlCount) <- withStore' $ \db ->
|
||||
(,,) <$> getSetChatTTL db <*> getChatItemTTL db user <*> getChatTTLCount db user
|
||||
(oldTTL_, globalTTL, ttlCount) <- withStore $ \db -> do
|
||||
oldTTL <- getSetChatTTL db user
|
||||
globalTTL <- liftIO $ getChatItemTTL db user
|
||||
ttlCount <- liftIO $ getChatTTLCount db user
|
||||
pure (oldTTL, globalTTL, ttlCount)
|
||||
let newTTL = fromMaybe globalTTL newTTL_
|
||||
oldTTL = fromMaybe globalTTL oldTTL_
|
||||
when (newTTL > 0 && (newTTL < oldTTL || oldTTL == 0)) $ do
|
||||
@@ -1704,9 +1709,13 @@ processChatCommand cxt nm = \case
|
||||
lift $ setChatItemsExpiration user globalTTL ttlCount
|
||||
ok user
|
||||
where
|
||||
getSetChatTTL db = case cType of
|
||||
CTDirect -> getDirectChatTTL db chatId <* setDirectChatTTL db chatId newTTL_
|
||||
CTGroup | isNothing scope -> getGroupChatTTL db chatId <* setGroupChatTTL db chatId newTTL_
|
||||
getSetChatTTL db currentUser = case cType of
|
||||
CTDirect -> do
|
||||
Contact {contactId} <- getContact db cxt currentUser chatId
|
||||
liftIO $ getDirectChatTTL db contactId <* setDirectChatTTL db contactId newTTL_
|
||||
CTGroup | isNothing scope -> do
|
||||
GroupInfo {groupId} <- getGroupInfo db cxt currentUser chatId
|
||||
liftIO $ getGroupChatTTL db groupId <* setGroupChatTTL db groupId newTTL_
|
||||
_ -> pure Nothing
|
||||
expireChat user globalTTL = do
|
||||
currentTs <- liftIO getCurrentTime
|
||||
|
||||
@@ -3919,13 +3919,13 @@ runDeliveryTaskWorker a deliveryKey Worker {doWork} = do
|
||||
withStore' $ \db -> setDeliveryTaskErrStatus db (deliveryTaskId task) "relay inactive"
|
||||
| otherwise ->
|
||||
withWorkItems a doWork (withStore' $ \db -> getNextDeliveryTasks db gInfo task) $ \nextTasks -> do
|
||||
let (body, acceptedTasks, largeTasks) = batchDeliveryTasks1 (vr cxt) maxEncodedMsgLength nextTasks
|
||||
let (body_, acceptedTasks, largeTasks) = batchDeliveryTasks1 (vr cxt) maxEncodedMsgLength nextTasks
|
||||
senderGMIds = S.toList . S.fromList $ map (\MessageDeliveryTask {senderGMId} -> senderGMId) acceptedTasks
|
||||
withStore' $ \db -> do
|
||||
createMsgDeliveryJob db gInfo jobScope senderGMIds body
|
||||
forM_ body_ $ \body -> createMsgDeliveryJob db gInfo jobScope senderGMIds body
|
||||
forM_ acceptedTasks $ \t -> updateDeliveryTaskStatus db (deliveryTaskId t) DTSProcessed
|
||||
forM_ largeTasks $ \t -> setDeliveryTaskErrStatus db (deliveryTaskId t) "large"
|
||||
lift . void $ getDeliveryJobWorker True deliveryKey
|
||||
when (isJust body_) . lift . void $ getDeliveryJobWorker True deliveryKey
|
||||
-- DJRelayRemoved is allowed when RSInactive - it forwards XGrpMemDel about relay's own deletion
|
||||
DJRelayRemoved
|
||||
| workerScope /= DWSGroup ->
|
||||
|
||||
@@ -24,7 +24,6 @@ import qualified Data.ByteString as BS
|
||||
import qualified Data.ByteString.Char8 as B
|
||||
import Data.Char (ord)
|
||||
import Data.Function (on)
|
||||
import Data.Foldable (foldr')
|
||||
import Data.List (foldl', sortBy)
|
||||
import Data.List.NonEmpty (NonEmpty (..))
|
||||
import qualified Data.List.NonEmpty as L
|
||||
@@ -79,15 +78,15 @@ batchMessages mode maxLen = addBatch . foldr addToBatch ([], [], [], 0, 0)
|
||||
let encoded = encodeBatch mode bodies
|
||||
in Right (MsgBatch encoded msgs) : batches
|
||||
|
||||
-- | Batches delivery tasks into (batch, accepted, large).
|
||||
-- | Batches delivery tasks into (batch if any task was accepted, accepted, large).
|
||||
-- Always uses binary batch format for relay groups.
|
||||
batchDeliveryTasks1 :: VersionRangeChat -> Int -> NonEmpty MessageDeliveryTask -> (ByteString, [MessageDeliveryTask], [MessageDeliveryTask])
|
||||
batchDeliveryTasks1 :: VersionRangeChat -> Int -> NonEmpty MessageDeliveryTask -> (Maybe ByteString, [MessageDeliveryTask], [MessageDeliveryTask])
|
||||
batchDeliveryTasks1 _vr maxLen = toResult . foldl' addToBatch ([], [], [], 0, 0) . L.toList
|
||||
where
|
||||
addToBatch :: ([ByteString], [MessageDeliveryTask], [MessageDeliveryTask], Int, Int) -> MessageDeliveryTask -> ([ByteString], [MessageDeliveryTask], [MessageDeliveryTask], Int, Int)
|
||||
addToBatch (msgBodies, accepted, large, len, n) task
|
||||
-- too large: skip, record in large
|
||||
| msgLen > maxLen = (msgBodies, accepted, task : large, len, n)
|
||||
-- element can't fit even a singleton batch (4-byte binary-batch framing)
|
||||
| msgLen + 4 > maxLen = (msgBodies, accepted, task : large, len, n)
|
||||
-- fits: include in batch
|
||||
-- batch overhead: '=' + count (2) + 2-byte length prefix per element
|
||||
| len' + (n + 1) * 2 + 2 <= maxLen = (msgBody : msgBodies, task : accepted, large, len', n + 1)
|
||||
@@ -98,10 +97,11 @@ batchDeliveryTasks1 _vr maxLen = toResult . foldl' addToBatch ([], [], [], 0, 0)
|
||||
msgBody = encodeFwdElement GrpMsgForward {fwdSender, fwdBrokerTs} verifiedMsg
|
||||
msgLen = B.length msgBody
|
||||
len' = len + msgLen
|
||||
toResult :: ([ByteString], [MessageDeliveryTask], [MessageDeliveryTask], Int, Int) -> (ByteString, [MessageDeliveryTask], [MessageDeliveryTask])
|
||||
toResult :: ([ByteString], [MessageDeliveryTask], [MessageDeliveryTask], Int, Int) -> (Maybe ByteString, [MessageDeliveryTask], [MessageDeliveryTask])
|
||||
toResult (msgBodies, accepted, large, _, _) =
|
||||
let encoded = encodeBinaryBatch (reverse msgBodies)
|
||||
in (encoded, reverse accepted, reverse large)
|
||||
body = if null accepted then Nothing else Just encoded
|
||||
in (body, reverse accepted, reverse large)
|
||||
|
||||
-- | Encode a batch element for relay groups: ><GrpMsgForward>[/<sigs>]<body>.
|
||||
encodeFwdElement :: GrpMsgForward -> VerifiedMsg 'Json -> ByteString
|
||||
|
||||
@@ -83,6 +83,7 @@ import Data.Functor ((<&>))
|
||||
import Data.Int (Int64)
|
||||
import Data.Maybe (fromMaybe, isJust, listToMaybe)
|
||||
import Data.Text (Text)
|
||||
import qualified Data.Text as T
|
||||
import Data.Time (addUTCTime)
|
||||
import Data.Time.Clock (UTCTime (..), getCurrentTime, nominalDay)
|
||||
import Data.Type.Equality
|
||||
@@ -462,7 +463,7 @@ createRcvStandaloneFileTransfer db userId (CryptoFile filePath cfArgs_) fileSize
|
||||
|
||||
createRcvFD_ :: DB.Connection -> UserId -> UTCTime -> FileDescr -> ExceptT StoreError IO RcvFileDescr
|
||||
createRcvFD_ db userId currentTs FileDescr {fileDescrText, fileDescrPartNo, fileDescrComplete} = do
|
||||
when (fileDescrPartNo /= 0) $ throwError SERcvFileInvalidDescrPart
|
||||
when (fileDescrPartNo /= 0 || not (rcvFileDescrWithinLimits fileDescrPartNo fileDescrText)) $ throwError SERcvFileInvalidDescrPart
|
||||
fileDescrId <- liftIO $ do
|
||||
DB.execute
|
||||
db
|
||||
@@ -490,8 +491,8 @@ appendRcvFD db userId fileId fd@FileDescr {fileDescrText, fileDescrPartNo, fileD
|
||||
fileDescrPartNo = rfdPNo,
|
||||
fileDescrComplete = rfdComplete
|
||||
} -> do
|
||||
when (fileDescrPartNo /= rfdPNo + 1 || rfdComplete) $ throwError SERcvFileInvalidDescrPart
|
||||
let fileDescrText' = rfdText <> fileDescrText
|
||||
when (fileDescrPartNo /= rfdPNo + 1 || rfdComplete || not (rcvFileDescrWithinLimits fileDescrPartNo fileDescrText')) $ throwError SERcvFileInvalidDescrPart
|
||||
liftIO $
|
||||
DB.execute
|
||||
db
|
||||
@@ -503,6 +504,23 @@ appendRcvFD db userId fileId fd@FileDescr {fileDescrText, fileDescrPartNo, fileD
|
||||
(fileDescrText', fileDescrPartNo, BI fileDescrComplete, fileDescrId)
|
||||
pure RcvFileDescr {fileDescrId, fileDescrText = fileDescrText', fileDescrPartNo, fileDescrComplete}
|
||||
|
||||
-- Upper bounds sized above the largest legitimate received description; derived from simplexmq's
|
||||
-- chunk tiers and redundancy, so a change there must revisit them.
|
||||
-- ~1280 chunks max = maxFileSizeHard (5gb) / largest chunk tier (4mb).
|
||||
-- ~150 chars per chunk in the description YAML = replicaId 24 + Ed25519 key 64 + SHA-256 digest 44 + chunkNo/colons.
|
||||
-- Total ~0.18 MB at 1 replica/chunk (~0.42 MB at 3x), under the 1mb text and 1024 part caps.
|
||||
maxRcvFileDescrParts :: Int
|
||||
maxRcvFileDescrParts = 1024
|
||||
|
||||
maxRcvFileDescrTextLength :: Int
|
||||
maxRcvFileDescrTextLength = 1024 * 1024
|
||||
|
||||
rcvFileDescrWithinLimits :: Int -> Text -> Bool
|
||||
rcvFileDescrWithinLimits partNo descrText =
|
||||
partNo >= 0
|
||||
&& partNo <= maxRcvFileDescrParts
|
||||
&& T.length descrText <= maxRcvFileDescrTextLength
|
||||
|
||||
getRcvFileDescrByRcvFileId :: DB.Connection -> FileTransferId -> ExceptT StoreError IO RcvFileDescr
|
||||
getRcvFileDescrByRcvFileId db fileId = do
|
||||
liftIO (getRcvFileDescrByRcvFileId_ db fileId) >>= \case
|
||||
|
||||
Reference in New Issue
Block a user