Merge branch 'master-ghc8107' into master-android

This commit is contained in:
spaced4ndy 2023-11-21 19:42:28 +04:00
commit f323c8e112
4 changed files with 73 additions and 11 deletions

View File

@ -423,8 +423,15 @@ object ChatController {
receiverStarted = false
break
}
val msg = recvMsg(ctrl)
if (msg != null) processReceivedMsg(msg)
try {
val msg = recvMsg(ctrl)
if (msg != null) processReceivedMsg(msg)
} catch (e: Exception) {
Log.e(TAG, "ChatController recvMsg/processReceivedMsg exception: " + e.stackTraceToString());
} catch (e: Throwable) {
Log.e(TAG, "ChatController recvMsg/processReceivedMsg throwable: " + e.stackTraceToString())
AlertManager.shared.showAlertMsg(generalGetString(MR.strings.error), e.stackTraceToString())
}
}
}
}
@ -3558,7 +3565,7 @@ class APIResponse(val resp: CR, val remoteHostId: Long?, val corr: String? = nul
fun decodeStr(str: String): APIResponse {
return try {
json.decodeFromString(str)
} catch(e: Exception) {
} catch(e: Throwable) {
try {
Log.d(TAG, e.localizedMessage ?: "")
val data = json.parseToJsonElement(str).jsonObject
@ -3587,11 +3594,18 @@ class APIResponse(val resp: CR, val remoteHostId: Long?, val corr: String? = nul
return APIResponse(CR.ChatRespError(user, ChatError.ChatErrorInvalidJSON(json.encodeToString(resp["chatError"]))), remoteHostId, corr)
}
} catch (e: Exception) {
Log.e(TAG, "Error while parsing chat(s): " + e.stackTraceToString())
Log.e(TAG, "Exception while parsing chat(s): " + e.stackTraceToString())
} catch (e: Throwable) {
Log.e(TAG, "Throwable while parsing chat(s): " + e.stackTraceToString())
AlertManager.shared.showAlertMsg(generalGetString(MR.strings.error), e.stackTraceToString())
}
APIResponse(CR.Response(type, json.encodeToString(data)), remoteHostId, corr)
} catch(e: Exception) {
APIResponse(CR.Invalid(str), remoteHostId = null)
} catch(e: Throwable) {
Log.e(TAG, "Throwable2 while parsing chat(s): " + e.stackTraceToString())
AlertManager.shared.showAlertMsg(generalGetString(MR.strings.error), e.stackTraceToString())
APIResponse(CR.Invalid(str), remoteHostId = null)
}
}
}
@ -4609,7 +4623,7 @@ sealed class AgentErrorType {
@Serializable @SerialName("SMP") class SMP(val smpErr: SMPErrorType): AgentErrorType()
// @Serializable @SerialName("NTF") class NTF(val ntfErr: SMPErrorType): AgentErrorType()
@Serializable @SerialName("XFTP") class XFTP(val xftpErr: XFTPErrorType): AgentErrorType()
@Serializable @SerialName("XFTP") class RCP(val rcpErr: RCErrorType): AgentErrorType()
@Serializable @SerialName("RCP") class RCP(val rcpErr: RCErrorType): AgentErrorType()
@Serializable @SerialName("BROKER") class BROKER(val brokerAddress: String, val brokerErr: BrokerErrorType): AgentErrorType()
@Serializable @SerialName("AGENT") class AGENT(val agentErr: SMPAgentError): AgentErrorType()
@Serializable @SerialName("INTERNAL") class INTERNAL(val internalErr: String): AgentErrorType()

View File

@ -359,8 +359,8 @@ responseToView hu@(currentRH, user_) ChatConfig {logLevel, showReactions, showRe
CRAgentConnDeleted acId -> ["completed deleting connection, agent connection id: " <> sShow acId | logLevel <= CLLInfo]
CRAgentUserDeleted auId -> ["completed deleting user" <> if logLevel <= CLLInfo then ", agent user id: " <> sShow auId else ""]
CRMessageError u prefix err -> ttyUser u [plain prefix <> ": " <> plain err | prefix == "error" || logLevel <= CLLWarning]
CRChatCmdError u e -> ttyUserPrefix' u $ viewChatError logLevel e
CRChatError u e -> ttyUser' u $ viewChatError logLevel e
CRChatCmdError u e -> ttyUserPrefix' u $ viewChatError logLevel testView e
CRChatError u e -> ttyUser' u $ viewChatError logLevel testView e
CRArchiveImported archiveErrs -> if null archiveErrs then ["ok"] else ["archive import errors: " <> plain (show archiveErrs)]
CRTimedAction _ _ -> []
where
@ -1733,8 +1733,8 @@ viewRemoteCtrl :: RemoteCtrlInfo -> StyledString
viewRemoteCtrl RemoteCtrlInfo {remoteCtrlId, ctrlDeviceName} =
plain $ tshow remoteCtrlId <> ". " <> ctrlDeviceName
viewChatError :: ChatLogLevel -> ChatError -> [StyledString]
viewChatError logLevel = \case
viewChatError :: ChatLogLevel -> Bool -> ChatError -> [StyledString]
viewChatError logLevel testView = \case
ChatError err -> case err of
CENoActiveUser -> ["error: active user is required"]
CENoConnectionUser agentConnId -> ["error: message user not found, conn id: " <> sShow agentConnId | logLevel <= CLLError]
@ -1844,6 +1844,9 @@ viewChatError logLevel = \case
SEGroupLinkNotFound g -> ["no group link, to create: " <> highlight ("/create link #" <> viewGroupName g)]
SERemoteCtrlNotFound rcId -> ["no remote controller " <> sShow rcId]
SERemoteHostNotFound rhId -> ["no remote host " <> sShow rhId]
SEDuplicateGroupMessage {groupId, sharedMsgId}
| testView -> ["duplicate group message, group id: " <> sShow groupId <> ", message id: " <> sShow sharedMsgId]
| otherwise -> []
e -> ["chat db error: " <> sShow e]
ChatErrorDatabase err -> case err of
DBErrorEncrypted -> ["error: chat database is already encrypted"]

View File

@ -9,6 +9,7 @@ import Control.Concurrent (threadDelay)
import Control.Concurrent.Async (concurrently_)
import Control.Monad (when, void)
import qualified Data.ByteString as B
import Data.List (isInfixOf)
import qualified Data.Text as T
import Simplex.Chat.Controller (ChatConfig (..), XFTPFileConfig (..))
import Simplex.Chat.Protocol (supportedChatVRange)
@ -107,6 +108,7 @@ chatGroupTests = do
it "sends and updates profile when creating contact" testMemberContactProfileUpdate
describe "group message forwarding" $ do
it "forward messages between invitee and introduced (x.msg.new)" testGroupMsgForward
it "deduplicate forwarded messages" testGroupMsgForwardDeduplicate
it "forward message edit (x.msg.update)" testGroupMsgForwardEdit
it "forward message reaction (x.msg.react)" testGroupMsgForwardReaction
it "forward message deletion (x.msg.del)" testGroupMsgForwardDeletion
@ -3947,6 +3949,44 @@ setupGroupForwarding3 gName alice bob cath = do
void $ withCCTransaction alice $ \db ->
DB.execute_ db "UPDATE group_member_intros SET intro_status='fwd'"
testGroupMsgForwardDeduplicate :: HasCallStack => FilePath -> IO ()
testGroupMsgForwardDeduplicate =
testChat3 aliceProfile bobProfile cathProfile $
\alice bob cath -> do
createGroup3 "team" alice bob cath
threadDelay 1000000 -- delay so intro_status doesn't get overwritten to connected
void $ withCCTransaction alice $ \db ->
DB.execute_ db "UPDATE group_member_intros SET intro_status='fwd'"
bob #> "#team hi there"
alice <# "#team bob> hi there"
cath
<### [ Predicate ("#team bob> hi there" `isInfixOf`),
StartsWith "duplicate group message, group id: 1"
]
threadDelay 1000000
-- cath sends x.grp.mem.con on deduplication, so alice doesn't forward anymore
cath #> "#team hey team"
alice <# "#team cath> hey team"
bob <# "#team cath> hey team"
alice ##> "/tail #team 2"
alice <# "#team bob> hi there"
alice <# "#team cath> hey team"
bob ##> "/tail #team 2"
bob <# "#team hi there"
bob <# "#team cath> hey team"
cath ##> "/tail #team 2"
cath <#. "#team bob> hi there"
cath <# "#team hey team"
testGroupMsgForwardEdit :: HasCallStack => FilePath -> IO ()
testGroupMsgForwardEdit =
testChat3 aliceProfile bobProfile cathProfile $

View File

@ -282,8 +282,12 @@ cc <##.. ls = do
unless prefix $ print ("expected to start from one of: " <> show ls, ", got: " <> l)
prefix `shouldBe` True
data ConsoleResponse = ConsoleString String | WithTime String | EndsWith String | StartsWith String
deriving (Show)
data ConsoleResponse
= ConsoleString String
| WithTime String
| EndsWith String
| StartsWith String
| Predicate (String -> Bool)
instance IsString ConsoleResponse where fromString = ConsoleString
@ -303,6 +307,7 @@ getInAnyOrder f cc ls = do
WithTime s -> dropTime_ l == Just s
EndsWith s -> s `isSuffixOf` l
StartsWith s -> s `isPrefixOf` l
Predicate p -> p l
filterFirst :: (a -> Bool) -> [a] -> [a]
filterFirst _ [] = []
filterFirst p (x:xs)