core: chat item on skipped messages (#705)

* core: chat item integrity

* create chat item on skipped messages (but only on content items)

* report skipped messages on all messages, not only content messages

* remove type signature

* remove migration

* update rfc
This commit is contained in:
Evgeny Poberezkin
2022-05-28 19:13:07 +01:00
committed by GitHub
parent c3c712aa02
commit 89908ef5dc
6 changed files with 89 additions and 24 deletions
+1 -1
View File
@@ -189,7 +189,7 @@ data ChatResponse
| CRChatItemDeleted {deletedChatItem :: AChatItem, toChatItem :: AChatItem}
| CRChatItemDeletedNotFound {contact :: Contact, sharedMsgId :: SharedMsgId}
| CRBroadcastSent MsgContent Int ZonedTime
| CRMsgIntegrityError {msgerror :: MsgErrorType} -- TODO make it chat item to support in mobile
| CRMsgIntegrityError {msgError :: MsgErrorType}
| CRCmdAccepted {corr :: CorrId}
| CRCmdOk
| CRChatHelp {helpSection :: HelpSection}
+28 -2
View File
@@ -33,7 +33,7 @@ import Simplex.Chat.Markdown
import Simplex.Chat.Protocol
import Simplex.Chat.Types
import Simplex.Chat.Util (eitherToMaybe, safeDecodeUtf8)
import Simplex.Messaging.Agent.Protocol (AgentErrorType, AgentMsgId, MsgMeta (..))
import Simplex.Messaging.Agent.Protocol (AgentErrorType, AgentMsgId, MsgErrorType (..), MsgMeta (..))
import Simplex.Messaging.Encoding.String
import Simplex.Messaging.Parsers (dropPrefix, enumJSON, fromTextField_, singleFieldJSON, sumTypeJSON)
import Simplex.Messaging.Protocol (MsgBody)
@@ -171,6 +171,13 @@ toCIDirection = \case
CDGroupSnd _ -> CIGroupSnd
CDGroupRcv _ m -> CIGroupRcv m
toChatInfo :: ChatDirection c d -> ChatInfo c
toChatInfo = \case
CDDirectSnd c -> DirectChat c
CDDirectRcv c -> DirectChat c
CDGroupSnd g -> GroupChat g
CDGroupRcv g _ -> GroupChat g
data NewChatItem d = NewChatItem
{ createdByMsgId :: Maybe MessageId,
itemSent :: SMsgDirection d,
@@ -240,6 +247,7 @@ instance MsgDirectionI d => ToJSON (JSONAnyChatItem c d) where
toJSON = J.genericToJSON J.defaultOptions
toEncoding = J.genericToEncoding J.defaultOptions
-- This type is not saved to DB, so all JSON encodings are platform-specific
data CIMeta (d :: MsgDirection) = CIMeta
{ itemId :: ChatItemId,
itemTs :: ChatItemTs,
@@ -435,7 +443,7 @@ instance StrEncoding ACIStatus where
"snd_new" -> pure $ ACIStatus SMDSnd CISSndNew
"snd_sent" -> pure $ ACIStatus SMDSnd CISSndSent
"snd_error_auth" -> pure $ ACIStatus SMDSnd CISSndErrorAuth
"snd_error" -> ACIStatus SMDSnd <$> (A.space *> strP)
"snd_error" -> ACIStatus SMDSnd . CISSndError <$> (A.space *> strP)
"rcv_new" -> pure $ ACIStatus SMDRcv CISRcvNew
"rcv_read" -> pure $ ACIStatus SMDRcv CISRcvRead
_ -> fail "bad status"
@@ -487,6 +495,7 @@ ciDeleteModeToText = \case
CIDMBroadcast -> "this item is deleted (broadcast)"
CIDMInternal -> "this item is deleted (internal)"
-- This type is used both in API and in DB, so we use different JSON encodings for the database and for the API
data CIContent (d :: MsgDirection) where
CISndMsgContent :: MsgContent -> CIContent 'MDSnd
CIRcvMsgContent :: MsgContent -> CIContent 'MDRcv
@@ -494,6 +503,7 @@ data CIContent (d :: MsgDirection) where
CIRcvDeleted :: CIDeleteMode -> CIContent 'MDRcv
CISndCall :: CICallStatus -> Int -> CIContent 'MDSnd
CIRcvCall :: CICallStatus -> Int -> CIContent 'MDRcv
CIRcvIntegrityError :: MsgErrorType -> CIContent 'MDRcv
deriving instance Show (CIContent d)
@@ -505,6 +515,16 @@ ciContentToText = \case
CIRcvDeleted cidm -> ciDeleteModeToText cidm
CISndCall status duration -> "outgoing call: " <> ciCallInfoText status duration
CIRcvCall status duration -> "incoming call: " <> ciCallInfoText status duration
CIRcvIntegrityError err -> msgIntegrityError err
msgIntegrityError :: MsgErrorType -> Text
msgIntegrityError = \case
MsgSkipped fromId toId
| fromId == toId -> "1 skipped message"
| otherwise -> T.pack (show $ toId - fromId + 1) <> " skipped messages"
MsgBadId msgId -> "unexpected message ID " <> T.pack (show msgId)
MsgBadHash -> "incorrect message hash"
MsgDuplicate -> "duplicate message ID"
msgDirToDeletedContent_ :: SMsgDirection d -> CIDeleteMode -> CIContent d
msgDirToDeletedContent_ msgDir mode = case msgDir of
@@ -539,6 +559,7 @@ data JSONCIContent
| JCIRcvDeleted {deleteMode :: CIDeleteMode}
| JCISndCall {status :: CICallStatus, duration :: Int} -- duration in seconds
| JCIRcvCall {status :: CICallStatus, duration :: Int}
| JCIRcvIntegrityError {msgError :: MsgErrorType}
deriving (Generic)
instance FromJSON JSONCIContent where
@@ -556,6 +577,7 @@ jsonCIContent = \case
CIRcvDeleted cidm -> JCIRcvDeleted cidm
CISndCall status duration -> JCISndCall {status, duration}
CIRcvCall status duration -> JCIRcvCall {status, duration}
CIRcvIntegrityError err -> JCIRcvIntegrityError err
aciContentJSON :: JSONCIContent -> ACIContent
aciContentJSON = \case
@@ -565,6 +587,7 @@ aciContentJSON = \case
JCIRcvDeleted cidm -> ACIContent SMDRcv $ CIRcvDeleted cidm
JCISndCall {status, duration} -> ACIContent SMDSnd $ CISndCall status duration
JCIRcvCall {status, duration} -> ACIContent SMDRcv $ CIRcvCall status duration
JCIRcvIntegrityError err -> ACIContent SMDRcv $ CIRcvIntegrityError err
-- platform independent
data DBJSONCIContent
@@ -574,6 +597,7 @@ data DBJSONCIContent
| DBJCIRcvDeleted {deleteMode :: CIDeleteMode}
| DBJCISndCall {status :: CICallStatus, duration :: Int}
| DBJCIRcvCall {status :: CICallStatus, duration :: Int}
| DBJCIRcvIntegrityError {msgError :: MsgErrorType}
deriving (Generic)
instance FromJSON DBJSONCIContent where
@@ -591,6 +615,7 @@ dbJsonCIContent = \case
CIRcvDeleted cidm -> DBJCIRcvDeleted cidm
CISndCall status duration -> DBJCISndCall {status, duration}
CIRcvCall status duration -> DBJCIRcvCall {status, duration}
CIRcvIntegrityError err -> DBJCIRcvIntegrityError err
aciContentDBJSON :: DBJSONCIContent -> ACIContent
aciContentDBJSON = \case
@@ -600,6 +625,7 @@ aciContentDBJSON = \case
DBJCIRcvDeleted cidm -> ACIContent SMDRcv $ CIRcvDeleted cidm
DBJCISndCall {status, duration} -> ACIContent SMDSnd $ CISndCall status duration
DBJCIRcvCall {status, duration} -> ACIContent SMDRcv $ CIRcvCall status duration
DBJCIRcvIntegrityError err -> ACIContent SMDRcv $ CIRcvIntegrityError err
data CICallStatus
= CISCallPending
+9
View File
@@ -131,6 +131,7 @@ module Simplex.Chat.Store
deletePendingGroupMessage,
createNewSndChatItem,
createNewRcvChatItem,
createNewChatItemNoMsg,
getChatPreviews,
getDirectChat,
getGroupChat,
@@ -2531,6 +2532,14 @@ createNewRcvChatItem st user chatDirection RcvMessage {msgId, chatMsgEvent} shar
CDGroupRcv GroupInfo {membership = GroupMember {memberId = userMemberId}} _ ->
(Just $ Just userMemberId == memberId, memberId)
createNewChatItemNoMsg :: forall c d m. (MsgDirectionI d, MonadUnliftIO m) => SQLiteStore -> User -> ChatDirection c d -> CIContent d -> UTCTime -> UTCTime -> m ChatItemId
createNewChatItemNoMsg st user chatDirection ciContent itemTs createdAt =
liftIO . withTransaction st $ \db ->
createNewChatItem_ db user chatDirection Nothing Nothing ciContent quoteRow itemTs createdAt
where
quoteRow :: NewQuoteRow
quoteRow = (Nothing, Nothing, Nothing, Nothing, Nothing)
createNewChatItem_ :: forall c d. MsgDirectionI d => DB.Connection -> User -> ChatDirection c d -> Maybe MessageId -> Maybe SharedMsgId -> CIContent d -> NewQuoteRow -> UTCTime -> UTCTime -> IO ChatItemId
createNewChatItem_ db User {userId} chatDirection msgId_ sharedMsgId ciContent quoteRow itemTs createdAt = do
DB.execute
+5
View File
@@ -208,6 +208,7 @@ viewChatItem chat ChatItem {chatDir, meta, content, quotedItem, file} = case cha
CIRcvMsgContent mc -> withRcvFile from $ rcvMsg from quote mc
CIRcvDeleted _ -> []
CIRcvCall {} -> []
CIRcvIntegrityError err -> viewRcvIntegrityError from err meta
where
from = ttyFromContact' c
where
@@ -223,6 +224,7 @@ viewChatItem chat ChatItem {chatDir, meta, content, quotedItem, file} = case cha
CIRcvMsgContent mc -> withRcvFile from $ rcvMsg from quote mc
CIRcvDeleted _ -> []
CIRcvCall {} -> []
CIRcvIntegrityError err -> viewRcvIntegrityError from err meta
where
from = ttyFromGroup' g m
where
@@ -295,6 +297,9 @@ msgPreview = msgPlain . preview . msgContentText
| T.length t <= 120 = t
| otherwise = T.take 120 t <> "..."
viewRcvIntegrityError :: StyledString -> MsgErrorType -> CIMeta 'MDRcv -> [StyledString]
viewRcvIntegrityError from msgErr meta = receivedWithTime_ from [] meta $ viewMsgIntegrityError msgErr
viewMsgIntegrityError :: MsgErrorType -> [StyledString]
viewMsgIntegrityError err = msgError $ case err of
MsgSkipped fromId toId ->