Merge branch 'master-ghc8107' into master-android
This commit is contained in:
commit
f323c8e112
@ -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()
|
||||
|
@ -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"]
|
||||
|
@ -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 $
|
||||
|
@ -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)
|
||||
|
Loading…
Reference in New Issue
Block a user