core: message statuses for sending proxies (#4161)

* core: delivery path

* update simplexmq

* via proxy snd flags

* error statuses

* rework errors

* proxy expired errors

* corrections

* move backwards compatibile parser to new type

* update simplexmq

* names

* refactor, style

* simplexmq

* refactor

---------

Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
This commit is contained in:
spaced4ndy
2024-05-15 15:30:05 +04:00
committed by GitHub
parent 3129602a78
commit 4c0d47bbd4
10 changed files with 191 additions and 57 deletions
+76 -13
View File
@@ -29,6 +29,7 @@ import qualified Data.ByteString.Lazy.Char8 as LB
import Data.Char (isSpace)
import Data.Int (Int64)
import Data.Kind (Constraint)
import Data.List.NonEmpty (NonEmpty)
import Data.Maybe (fromMaybe, isJust, isNothing)
import Data.Text (Text)
import qualified Data.Text as T
@@ -345,6 +346,7 @@ data CIMeta (c :: ChatType) (d :: MsgDirection) = CIMeta
itemTs :: ChatItemTs,
itemText :: Text,
itemStatus :: CIStatus d,
sentViaProxy :: Maybe Bool,
itemSharedMsgId :: Maybe SharedMsgId,
itemForwarded :: Maybe CIForwardedFrom,
itemDeleted :: Maybe (CIDeleted c),
@@ -359,8 +361,8 @@ data CIMeta (c :: ChatType) (d :: MsgDirection) = CIMeta
}
deriving (Show)
mkCIMeta :: forall c d. ChatTypeI c => ChatItemId -> CIContent d -> Text -> CIStatus d -> Maybe SharedMsgId -> Maybe CIForwardedFrom -> Maybe (CIDeleted c) -> Bool -> Maybe CITimed -> Maybe Bool -> UTCTime -> ChatItemTs -> Maybe GroupMemberId -> UTCTime -> UTCTime -> CIMeta c d
mkCIMeta itemId itemContent itemText itemStatus itemSharedMsgId itemForwarded itemDeleted itemEdited itemTimed itemLive currentTs itemTs forwardedByMember createdAt updatedAt =
mkCIMeta :: forall c d. ChatTypeI c => ChatItemId -> CIContent d -> Text -> CIStatus d -> Maybe Bool -> Maybe SharedMsgId -> Maybe CIForwardedFrom -> Maybe (CIDeleted c) -> Bool -> Maybe CITimed -> Maybe Bool -> UTCTime -> ChatItemTs -> Maybe GroupMemberId -> UTCTime -> UTCTime -> CIMeta c d
mkCIMeta itemId itemContent itemText itemStatus sentViaProxy itemSharedMsgId itemForwarded itemDeleted itemEdited itemTimed itemLive currentTs itemTs forwardedByMember createdAt updatedAt =
let deletable = case itemContent of
CISndMsgContent _ ->
case chatTypeI @c of
@@ -368,7 +370,7 @@ mkCIMeta itemId itemContent itemText itemStatus itemSharedMsgId itemForwarded it
_ -> diffUTCTime currentTs itemTs < nominalDay && isNothing itemDeleted
_ -> False
editable = deletable && isNothing itemForwarded
in CIMeta {itemId, itemTs, itemText, itemStatus, itemSharedMsgId, itemForwarded, itemDeleted, itemEdited, itemTimed, itemLive, deletable, editable, forwardedByMember, createdAt, updatedAt}
in CIMeta {itemId, itemTs, itemText, itemStatus, sentViaProxy, itemSharedMsgId, itemForwarded, itemDeleted, itemEdited, itemTimed, itemLive, deletable, editable, forwardedByMember, createdAt, updatedAt}
dummyMeta :: ChatItemId -> UTCTime -> Text -> CIMeta c 'MDSnd
dummyMeta itemId ts itemText =
@@ -377,6 +379,7 @@ dummyMeta itemId ts itemText =
itemTs = ts,
itemText,
itemStatus = CISSndNew,
sentViaProxy = Nothing,
itemSharedMsgId = Nothing,
itemForwarded = Nothing,
itemDeleted = Nothing,
@@ -683,8 +686,9 @@ data CIStatus (d :: MsgDirection) where
CISSndNew :: CIStatus 'MDSnd
CISSndSent :: SndCIStatusProgress -> CIStatus 'MDSnd
CISSndRcvd :: MsgReceiptStatus -> SndCIStatusProgress -> CIStatus 'MDSnd
CISSndErrorAuth :: CIStatus 'MDSnd
CISSndError :: String -> CIStatus 'MDSnd
CISSndErrorAuth :: CIStatus 'MDSnd -- deprecated
CISSndError :: SndError -> CIStatus 'MDSnd
CISSndWarning :: SndError -> CIStatus 'MDSnd
CISRcvNew :: CIStatus 'MDRcv
CISRcvRead :: CIStatus 'MDRcv
CISInvalid :: Text -> CIStatus 'MDSnd
@@ -703,7 +707,8 @@ instance MsgDirectionI d => StrEncoding (CIStatus d) where
CISSndSent sndProgress -> "snd_sent " <> strEncode sndProgress
CISSndRcvd msgRcptStatus sndProgress -> "snd_rcvd " <> strEncode msgRcptStatus <> " " <> strEncode sndProgress
CISSndErrorAuth -> "snd_error_auth"
CISSndError e -> "snd_error " <> encodeUtf8 (T.pack e)
CISSndError sndErr -> "snd_error " <> strEncode sndErr
CISSndWarning sndErr -> "snd_warning " <> strEncode sndErr
CISRcvNew -> "rcv_new"
CISRcvRead -> "rcv_read"
CISInvalid {} -> "invalid"
@@ -721,17 +726,68 @@ instance StrEncoding ACIStatus where
"snd_sent" -> ACIStatus SMDSnd . CISSndSent <$> ((A.space *> strP) <|> pure SSPComplete)
"snd_rcvd" -> ACIStatus SMDSnd <$> (CISSndRcvd <$> (A.space *> strP) <*> ((A.space *> strP) <|> pure SSPComplete))
"snd_error_auth" -> pure $ ACIStatus SMDSnd CISSndErrorAuth
"snd_error" -> ACIStatus SMDSnd . CISSndError . T.unpack . safeDecodeUtf8 <$> (A.space *> A.takeByteString)
"snd_error" -> ACIStatus SMDSnd . CISSndError <$> (A.space *> strP)
"snd_warning" -> ACIStatus SMDSnd . CISSndWarning <$> (A.space *> strP)
"rcv_new" -> pure $ ACIStatus SMDRcv CISRcvNew
"rcv_read" -> pure $ ACIStatus SMDRcv CISRcvRead
_ -> fail "bad status"
-- see serverHostError in agent
data SndError
= SndErrAuth
| SndErrQuota
| SndErrExpired -- TIMEOUT/NETWORK errors
| SndErrRelay {srvError :: SrvError} -- BROKER errors (other than TIMEOUT/NETWORK)
| SndErrProxy {proxyServer :: String, srvError :: SrvError} -- SMP PROXY errors
| SndErrProxyRelay {proxyServer :: String, srvError :: SrvError} -- PROXY BROKER errors
| SndErrOther {sndError :: Text} -- other errors
deriving (Eq, Show)
data SrvError
= SrvErrHost
| SrvErrVersion
| SrvErrOther {srvError :: Text}
deriving (Eq, Show)
instance StrEncoding SndError where
strEncode = \case
SndErrAuth -> "auth"
SndErrQuota -> "quota"
SndErrExpired -> "expired"
SndErrRelay srvErr -> "relay " <> strEncode srvErr
SndErrProxy proxy srvErr -> "proxy " <> encodeUtf8 (T.pack proxy) <> " " <> strEncode srvErr
SndErrProxyRelay proxy srvErr -> "proxy_relay " <> encodeUtf8 (T.pack proxy) <> " " <> strEncode srvErr
SndErrOther e -> "other " <> encodeUtf8 e
strP =
A.takeWhile1 (/= ' ') >>= \case
"auth" -> pure SndErrAuth
"quota" -> pure SndErrQuota
"expired" -> pure SndErrExpired
"relay" -> SndErrRelay <$> (A.space *> strP)
"proxy" -> SndErrProxy . T.unpack . safeDecodeUtf8 <$> (A.space *> A.takeWhile1 (/= ' ') <* A.space) <*> strP
"proxy_relay" -> SndErrProxyRelay . T.unpack . safeDecodeUtf8 <$> (A.space *> A.takeWhile1 (/= ' ') <* A.space) <*> strP
"other" -> SndErrOther . safeDecodeUtf8 <$> (A.space *> A.takeByteString)
s -> SndErrOther . safeDecodeUtf8 . (s <>) <$> A.takeByteString -- for backward compatibility with `CISSndError String`
instance StrEncoding SrvError where
strEncode = \case
SrvErrHost -> "host"
SrvErrVersion -> "version"
SrvErrOther e -> "other " <> encodeUtf8 e
strP =
A.takeWhile1 (/= ' ') >>= \case
"host" -> pure SrvErrHost
"version" -> pure SrvErrVersion
"other" -> SrvErrOther . safeDecodeUtf8 <$> (A.space *> A.takeByteString)
_ -> fail "bad SrvError"
data JSONCIStatus
= JCISSndNew
| JCISSndSent {sndProgress :: SndCIStatusProgress}
| JCISSndRcvd {msgRcptStatus :: MsgReceiptStatus, sndProgress :: SndCIStatusProgress}
| JCISSndErrorAuth
| JCISSndError {agentError :: String}
| JCISSndErrorAuth -- deprecated
| JCISSndError {agentError :: SndError}
| JCISSndWarning {agentError :: SndError}
| JCISRcvNew
| JCISRcvRead
| JCISInvalid {text :: Text}
@@ -743,7 +799,8 @@ jsonCIStatus = \case
CISSndSent sndProgress -> JCISSndSent sndProgress
CISSndRcvd msgRcptStatus sndProgress -> JCISSndRcvd msgRcptStatus sndProgress
CISSndErrorAuth -> JCISSndErrorAuth
CISSndError e -> JCISSndError e
CISSndError sndErr -> JCISSndError sndErr
CISSndWarning sndErr -> JCISSndWarning sndErr
CISRcvNew -> JCISRcvNew
CISRcvRead -> JCISRcvRead
CISInvalid text -> JCISInvalid text
@@ -754,7 +811,8 @@ jsonACIStatus = \case
JCISSndSent sndProgress -> ACIStatus SMDSnd $ CISSndSent sndProgress
JCISSndRcvd msgRcptStatus sndProgress -> ACIStatus SMDSnd $ CISSndRcvd msgRcptStatus sndProgress
JCISSndErrorAuth -> ACIStatus SMDSnd CISSndErrorAuth
JCISSndError e -> ACIStatus SMDSnd $ CISSndError e
JCISSndError sndErr -> ACIStatus SMDSnd $ CISSndError sndErr
JCISSndWarning sndErr -> ACIStatus SMDSnd $ CISSndWarning sndErr
JCISRcvNew -> ACIStatus SMDRcv CISRcvNew
JCISRcvRead -> ACIStatus SMDRcv CISRcvRead
JCISInvalid text -> ACIStatus SMDSnd $ CISInvalid text
@@ -1041,7 +1099,7 @@ instance TextEncoding CIForwardedFromTag where
data ChatItemInfo = ChatItemInfo
{ itemVersions :: [ChatItemVersion],
memberDeliveryStatuses :: Maybe [MemberDeliveryStatus],
memberDeliveryStatuses :: Maybe (NonEmpty MemberDeliveryStatus),
forwardedFromChatItem :: Maybe AChatItem
}
deriving (Show)
@@ -1070,7 +1128,8 @@ mkItemVersion ChatItem {content, meta} = version <$> ciMsgContent content
data MemberDeliveryStatus = MemberDeliveryStatus
{ groupMemberId :: GroupMemberId,
memberDeliveryStatus :: CIStatus 'MDSnd
memberDeliveryStatus :: CIStatus 'MDSnd,
sentViaProxy :: Maybe Bool
}
deriving (Eq, Show)
@@ -1108,6 +1167,10 @@ $(JQ.deriveJSON defaultJSON ''CITimed)
$(JQ.deriveJSON (enumJSON $ dropPrefix "SSP") ''SndCIStatusProgress)
$(JQ.deriveJSON (sumTypeJSON $ dropPrefix "SrvErr") ''SrvError)
$(JQ.deriveJSON (sumTypeJSON $ dropPrefix "SndErr") ''SndError)
$(JQ.deriveJSON (sumTypeJSON $ dropPrefix "JCIS") ''JSONCIStatus)
instance MsgDirectionI d => FromJSON (CIStatus d) where
@@ -0,0 +1,20 @@
{-# LANGUAGE QuasiQuotes #-}
module Simplex.Chat.Migrations.M20240510_chat_items_via_proxy where
import Database.SQLite.Simple (Query)
import Database.SQLite.Simple.QQ (sql)
m20240510_chat_items_via_proxy :: Query
m20240510_chat_items_via_proxy =
[sql|
ALTER TABLE chat_items ADD COLUMN via_proxy INTEGER;
ALTER TABLE group_snd_item_statuses ADD COLUMN via_proxy INTEGER;
|]
down_m20240510_chat_items_via_proxy :: Query
down_m20240510_chat_items_via_proxy =
[sql|
ALTER TABLE chat_items DROP COLUMN via_proxy;
ALTER TABLE group_snd_item_statuses DROP COLUMN via_proxy;
|]
+4 -1
View File
@@ -392,7 +392,8 @@ CREATE TABLE chat_items(
fwd_from_msg_dir INTEGER,
fwd_from_contact_id INTEGER REFERENCES contacts ON DELETE SET NULL,
fwd_from_group_id INTEGER REFERENCES groups ON DELETE SET NULL,
fwd_from_chat_item_id INTEGER REFERENCES chat_items ON DELETE SET NULL
fwd_from_chat_item_id INTEGER REFERENCES chat_items ON DELETE SET NULL,
via_proxy INTEGER
);
CREATE TABLE chat_item_messages(
chat_item_id INTEGER NOT NULL REFERENCES chat_items ON DELETE CASCADE,
@@ -503,6 +504,8 @@ CREATE TABLE group_snd_item_statuses(
group_snd_item_status TEXT NOT NULL,
created_at TEXT NOT NULL DEFAULT(datetime('now')),
updated_at TEXT NOT NULL DEFAULT(datetime('now'))
,
via_proxy INTEGER
);
CREATE TABLE IF NOT EXISTS "sent_probes"(
sent_probe_id INTEGER PRIMARY KEY,
+39 -17
View File
@@ -95,6 +95,7 @@ module Simplex.Chat.Store.Messages
lookupChatItemByFileId,
getChatItemByGroupId,
updateDirectChatItemStatus,
setDirectSndChatItemViaProxy,
getTimedItems,
getChatItemTTL,
setChatItemTTL,
@@ -108,6 +109,7 @@ module Simplex.Chat.Store.Messages
createGroupSndStatus,
getGroupSndStatus,
updateGroupSndStatus,
setGroupSndViaProxy,
getGroupSndStatuses,
getGroupSndStatusCounts,
getGroupHistoryItems,
@@ -806,7 +808,7 @@ getLocalChatPreview_ db user (LocalChatPD _ noteFolderId lastItemId_ stats) = do
-- this function can be changed so it never fails, not only avoid failure on invalid json
toLocalChatItem :: UTCTime -> ChatItemRow -> Either StoreError (CChatItem 'CTLocal)
toLocalChatItem currentTs ((itemId, itemTs, AMsgDirection msgDir, itemContentText, itemText, itemStatus, sharedMsgId) :. (itemDeleted, deletedTs, itemEdited, createdAt, updatedAt) :. forwardedFromRow :. (timedTTL, timedDeleteAt, itemLive) :. (fileId_, fileName_, fileSize_, filePath, fileKey, fileNonce, fileStatus_, fileProtocol_)) =
toLocalChatItem currentTs ((itemId, itemTs, AMsgDirection msgDir, itemContentText, itemText, itemStatus, sentViaProxy, sharedMsgId) :. (itemDeleted, deletedTs, itemEdited, createdAt, updatedAt) :. forwardedFromRow :. (timedTTL, timedDeleteAt, itemLive) :. (fileId_, fileName_, fileSize_, filePath, fileKey, fileNonce, fileStatus_, fileProtocol_)) =
chatItem $ fromRight invalid $ dbParseACIContent itemContentText
where
invalid = ACIContent msgDir $ CIInvalidJSON itemContentText
@@ -839,7 +841,7 @@ toLocalChatItem currentTs ((itemId, itemTs, AMsgDirection msgDir, itemContentTex
_ -> Just (CIDeleted @CTLocal deletedTs)
itemEdited' = fromMaybe False itemEdited
itemForwarded = toCIForwardedFrom forwardedFromRow
in mkCIMeta itemId content itemText status sharedMsgId itemForwarded itemDeleted' itemEdited' ciTimed itemLive currentTs itemTs Nothing createdAt updatedAt
in mkCIMeta itemId content itemText status sentViaProxy sharedMsgId itemForwarded itemDeleted' itemEdited' ciTimed itemLive currentTs itemTs Nothing createdAt updatedAt
ciTimed :: Maybe CITimed
ciTimed = timedTTL >>= \ttl -> Just CITimed {ttl, deleteAt = timedDeleteAt}
@@ -1407,7 +1409,7 @@ type ChatItemModeRow = (Maybe Int, Maybe UTCTime, Maybe Bool)
type ChatItemForwardedFromRow = (Maybe CIForwardedFromTag, Maybe Text, Maybe MsgDirection, Maybe Int64, Maybe Int64, Maybe Int64)
type ChatItemRow =
(Int64, ChatItemTs, AMsgDirection, Text, Text, ACIStatus, Maybe SharedMsgId)
(Int64, ChatItemTs, AMsgDirection, Text, Text, ACIStatus, Maybe Bool, Maybe SharedMsgId)
:. (Int, Maybe UTCTime, Maybe Bool, UTCTime, UTCTime)
:. ChatItemForwardedFromRow
:. ChatItemModeRow
@@ -1426,7 +1428,7 @@ toQuote (quotedItemId, quotedSharedMsgId, quotedSentAt, quotedMsgContent, _) dir
-- this function can be changed so it never fails, not only avoid failure on invalid json
toDirectChatItem :: UTCTime -> ChatItemRow :. QuoteRow -> Either StoreError (CChatItem 'CTDirect)
toDirectChatItem currentTs (((itemId, itemTs, AMsgDirection msgDir, itemContentText, itemText, itemStatus, sharedMsgId) :. (itemDeleted, deletedTs, itemEdited, createdAt, updatedAt) :. forwardedFromRow :. (timedTTL, timedDeleteAt, itemLive) :. (fileId_, fileName_, fileSize_, filePath, fileKey, fileNonce, fileStatus_, fileProtocol_)) :. quoteRow) =
toDirectChatItem currentTs (((itemId, itemTs, AMsgDirection msgDir, itemContentText, itemText, itemStatus, sentViaProxy, sharedMsgId) :. (itemDeleted, deletedTs, itemEdited, createdAt, updatedAt) :. forwardedFromRow :. (timedTTL, timedDeleteAt, itemLive) :. (fileId_, fileName_, fileSize_, filePath, fileKey, fileNonce, fileStatus_, fileProtocol_)) :. quoteRow) =
chatItem $ fromRight invalid $ dbParseACIContent itemContentText
where
invalid = ACIContent msgDir $ CIInvalidJSON itemContentText
@@ -1459,7 +1461,7 @@ toDirectChatItem currentTs (((itemId, itemTs, AMsgDirection msgDir, itemContentT
_ -> Just (CIDeleted @CTDirect deletedTs)
itemEdited' = fromMaybe False itemEdited
itemForwarded = toCIForwardedFrom forwardedFromRow
in mkCIMeta itemId content itemText status sharedMsgId itemForwarded itemDeleted' itemEdited' ciTimed itemLive currentTs itemTs Nothing createdAt updatedAt
in mkCIMeta itemId content itemText status sentViaProxy sharedMsgId itemForwarded itemDeleted' itemEdited' ciTimed itemLive currentTs itemTs Nothing createdAt updatedAt
ciTimed :: Maybe CITimed
ciTimed = timedTTL >>= \ttl -> Just CITimed {ttl, deleteAt = timedDeleteAt}
@@ -1483,7 +1485,7 @@ toGroupQuote qr@(_, _, _, _, quotedSent) quotedMember_ = toQuote qr $ direction
-- this function can be changed so it never fails, not only avoid failure on invalid json
toGroupChatItem :: UTCTime -> Int64 -> ChatItemRow :. Only (Maybe GroupMemberId) :. MaybeGroupMemberRow :. GroupQuoteRow :. MaybeGroupMemberRow -> Either StoreError (CChatItem 'CTGroup)
toGroupChatItem currentTs userContactId (((itemId, itemTs, AMsgDirection msgDir, itemContentText, itemText, itemStatus, sharedMsgId) :. (itemDeleted, deletedTs, itemEdited, createdAt, updatedAt) :. forwardedFromRow :. (timedTTL, timedDeleteAt, itemLive) :. (fileId_, fileName_, fileSize_, filePath, fileKey, fileNonce, fileStatus_, fileProtocol_)) :. Only forwardedByMember :. memberRow_ :. (quoteRow :. quotedMemberRow_) :. deletedByGroupMemberRow_) = do
toGroupChatItem currentTs userContactId (((itemId, itemTs, AMsgDirection msgDir, itemContentText, itemText, itemStatus, sentViaProxy, sharedMsgId) :. (itemDeleted, deletedTs, itemEdited, createdAt, updatedAt) :. forwardedFromRow :. (timedTTL, timedDeleteAt, itemLive) :. (fileId_, fileName_, fileSize_, filePath, fileKey, fileNonce, fileStatus_, fileProtocol_)) :. Only forwardedByMember :. memberRow_ :. (quoteRow :. quotedMemberRow_) :. deletedByGroupMemberRow_) = do
chatItem $ fromRight invalid $ dbParseACIContent itemContentText
where
member_ = toMaybeGroupMember userContactId memberRow_
@@ -1521,7 +1523,7 @@ toGroupChatItem currentTs userContactId (((itemId, itemTs, AMsgDirection msgDir,
_ -> Just (maybe (CIDeleted @CTGroup deletedTs) (CIModerated deletedTs) deletedByGroupMember_)
itemEdited' = fromMaybe False itemEdited
itemForwarded = toCIForwardedFrom forwardedFromRow
in mkCIMeta itemId content itemText status sharedMsgId itemForwarded itemDeleted' itemEdited' ciTimed itemLive currentTs itemTs forwardedByMember createdAt updatedAt
in mkCIMeta itemId content itemText status sentViaProxy sharedMsgId itemForwarded itemDeleted' itemEdited' ciTimed itemLive currentTs itemTs forwardedByMember createdAt updatedAt
ciTimed :: Maybe CITimed
ciTimed = timedTTL >>= \ttl -> Just CITimed {ttl, deleteAt = timedDeleteAt}
@@ -1600,6 +1602,11 @@ updateDirectChatItemStatus db user@User {userId} ct@Contact {contactId} itemId i
liftIO $ DB.execute db "UPDATE chat_items SET item_status = ?, updated_at = ? WHERE user_id = ? AND contact_id = ? AND chat_item_id = ?" (itemStatus, currentTs, userId, contactId, itemId)
pure ci {meta = (meta ci) {itemStatus}}
setDirectSndChatItemViaProxy :: DB.Connection -> User -> Contact -> ChatItem 'CTDirect 'MDSnd -> Bool -> IO (ChatItem 'CTDirect 'MDSnd)
setDirectSndChatItemViaProxy db User {userId} Contact {contactId} ci viaProxy = do
DB.execute db "UPDATE chat_items SET via_proxy = ? WHERE user_id = ? AND contact_id = ? AND chat_item_id = ?" (viaProxy, userId, contactId, chatItemId' ci)
pure ci {meta = (meta ci) {sentViaProxy = Just viaProxy}}
updateDirectChatItem :: MsgDirectionI d => DB.Connection -> User -> Contact -> ChatItemId -> CIContent d -> Bool -> Bool -> Maybe CITimed -> Maybe MessageId -> ExceptT StoreError IO (ChatItem 'CTDirect d)
updateDirectChatItem db user ct@Contact {contactId} itemId newContent edited live timed_ msgId_ = do
ci <- liftEither . correctDir =<< getDirectCIWithReactions db user ct itemId
@@ -1758,7 +1765,7 @@ getDirectChatItem db User {userId} contactId itemId = ExceptT $ do
[sql|
SELECT
-- ChatItem
i.chat_item_id, i.item_ts, i.item_sent, i.item_content, i.item_text, i.item_status, i.shared_msg_id,
i.chat_item_id, i.item_ts, i.item_sent, i.item_content, i.item_text, i.item_status, i.via_proxy, i.shared_msg_id,
i.item_deleted, i.item_deleted_ts, i.item_edited, i.created_at, i.updated_at,
i.fwd_from_tag, i.fwd_from_chat_name, i.fwd_from_msg_dir, i.fwd_from_contact_id, i.fwd_from_group_id, i.fwd_from_chat_item_id,
i.timed_ttl, i.timed_delete_at, i.item_live,
@@ -2001,7 +2008,7 @@ getGroupChatItem db User {userId, userContactId} groupId itemId = ExceptT $ do
[sql|
SELECT
-- ChatItem
i.chat_item_id, i.item_ts, i.item_sent, i.item_content, i.item_text, i.item_status, i.shared_msg_id,
i.chat_item_id, i.item_ts, i.item_sent, i.item_content, i.item_text, i.item_status, i.via_proxy, i.shared_msg_id,
i.item_deleted, i.item_deleted_ts, i.item_edited, i.created_at, i.updated_at,
i.fwd_from_tag, i.fwd_from_chat_name, i.fwd_from_msg_dir, i.fwd_from_contact_id, i.fwd_from_group_id, i.fwd_from_chat_item_id,
i.timed_ttl, i.timed_delete_at, i.item_live,
@@ -2105,7 +2112,7 @@ getLocalChatItem db User {userId} folderId itemId = ExceptT $ do
[sql|
SELECT
-- ChatItem
i.chat_item_id, i.item_ts, i.item_sent, i.item_content, i.item_text, i.item_status, i.shared_msg_id,
i.chat_item_id, i.item_ts, i.item_sent, i.item_content, i.item_text, i.item_status, i.via_proxy, i.shared_msg_id,
i.item_deleted, i.item_deleted_ts, i.item_edited, i.created_at, i.updated_at,
i.fwd_from_tag, i.fwd_from_chat_name, i.fwd_from_msg_dir, i.fwd_from_contact_id, i.fwd_from_group_id, i.fwd_from_chat_item_id,
i.timed_ttl, i.timed_delete_at, i.item_live,
@@ -2538,16 +2545,31 @@ updateGroupSndStatus db itemId memberId status = do
|]
(status, currentTs, itemId, memberId)
getGroupSndStatuses :: DB.Connection -> ChatItemId -> IO [(GroupMemberId, CIStatus 'MDSnd)]
getGroupSndStatuses db itemId =
DB.query
setGroupSndViaProxy :: DB.Connection -> ChatItemId -> GroupMemberId -> Bool -> IO ()
setGroupSndViaProxy db itemId memberId viaProxy =
DB.execute
db
[sql|
SELECT group_member_id, group_snd_item_status
FROM group_snd_item_statuses
WHERE chat_item_id = ?
UPDATE group_snd_item_statuses
SET via_proxy = ?
WHERE chat_item_id = ? AND group_member_id = ?
|]
(Only itemId)
(viaProxy, itemId, memberId)
getGroupSndStatuses :: DB.Connection -> ChatItemId -> IO [MemberDeliveryStatus]
getGroupSndStatuses db itemId =
map memStatus
<$> DB.query
db
[sql|
SELECT group_member_id, group_snd_item_status, via_proxy
FROM group_snd_item_statuses
WHERE chat_item_id = ?
|]
(Only itemId)
where
memStatus (groupMemberId, memberDeliveryStatus, sentViaProxy) =
MemberDeliveryStatus {groupMemberId, memberDeliveryStatus, sentViaProxy}
getGroupSndStatusCounts :: DB.Connection -> ChatItemId -> IO [(CIStatus 'MDSnd, Int)]
getGroupSndStatusCounts db itemId =
+3 -1
View File
@@ -107,6 +107,7 @@ import Simplex.Chat.Migrations.M20240324_custom_data
import Simplex.Chat.Migrations.M20240402_item_forwarded
import Simplex.Chat.Migrations.M20240430_ui_theme
import Simplex.Chat.Migrations.M20240501_chat_deleted
import Simplex.Chat.Migrations.M20240510_chat_items_via_proxy
import Simplex.Messaging.Agent.Store.SQLite.Migrations (Migration (..))
schemaMigrations :: [(String, Query, Maybe Query)]
@@ -213,7 +214,8 @@ schemaMigrations =
("20240324_custom_data", m20240324_custom_data, Just down_m20240324_custom_data),
("20240402_item_forwarded", m20240402_item_forwarded, Just down_m20240402_item_forwarded),
("20240430_ui_theme", m20240430_ui_theme, Just down_m20240430_ui_theme),
("20240501_chat_deleted", m20240501_chat_deleted, Just down_m20240501_chat_deleted)
("20240501_chat_deleted", m20240501_chat_deleted, Just down_m20240501_chat_deleted),
("20240510_chat_items_via_proxy", m20240510_chat_items_via_proxy, Just down_m20240510_chat_items_via_proxy)
]
-- | The list of migrations in ascending order by date