mirror of
https://github.com/simplex-chat/simplex-chat.git
synced 2026-03-31 09:46:03 +00:00
core: add FromJSON instance to ChatResponse (#3129)
* Start adding FromJSON instances to ChatResponse * progress * FromJSON instance for ChatResponse compiles * restore removed encodings * remove comment * diff * update simplexmq, use TH for JSON --------- Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>
This commit is contained in:
committed by
GitHub
parent
27e8a81c9f
commit
fc9db9c381
@@ -9,7 +9,7 @@ constraints: zip +disable-bzip2 +disable-zstd
|
||||
source-repository-package
|
||||
type: git
|
||||
location: https://github.com/simplex-chat/simplexmq.git
|
||||
tag: 753a6c7542c3764fda9ce3f4c4cdc9f2329816d3
|
||||
tag: 96a38505d63ec9a12096991e7725b250e397af72
|
||||
|
||||
source-repository-package
|
||||
type: git
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"https://github.com/simplex-chat/simplexmq.git"."ec1b72cb8013a65a5d9783104a47ae44f5730089" = "1lz5rvgxp242zg95r9zd9j50y45314cf8nfpjg1qsa55nrk2w19b";
|
||||
"https://github.com/simplex-chat/simplexmq.git"."96a38505d63ec9a12096991e7725b250e397af72" = "0kllakklvfrbpjlk6zi5mbxqm1prp6xdwyh2y4fw9n6c8b76is98";
|
||||
"https://github.com/simplex-chat/hs-socks.git"."a30cc7a79a08d8108316094f8f2f82a0c5e1ac51" = "0yasvnr7g91k76mjkamvzab2kvlb1g5pspjyjn2fr6v83swjhj38";
|
||||
"https://github.com/kazu-yamamoto/http2.git"."b5a1b7200cf5bc7044af34ba325284271f6dff25" = "0dqb50j57an64nf4qcf5vcz4xkd1vzvghvf8bk529c1k30r9nfzb";
|
||||
"https://github.com/simplex-chat/direct-sqlcipher.git"."f814ee68b16a9447fbb467ccc8f29bdd3546bfd9" = "0kiwhvml42g9anw4d2v0zd1fpc790pj9syg5x3ik4l97fnkbbwpp";
|
||||
|
||||
@@ -469,11 +469,11 @@ processChatCommand = \case
|
||||
DeleteUser uName delSMPQueues viewPwd_ -> withUserName uName $ \userId -> APIDeleteUser userId delSMPQueues viewPwd_
|
||||
StartChat subConns enableExpireCIs startXFTPWorkers -> withUser' $ \_ ->
|
||||
asks agentAsync >>= readTVarIO >>= \case
|
||||
Just _ -> pure CRChatRunning
|
||||
_ -> checkStoreNotChanged $ startChatController subConns enableExpireCIs startXFTPWorkers $> CRChatStarted
|
||||
Just _ -> pure $ CRChatRunning Nothing
|
||||
_ -> checkStoreNotChanged $ startChatController subConns enableExpireCIs startXFTPWorkers $> CRChatStarted Nothing
|
||||
APIStopChat -> do
|
||||
ask >>= stopChatController
|
||||
pure CRChatStopped
|
||||
pure $ CRChatStopped Nothing
|
||||
APIActivateChat -> withUser $ \_ -> do
|
||||
restoreCalls
|
||||
withAgent foregroundAgent
|
||||
@@ -2814,7 +2814,7 @@ processAgentMessageNoConn = \case
|
||||
DISCONNECT p h -> hostEvent $ CRHostDisconnected p h
|
||||
DOWN srv conns -> serverEvent srv conns CRContactsDisconnected "disconnected"
|
||||
UP srv conns -> serverEvent srv conns CRContactsSubscribed "connected"
|
||||
SUSPENDED -> toView CRChatSuspended
|
||||
SUSPENDED -> toView $ CRChatSuspended Nothing
|
||||
DEL_USER agentUserId -> toView $ CRAgentUserDeleted agentUserId
|
||||
where
|
||||
hostEvent :: ChatResponse -> m ()
|
||||
|
||||
@@ -49,6 +49,9 @@ data CallStateTag
|
||||
| CSTCallNegotiated
|
||||
deriving (Show, Generic)
|
||||
|
||||
instance FromJSON CallStateTag where
|
||||
parseJSON = J.genericParseJSON . enumJSON $ dropPrefix "CSTCall"
|
||||
|
||||
instance ToJSON CallStateTag where
|
||||
toJSON = J.genericToJSON . enumJSON $ dropPrefix "CSTCall"
|
||||
toEncoding = J.genericToEncoding . enumJSON $ dropPrefix "CSTCall"
|
||||
@@ -132,7 +135,7 @@ data RcvCallInvitation = RcvCallInvitation
|
||||
sharedKey :: Maybe C.Key,
|
||||
callTs :: UTCTime
|
||||
}
|
||||
deriving (Show, Generic)
|
||||
deriving (Show, Generic, FromJSON)
|
||||
|
||||
instance ToJSON RcvCallInvitation where
|
||||
toJSON = J.genericToJSON J.defaultOptions {J.omitNothingFields = True}
|
||||
@@ -157,10 +160,7 @@ data CallInvitation = CallInvitation
|
||||
{ callType :: CallType,
|
||||
callDhPubKey :: Maybe C.PublicKeyX25519
|
||||
}
|
||||
deriving (Eq, Show, Generic)
|
||||
|
||||
instance FromJSON CallInvitation where
|
||||
parseJSON = J.genericParseJSON J.defaultOptions {J.omitNothingFields = True}
|
||||
deriving (Eq, Show, Generic, FromJSON)
|
||||
|
||||
instance ToJSON CallInvitation where
|
||||
toJSON = J.genericToJSON J.defaultOptions {J.omitNothingFields = True}
|
||||
@@ -190,10 +190,7 @@ data CallOffer = CallOffer
|
||||
rtcSession :: WebRTCSession,
|
||||
callDhPubKey :: Maybe C.PublicKeyX25519
|
||||
}
|
||||
deriving (Eq, Show, Generic)
|
||||
|
||||
instance FromJSON CallOffer where
|
||||
parseJSON = J.genericParseJSON J.defaultOptions {J.omitNothingFields = True}
|
||||
deriving (Eq, Show, Generic, FromJSON)
|
||||
|
||||
instance ToJSON CallOffer where
|
||||
toJSON = J.genericToJSON J.defaultOptions {J.omitNothingFields = True}
|
||||
@@ -203,10 +200,7 @@ data WebRTCCallOffer = WebRTCCallOffer
|
||||
{ callType :: CallType,
|
||||
rtcSession :: WebRTCSession
|
||||
}
|
||||
deriving (Eq, Show, Generic)
|
||||
|
||||
instance FromJSON WebRTCCallOffer where
|
||||
parseJSON = J.genericParseJSON J.defaultOptions {J.omitNothingFields = True}
|
||||
deriving (Eq, Show, Generic, FromJSON)
|
||||
|
||||
instance ToJSON WebRTCCallOffer where
|
||||
toJSON = J.genericToJSON J.defaultOptions {J.omitNothingFields = True}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
{-# LANGUAGE ConstraintKinds #-}
|
||||
{-# LANGUAGE CPP #-}
|
||||
{-# LANGUAGE DataKinds #-}
|
||||
{-# LANGUAGE DeriveAnyClass #-}
|
||||
{-# LANGUAGE DeriveGeneric #-}
|
||||
@@ -12,6 +13,7 @@
|
||||
{-# LANGUAGE StandaloneDeriving #-}
|
||||
{-# LANGUAGE StrictData #-}
|
||||
{-# LANGUAGE TemplateHaskell #-}
|
||||
{-# LANGUAGE TypeApplications #-}
|
||||
|
||||
module Simplex.Chat.Controller where
|
||||
|
||||
@@ -24,11 +26,13 @@ import Control.Monad.Reader
|
||||
import Crypto.Random (ChaChaDRG)
|
||||
import Data.Aeson (FromJSON (..), ToJSON (..), (.:), (.:?))
|
||||
import qualified Data.Aeson as J
|
||||
import qualified Data.Aeson.TH as JQ
|
||||
import qualified Data.Aeson.Types as JT
|
||||
import qualified Data.Attoparsec.ByteString.Char8 as A
|
||||
import Data.ByteString.Char8 (ByteString)
|
||||
import qualified Data.ByteString.Char8 as B
|
||||
import Data.Char (ord)
|
||||
import Data.Constraint (Dict (..))
|
||||
import Data.Int (Int64)
|
||||
import Data.List.NonEmpty (NonEmpty)
|
||||
import Data.Map.Strict (Map)
|
||||
@@ -64,7 +68,7 @@ import qualified Simplex.Messaging.Crypto.File as CF
|
||||
import Simplex.Messaging.Encoding.String
|
||||
import Simplex.Messaging.Notifications.Protocol (DeviceToken (..), NtfTknStatus)
|
||||
import Simplex.Messaging.Parsers (dropPrefix, enumJSON, parseAll, parseString, sumTypeJSON)
|
||||
import Simplex.Messaging.Protocol (AProtoServerWithAuth, AProtocolType, CorrId, MsgFlags, NtfServer, ProtoServerWithAuth, ProtocolTypeI, QueueId, SProtocolType, SubscriptionMode (..), UserProtocol, XFTPServerWithAuth)
|
||||
import Simplex.Messaging.Protocol (AProtoServerWithAuth, AProtocolType (..), CorrId, MsgFlags, NtfServer, ProtoServerWithAuth, ProtocolTypeI, QueueId, SProtocolType, SubscriptionMode (..), UserProtocol, XFTPServerWithAuth, userProtocol)
|
||||
import Simplex.Messaging.TMap (TMap)
|
||||
import Simplex.Messaging.Transport (simplexMQVersion)
|
||||
import Simplex.Messaging.Transport.Client (TransportHost)
|
||||
@@ -200,6 +204,9 @@ data ChatController = ChatController
|
||||
data HelpSection = HSMain | HSFiles | HSGroups | HSContacts | HSMyAddress | HSIncognito | HSMarkdown | HSMessages | HSSettings | HSDatabase
|
||||
deriving (Show, Generic)
|
||||
|
||||
instance FromJSON HelpSection where
|
||||
parseJSON = J.genericParseJSON . enumJSON $ dropPrefix "HS"
|
||||
|
||||
instance ToJSON HelpSection where
|
||||
toJSON = J.genericToJSON . enumJSON $ dropPrefix "HS"
|
||||
toEncoding = J.genericToEncoding . enumJSON $ dropPrefix "HS"
|
||||
@@ -438,10 +445,10 @@ data ChatCommand
|
||||
data ChatResponse
|
||||
= CRActiveUser {user :: User}
|
||||
| CRUsersList {users :: [UserInfo]}
|
||||
| CRChatStarted
|
||||
| CRChatRunning
|
||||
| CRChatStopped
|
||||
| CRChatSuspended
|
||||
| CRChatStarted {_nullary :: Maybe Int}
|
||||
| CRChatRunning {_nullary :: Maybe Int}
|
||||
| CRChatStopped {_nullary :: Maybe Int}
|
||||
| CRChatSuspended {_nullary :: Maybe Int}
|
||||
| CRApiChats {user :: User, chats :: [AChat]}
|
||||
| CRChats {chats :: [AChat]}
|
||||
| CRApiChat {user :: User, chat :: AChat}
|
||||
@@ -605,7 +612,7 @@ data ChatResponse
|
||||
| CRRemoteHostDeleted {remoteHostId :: RemoteHostId}
|
||||
| CRRemoteCtrlList {remoteCtrls :: [RemoteCtrlInfo]}
|
||||
| CRRemoteCtrlRegistered {remoteCtrlId :: RemoteCtrlId}
|
||||
| CRRemoteCtrlStarted
|
||||
| CRRemoteCtrlStarted {_nullary :: Maybe Int}
|
||||
| CRRemoteCtrlAnnounce {fingerprint :: C.KeyHash} -- unregistered fingerprint, needs confirmation
|
||||
| CRRemoteCtrlFound {remoteCtrl :: RemoteCtrl} -- registered fingerprint, may connect
|
||||
| CRRemoteCtrlAccepted {remoteCtrlId :: RemoteCtrlId}
|
||||
@@ -629,7 +636,7 @@ data ChatResponse
|
||||
| CRChatError {user_ :: Maybe User, chatError :: ChatError}
|
||||
| CRArchiveImported {archiveErrors :: [ArchiveError]}
|
||||
| CRTimedAction {action :: String, durationMilliseconds :: Int64}
|
||||
deriving (Show, Generic)
|
||||
deriving (Show)
|
||||
|
||||
logResponseToFile :: ChatResponse -> Bool
|
||||
logResponseToFile = \case
|
||||
@@ -650,17 +657,12 @@ logResponseToFile = \case
|
||||
CRMessageError {} -> True
|
||||
_ -> False
|
||||
|
||||
instance FromJSON ChatResponse where
|
||||
parseJSON todo = pure $ CRCmdOk Nothing -- TODO: actually use the instances
|
||||
|
||||
instance ToJSON ChatResponse where
|
||||
toJSON = J.genericToJSON . sumTypeJSON $ dropPrefix "CR"
|
||||
toEncoding = J.genericToEncoding . sumTypeJSON $ dropPrefix "CR"
|
||||
|
||||
data RemoteCtrlOOB = RemoteCtrlOOB
|
||||
{ caFingerprint :: C.KeyHash
|
||||
}
|
||||
deriving (Show, Generic, ToJSON)
|
||||
deriving (Show, Generic, FromJSON)
|
||||
|
||||
instance ToJSON RemoteCtrlOOB where toEncoding = J.genericToEncoding J.defaultOptions
|
||||
|
||||
data RemoteHostInfo = RemoteHostInfo
|
||||
{ remoteHostId :: RemoteHostId,
|
||||
@@ -668,14 +670,18 @@ data RemoteHostInfo = RemoteHostInfo
|
||||
displayName :: Text,
|
||||
sessionActive :: Bool
|
||||
}
|
||||
deriving (Show, Generic, ToJSON)
|
||||
deriving (Show, Generic, FromJSON)
|
||||
|
||||
instance ToJSON RemoteHostInfo where toEncoding = J.genericToEncoding J.defaultOptions
|
||||
|
||||
data RemoteCtrlInfo = RemoteCtrlInfo
|
||||
{ remoteCtrlId :: RemoteCtrlId,
|
||||
displayName :: Text,
|
||||
sessionActive :: Bool
|
||||
}
|
||||
deriving (Eq, Show, Generic, ToJSON)
|
||||
deriving (Eq, Show, Generic, FromJSON)
|
||||
|
||||
instance ToJSON RemoteCtrlInfo where toEncoding = J.genericToEncoding J.defaultOptions
|
||||
|
||||
newtype UserPwd = UserPwd {unUserPwd :: Text}
|
||||
deriving (Eq, Show)
|
||||
@@ -695,6 +701,9 @@ instance StrEncoding AgentQueueId where
|
||||
strDecode s = AgentQueueId <$> strDecode s
|
||||
strP = AgentQueueId <$> strP
|
||||
|
||||
instance FromJSON AgentQueueId where
|
||||
parseJSON = strParseJSON "AgentQueueId"
|
||||
|
||||
instance ToJSON AgentQueueId where
|
||||
toJSON = strToJSON
|
||||
toEncoding = strToJEncoding
|
||||
@@ -713,12 +722,23 @@ data UserProtoServers p = UserProtoServers
|
||||
}
|
||||
deriving (Show, Generic)
|
||||
|
||||
instance ProtocolTypeI p => FromJSON (UserProtoServers p) where
|
||||
parseJSON = J.genericParseJSON J.defaultOptions
|
||||
|
||||
instance ProtocolTypeI p => ToJSON (UserProtoServers p) where
|
||||
toJSON = J.genericToJSON J.defaultOptions
|
||||
toEncoding = J.genericToEncoding J.defaultOptions
|
||||
|
||||
data AUserProtoServers = forall p. (ProtocolTypeI p, UserProtocol p) => AUPS (UserProtoServers p)
|
||||
|
||||
instance FromJSON AUserProtoServers where
|
||||
parseJSON v = J.withObject "AUserProtoServers" parse v
|
||||
where
|
||||
parse o = do
|
||||
AProtocolType (p :: SProtocolType p) <- o .: "serverProtocol"
|
||||
case userProtocol p of
|
||||
Just Dict -> AUPS <$> J.parseJSON @(UserProtoServers p) v
|
||||
Nothing -> fail $ "AUserProtoServers: unsupported protocol " <> show p
|
||||
|
||||
instance ToJSON AUserProtoServers where
|
||||
toJSON (AUPS s) = J.genericToJSON J.defaultOptions s
|
||||
toEncoding (AUPS s) = J.genericToEncoding J.defaultOptions s
|
||||
@@ -747,7 +767,7 @@ data ContactSubStatus = ContactSubStatus
|
||||
{ contact :: Contact,
|
||||
contactError :: Maybe ChatError
|
||||
}
|
||||
deriving (Show, Generic)
|
||||
deriving (Show, Generic, FromJSON)
|
||||
|
||||
instance ToJSON ContactSubStatus where
|
||||
toJSON = J.genericToJSON J.defaultOptions {J.omitNothingFields = True}
|
||||
@@ -757,7 +777,7 @@ data MemberSubStatus = MemberSubStatus
|
||||
{ member :: GroupMember,
|
||||
memberError :: Maybe ChatError
|
||||
}
|
||||
deriving (Show, Generic)
|
||||
deriving (Show, Generic, FromJSON)
|
||||
|
||||
instance ToJSON MemberSubStatus where
|
||||
toJSON = J.genericToJSON J.defaultOptions {J.omitNothingFields = True}
|
||||
@@ -767,7 +787,7 @@ data UserContactSubStatus = UserContactSubStatus
|
||||
{ userContact :: UserContact,
|
||||
userContactError :: Maybe ChatError
|
||||
}
|
||||
deriving (Show, Generic)
|
||||
deriving (Show, Generic, FromJSON)
|
||||
|
||||
instance ToJSON UserContactSubStatus where
|
||||
toJSON = J.genericToJSON J.defaultOptions {J.omitNothingFields = True}
|
||||
@@ -777,7 +797,7 @@ data PendingSubStatus = PendingSubStatus
|
||||
{ connection :: PendingContactConnection,
|
||||
connError :: Maybe ChatError
|
||||
}
|
||||
deriving (Show, Generic)
|
||||
deriving (Show, Generic, FromJSON)
|
||||
|
||||
instance ToJSON PendingSubStatus where
|
||||
toJSON = J.genericToJSON J.defaultOptions {J.omitNothingFields = True}
|
||||
@@ -789,7 +809,7 @@ data UserProfileUpdateSummary = UserProfileUpdateSummary
|
||||
updateFailures :: Int,
|
||||
changedContacts :: [Contact]
|
||||
}
|
||||
deriving (Show, Generic)
|
||||
deriving (Show, Generic, FromJSON)
|
||||
|
||||
instance ToJSON UserProfileUpdateSummary where toEncoding = J.genericToEncoding J.defaultOptions
|
||||
|
||||
@@ -825,12 +845,10 @@ data XFTPFileConfig = XFTPFileConfig
|
||||
defaultXFTPFileConfig :: XFTPFileConfig
|
||||
defaultXFTPFileConfig = XFTPFileConfig {minFileSize = 0}
|
||||
|
||||
instance ToJSON XFTPFileConfig where
|
||||
toJSON = J.genericToJSON J.defaultOptions {J.omitNothingFields = True}
|
||||
toEncoding = J.genericToEncoding J.defaultOptions {J.omitNothingFields = True}
|
||||
instance ToJSON XFTPFileConfig where toEncoding = J.genericToEncoding J.defaultOptions
|
||||
|
||||
data NtfMsgInfo = NtfMsgInfo {msgTs :: UTCTime, msgFlags :: MsgFlags}
|
||||
deriving (Show, Generic)
|
||||
deriving (Show, Generic, FromJSON)
|
||||
|
||||
instance ToJSON NtfMsgInfo where toEncoding = J.genericToEncoding J.defaultOptions
|
||||
|
||||
@@ -842,7 +860,7 @@ data SwitchProgress = SwitchProgress
|
||||
switchPhase :: SwitchPhase,
|
||||
connectionStats :: ConnectionStats
|
||||
}
|
||||
deriving (Show, Generic)
|
||||
deriving (Show, Generic, FromJSON)
|
||||
|
||||
instance ToJSON SwitchProgress where toEncoding = J.genericToEncoding J.defaultOptions
|
||||
|
||||
@@ -850,7 +868,7 @@ data RatchetSyncProgress = RatchetSyncProgress
|
||||
{ ratchetSyncStatus :: RatchetSyncState,
|
||||
connectionStats :: ConnectionStats
|
||||
}
|
||||
deriving (Show, Generic)
|
||||
deriving (Show, Generic, FromJSON)
|
||||
|
||||
instance ToJSON RatchetSyncProgress where toEncoding = J.genericToEncoding J.defaultOptions
|
||||
|
||||
@@ -858,7 +876,7 @@ data ParsedServerAddress = ParsedServerAddress
|
||||
{ serverAddress :: Maybe ServerAddress,
|
||||
parseError :: String
|
||||
}
|
||||
deriving (Show, Generic)
|
||||
deriving (Show, Generic, FromJSON)
|
||||
|
||||
instance ToJSON ParsedServerAddress where toEncoding = J.genericToEncoding J.defaultOptions
|
||||
|
||||
@@ -869,7 +887,7 @@ data ServerAddress = ServerAddress
|
||||
keyHash :: String,
|
||||
basicAuth :: String
|
||||
}
|
||||
deriving (Show, Generic)
|
||||
deriving (Show, Generic, FromJSON)
|
||||
|
||||
instance ToJSON ServerAddress where toEncoding = J.genericToEncoding J.defaultOptions
|
||||
|
||||
@@ -893,7 +911,7 @@ data CoreVersionInfo = CoreVersionInfo
|
||||
simplexmqVersion :: String,
|
||||
simplexmqCommit :: String
|
||||
}
|
||||
deriving (Show, Generic)
|
||||
deriving (Show, Generic, FromJSON)
|
||||
|
||||
instance ToJSON CoreVersionInfo where toEncoding = J.genericToEncoding J.defaultOptions
|
||||
|
||||
@@ -906,7 +924,7 @@ data SlowSQLQuery = SlowSQLQuery
|
||||
{ query :: Text,
|
||||
queryStats :: SlowQueryStats
|
||||
}
|
||||
deriving (Show, Generic)
|
||||
deriving (Show, Generic, FromJSON)
|
||||
|
||||
instance ToJSON SlowSQLQuery where toEncoding = J.genericToEncoding J.defaultOptions
|
||||
|
||||
@@ -919,6 +937,9 @@ data ChatError
|
||||
| ChatErrorRemoteHost {remoteHostId :: RemoteHostId, remoteHostError :: RemoteHostError}
|
||||
deriving (Show, Exception, Generic)
|
||||
|
||||
instance FromJSON ChatError where
|
||||
parseJSON = J.genericParseJSON . sumTypeJSON $ dropPrefix "Chat"
|
||||
|
||||
instance ToJSON ChatError where
|
||||
toJSON = J.genericToJSON . sumTypeJSON $ dropPrefix "Chat"
|
||||
toEncoding = J.genericToEncoding . sumTypeJSON $ dropPrefix "Chat"
|
||||
@@ -1002,6 +1023,9 @@ data ChatErrorType
|
||||
| CEException {message :: String}
|
||||
deriving (Show, Exception, Generic)
|
||||
|
||||
instance FromJSON ChatErrorType where
|
||||
parseJSON = J.genericParseJSON . sumTypeJSON $ dropPrefix "CE"
|
||||
|
||||
instance ToJSON ChatErrorType where
|
||||
toJSON = J.genericToJSON . sumTypeJSON $ dropPrefix "CE"
|
||||
toEncoding = J.genericToEncoding . sumTypeJSON $ dropPrefix "CE"
|
||||
@@ -1014,6 +1038,9 @@ data DatabaseError
|
||||
| DBErrorOpen {sqliteError :: SQLiteError}
|
||||
deriving (Show, Exception, Generic)
|
||||
|
||||
instance FromJSON DatabaseError where
|
||||
parseJSON = J.genericParseJSON . sumTypeJSON $ dropPrefix "DB"
|
||||
|
||||
instance ToJSON DatabaseError where
|
||||
toJSON = J.genericToJSON . sumTypeJSON $ dropPrefix "DB"
|
||||
toEncoding = J.genericToEncoding . sumTypeJSON $ dropPrefix "DB"
|
||||
@@ -1021,6 +1048,9 @@ instance ToJSON DatabaseError where
|
||||
data SQLiteError = SQLiteErrorNotADatabase | SQLiteError String
|
||||
deriving (Show, Exception, Generic)
|
||||
|
||||
instance FromJSON SQLiteError where
|
||||
parseJSON = J.genericParseJSON . sumTypeJSON $ dropPrefix "SQLite"
|
||||
|
||||
instance ToJSON SQLiteError where
|
||||
toJSON = J.genericToJSON . sumTypeJSON $ dropPrefix "SQLite"
|
||||
toEncoding = J.genericToEncoding . sumTypeJSON $ dropPrefix "SQLite"
|
||||
@@ -1070,6 +1100,9 @@ data ArchiveError
|
||||
| AEImportFile {file :: String, chatError :: ChatError}
|
||||
deriving (Show, Exception, Generic)
|
||||
|
||||
instance FromJSON ArchiveError where
|
||||
parseJSON = J.genericParseJSON . sumTypeJSON $ dropPrefix "AE"
|
||||
|
||||
instance ToJSON ArchiveError where
|
||||
toJSON = J.genericToJSON . sumTypeJSON $ dropPrefix "AE"
|
||||
toEncoding = J.genericToEncoding . sumTypeJSON $ dropPrefix "AE"
|
||||
@@ -1156,3 +1189,5 @@ withStoreCtx ctx_ action = do
|
||||
where
|
||||
handleInternal :: String -> SomeException -> IO (Either StoreError a)
|
||||
handleInternal ctxStr e = pure . Left . SEInternalError $ show e <> ctxStr
|
||||
|
||||
$(JQ.deriveJSON (sumTypeJSON $ dropPrefix "CR") ''ChatResponse)
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
{-# LANGUAGE DeriveAnyClass #-}
|
||||
{-# LANGUAGE DeriveGeneric #-}
|
||||
{-# LANGUAGE GADTs #-}
|
||||
{-# LANGUAGE LambdaCase #-}
|
||||
@@ -10,7 +11,7 @@
|
||||
module Simplex.Chat.Markdown where
|
||||
|
||||
import Control.Applicative (optional, (<|>))
|
||||
import Data.Aeson (ToJSON)
|
||||
import Data.Aeson (FromJSON, ToJSON)
|
||||
import qualified Data.Aeson as J
|
||||
import Data.Attoparsec.Text (Parser)
|
||||
import qualified Data.Attoparsec.Text as A
|
||||
@@ -56,6 +57,9 @@ data Format
|
||||
data SimplexLinkType = XLContact | XLInvitation | XLGroup
|
||||
deriving (Eq, Show, Generic)
|
||||
|
||||
instance FromJSON SimplexLinkType where
|
||||
parseJSON = J.genericParseJSON . enumJSON $ dropPrefix "XL"
|
||||
|
||||
instance ToJSON SimplexLinkType where
|
||||
toJSON = J.genericToJSON . enumJSON $ dropPrefix "XL"
|
||||
toEncoding = J.genericToEncoding . enumJSON $ dropPrefix "XL"
|
||||
@@ -66,6 +70,9 @@ colored = Colored . FormatColor
|
||||
markdown :: Format -> Text -> Markdown
|
||||
markdown = Markdown . Just
|
||||
|
||||
instance FromJSON Format where
|
||||
parseJSON = J.genericParseJSON $ sumTypeJSON fstToLower
|
||||
|
||||
instance ToJSON Format where
|
||||
toJSON = J.genericToJSON $ sumTypeJSON fstToLower
|
||||
toEncoding = J.genericToEncoding $ sumTypeJSON fstToLower
|
||||
@@ -91,6 +98,18 @@ instance IsString Markdown where fromString = unmarked . T.pack
|
||||
newtype FormatColor = FormatColor Color
|
||||
deriving (Eq, Show)
|
||||
|
||||
instance FromJSON FormatColor where
|
||||
parseJSON = J.withText "FormatColor" $ fmap FormatColor . \case
|
||||
"red" -> pure Red
|
||||
"green" -> pure Green
|
||||
"blue" -> pure Blue
|
||||
"yellow" -> pure Yellow
|
||||
"cyan" -> pure Cyan
|
||||
"magenta" -> pure Magenta
|
||||
"black" -> pure Black
|
||||
"white" -> pure White
|
||||
unexpected -> fail $ "unexpected FormatColor: " <> show unexpected
|
||||
|
||||
instance ToJSON FormatColor where
|
||||
toJSON (FormatColor c) = case c of
|
||||
Red -> "red"
|
||||
@@ -103,7 +122,7 @@ instance ToJSON FormatColor where
|
||||
White -> "white"
|
||||
|
||||
data FormattedText = FormattedText {format :: Maybe Format, text :: Text}
|
||||
deriving (Eq, Show, Generic)
|
||||
deriving (Eq, Show, Generic, FromJSON)
|
||||
|
||||
instance ToJSON FormattedText where
|
||||
toEncoding = J.genericToEncoding J.defaultOptions {J.omitNothingFields = True}
|
||||
@@ -129,7 +148,7 @@ parseMaybeMarkdownList s
|
||||
| otherwise = Just . reverse $ foldl' acc [] ml
|
||||
where
|
||||
ml = intercalate ["\n"] . map (markdownToList . parseMarkdown) $ T.lines s
|
||||
acc [] m = [m]
|
||||
acc [] m = [m]
|
||||
acc ms@(FormattedText f t : ms') ft@(FormattedText f' t')
|
||||
| f == f' = FormattedText f (t <> t') : ms'
|
||||
| otherwise = ft : ms
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
module Simplex.Chat.Messages where
|
||||
|
||||
import Control.Applicative ((<|>))
|
||||
import Data.Aeson (FromJSON, ToJSON)
|
||||
import Data.Aeson (FromJSON, ToJSON, (.:))
|
||||
import qualified Data.Aeson as J
|
||||
import qualified Data.Aeson.Encoding as JE
|
||||
import qualified Data.Attoparsec.ByteString.Char8 as A
|
||||
@@ -66,6 +66,9 @@ chatNameStr (ChatName cType name) = chatTypeStr cType <> T.unpack name
|
||||
data ChatRef = ChatRef ChatType Int64
|
||||
deriving (Eq, Show, Ord)
|
||||
|
||||
instance FromJSON ChatType where
|
||||
parseJSON = J.genericParseJSON . sumTypeJSON $ dropPrefix "CT"
|
||||
|
||||
instance ToJSON ChatType where
|
||||
toJSON = J.genericToJSON . enumJSON $ dropPrefix "CT"
|
||||
toEncoding = J.genericToEncoding . enumJSON $ dropPrefix "CT"
|
||||
@@ -110,10 +113,16 @@ data JSONChatInfo
|
||||
| JCInfoContactConnection {contactConnection :: PendingContactConnection}
|
||||
deriving (Generic)
|
||||
|
||||
instance FromJSON JSONChatInfo where
|
||||
parseJSON = J.genericParseJSON . sumTypeJSON $ dropPrefix "JCInfo"
|
||||
|
||||
instance ToJSON JSONChatInfo where
|
||||
toJSON = J.genericToJSON . sumTypeJSON $ dropPrefix "JCInfo"
|
||||
toEncoding = J.genericToEncoding . sumTypeJSON $ dropPrefix "JCInfo"
|
||||
|
||||
instance ChatTypeI c => FromJSON (ChatInfo c) where
|
||||
parseJSON v = (\(AChatInfo _ c) -> checkChatType c) <$?> J.parseJSON v
|
||||
|
||||
instance ToJSON (ChatInfo c) where
|
||||
toJSON = J.toJSON . jsonChatInfo
|
||||
toEncoding = J.toEncoding . jsonChatInfo
|
||||
@@ -125,10 +134,20 @@ jsonChatInfo = \case
|
||||
ContactRequest g -> JCInfoContactRequest g
|
||||
ContactConnection c -> JCInfoContactConnection c
|
||||
|
||||
data AChatInfo = forall c. AChatInfo (SChatType c) (ChatInfo c)
|
||||
data AChatInfo = forall c. ChatTypeI c => AChatInfo (SChatType c) (ChatInfo c)
|
||||
|
||||
deriving instance Show AChatInfo
|
||||
|
||||
jsonAChatInfo :: JSONChatInfo -> AChatInfo
|
||||
jsonAChatInfo = \case
|
||||
JCInfoDirect c -> AChatInfo SCTDirect $ DirectChat c
|
||||
JCInfoGroup g -> AChatInfo SCTGroup $ GroupChat g
|
||||
JCInfoContactRequest g -> AChatInfo SCTContactRequest $ ContactRequest g
|
||||
JCInfoContactConnection c -> AChatInfo SCTContactConnection $ ContactConnection c
|
||||
|
||||
instance FromJSON AChatInfo where
|
||||
parseJSON v = jsonAChatInfo <$> J.parseJSON v
|
||||
|
||||
instance ToJSON AChatInfo where
|
||||
toJSON (AChatInfo _ c) = J.toJSON c
|
||||
toEncoding (AChatInfo _ c) = J.toEncoding c
|
||||
@@ -144,7 +163,10 @@ data ChatItem (c :: ChatType) (d :: MsgDirection) = ChatItem
|
||||
}
|
||||
deriving (Show, Generic)
|
||||
|
||||
instance MsgDirectionI d => ToJSON (ChatItem c d) where
|
||||
instance (ChatTypeI c, MsgDirectionI d) => FromJSON (ChatItem c d) where
|
||||
parseJSON = J.genericParseJSON J.defaultOptions
|
||||
|
||||
instance (ChatTypeI c, MsgDirectionI d) => ToJSON (ChatItem c d) where
|
||||
toJSON = J.genericToJSON J.defaultOptions {J.omitNothingFields = True}
|
||||
toEncoding = J.genericToEncoding J.defaultOptions {J.omitNothingFields = True}
|
||||
|
||||
@@ -156,6 +178,16 @@ data CIDirection (c :: ChatType) (d :: MsgDirection) where
|
||||
|
||||
deriving instance Show (CIDirection c d)
|
||||
|
||||
data CCIDirection c = forall d. MsgDirectionI d => CCID (SMsgDirection d) (CIDirection c d)
|
||||
|
||||
instance ChatTypeI c => FromJSON (CCIDirection c) where
|
||||
parseJSON v = (\(ACID _ d x) -> checkChatType (CCID d x)) <$?> J.parseJSON v
|
||||
|
||||
data ACIDirection = forall c d. (ChatTypeI c, MsgDirectionI d) => ACID (SChatType c) (SMsgDirection d) (CIDirection c d)
|
||||
|
||||
instance FromJSON ACIDirection where
|
||||
parseJSON v = jsonACIDirection <$> J.parseJSON v
|
||||
|
||||
data JSONCIDirection
|
||||
= JCIDirectSnd
|
||||
| JCIDirectRcv
|
||||
@@ -163,10 +195,16 @@ data JSONCIDirection
|
||||
| JCIGroupRcv {groupMember :: GroupMember}
|
||||
deriving (Generic, Show)
|
||||
|
||||
instance FromJSON JSONCIDirection where
|
||||
parseJSON = J.genericParseJSON . sumTypeJSON $ dropPrefix "JCI"
|
||||
|
||||
instance ToJSON JSONCIDirection where
|
||||
toJSON = J.genericToJSON . sumTypeJSON $ dropPrefix "JCI"
|
||||
toEncoding = J.genericToEncoding . sumTypeJSON $ dropPrefix "JCI"
|
||||
|
||||
instance (ChatTypeI c, MsgDirectionI d) => FromJSON (CIDirection c d) where
|
||||
parseJSON v = (\(CCID _ x') -> checkDirection x') <$?> J.parseJSON v
|
||||
|
||||
instance ToJSON (CIDirection c d) where
|
||||
toJSON = J.toJSON . jsonCIDirection
|
||||
toEncoding = J.toEncoding . jsonCIDirection
|
||||
@@ -178,8 +216,15 @@ jsonCIDirection = \case
|
||||
CIGroupSnd -> JCIGroupSnd
|
||||
CIGroupRcv m -> JCIGroupRcv m
|
||||
|
||||
jsonACIDirection :: JSONCIDirection -> ACIDirection
|
||||
jsonACIDirection = \case
|
||||
JCIDirectSnd -> ACID SCTDirect SMDSnd CIDirectSnd
|
||||
JCIDirectRcv -> ACID SCTDirect SMDRcv CIDirectRcv
|
||||
JCIGroupSnd -> ACID SCTGroup SMDSnd CIGroupSnd
|
||||
JCIGroupRcv m -> ACID SCTGroup SMDRcv $ CIGroupRcv m
|
||||
|
||||
data CIReactionCount = CIReactionCount {reaction :: MsgReaction, userReacted :: Bool, totalReacted :: Int}
|
||||
deriving (Show, Generic)
|
||||
deriving (Show, Generic, FromJSON)
|
||||
|
||||
instance ToJSON CIReactionCount where toEncoding = J.genericToEncoding J.defaultOptions
|
||||
|
||||
@@ -187,7 +232,15 @@ data CChatItem c = forall d. MsgDirectionI d => CChatItem (SMsgDirection d) (Cha
|
||||
|
||||
deriving instance Show (CChatItem c)
|
||||
|
||||
instance ToJSON (CChatItem c) where
|
||||
instance forall c. ChatTypeI c => FromJSON (CChatItem c) where
|
||||
parseJSON v = J.withObject "CChatItem" parse v
|
||||
where
|
||||
parse o = do
|
||||
CCID d (_ :: CIDirection c d) <- o .: "chatDir"
|
||||
ci <- J.parseJSON @(ChatItem c d) v
|
||||
pure $ CChatItem d ci
|
||||
|
||||
instance ChatTypeI c => ToJSON (CChatItem c) where
|
||||
toJSON (CChatItem _ ci) = J.toJSON ci
|
||||
toEncoding (CChatItem _ ci) = J.toEncoding ci
|
||||
|
||||
@@ -279,14 +332,19 @@ data Chat c = Chat
|
||||
}
|
||||
deriving (Show, Generic)
|
||||
|
||||
instance ToJSON (Chat c) where
|
||||
toJSON = J.genericToJSON J.defaultOptions
|
||||
toEncoding = J.genericToEncoding J.defaultOptions
|
||||
instance ChatTypeI c => ToJSON (Chat c) where toEncoding = J.genericToEncoding J.defaultOptions
|
||||
|
||||
data AChat = forall c. AChat (SChatType c) (Chat c)
|
||||
data AChat = forall c. ChatTypeI c => AChat (SChatType c) (Chat c)
|
||||
|
||||
deriving instance Show AChat
|
||||
|
||||
instance FromJSON AChat where
|
||||
parseJSON = J.withObject "AChat" $ \o -> do
|
||||
AChatInfo c chatInfo <- o .: "chatInfo"
|
||||
chatItems <- o .: "chatItems"
|
||||
chatStats <- o .: "chatStats"
|
||||
pure $ AChat c Chat {chatInfo, chatItems, chatStats}
|
||||
|
||||
instance ToJSON AChat where
|
||||
toJSON (AChat _ c) = J.toJSON c
|
||||
toEncoding (AChat _ c) = J.toEncoding c
|
||||
@@ -296,17 +354,21 @@ data ChatStats = ChatStats
|
||||
minUnreadItemId :: ChatItemId,
|
||||
unreadChat :: Bool
|
||||
}
|
||||
deriving (Show, Generic)
|
||||
deriving (Show, Generic, FromJSON)
|
||||
|
||||
instance ToJSON ChatStats where
|
||||
toJSON = J.genericToJSON J.defaultOptions
|
||||
toEncoding = J.genericToEncoding J.defaultOptions
|
||||
instance ToJSON ChatStats where toEncoding = J.genericToEncoding J.defaultOptions
|
||||
|
||||
-- | type to show a mix of messages from multiple chats
|
||||
data AChatItem = forall c d. MsgDirectionI d => AChatItem (SChatType c) (SMsgDirection d) (ChatInfo c) (ChatItem c d)
|
||||
data AChatItem = forall c d. (ChatTypeI c, MsgDirectionI d) => AChatItem (SChatType c) (SMsgDirection d) (ChatInfo c) (ChatItem c d)
|
||||
|
||||
deriving instance Show AChatItem
|
||||
|
||||
instance FromJSON AChatItem where
|
||||
parseJSON = J.withObject "AChatItem" $ \o -> do
|
||||
AChatInfo c chatInfo <- o .: "chatInfo"
|
||||
CChatItem d chatItem <- o .: "chatItem"
|
||||
pure $ AChatItem c d chatInfo chatItem
|
||||
|
||||
instance ToJSON AChatItem where
|
||||
toJSON (AChatItem _ _ chat item) = J.toJSON $ JSONAnyChatItem chat item
|
||||
toEncoding (AChatItem _ _ chat item) = J.toEncoding $ JSONAnyChatItem chat item
|
||||
@@ -330,7 +392,7 @@ updateFileStatus ci@ChatItem {file} status = case file of
|
||||
Just f -> ci {file = Just (f :: CIFile d) {fileStatus = status}}
|
||||
Nothing -> ci
|
||||
|
||||
instance MsgDirectionI d => ToJSON (JSONAnyChatItem c d) where
|
||||
instance (ChatTypeI c, MsgDirectionI d) => ToJSON (JSONAnyChatItem c d) where
|
||||
toJSON = J.genericToJSON J.defaultOptions
|
||||
toEncoding = J.genericToEncoding J.defaultOptions
|
||||
|
||||
@@ -349,7 +411,7 @@ data CIMeta (c :: ChatType) (d :: MsgDirection) = CIMeta
|
||||
createdAt :: UTCTime,
|
||||
updatedAt :: UTCTime
|
||||
}
|
||||
deriving (Show, Generic)
|
||||
deriving (Show, Generic, FromJSON)
|
||||
|
||||
mkCIMeta :: ChatItemId -> CIContent d -> Text -> CIStatus d -> Maybe SharedMsgId -> Maybe (CIDeleted c) -> Bool -> Maybe CITimed -> Maybe Bool -> UTCTime -> ChatItemTs -> UTCTime -> UTCTime -> CIMeta c d
|
||||
mkCIMeta itemId itemContent itemText itemStatus itemSharedMsgId itemDeleted itemEdited itemTimed itemLive currentTs itemTs createdAt updatedAt =
|
||||
@@ -358,13 +420,13 @@ mkCIMeta itemId itemContent itemText itemStatus itemSharedMsgId itemDeleted item
|
||||
_ -> False
|
||||
in CIMeta {itemId, itemTs, itemText, itemStatus, itemSharedMsgId, itemDeleted, itemEdited, itemTimed, itemLive, editable, createdAt, updatedAt}
|
||||
|
||||
instance ToJSON (CIMeta c d) where toEncoding = J.genericToEncoding J.defaultOptions
|
||||
instance ChatTypeI c => ToJSON (CIMeta c d) where toEncoding = J.genericToEncoding J.defaultOptions
|
||||
|
||||
data CITimed = CITimed
|
||||
{ ttl :: Int, -- seconds
|
||||
deleteAt :: Maybe UTCTime -- this is initially Nothing for received items, the timer starts when they are read
|
||||
}
|
||||
deriving (Show, Generic)
|
||||
deriving (Show, Generic, FromJSON)
|
||||
|
||||
instance ToJSON CITimed where toEncoding = J.genericToEncoding J.defaultOptions
|
||||
|
||||
@@ -402,6 +464,9 @@ data CIQuote (c :: ChatType) = CIQuote
|
||||
}
|
||||
deriving (Show, Generic)
|
||||
|
||||
instance ChatTypeI c => FromJSON (CIQuote c) where
|
||||
parseJSON = J.genericParseJSON J.defaultOptions
|
||||
|
||||
instance ToJSON (CIQuote c) where
|
||||
toJSON = J.genericToJSON J.defaultOptions {J.omitNothingFields = True}
|
||||
toEncoding = J.genericToEncoding J.defaultOptions {J.omitNothingFields = True}
|
||||
@@ -414,24 +479,39 @@ data CIReaction (c :: ChatType) (d :: MsgDirection) = CIReaction
|
||||
}
|
||||
deriving (Show, Generic)
|
||||
|
||||
instance ToJSON (CIReaction c d) where
|
||||
toJSON = J.genericToJSON J.defaultOptions {J.omitNothingFields = True}
|
||||
toEncoding = J.genericToEncoding J.defaultOptions {J.omitNothingFields = True}
|
||||
instance (ChatTypeI c, MsgDirectionI d) => FromJSON (CIReaction c d) where
|
||||
parseJSON = J.genericParseJSON J.defaultOptions
|
||||
|
||||
data ACIReaction = forall c d. ACIReaction (SChatType c) (SMsgDirection d) (ChatInfo c) (CIReaction c d)
|
||||
instance ChatTypeI c => ToJSON (CIReaction c d) where
|
||||
toEncoding = J.genericToEncoding J.defaultOptions
|
||||
|
||||
data AnyCIReaction = forall c d. ChatTypeI c => ACIR (SChatType c) (SMsgDirection d) (CIReaction c d)
|
||||
|
||||
instance FromJSON AnyCIReaction where
|
||||
parseJSON v = J.withObject "AnyCIReaction" parse v
|
||||
where
|
||||
parse o = do
|
||||
ACID c d (_ :: CIDirection c d) <- o .: "chatDir"
|
||||
ACIR c d <$> J.parseJSON @(CIReaction c d) v
|
||||
|
||||
data ACIReaction = forall c d. ChatTypeI c => ACIReaction (SChatType c) (SMsgDirection d) (ChatInfo c) (CIReaction c d)
|
||||
|
||||
deriving instance Show ACIReaction
|
||||
|
||||
instance FromJSON ACIReaction where
|
||||
parseJSON = J.withObject "ACIReaction" $ \o -> do
|
||||
ACIR c d reaction <- o .: "chatReaction"
|
||||
cInfo <- o .: "chatInfo"
|
||||
pure $ ACIReaction c d cInfo reaction
|
||||
|
||||
instance ToJSON ACIReaction where
|
||||
toJSON (ACIReaction _ _ chat reaction) = J.toJSON $ JSONCIReaction chat reaction
|
||||
toEncoding (ACIReaction _ _ chat reaction) = J.toEncoding $ JSONCIReaction chat reaction
|
||||
toJSON (ACIReaction _ _ cInfo reaction) = J.toJSON $ JSONCIReaction cInfo reaction
|
||||
toEncoding (ACIReaction _ _ cInfo reaction) = J.toEncoding $ JSONCIReaction cInfo reaction
|
||||
|
||||
data JSONCIReaction c d = JSONCIReaction {chatInfo :: ChatInfo c, chatReaction :: CIReaction c d}
|
||||
deriving (Generic)
|
||||
|
||||
instance ToJSON (JSONCIReaction c d) where
|
||||
toJSON = J.genericToJSON J.defaultOptions
|
||||
toEncoding = J.genericToEncoding J.defaultOptions
|
||||
instance ChatTypeI c => ToJSON (JSONCIReaction c d) where toEncoding = J.genericToEncoding J.defaultOptions
|
||||
|
||||
data CIQDirection (c :: ChatType) where
|
||||
CIQDirectSnd :: CIQDirection 'CTDirect
|
||||
@@ -441,6 +521,11 @@ data CIQDirection (c :: ChatType) where
|
||||
|
||||
deriving instance Show (CIQDirection c)
|
||||
|
||||
data ACIQDirection = forall c. ChatTypeI c => ACIQDirection (SChatType c) (CIQDirection c)
|
||||
|
||||
instance ChatTypeI c => FromJSON (CIQDirection c) where
|
||||
parseJSON v = (\(ACIQDirection _ x) -> checkChatType x) . jsonACIQDirection <$?> J.parseJSON v
|
||||
|
||||
instance ToJSON (CIQDirection c) where
|
||||
toJSON = J.toJSON . jsonCIQDirection
|
||||
toEncoding = J.toEncoding . jsonCIQDirection
|
||||
@@ -453,6 +538,14 @@ jsonCIQDirection = \case
|
||||
CIQGroupRcv (Just m) -> Just $ JCIGroupRcv m
|
||||
CIQGroupRcv Nothing -> Nothing
|
||||
|
||||
jsonACIQDirection :: Maybe JSONCIDirection -> ACIQDirection
|
||||
jsonACIQDirection = \case
|
||||
Just JCIDirectSnd -> ACIQDirection SCTDirect CIQDirectSnd
|
||||
Just JCIDirectRcv -> ACIQDirection SCTDirect CIQDirectRcv
|
||||
Just JCIGroupSnd -> ACIQDirection SCTGroup CIQGroupSnd
|
||||
Just (JCIGroupRcv m) -> ACIQDirection SCTGroup $ CIQGroupRcv (Just m)
|
||||
Nothing -> ACIQDirection SCTGroup $ CIQGroupRcv Nothing
|
||||
|
||||
quoteMsgDirection :: CIQDirection c -> MsgDirection
|
||||
quoteMsgDirection = \case
|
||||
CIQDirectSnd -> MDSnd
|
||||
@@ -470,6 +563,9 @@ data CIFile (d :: MsgDirection) = CIFile
|
||||
}
|
||||
deriving (Show, Generic)
|
||||
|
||||
instance MsgDirectionI d => FromJSON (CIFile d) where
|
||||
parseJSON = J.genericParseJSON J.defaultOptions
|
||||
|
||||
instance MsgDirectionI d => ToJSON (CIFile d) where
|
||||
toJSON = J.genericToJSON J.defaultOptions {J.omitNothingFields = True}
|
||||
toEncoding = J.genericToEncoding J.defaultOptions {J.omitNothingFields = True}
|
||||
@@ -481,6 +577,9 @@ instance FromField FileProtocol where fromField = fromTextField_ textDecode
|
||||
|
||||
instance ToField FileProtocol where toField = toField . textEncode
|
||||
|
||||
instance FromJSON FileProtocol where
|
||||
parseJSON = textParseJSON "FileProtocol"
|
||||
|
||||
instance ToJSON FileProtocol where
|
||||
toJSON = J.String . textEncode
|
||||
toEncoding = JE.text . textEncode
|
||||
@@ -527,6 +626,9 @@ ciFileEnded = \case
|
||||
CIFSRcvError -> True
|
||||
CIFSInvalid {} -> True
|
||||
|
||||
instance MsgDirectionI d => FromJSON (CIFileStatus d) where
|
||||
parseJSON v = (\(AFS _ s) -> checkDirection s) . aciFileStatusJSON <$?> J.parseJSON v
|
||||
|
||||
instance ToJSON (CIFileStatus d) where
|
||||
toJSON = J.toJSON . jsonCIFileStatus
|
||||
toEncoding = J.toEncoding . jsonCIFileStatus
|
||||
@@ -594,6 +696,9 @@ data JSONCIFileStatus
|
||||
| JCIFSInvalid {text :: Text}
|
||||
deriving (Generic)
|
||||
|
||||
instance FromJSON JSONCIFileStatus where
|
||||
parseJSON = J.genericParseJSON . sumTypeJSON $ dropPrefix "JCIFS"
|
||||
|
||||
instance ToJSON JSONCIFileStatus where
|
||||
toJSON = J.genericToJSON . sumTypeJSON $ dropPrefix "JCIFS"
|
||||
toEncoding = J.genericToEncoding . sumTypeJSON $ dropPrefix "JCIFS"
|
||||
@@ -658,6 +763,9 @@ deriving instance Eq (CIStatus d)
|
||||
|
||||
deriving instance Show (CIStatus d)
|
||||
|
||||
instance MsgDirectionI d => FromJSON (CIStatus d) where
|
||||
parseJSON v = (\(ACIStatus _ s) -> checkDirection s) . jsonACIStatus <$?> J.parseJSON v
|
||||
|
||||
instance ToJSON (CIStatus d) where
|
||||
toJSON = J.toJSON . jsonCIStatus
|
||||
toEncoding = J.toEncoding . jsonCIStatus
|
||||
@@ -712,6 +820,9 @@ data JSONCIStatus
|
||||
| JCISInvalid {text :: Text}
|
||||
deriving (Show, Generic)
|
||||
|
||||
instance FromJSON JSONCIStatus where
|
||||
parseJSON = J.genericParseJSON . sumTypeJSON $ dropPrefix "JCIS"
|
||||
|
||||
instance ToJSON JSONCIStatus where
|
||||
toJSON = J.genericToJSON . sumTypeJSON $ dropPrefix "JCIS"
|
||||
toEncoding = J.genericToEncoding . sumTypeJSON $ dropPrefix "JCIS"
|
||||
@@ -727,6 +838,17 @@ jsonCIStatus = \case
|
||||
CISRcvRead -> JCISRcvRead
|
||||
CISInvalid text -> JCISInvalid text
|
||||
|
||||
jsonACIStatus :: JSONCIStatus -> ACIStatus
|
||||
jsonACIStatus = \case
|
||||
JCISSndNew -> ACIStatus SMDSnd CISSndNew
|
||||
JCISSndSent sndProgress -> ACIStatus SMDSnd $ CISSndSent sndProgress
|
||||
JCISSndRcvd msgRcptStatus sndProgress -> ACIStatus SMDSnd $ CISSndRcvd msgRcptStatus sndProgress
|
||||
JCISSndErrorAuth -> ACIStatus SMDSnd CISSndErrorAuth
|
||||
JCISSndError e -> ACIStatus SMDSnd $ CISSndError e
|
||||
JCISRcvNew -> ACIStatus SMDRcv CISRcvNew
|
||||
JCISRcvRead -> ACIStatus SMDRcv CISRcvRead
|
||||
JCISInvalid text -> ACIStatus SMDSnd $ CISInvalid text
|
||||
|
||||
ciStatusNew :: forall d. MsgDirectionI d => CIStatus d
|
||||
ciStatusNew = case msgDirection @d of
|
||||
SMDSnd -> CISSndNew
|
||||
@@ -757,6 +879,9 @@ data SndCIStatusProgress
|
||||
| SSPComplete
|
||||
deriving (Eq, Show, Generic)
|
||||
|
||||
instance FromJSON SndCIStatusProgress where
|
||||
parseJSON = J.genericParseJSON . sumTypeJSON $ dropPrefix "SSP"
|
||||
|
||||
instance ToJSON SndCIStatusProgress where
|
||||
toJSON = J.genericToJSON . enumJSON $ dropPrefix "SSP"
|
||||
toEncoding = J.genericToEncoding . enumJSON $ dropPrefix "SSP"
|
||||
@@ -796,6 +921,8 @@ instance TestEquality SChatType where
|
||||
testEquality SCTContactConnection SCTContactConnection = Just Refl
|
||||
testEquality _ _ = Nothing
|
||||
|
||||
data AChatType = forall c. ChatTypeI c => ACT (SChatType c)
|
||||
|
||||
class ChatTypeI (c :: ChatType) where
|
||||
chatTypeI :: SChatType c
|
||||
|
||||
@@ -803,6 +930,36 @@ instance ChatTypeI 'CTDirect where chatTypeI = SCTDirect
|
||||
|
||||
instance ChatTypeI 'CTGroup where chatTypeI = SCTGroup
|
||||
|
||||
instance ChatTypeI 'CTContactRequest where chatTypeI = SCTContactRequest
|
||||
|
||||
instance ChatTypeI 'CTContactConnection where chatTypeI = SCTContactConnection
|
||||
|
||||
instance ChatTypeI c => FromJSON (SChatType c) where
|
||||
parseJSON v = (\(ACT t) -> checkChatType t) . aChatType <$?> J.parseJSON v
|
||||
|
||||
instance ToJSON (SChatType c) where
|
||||
toJSON = J.toJSON . toChatType
|
||||
toEncoding = J.toEncoding . toChatType
|
||||
|
||||
toChatType :: SChatType c -> ChatType
|
||||
toChatType = \case
|
||||
SCTDirect -> CTDirect
|
||||
SCTGroup -> CTGroup
|
||||
SCTContactRequest -> CTContactRequest
|
||||
SCTContactConnection -> CTContactConnection
|
||||
|
||||
aChatType :: ChatType -> AChatType
|
||||
aChatType = \case
|
||||
CTDirect -> ACT SCTDirect
|
||||
CTGroup -> ACT SCTGroup
|
||||
CTContactRequest -> ACT SCTContactRequest
|
||||
CTContactConnection -> ACT SCTContactConnection
|
||||
|
||||
checkChatType :: forall t c c'. (ChatTypeI c, ChatTypeI c') => t c' -> Either String (t c)
|
||||
checkChatType x = case testEquality (chatTypeI @c) (chatTypeI @c') of
|
||||
Just Refl -> Right x
|
||||
Nothing -> Left "bad chat type"
|
||||
|
||||
data NewMessage e = NewMessage
|
||||
{ chatMsgEvent :: ChatMsgEvent e,
|
||||
msgBody :: MsgBody
|
||||
@@ -920,35 +1077,43 @@ msgDeliveryStatusT' s =
|
||||
Just Refl -> Just st
|
||||
_ -> Nothing
|
||||
|
||||
checkDirection :: forall t d d'. (MsgDirectionI d, MsgDirectionI d') => t d' -> Either String (t d)
|
||||
checkDirection x = case testEquality (msgDirection @d) (msgDirection @d') of
|
||||
Just Refl -> Right x
|
||||
Nothing -> Left "bad direction"
|
||||
|
||||
data CIDeleted (c :: ChatType) where
|
||||
CIDeleted :: Maybe UTCTime -> CIDeleted c
|
||||
CIModerated :: Maybe UTCTime -> GroupMember -> CIDeleted 'CTGroup
|
||||
|
||||
deriving instance Show (CIDeleted c)
|
||||
|
||||
instance ToJSON (CIDeleted d) where
|
||||
data ACIDeleted = forall c. ChatTypeI c => ACIDeleted (SChatType c) (CIDeleted c)
|
||||
|
||||
instance ChatTypeI c => FromJSON (CIDeleted c) where
|
||||
parseJSON v = (\(ACIDeleted _ x) -> checkChatType x) . jsonACIDeleted <$?> J.parseJSON v
|
||||
|
||||
instance ChatTypeI c => ToJSON (CIDeleted c) where
|
||||
toJSON = J.toJSON . jsonCIDeleted
|
||||
toEncoding = J.toEncoding . jsonCIDeleted
|
||||
|
||||
data JSONCIDeleted
|
||||
= JCIDDeleted {deletedTs :: Maybe UTCTime}
|
||||
= JCIDDeleted {deletedTs :: Maybe UTCTime, chatType :: ChatType}
|
||||
| JCIDModerated {deletedTs :: Maybe UTCTime, byGroupMember :: GroupMember}
|
||||
deriving (Show, Generic)
|
||||
|
||||
instance FromJSON JSONCIDeleted where
|
||||
parseJSON = J.genericParseJSON . sumTypeJSON $ dropPrefix "JCID"
|
||||
|
||||
instance ToJSON JSONCIDeleted where
|
||||
toJSON = J.genericToJSON . sumTypeJSON $ dropPrefix "JCID"
|
||||
toEncoding = J.genericToEncoding . sumTypeJSON $ dropPrefix "JCID"
|
||||
|
||||
jsonCIDeleted :: CIDeleted d -> JSONCIDeleted
|
||||
jsonCIDeleted :: forall d. ChatTypeI d => CIDeleted d -> JSONCIDeleted
|
||||
jsonCIDeleted = \case
|
||||
CIDeleted ts -> JCIDDeleted ts
|
||||
CIDeleted ts -> JCIDDeleted ts (toChatType $ chatTypeI @d)
|
||||
CIModerated ts m -> JCIDModerated ts m
|
||||
|
||||
jsonACIDeleted :: JSONCIDeleted -> ACIDeleted
|
||||
jsonACIDeleted = \case
|
||||
JCIDDeleted ts cType -> case aChatType cType of ACT c -> ACIDeleted c $ CIDeleted ts
|
||||
JCIDModerated ts m -> ACIDeleted SCTGroup (CIModerated ts m)
|
||||
|
||||
itemDeletedTs :: CIDeleted d -> Maybe UTCTime
|
||||
itemDeletedTs = \case
|
||||
CIDeleted ts -> ts
|
||||
@@ -958,7 +1123,7 @@ data ChatItemInfo = ChatItemInfo
|
||||
{ itemVersions :: [ChatItemVersion],
|
||||
memberDeliveryStatuses :: Maybe [MemberDeliveryStatus]
|
||||
}
|
||||
deriving (Eq, Show, Generic)
|
||||
deriving (Eq, Show, Generic, FromJSON)
|
||||
|
||||
instance ToJSON ChatItemInfo where toEncoding = J.genericToEncoding J.defaultOptions
|
||||
|
||||
@@ -969,7 +1134,7 @@ data ChatItemVersion = ChatItemVersion
|
||||
itemVersionTs :: UTCTime,
|
||||
createdAt :: UTCTime
|
||||
}
|
||||
deriving (Eq, Show, Generic)
|
||||
deriving (Eq, Show, Generic, FromJSON)
|
||||
|
||||
instance ToJSON ChatItemVersion where toEncoding = J.genericToEncoding J.defaultOptions
|
||||
|
||||
@@ -990,7 +1155,7 @@ data MemberDeliveryStatus = MemberDeliveryStatus
|
||||
{ groupMemberId :: GroupMemberId,
|
||||
memberDeliveryStatus :: CIStatus 'MDSnd
|
||||
}
|
||||
deriving (Eq, Show, Generic)
|
||||
deriving (Eq, Show, Generic, FromJSON)
|
||||
|
||||
instance ToJSON MemberDeliveryStatus where toEncoding = J.genericToEncoding J.defaultOptions
|
||||
|
||||
|
||||
@@ -9,12 +9,14 @@
|
||||
{-# LANGUAGE OverloadedStrings #-}
|
||||
{-# LANGUAGE ScopedTypeVariables #-}
|
||||
{-# LANGUAGE StandaloneDeriving #-}
|
||||
{-# LANGUAGE TemplateHaskell #-}
|
||||
{-# LANGUAGE TypeApplications #-}
|
||||
|
||||
module Simplex.Chat.Messages.CIContent where
|
||||
|
||||
import Data.Aeson (FromJSON, ToJSON)
|
||||
import qualified Data.Aeson as J
|
||||
import qualified Data.Aeson.TH as JQ
|
||||
import Data.Int (Int64)
|
||||
import Data.Text (Text)
|
||||
import Data.Text.Encoding (decodeLatin1, encodeUtf8)
|
||||
@@ -34,7 +36,7 @@ import Simplex.Chat.Types.Util
|
||||
import Simplex.Messaging.Agent.Protocol (MsgErrorType (..), RatchetSyncState (..), SwitchPhase (..))
|
||||
import Simplex.Messaging.Encoding.String
|
||||
import Simplex.Messaging.Parsers (dropPrefix, enumJSON, fstToLower, singleFieldJSON, sumTypeJSON)
|
||||
import Simplex.Messaging.Util (safeDecodeUtf8, tshow)
|
||||
import Simplex.Messaging.Util (safeDecodeUtf8, tshow, (<$?>))
|
||||
|
||||
data MsgDirection = MDRcv | MDSnd
|
||||
deriving (Eq, Show, Generic)
|
||||
@@ -69,6 +71,13 @@ instance TestEquality SMsgDirection where
|
||||
testEquality SMDSnd SMDSnd = Just Refl
|
||||
testEquality _ _ = Nothing
|
||||
|
||||
instance MsgDirectionI d => FromJSON (SMsgDirection d) where
|
||||
parseJSON v = (\(AMsgDirection d) -> checkDirection d) . fromMsgDirection <$?> J.parseJSON v
|
||||
|
||||
instance ToJSON (SMsgDirection d) where
|
||||
toJSON = J.toJSON . toMsgDirection
|
||||
toEncoding = J.toEncoding . toMsgDirection
|
||||
|
||||
instance ToField (SMsgDirection d) where toField = toField . msgDirectionInt . toMsgDirection
|
||||
|
||||
data AMsgDirection = forall d. MsgDirectionI d => AMsgDirection (SMsgDirection d)
|
||||
@@ -92,6 +101,11 @@ instance MsgDirectionI 'MDRcv where msgDirection = SMDRcv
|
||||
|
||||
instance MsgDirectionI 'MDSnd where msgDirection = SMDSnd
|
||||
|
||||
checkDirection :: forall t d d'. (MsgDirectionI d, MsgDirectionI d') => t d' -> Either String (t d)
|
||||
checkDirection x = case testEquality (msgDirection @d) (msgDirection @d') of
|
||||
Just Refl -> Right x
|
||||
Nothing -> Left "bad direction"
|
||||
|
||||
msgDirectionInt :: MsgDirection -> Int
|
||||
msgDirectionInt = \case
|
||||
MDRcv -> 0
|
||||
@@ -481,27 +495,10 @@ msgDirToModeratedContent_ = \case
|
||||
ciModeratedText :: Text
|
||||
ciModeratedText = "moderated"
|
||||
|
||||
-- platform independent
|
||||
instance MsgDirectionI d => ToField (CIContent d) where
|
||||
toField = toField . encodeJSON . dbJsonCIContent
|
||||
|
||||
-- platform specific
|
||||
instance MsgDirectionI d => ToJSON (CIContent d) where
|
||||
toJSON = J.toJSON . jsonCIContent
|
||||
toEncoding = J.toEncoding . jsonCIContent
|
||||
|
||||
data ACIContent = forall d. MsgDirectionI d => ACIContent (SMsgDirection d) (CIContent d)
|
||||
|
||||
deriving instance Show ACIContent
|
||||
|
||||
-- platform independent
|
||||
dbParseACIContent :: Text -> Either String ACIContent
|
||||
dbParseACIContent = fmap aciContentDBJSON . J.eitherDecodeStrict' . encodeUtf8
|
||||
|
||||
-- platform specific
|
||||
instance FromJSON ACIContent where
|
||||
parseJSON = fmap aciContentJSON . J.parseJSON
|
||||
|
||||
-- platform specific
|
||||
data JSONCIContent
|
||||
= JCISndMsgContent {msgContent :: MsgContent}
|
||||
@@ -527,17 +524,9 @@ data JSONCIContent
|
||||
| JCISndGroupFeature {groupFeature :: GroupFeature, preference :: GroupPreference, param :: Maybe Int}
|
||||
| JCIRcvChatFeatureRejected {feature :: ChatFeature}
|
||||
| JCIRcvGroupFeatureRejected {groupFeature :: GroupFeature}
|
||||
| JCISndModerated
|
||||
| JCIRcvModerated
|
||||
| JCISndModerated {_nullary :: Maybe Int}
|
||||
| JCIRcvModerated {_nullary :: Maybe Int}
|
||||
| JCIInvalidJSON {direction :: MsgDirection, json :: Text}
|
||||
deriving (Generic)
|
||||
|
||||
instance FromJSON JSONCIContent where
|
||||
parseJSON = J.genericParseJSON . sumTypeJSON $ dropPrefix "JCI"
|
||||
|
||||
instance ToJSON JSONCIContent where
|
||||
toJSON = J.genericToJSON . sumTypeJSON $ dropPrefix "JCI"
|
||||
toEncoding = J.genericToEncoding . sumTypeJSON $ dropPrefix "JCI"
|
||||
|
||||
jsonCIContent :: forall d. MsgDirectionI d => CIContent d -> JSONCIContent
|
||||
jsonCIContent = \case
|
||||
@@ -564,8 +553,8 @@ jsonCIContent = \case
|
||||
CISndGroupFeature groupFeature preference param -> JCISndGroupFeature {groupFeature, preference, param}
|
||||
CIRcvChatFeatureRejected feature -> JCIRcvChatFeatureRejected {feature}
|
||||
CIRcvGroupFeatureRejected groupFeature -> JCIRcvGroupFeatureRejected {groupFeature}
|
||||
CISndModerated -> JCISndModerated
|
||||
CIRcvModerated -> JCISndModerated
|
||||
CISndModerated -> JCISndModerated Nothing
|
||||
CIRcvModerated -> JCISndModerated Nothing
|
||||
CIInvalidJSON json -> JCIInvalidJSON (toMsgDirection $ msgDirection @d) json
|
||||
|
||||
aciContentJSON :: JSONCIContent -> ACIContent
|
||||
@@ -593,8 +582,8 @@ aciContentJSON = \case
|
||||
JCISndGroupFeature {groupFeature, preference, param} -> ACIContent SMDSnd $ CISndGroupFeature groupFeature preference param
|
||||
JCIRcvChatFeatureRejected {feature} -> ACIContent SMDRcv $ CIRcvChatFeatureRejected feature
|
||||
JCIRcvGroupFeatureRejected {groupFeature} -> ACIContent SMDRcv $ CIRcvGroupFeatureRejected groupFeature
|
||||
JCISndModerated -> ACIContent SMDSnd CISndModerated
|
||||
JCIRcvModerated -> ACIContent SMDRcv CIRcvModerated
|
||||
JCISndModerated _ -> ACIContent SMDSnd CISndModerated
|
||||
JCIRcvModerated _ -> ACIContent SMDRcv CIRcvModerated
|
||||
JCIInvalidJSON dir json -> case fromMsgDirection dir of
|
||||
AMsgDirection d -> ACIContent d $ CIInvalidJSON json
|
||||
|
||||
@@ -623,17 +612,9 @@ data DBJSONCIContent
|
||||
| DBJCISndGroupFeature {groupFeature :: GroupFeature, preference :: GroupPreference, param :: Maybe Int}
|
||||
| DBJCIRcvChatFeatureRejected {feature :: ChatFeature}
|
||||
| DBJCIRcvGroupFeatureRejected {groupFeature :: GroupFeature}
|
||||
| DBJCISndModerated
|
||||
| DBJCIRcvModerated
|
||||
| DBJCISndModerated {_nullary :: Maybe Int}
|
||||
| DBJCIRcvModerated {_nullary :: Maybe Int}
|
||||
| DBJCIInvalidJSON {direction :: MsgDirection, json :: Text}
|
||||
deriving (Generic)
|
||||
|
||||
instance FromJSON DBJSONCIContent where
|
||||
parseJSON = J.genericParseJSON . singleFieldJSON $ dropPrefix "DBJCI"
|
||||
|
||||
instance ToJSON DBJSONCIContent where
|
||||
toJSON = J.genericToJSON . singleFieldJSON $ dropPrefix "DBJCI"
|
||||
toEncoding = J.genericToEncoding . singleFieldJSON $ dropPrefix "DBJCI"
|
||||
|
||||
dbJsonCIContent :: forall d. MsgDirectionI d => CIContent d -> DBJSONCIContent
|
||||
dbJsonCIContent = \case
|
||||
@@ -660,8 +641,8 @@ dbJsonCIContent = \case
|
||||
CISndGroupFeature groupFeature preference param -> DBJCISndGroupFeature {groupFeature, preference, param}
|
||||
CIRcvChatFeatureRejected feature -> DBJCIRcvChatFeatureRejected {feature}
|
||||
CIRcvGroupFeatureRejected groupFeature -> DBJCIRcvGroupFeatureRejected {groupFeature}
|
||||
CISndModerated -> DBJCISndModerated
|
||||
CIRcvModerated -> DBJCIRcvModerated
|
||||
CISndModerated -> DBJCISndModerated Nothing
|
||||
CIRcvModerated -> DBJCIRcvModerated Nothing
|
||||
CIInvalidJSON json -> DBJCIInvalidJSON (toMsgDirection $ msgDirection @d) json
|
||||
|
||||
aciContentDBJSON :: DBJSONCIContent -> ACIContent
|
||||
@@ -689,8 +670,8 @@ aciContentDBJSON = \case
|
||||
DBJCISndGroupFeature {groupFeature, preference, param} -> ACIContent SMDSnd $ CISndGroupFeature groupFeature preference param
|
||||
DBJCIRcvChatFeatureRejected {feature} -> ACIContent SMDRcv $ CIRcvChatFeatureRejected feature
|
||||
DBJCIRcvGroupFeatureRejected {groupFeature} -> ACIContent SMDRcv $ CIRcvGroupFeatureRejected groupFeature
|
||||
DBJCISndModerated -> ACIContent SMDSnd CISndModerated
|
||||
DBJCIRcvModerated -> ACIContent SMDRcv CIRcvModerated
|
||||
DBJCISndModerated _ -> ACIContent SMDSnd CISndModerated
|
||||
DBJCIRcvModerated _ -> ACIContent SMDRcv CIRcvModerated
|
||||
DBJCIInvalidJSON dir json -> case fromMsgDirection dir of
|
||||
AMsgDirection d -> ACIContent d $ CIInvalidJSON json
|
||||
|
||||
@@ -703,14 +684,7 @@ data CICallStatus
|
||||
| CISCallProgress
|
||||
| CISCallEnded
|
||||
| CISCallError
|
||||
deriving (Show, Generic)
|
||||
|
||||
instance FromJSON CICallStatus where
|
||||
parseJSON = J.genericParseJSON . enumJSON $ dropPrefix "CISCall"
|
||||
|
||||
instance ToJSON CICallStatus where
|
||||
toJSON = J.genericToJSON . enumJSON $ dropPrefix "CISCall"
|
||||
toEncoding = J.genericToEncoding . enumJSON $ dropPrefix "CISCall"
|
||||
deriving (Show)
|
||||
|
||||
ciCallInfoText :: CICallStatus -> Int -> Text
|
||||
ciCallInfoText status duration = case status of
|
||||
@@ -722,3 +696,31 @@ ciCallInfoText status duration = case status of
|
||||
CISCallProgress -> "in progress " <> durationText duration
|
||||
CISCallEnded -> "ended " <> durationText duration
|
||||
CISCallError -> "error"
|
||||
|
||||
$(JQ.deriveJSON (enumJSON $ dropPrefix "CISCall") ''CICallStatus)
|
||||
|
||||
-- platform specific
|
||||
$(JQ.deriveJSON (sumTypeJSON $ dropPrefix "JCI") ''JSONCIContent)
|
||||
|
||||
-- platform independent
|
||||
$(JQ.deriveJSON (singleFieldJSON $ dropPrefix "DBJCI") ''DBJSONCIContent)
|
||||
|
||||
-- platform independent
|
||||
instance MsgDirectionI d => ToField (CIContent d) where
|
||||
toField = toField . encodeJSON . dbJsonCIContent
|
||||
|
||||
-- platform specific
|
||||
instance MsgDirectionI d => ToJSON (CIContent d) where
|
||||
toJSON = J.toJSON . jsonCIContent
|
||||
toEncoding = J.toEncoding . jsonCIContent
|
||||
|
||||
instance MsgDirectionI d => FromJSON (CIContent d) where
|
||||
parseJSON v = (\(ACIContent _ c) -> checkDirection c) <$?> J.parseJSON v
|
||||
|
||||
-- platform independent
|
||||
dbParseACIContent :: Text -> Either String ACIContent
|
||||
dbParseACIContent = fmap aciContentDBJSON . J.eitherDecodeStrict' . encodeUtf8
|
||||
|
||||
-- platform specific
|
||||
instance FromJSON ACIContent where
|
||||
parseJSON = fmap aciContentJSON . J.parseJSON
|
||||
|
||||
@@ -72,6 +72,9 @@ data ConnectionEntity
|
||||
| UserContactConnection {entityConnection :: Connection, userContact :: UserContact}
|
||||
deriving (Eq, Show, Generic)
|
||||
|
||||
instance FromJSON ConnectionEntity where
|
||||
parseJSON = J.genericParseJSON $ sumTypeJSON fstToLower
|
||||
|
||||
instance ToJSON ConnectionEntity where
|
||||
toJSON = J.genericToJSON $ sumTypeJSON fstToLower
|
||||
toEncoding = J.genericToEncoding $ sumTypeJSON fstToLower
|
||||
|
||||
@@ -201,7 +201,7 @@ startRemoteCtrl =
|
||||
chatWriteVar remoteCtrlSession Nothing
|
||||
toView $ CRRemoteCtrlStopped {remoteCtrlId}
|
||||
chatWriteVar remoteCtrlSession $ Just RemoteCtrlSession {discoverer, supervisor, hostServer = Nothing, discovered, accepted}
|
||||
pure CRRemoteCtrlStarted
|
||||
pure $ CRRemoteCtrlStarted Nothing
|
||||
|
||||
discoverRemoteCtrls :: (ChatMonad m) => TM.TMap C.KeyHash TransportHost -> m ()
|
||||
discoverRemoteCtrls discovered = Discovery.openListener >>= go
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
{-# LANGUAGE DeriveAnyClass #-}
|
||||
{-# LANGUAGE DeriveGeneric #-}
|
||||
{-# LANGUAGE DuplicateRecordFields #-}
|
||||
{-# LANGUAGE TemplateHaskell #-}
|
||||
|
||||
module Simplex.Chat.Remote.Types where
|
||||
|
||||
import Control.Concurrent.Async (Async)
|
||||
import Data.Aeson (ToJSON (..))
|
||||
import qualified Data.Aeson.TH as J
|
||||
import Data.Int (Int64)
|
||||
import Data.Text (Text)
|
||||
import GHC.Generics (Generic)
|
||||
import qualified Simplex.Messaging.Crypto as C
|
||||
import Simplex.Messaging.TMap (TMap)
|
||||
import Simplex.Messaging.Transport.Client (TransportHost)
|
||||
@@ -37,7 +37,9 @@ data RemoteCtrl = RemoteCtrl
|
||||
fingerprint :: C.KeyHash,
|
||||
accepted :: Maybe Bool
|
||||
}
|
||||
deriving (Show, Generic, ToJSON)
|
||||
deriving (Show)
|
||||
|
||||
$(J.deriveJSON J.defaultOptions ''RemoteCtrl)
|
||||
|
||||
data RemoteHostSession
|
||||
= RemoteHostSessionStarting
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
{-# LANGUAGE DeriveAnyClass #-}
|
||||
{-# LANGUAGE DeriveGeneric #-}
|
||||
{-# LANGUAGE DuplicateRecordFields #-}
|
||||
{-# LANGUAGE NamedFieldPuns #-}
|
||||
@@ -59,7 +60,7 @@ where
|
||||
import Control.Monad
|
||||
import Control.Monad.Except
|
||||
import Control.Monad.IO.Class
|
||||
import Data.Aeson (ToJSON)
|
||||
import Data.Aeson (FromJSON, ToJSON)
|
||||
import qualified Data.Aeson as J
|
||||
import Data.Functor (($>))
|
||||
import Data.Int (Int64)
|
||||
@@ -398,7 +399,7 @@ data UserContactLink = UserContactLink
|
||||
{ connReqContact :: ConnReqContact,
|
||||
autoAccept :: Maybe AutoAccept
|
||||
}
|
||||
deriving (Show, Generic)
|
||||
deriving (Show, Generic, FromJSON)
|
||||
|
||||
instance ToJSON UserContactLink where toEncoding = J.genericToEncoding J.defaultOptions
|
||||
|
||||
@@ -406,7 +407,7 @@ data AutoAccept = AutoAccept
|
||||
{ acceptIncognito :: IncognitoEnabled,
|
||||
autoReply :: Maybe MsgContent
|
||||
}
|
||||
deriving (Show, Generic)
|
||||
deriving (Show, Generic, FromJSON)
|
||||
|
||||
instance ToJSON AutoAccept where toEncoding = J.genericToEncoding J.defaultOptions
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ import Control.Monad
|
||||
import Control.Monad.Except
|
||||
import Control.Monad.IO.Class
|
||||
import Crypto.Random (ChaChaDRG, randomBytesGenerate)
|
||||
import Data.Aeson (ToJSON)
|
||||
import Data.Aeson (FromJSON, ToJSON)
|
||||
import qualified Data.Aeson as J
|
||||
import qualified Data.ByteString.Base64 as B64
|
||||
import Data.ByteString.Char8 (ByteString)
|
||||
@@ -102,6 +102,9 @@ data StoreError
|
||||
| SENoGroupSndStatus {itemId :: ChatItemId, groupMemberId :: GroupMemberId}
|
||||
deriving (Show, Exception, Generic)
|
||||
|
||||
instance FromJSON StoreError where
|
||||
parseJSON = J.genericParseJSON . sumTypeJSON $ dropPrefix "SE"
|
||||
|
||||
instance ToJSON StoreError where
|
||||
toJSON = J.genericToJSON . sumTypeJSON $ dropPrefix "SE"
|
||||
toEncoding = J.genericToEncoding . sumTypeJSON $ dropPrefix "SE"
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
{-# LANGUAGE PatternSynonyms #-}
|
||||
{-# LANGUAGE ScopedTypeVariables #-}
|
||||
{-# LANGUAGE StrictData #-}
|
||||
{-# LANGUAGE TemplateHaskell #-}
|
||||
{-# LANGUAGE TypeFamilyDependencies #-}
|
||||
{-# LANGUAGE UndecidableInstances #-}
|
||||
|
||||
@@ -25,9 +26,10 @@
|
||||
module Simplex.Chat.Types where
|
||||
|
||||
import Crypto.Number.Serialize (os2ip)
|
||||
import Data.Aeson (FromJSON (..), ToJSON (..), (.=))
|
||||
import Data.Aeson (FromJSON (..), ToJSON (..), (.:), (.=))
|
||||
import qualified Data.Aeson as J
|
||||
import qualified Data.Aeson.Encoding as JE
|
||||
import qualified Data.Aeson.TH as JQ
|
||||
import qualified Data.Aeson.Types as JT
|
||||
import qualified Data.Attoparsec.ByteString.Char8 as A
|
||||
import Data.ByteString.Char8 (ByteString, pack, unpack)
|
||||
@@ -112,18 +114,14 @@ data User = User
|
||||
sendRcptsContacts :: Bool,
|
||||
sendRcptsSmallGroups :: Bool
|
||||
}
|
||||
deriving (Show, Generic, FromJSON)
|
||||
|
||||
instance ToJSON User where
|
||||
toEncoding = J.genericToEncoding J.defaultOptions {J.omitNothingFields = True}
|
||||
toJSON = J.genericToJSON J.defaultOptions {J.omitNothingFields = True}
|
||||
deriving (Show)
|
||||
|
||||
data NewUser = NewUser
|
||||
{ profile :: Maybe Profile,
|
||||
sameServers :: Bool,
|
||||
pastTimestamp :: Bool
|
||||
}
|
||||
deriving (Show, Generic, FromJSON)
|
||||
deriving (Show)
|
||||
|
||||
newtype B64UrlByteString = B64UrlByteString ByteString
|
||||
deriving (Eq, Show)
|
||||
@@ -144,19 +142,13 @@ instance ToJSON B64UrlByteString where
|
||||
toEncoding = strToJEncoding
|
||||
|
||||
data UserPwdHash = UserPwdHash {hash :: B64UrlByteString, salt :: B64UrlByteString}
|
||||
deriving (Eq, Show, Generic, FromJSON)
|
||||
|
||||
instance ToJSON UserPwdHash where toEncoding = J.genericToEncoding J.defaultOptions
|
||||
deriving (Eq, Show)
|
||||
|
||||
data UserInfo = UserInfo
|
||||
{ user :: User,
|
||||
unreadCount :: Int
|
||||
}
|
||||
deriving (Show, Generic, FromJSON)
|
||||
|
||||
instance ToJSON UserInfo where
|
||||
toJSON = J.genericToJSON J.defaultOptions
|
||||
toEncoding = J.genericToEncoding J.defaultOptions
|
||||
deriving (Show)
|
||||
|
||||
type ContactId = Int64
|
||||
|
||||
@@ -179,11 +171,7 @@ data Contact = Contact
|
||||
contactGroupMemberId :: Maybe GroupMemberId,
|
||||
contactGrpInvSent :: Bool
|
||||
}
|
||||
deriving (Eq, Show, Generic)
|
||||
|
||||
instance ToJSON Contact where
|
||||
toJSON = J.genericToJSON J.defaultOptions {J.omitNothingFields = True}
|
||||
toEncoding = J.genericToEncoding J.defaultOptions {J.omitNothingFields = True}
|
||||
deriving (Eq, Show)
|
||||
|
||||
contactConn :: Contact -> Connection
|
||||
contactConn Contact {activeConn} = activeConn
|
||||
@@ -221,6 +209,9 @@ instance FromField ContactStatus where fromField = fromTextField_ textDecode
|
||||
|
||||
instance ToField ContactStatus where toField = toField . textEncode
|
||||
|
||||
instance FromJSON ContactStatus where
|
||||
parseJSON = textParseJSON "ContactStatus"
|
||||
|
||||
instance ToJSON ContactStatus where
|
||||
toJSON = J.String . textEncode
|
||||
toEncoding = JE.text . textEncode
|
||||
@@ -240,9 +231,7 @@ data ContactRef = ContactRef
|
||||
agentConnId :: AgentConnId,
|
||||
localDisplayName :: ContactName
|
||||
}
|
||||
deriving (Eq, Show, Generic)
|
||||
|
||||
instance ToJSON ContactRef where toEncoding = J.genericToEncoding J.defaultOptions
|
||||
deriving (Eq, Show)
|
||||
|
||||
data ContactOrGroupMember = CGMContact Contact | CGMGroupMember GroupInfo GroupMember
|
||||
deriving (Show)
|
||||
@@ -262,15 +251,13 @@ data UserContact = UserContact
|
||||
connReqContact :: ConnReqContact,
|
||||
groupId :: Maybe GroupId
|
||||
}
|
||||
deriving (Eq, Show, Generic)
|
||||
deriving (Eq, Show, Generic, FromJSON)
|
||||
|
||||
instance ToJSON UserContact where toEncoding = J.genericToEncoding J.defaultOptions
|
||||
|
||||
userContactGroupId :: UserContact -> Maybe GroupId
|
||||
userContactGroupId UserContact {groupId} = groupId
|
||||
|
||||
instance ToJSON UserContact where
|
||||
toJSON = J.genericToJSON J.defaultOptions
|
||||
toEncoding = J.genericToEncoding J.defaultOptions
|
||||
|
||||
data UserContactRequest = UserContactRequest
|
||||
{ contactRequestId :: Int64,
|
||||
agentInvitationId :: AgentInvId,
|
||||
@@ -284,7 +271,7 @@ data UserContactRequest = UserContactRequest
|
||||
updatedAt :: UTCTime,
|
||||
xContactId :: Maybe XContactId
|
||||
}
|
||||
deriving (Eq, Show, Generic)
|
||||
deriving (Eq, Show, Generic, FromJSON)
|
||||
|
||||
instance ToJSON UserContactRequest where
|
||||
toEncoding = J.genericToEncoding J.defaultOptions
|
||||
@@ -341,7 +328,7 @@ optionalFullName displayName fullName
|
||||
| otherwise = " (" <> fullName <> ")"
|
||||
|
||||
data Group = Group {groupInfo :: GroupInfo, members :: [GroupMember]}
|
||||
deriving (Eq, Show, Generic)
|
||||
deriving (Eq, Show, Generic, FromJSON)
|
||||
|
||||
instance ToJSON Group where toEncoding = J.genericToEncoding J.defaultOptions
|
||||
|
||||
@@ -359,7 +346,7 @@ data GroupInfo = GroupInfo
|
||||
updatedAt :: UTCTime,
|
||||
chatTs :: Maybe UTCTime
|
||||
}
|
||||
deriving (Eq, Show, Generic)
|
||||
deriving (Eq, Show, Generic, FromJSON)
|
||||
|
||||
instance ToJSON GroupInfo where toEncoding = J.genericToEncoding J.defaultOptions
|
||||
|
||||
@@ -369,7 +356,7 @@ groupName' GroupInfo {localDisplayName = g} = g
|
||||
data GroupSummary = GroupSummary
|
||||
{ currentMembers :: Int
|
||||
}
|
||||
deriving (Show, Generic)
|
||||
deriving (Show, Generic, FromJSON)
|
||||
|
||||
instance ToJSON GroupSummary where toEncoding = J.genericToEncoding J.defaultOptions
|
||||
|
||||
@@ -639,7 +626,7 @@ data GroupMember = GroupMember
|
||||
memberContactProfileId :: ProfileId,
|
||||
activeConn :: Maybe Connection
|
||||
}
|
||||
deriving (Eq, Show, Generic)
|
||||
deriving (Eq, Show, Generic, FromJSON)
|
||||
|
||||
instance ToJSON GroupMember where
|
||||
toJSON = J.genericToJSON J.defaultOptions {J.omitNothingFields = True}
|
||||
@@ -710,6 +697,9 @@ instance ToJSON MemberId where
|
||||
data InvitedBy = IBContact {byContactId :: Int64} | IBUser | IBUnknown
|
||||
deriving (Eq, Show, Generic)
|
||||
|
||||
instance FromJSON InvitedBy where
|
||||
parseJSON = J.genericParseJSON . sumTypeJSON $ dropPrefix "IB"
|
||||
|
||||
instance ToJSON InvitedBy where
|
||||
toJSON = J.genericToJSON . sumTypeJSON $ dropPrefix "IB"
|
||||
toEncoding = J.genericToEncoding . sumTypeJSON $ dropPrefix "IB"
|
||||
@@ -803,6 +793,9 @@ instance FromField GroupMemberCategory where fromField = fromTextField_ textDeco
|
||||
|
||||
instance ToField GroupMemberCategory where toField = toField . textEncode
|
||||
|
||||
instance FromJSON GroupMemberCategory where
|
||||
parseJSON = textParseJSON "GroupMemberCategory"
|
||||
|
||||
instance ToJSON GroupMemberCategory where
|
||||
toJSON = J.String . textEncode
|
||||
toEncoding = JE.text . textEncode
|
||||
@@ -840,6 +833,9 @@ instance FromField GroupMemberStatus where fromField = fromTextField_ textDecode
|
||||
|
||||
instance ToField GroupMemberStatus where toField = toField . textEncode
|
||||
|
||||
instance FromJSON GroupMemberStatus where
|
||||
parseJSON = textParseJSON "GroupMemberStatus"
|
||||
|
||||
instance ToJSON GroupMemberStatus where
|
||||
toJSON = J.String . textEncode
|
||||
toEncoding = JE.text . textEncode
|
||||
@@ -931,7 +927,7 @@ data SndFileTransfer = SndFileTransfer
|
||||
fileDescrId :: Maybe Int64,
|
||||
fileInline :: Maybe InlineFileMode
|
||||
}
|
||||
deriving (Eq, Show, Generic)
|
||||
deriving (Eq, Show, Generic, FromJSON)
|
||||
|
||||
instance ToJSON SndFileTransfer where toEncoding = J.genericToEncoding J.defaultOptions
|
||||
|
||||
@@ -997,7 +993,7 @@ instance FromField InlineFileMode where fromField = fromTextField_ textDecode
|
||||
instance ToField InlineFileMode where toField = toField . textEncode
|
||||
|
||||
instance FromJSON InlineFileMode where
|
||||
parseJSON = J.withText "InlineFileMode" $ maybe (fail "bad InlineFileMode") pure . textDecode
|
||||
parseJSON = textParseJSON "InlineFileMode"
|
||||
|
||||
instance ToJSON InlineFileMode where
|
||||
toJSON = J.String . textEncode
|
||||
@@ -1017,7 +1013,7 @@ data RcvFileTransfer = RcvFileTransfer
|
||||
-- SMP files are encrypted after all chunks are received
|
||||
cryptoArgs :: Maybe CryptoFileArgs
|
||||
}
|
||||
deriving (Eq, Show, Generic)
|
||||
deriving (Eq, Show, Generic, FromJSON)
|
||||
|
||||
instance ToJSON RcvFileTransfer where toEncoding = J.genericToEncoding J.defaultOptions
|
||||
|
||||
@@ -1026,7 +1022,7 @@ data XFTPRcvFile = XFTPRcvFile
|
||||
agentRcvFileId :: Maybe AgentRcvFileId,
|
||||
agentRcvFileDeleted :: Bool
|
||||
}
|
||||
deriving (Eq, Show, Generic)
|
||||
deriving (Eq, Show, Generic, FromJSON)
|
||||
|
||||
instance ToJSON XFTPRcvFile where toEncoding = J.genericToEncoding J.defaultOptions
|
||||
|
||||
@@ -1036,7 +1032,7 @@ data RcvFileDescr = RcvFileDescr
|
||||
fileDescrPartNo :: Int,
|
||||
fileDescrComplete :: Bool
|
||||
}
|
||||
deriving (Eq, Show, Generic)
|
||||
deriving (Eq, Show, Generic, FromJSON)
|
||||
|
||||
instance ToJSON RcvFileDescr where toEncoding = J.genericToEncoding J.defaultOptions
|
||||
|
||||
@@ -1048,6 +1044,9 @@ data RcvFileStatus
|
||||
| RFSCancelled (Maybe RcvFileInfo)
|
||||
deriving (Eq, Show, Generic)
|
||||
|
||||
instance FromJSON RcvFileStatus where
|
||||
parseJSON = J.genericParseJSON . sumTypeJSON $ dropPrefix "RFS"
|
||||
|
||||
instance ToJSON RcvFileStatus where
|
||||
toJSON = J.genericToJSON . sumTypeJSON $ dropPrefix "RFS"
|
||||
toEncoding = J.genericToEncoding . sumTypeJSON $ dropPrefix "RFS"
|
||||
@@ -1065,7 +1064,7 @@ data RcvFileInfo = RcvFileInfo
|
||||
connId :: Maybe Int64,
|
||||
agentConnId :: Maybe AgentConnId
|
||||
}
|
||||
deriving (Eq, Show, Generic)
|
||||
deriving (Eq, Show, Generic, FromJSON)
|
||||
|
||||
instance ToJSON RcvFileInfo where toEncoding = J.genericToEncoding J.defaultOptions
|
||||
|
||||
@@ -1094,6 +1093,9 @@ instance StrEncoding AgentConnId where
|
||||
strDecode s = AgentConnId <$> strDecode s
|
||||
strP = AgentConnId <$> strP
|
||||
|
||||
instance FromJSON AgentConnId where
|
||||
parseJSON = strParseJSON "AgentConnId"
|
||||
|
||||
instance ToJSON AgentConnId where
|
||||
toJSON = strToJSON
|
||||
toEncoding = strToJEncoding
|
||||
@@ -1110,6 +1112,9 @@ instance StrEncoding AgentSndFileId where
|
||||
strDecode s = AgentSndFileId <$> strDecode s
|
||||
strP = AgentSndFileId <$> strP
|
||||
|
||||
instance FromJSON AgentSndFileId where
|
||||
parseJSON = strParseJSON "AgentSndFileId"
|
||||
|
||||
instance ToJSON AgentSndFileId where
|
||||
toJSON = strToJSON
|
||||
toEncoding = strToJEncoding
|
||||
@@ -1126,6 +1131,9 @@ instance StrEncoding AgentRcvFileId where
|
||||
strDecode s = AgentRcvFileId <$> strDecode s
|
||||
strP = AgentRcvFileId <$> strP
|
||||
|
||||
instance FromJSON AgentRcvFileId where
|
||||
parseJSON = strParseJSON "AgentRcvFileId"
|
||||
|
||||
instance ToJSON AgentRcvFileId where
|
||||
toJSON = strToJSON
|
||||
toEncoding = strToJEncoding
|
||||
@@ -1142,6 +1150,9 @@ instance StrEncoding AgentInvId where
|
||||
strDecode s = AgentInvId <$> strDecode s
|
||||
strP = AgentInvId <$> strP
|
||||
|
||||
instance FromJSON AgentInvId where
|
||||
parseJSON = strParseJSON "AgentInvId"
|
||||
|
||||
instance ToJSON AgentInvId where
|
||||
toJSON = strToJSON
|
||||
toEncoding = strToJEncoding
|
||||
@@ -1158,6 +1169,9 @@ data FileTransfer
|
||||
| FTRcv {rcvFileTransfer :: RcvFileTransfer}
|
||||
deriving (Show, Generic)
|
||||
|
||||
instance FromJSON FileTransfer where
|
||||
parseJSON = J.genericParseJSON . sumTypeJSON $ dropPrefix "FT"
|
||||
|
||||
instance ToJSON FileTransfer where
|
||||
toJSON = J.genericToJSON . sumTypeJSON $ dropPrefix "FT"
|
||||
toEncoding = J.genericToEncoding . sumTypeJSON $ dropPrefix "FT"
|
||||
@@ -1172,7 +1186,7 @@ data FileTransferMeta = FileTransferMeta
|
||||
chunkSize :: Integer,
|
||||
cancelled :: Bool
|
||||
}
|
||||
deriving (Eq, Show, Generic)
|
||||
deriving (Eq, Show, Generic, FromJSON)
|
||||
|
||||
instance ToJSON FileTransferMeta where toEncoding = J.genericToEncoding J.defaultOptions
|
||||
|
||||
@@ -1182,7 +1196,7 @@ data XFTPSndFile = XFTPSndFile
|
||||
agentSndFileDeleted :: Bool,
|
||||
cryptoArgs :: Maybe CryptoFileArgs
|
||||
}
|
||||
deriving (Eq, Show, Generic)
|
||||
deriving (Eq, Show, Generic, FromJSON)
|
||||
|
||||
instance ToJSON XFTPSndFile where toEncoding = J.genericToEncoding J.defaultOptions
|
||||
|
||||
@@ -1197,6 +1211,9 @@ instance FromField FileStatus where fromField = fromTextField_ textDecode
|
||||
|
||||
instance ToField FileStatus where toField = toField . textEncode
|
||||
|
||||
instance FromJSON FileStatus where
|
||||
parseJSON = textParseJSON "FileStatus"
|
||||
|
||||
instance ToJSON FileStatus where
|
||||
toJSON = J.String . textEncode
|
||||
toEncoding = JE.text . textEncode
|
||||
@@ -1250,11 +1267,9 @@ connDisabled :: Connection -> Bool
|
||||
connDisabled Connection {authErrCounter} = authErrCounter >= authErrDisableCount
|
||||
|
||||
data SecurityCode = SecurityCode {securityCode :: Text, verifiedAt :: UTCTime}
|
||||
deriving (Eq, Show, Generic)
|
||||
deriving (Eq, Show, Generic, FromJSON)
|
||||
|
||||
instance ToJSON SecurityCode where
|
||||
toJSON = J.genericToJSON J.defaultOptions {J.omitNothingFields = True}
|
||||
toEncoding = J.genericToEncoding J.defaultOptions {J.omitNothingFields = True}
|
||||
instance ToJSON SecurityCode where toEncoding = J.genericToEncoding J.defaultOptions
|
||||
|
||||
verificationCode :: ByteString -> Text
|
||||
verificationCode = T.pack . unwords . chunks 5 . show . os2ip
|
||||
@@ -1273,6 +1288,9 @@ aConnId Connection {agentConnId = AgentConnId cId} = cId
|
||||
connIncognito :: Connection -> Bool
|
||||
connIncognito Connection {customUserProfileId} = isJust customUserProfileId
|
||||
|
||||
instance FromJSON Connection where
|
||||
parseJSON = J.genericParseJSON J.defaultOptions {J.omitNothingFields = True}
|
||||
|
||||
instance ToJSON Connection where
|
||||
toJSON = J.genericToJSON J.defaultOptions {J.omitNothingFields = True}
|
||||
toEncoding = J.genericToEncoding J.defaultOptions {J.omitNothingFields = True}
|
||||
@@ -1290,7 +1308,7 @@ data PendingContactConnection = PendingContactConnection
|
||||
createdAt :: UTCTime,
|
||||
updatedAt :: UTCTime
|
||||
}
|
||||
deriving (Eq, Show, Generic)
|
||||
deriving (Eq, Show, Generic, FromJSON)
|
||||
|
||||
aConnId' :: PendingContactConnection -> ConnId
|
||||
aConnId' PendingContactConnection {pccAgentConnId = AgentConnId cId} = cId
|
||||
@@ -1318,6 +1336,9 @@ instance FromField ConnStatus where fromField = fromTextField_ textDecode
|
||||
|
||||
instance ToField ConnStatus where toField = toField . textEncode
|
||||
|
||||
instance FromJSON ConnStatus where
|
||||
parseJSON = textParseJSON "ConnStatus"
|
||||
|
||||
instance ToJSON ConnStatus where
|
||||
toJSON = J.String . textEncode
|
||||
toEncoding = JE.text . textEncode
|
||||
@@ -1348,6 +1369,9 @@ instance FromField ConnType where fromField = fromTextField_ textDecode
|
||||
|
||||
instance ToField ConnType where toField = toField . textEncode
|
||||
|
||||
instance FromJSON ConnType where
|
||||
parseJSON = textParseJSON "ConnType"
|
||||
|
||||
instance ToJSON ConnType where
|
||||
toJSON = J.String . textEncode
|
||||
toEncoding = JE.text . textEncode
|
||||
@@ -1550,6 +1574,24 @@ instance ToJSON ChatVersionRange where
|
||||
|
||||
newtype JVersionRange = JVersionRange {fromJVersionRange :: VersionRange} deriving (Eq, Show)
|
||||
|
||||
instance FromJSON JVersionRange where
|
||||
parseJSON = J.withObject "JVersionRange" $ \o -> do
|
||||
minv <- o .: "minVersion"
|
||||
maxv <- o .: "maxVersion"
|
||||
maybe (fail "bad version range") (pure . JVersionRange) $ safeVersionRange minv maxv
|
||||
|
||||
instance ToJSON JVersionRange where
|
||||
toJSON (JVersionRange (VersionRange minV maxV)) = J.object ["minVersion" .= minV, "maxVersion" .= maxV]
|
||||
toEncoding (JVersionRange (VersionRange minV maxV)) = J.pairs $ "minVersion" .= minV <> "maxVersion" .= maxV
|
||||
|
||||
$(JQ.deriveJSON defOpts ''UserPwdHash)
|
||||
|
||||
$(JQ.deriveJSON defOpts ''User)
|
||||
|
||||
$(JQ.deriveJSON defOpts ''NewUser)
|
||||
|
||||
$(JQ.deriveJSON defOpts ''UserInfo)
|
||||
|
||||
$(JQ.deriveJSON defOpts ''Contact)
|
||||
|
||||
$(JQ.deriveJSON defOpts ''ContactRef)
|
||||
|
||||
@@ -338,7 +338,7 @@ data ContactUserPreferences = ContactUserPreferences
|
||||
voice :: ContactUserPreference VoicePreference,
|
||||
calls :: ContactUserPreference CallsPreference
|
||||
}
|
||||
deriving (Eq, Show, Generic)
|
||||
deriving (Eq, Show, Generic, FromJSON)
|
||||
|
||||
data ContactUserPreference p = ContactUserPreference
|
||||
{ enabled :: PrefEnabled,
|
||||
@@ -352,8 +352,13 @@ data ContactUserPref p = CUPContact {preference :: p} | CUPUser {preference :: p
|
||||
|
||||
instance ToJSON ContactUserPreferences where toEncoding = J.genericToEncoding J.defaultOptions
|
||||
|
||||
instance FromJSON p => FromJSON (ContactUserPreference p) where parseJSON = J.genericParseJSON J.defaultOptions
|
||||
|
||||
instance ToJSON p => ToJSON (ContactUserPreference p) where toEncoding = J.genericToEncoding J.defaultOptions
|
||||
|
||||
instance FromJSON p => FromJSON (ContactUserPref p) where
|
||||
parseJSON = J.genericParseJSON . sumTypeJSON $ dropPrefix "CUP"
|
||||
|
||||
instance ToJSON p => ToJSON (ContactUserPref p) where
|
||||
toJSON = J.genericToJSON . sumTypeJSON $ dropPrefix "CUP"
|
||||
toEncoding = J.genericToEncoding . sumTypeJSON $ dropPrefix "CUP"
|
||||
|
||||
@@ -28,3 +28,6 @@ fromBlobField_ p = \case
|
||||
Right k -> Ok k
|
||||
Left e -> returnError ConversionFailed f ("could not parse field: " ++ e)
|
||||
f -> returnError ConversionFailed f "expecting SQLBlob column type"
|
||||
|
||||
defOpts :: J.Options
|
||||
defOpts = J.defaultOptions {J.omitNothingFields = True}
|
||||
|
||||
@@ -73,10 +73,10 @@ responseToView :: Maybe User -> ChatConfig -> Bool -> CurrentTime -> TimeZone ->
|
||||
responseToView user_ ChatConfig {logLevel, showReactions, showReceipts, testView} liveItems ts tz = \case
|
||||
CRActiveUser User {profile} -> viewUserProfile $ fromLocalProfile profile
|
||||
CRUsersList users -> viewUsersList users
|
||||
CRChatStarted -> ["chat started"]
|
||||
CRChatRunning -> ["chat is running"]
|
||||
CRChatStopped -> ["chat stopped"]
|
||||
CRChatSuspended -> ["chat suspended"]
|
||||
CRChatStarted _ -> ["chat started"]
|
||||
CRChatRunning _ -> ["chat is running"]
|
||||
CRChatStopped _ -> ["chat stopped"]
|
||||
CRChatSuspended _ -> ["chat suspended"]
|
||||
CRApiChats u chats -> ttyUser u $ if testView then testViewChats chats else [plain . bshow $ J.encode chats]
|
||||
CRChats chats -> viewChats ts tz chats
|
||||
CRApiChat u chat -> ttyUser u $ if testView then testViewChat chat else [plain . bshow $ J.encode chat]
|
||||
@@ -267,7 +267,7 @@ responseToView user_ ChatConfig {logLevel, showReactions, showReceipts, testView
|
||||
CRRemoteHostDeleted rhId -> ["remote host " <> sShow rhId <> " deleted"]
|
||||
CRRemoteCtrlList cs -> viewRemoteCtrls cs
|
||||
CRRemoteCtrlRegistered rcId -> ["remote controller " <> sShow rcId <> " registered"]
|
||||
CRRemoteCtrlStarted -> ["remote controller started"]
|
||||
CRRemoteCtrlStarted _ -> ["remote controller started"]
|
||||
CRRemoteCtrlAnnounce fingerprint -> ["remote controller announced", "connection code:", plain $ strEncode fingerprint]
|
||||
CRRemoteCtrlFound rc -> ["remote controller found:", viewRemoteCtrl rc]
|
||||
CRRemoteCtrlAccepted rcId -> ["remote controller " <> sShow rcId <> " accepted"]
|
||||
|
||||
@@ -49,7 +49,7 @@ extra-deps:
|
||||
# - simplexmq-1.0.0@sha256:34b2004728ae396e3ae449cd090ba7410781e2b3cefc59259915f4ca5daa9ea8,8561
|
||||
# - ../simplexmq
|
||||
- github: simplex-chat/simplexmq
|
||||
commit: ec1b72cb8013a65a5d9783104a47ae44f5730089
|
||||
commit: 96a38505d63ec9a12096991e7725b250e397af72
|
||||
- github: kazu-yamamoto/http2
|
||||
commit: b5a1b7200cf5bc7044af34ba325284271f6dff25
|
||||
# - ../direct-sqlcipher
|
||||
|
||||
Reference in New Issue
Block a user