{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE CPP #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE DeriveAnyClass #-}
{-# LANGUAGE DuplicateRecordFields #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE NamedFieldPuns #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE TemplateHaskell #-}

module Simplex.Chat.Remote.Types where

import Control.Concurrent.Async (Async)
import Control.Concurrent.STM
import Control.Exception (Exception)
import Control.Monad (when)
import qualified Data.Aeson.TH as J
import Data.ByteString (ByteString)
import Data.Int (Int64)
import Data.Text (Text)
import Data.Word (Word16, Word32)
import Simplex.Chat.Remote.AppVersion
import Simplex.Chat.Types (verificationCode)
import qualified Simplex.Messaging.Crypto as C
import Simplex.Messaging.Crypto.File (CryptoFile)
import Simplex.Messaging.Parsers (defaultJSON, dropPrefix, enumJSON, sumTypeJSON)
import Simplex.Messaging.Transport (TLS (..), TSbChainKeys (..), TransportPeer (..))
import Simplex.Messaging.Transport.HTTP2.Client (HTTP2Client)
import qualified Simplex.Messaging.TMap as TM
import Simplex.Messaging.Util (AnyError (..), tshow)
import Simplex.RemoteControl.Client
import Simplex.RemoteControl.Types

data RemoteHostClient = RemoteHostClient
  { RemoteHostClient -> PlatformEncoding
hostEncoding :: PlatformEncoding,
    RemoteHostClient -> Text
hostDeviceName :: Text,
    RemoteHostClient -> HTTP2Client
httpClient :: HTTP2Client,
    RemoteHostClient -> RemoteCrypto
encryption :: RemoteCrypto,
    RemoteHostClient -> Bool
encryptHostFiles :: Bool,
    RemoteHostClient -> FilePath
storePath :: FilePath
  }

data RemoteCrypto = RemoteCrypto
  { RemoteCrypto -> ByteString
sessionCode :: ByteString,
    RemoteCrypto -> TVar Word32
sndCounter :: TVar Word32,
    RemoteCrypto -> TVar Word32
rcvCounter :: TVar Word32,
    RemoteCrypto -> TSbChainKeys
chainKeys :: TSbChainKeys,
    RemoteCrypto -> TMap Word32 (SbKeyNonce, SbKeyNonce)
skippedKeys :: TM.TMap Word32 (C.SbKeyNonce, C.SbKeyNonce),
    RemoteCrypto -> RemoteSignatures
signatures :: RemoteSignatures
  }

getRemoteSndKeys :: RemoteCrypto -> STM (Word32, C.SbKeyNonce, C.SbKeyNonce)
getRemoteSndKeys :: RemoteCrypto -> STM (Word32, SbKeyNonce, SbKeyNonce)
getRemoteSndKeys RemoteCrypto {TVar Word32
sndCounter :: RemoteCrypto -> TVar Word32
sndCounter :: TVar Word32
sndCounter, chainKeys :: RemoteCrypto -> TSbChainKeys
chainKeys = TSbChainKeys {TVar SbChainKey
sndKey :: TVar SbChainKey
sndKey :: TSbChainKeys -> TVar SbChainKey
sndKey}} = do
  Word32
corrId <- TVar Word32 -> (Word32 -> (Word32, Word32)) -> STM Word32
forall s a. TVar s -> (s -> (a, s)) -> STM a
stateTVar TVar Word32
sndCounter ((Word32 -> (Word32, Word32)) -> STM Word32)
-> (Word32 -> (Word32, Word32)) -> STM Word32
forall a b. (a -> b) -> a -> b
$ \Word32
c -> let !c' :: Word32
c' = Word32
c Word32 -> Word32 -> Word32
forall a. Num a => a -> a -> a
+ Word32
1 in (Word32
c', Word32
c')
  SbKeyNonce
cmdKN <- TVar SbChainKey
-> (SbChainKey -> (SbKeyNonce, SbChainKey)) -> STM SbKeyNonce
forall s a. TVar s -> (s -> (a, s)) -> STM a
stateTVar TVar SbChainKey
sndKey SbChainKey -> (SbKeyNonce, SbChainKey)
C.sbcHkdf
  SbKeyNonce
fileKN <- TVar SbChainKey
-> (SbChainKey -> (SbKeyNonce, SbChainKey)) -> STM SbKeyNonce
forall s a. TVar s -> (s -> (a, s)) -> STM a
stateTVar TVar SbChainKey
sndKey SbChainKey -> (SbKeyNonce, SbChainKey)
C.sbcHkdf
  (Word32, SbKeyNonce, SbKeyNonce)
-> STM (Word32, SbKeyNonce, SbKeyNonce)
forall a. a -> STM a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Word32
corrId, SbKeyNonce
cmdKN, SbKeyNonce
fileKN)

getRemoteRcvKeys :: RemoteCrypto -> Word32 -> STM (Either RemoteProtocolError (C.SbKeyNonce, C.SbKeyNonce))
getRemoteRcvKeys :: RemoteCrypto
-> Word32
-> STM (Either RemoteProtocolError (SbKeyNonce, SbKeyNonce))
getRemoteRcvKeys RemoteCrypto {TVar Word32
rcvCounter :: RemoteCrypto -> TVar Word32
rcvCounter :: TVar Word32
rcvCounter, chainKeys :: RemoteCrypto -> TSbChainKeys
chainKeys = TSbChainKeys {TVar SbChainKey
rcvKey :: TVar SbChainKey
rcvKey :: TSbChainKeys -> TVar SbChainKey
rcvKey}, TMap Word32 (SbKeyNonce, SbKeyNonce)
skippedKeys :: RemoteCrypto -> TMap Word32 (SbKeyNonce, SbKeyNonce)
skippedKeys :: TMap Word32 (SbKeyNonce, SbKeyNonce)
skippedKeys} !Word32
corrId =
  TVar Word32 -> STM Word32
forall a. TVar a -> STM a
readTVar TVar Word32
rcvCounter STM Word32
-> (Word32
    -> STM (Either RemoteProtocolError (SbKeyNonce, SbKeyNonce)))
-> STM (Either RemoteProtocolError (SbKeyNonce, SbKeyNonce))
forall a b. STM a -> (a -> STM b) -> STM b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= Word32 -> STM (Either RemoteProtocolError (SbKeyNonce, SbKeyNonce))
getRcvKeys
  where
    getRcvKeys :: Word32 -> STM (Either RemoteProtocolError (SbKeyNonce, SbKeyNonce))
getRcvKeys Word32
prevCorrId
      | Word32
prevCorrId Word32 -> Word32 -> Bool
forall a. Ord a => a -> a -> Bool
> Word32
corrId =
          let err :: RemoteProtocolError
err = Word32 -> RemoteProtocolError
PREEarlierId (Word32 -> RemoteProtocolError) -> Word32 -> RemoteProtocolError
forall a b. (a -> b) -> a -> b
$ Word32
prevCorrId Word32 -> Word32 -> Word32
forall a. Num a => a -> a -> a
- Word32
corrId
           in Either RemoteProtocolError (SbKeyNonce, SbKeyNonce)
-> ((SbKeyNonce, SbKeyNonce)
    -> Either RemoteProtocolError (SbKeyNonce, SbKeyNonce))
-> Maybe (SbKeyNonce, SbKeyNonce)
-> Either RemoteProtocolError (SbKeyNonce, SbKeyNonce)
forall b a. b -> (a -> b) -> Maybe a -> b
maybe (RemoteProtocolError
-> Either RemoteProtocolError (SbKeyNonce, SbKeyNonce)
forall a b. a -> Either a b
Left RemoteProtocolError
err) (SbKeyNonce, SbKeyNonce)
-> Either RemoteProtocolError (SbKeyNonce, SbKeyNonce)
forall a b. b -> Either a b
Right (Maybe (SbKeyNonce, SbKeyNonce)
 -> Either RemoteProtocolError (SbKeyNonce, SbKeyNonce))
-> STM (Maybe (SbKeyNonce, SbKeyNonce))
-> STM (Either RemoteProtocolError (SbKeyNonce, SbKeyNonce))
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Word32
-> TMap Word32 (SbKeyNonce, SbKeyNonce)
-> STM (Maybe (SbKeyNonce, SbKeyNonce))
forall k a. Ord k => k -> TMap k a -> STM (Maybe a)
TM.lookupDelete Word32
corrId TMap Word32 (SbKeyNonce, SbKeyNonce)
skippedKeys
      | Word32
prevCorrId Word32 -> Word32 -> Bool
forall a. Eq a => a -> a -> Bool
== Word32
corrId =
          Either RemoteProtocolError (SbKeyNonce, SbKeyNonce)
-> STM (Either RemoteProtocolError (SbKeyNonce, SbKeyNonce))
forall a. a -> STM a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Either RemoteProtocolError (SbKeyNonce, SbKeyNonce)
 -> STM (Either RemoteProtocolError (SbKeyNonce, SbKeyNonce)))
-> Either RemoteProtocolError (SbKeyNonce, SbKeyNonce)
-> STM (Either RemoteProtocolError (SbKeyNonce, SbKeyNonce))
forall a b. (a -> b) -> a -> b
$ RemoteProtocolError
-> Either RemoteProtocolError (SbKeyNonce, SbKeyNonce)
forall a b. a -> Either a b
Left RemoteProtocolError
PREDuplicateId
      | Word32
prevCorrId Word32 -> Word32 -> Word32
forall a. Num a => a -> a -> a
+ Word32
maxSkip Word32 -> Word32 -> Bool
forall a. Ord a => a -> a -> Bool
< Word32
corrId =
          Either RemoteProtocolError (SbKeyNonce, SbKeyNonce)
-> STM (Either RemoteProtocolError (SbKeyNonce, SbKeyNonce))
forall a. a -> STM a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Either RemoteProtocolError (SbKeyNonce, SbKeyNonce)
 -> STM (Either RemoteProtocolError (SbKeyNonce, SbKeyNonce)))
-> Either RemoteProtocolError (SbKeyNonce, SbKeyNonce)
-> STM (Either RemoteProtocolError (SbKeyNonce, SbKeyNonce))
forall a b. (a -> b) -> a -> b
$ RemoteProtocolError
-> Either RemoteProtocolError (SbKeyNonce, SbKeyNonce)
forall a b. a -> Either a b
Left (RemoteProtocolError
 -> Either RemoteProtocolError (SbKeyNonce, SbKeyNonce))
-> RemoteProtocolError
-> Either RemoteProtocolError (SbKeyNonce, SbKeyNonce)
forall a b. (a -> b) -> a -> b
$ Word32 -> RemoteProtocolError
RPEManySkippedIds (Word32
corrId Word32 -> Word32 -> Word32
forall a. Num a => a -> a -> a
- Word32
prevCorrId)
      | Bool
otherwise = do -- prevCorrId < corrId
          TVar Word32 -> Word32 -> STM ()
forall a. TVar a -> a -> STM ()
writeTVar TVar Word32
rcvCounter Word32
corrId
          Word32 -> STM ()
skipKeys (Word32
prevCorrId Word32 -> Word32 -> Word32
forall a. Num a => a -> a -> a
+ Word32
1)
          (SbKeyNonce, SbKeyNonce)
-> Either RemoteProtocolError (SbKeyNonce, SbKeyNonce)
forall a b. b -> Either a b
Right ((SbKeyNonce, SbKeyNonce)
 -> Either RemoteProtocolError (SbKeyNonce, SbKeyNonce))
-> STM (SbKeyNonce, SbKeyNonce)
-> STM (Either RemoteProtocolError (SbKeyNonce, SbKeyNonce))
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> STM (SbKeyNonce, SbKeyNonce)
getKeys
    maxSkip :: Word32
maxSkip = Word32
256
    getKeys :: STM (SbKeyNonce, SbKeyNonce)
getKeys = (,) (SbKeyNonce -> SbKeyNonce -> (SbKeyNonce, SbKeyNonce))
-> STM SbKeyNonce -> STM (SbKeyNonce -> (SbKeyNonce, SbKeyNonce))
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> TVar SbChainKey
-> (SbChainKey -> (SbKeyNonce, SbChainKey)) -> STM SbKeyNonce
forall s a. TVar s -> (s -> (a, s)) -> STM a
stateTVar TVar SbChainKey
rcvKey SbChainKey -> (SbKeyNonce, SbChainKey)
C.sbcHkdf STM (SbKeyNonce -> (SbKeyNonce, SbKeyNonce))
-> STM SbKeyNonce -> STM (SbKeyNonce, SbKeyNonce)
forall a b. STM (a -> b) -> STM a -> STM b
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> TVar SbChainKey
-> (SbChainKey -> (SbKeyNonce, SbChainKey)) -> STM SbKeyNonce
forall s a. TVar s -> (s -> (a, s)) -> STM a
stateTVar TVar SbChainKey
rcvKey SbChainKey -> (SbKeyNonce, SbChainKey)
C.sbcHkdf
    skipKeys :: Word32 -> STM ()
skipKeys !Word32
cId =
      Bool -> STM () -> STM ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (Word32
cId Word32 -> Word32 -> Bool
forall a. Ord a => a -> a -> Bool
< Word32
corrId) (STM () -> STM ()) -> STM () -> STM ()
forall a b. (a -> b) -> a -> b
$ do
        (SbKeyNonce, SbKeyNonce)
keys <- STM (SbKeyNonce, SbKeyNonce)
getKeys
        Word32
-> (SbKeyNonce, SbKeyNonce)
-> TMap Word32 (SbKeyNonce, SbKeyNonce)
-> STM ()
forall k a. Ord k => k -> a -> TMap k a -> STM ()
TM.insert Word32
cId (SbKeyNonce, SbKeyNonce)
keys TMap Word32 (SbKeyNonce, SbKeyNonce)
skippedKeys
        Word32 -> STM ()
skipKeys (Word32
cId Word32 -> Word32 -> Word32
forall a. Num a => a -> a -> a
+ Word32
1)

data RemoteSignatures
  = RSSign
      { RemoteSignatures -> PrivateKeyEd25519
idPrivKey :: C.PrivateKeyEd25519,
        RemoteSignatures -> PrivateKeyEd25519
sessPrivKey :: C.PrivateKeyEd25519
      }
  | RSVerify
      { RemoteSignatures -> PublicKeyEd25519
idPubKey :: C.PublicKeyEd25519,
        RemoteSignatures -> PublicKeyEd25519
sessPubKey :: C.PublicKeyEd25519
      }

type SessionSeq = Int

data RHPendingSession = RHPendingSession
  { RHPendingSession -> RHKey
rhKey :: RHKey,
    RHPendingSession -> RCHostClient
rchClient :: RCHostClient,
    RHPendingSession -> Async ()
rhsWaitSession :: Async (),
    RHPendingSession -> Maybe RemoteHostInfo
remoteHost_ :: Maybe RemoteHostInfo
  }

data RemoteHostSession
  = RHSessionStarting
  | RHSessionConnecting {RemoteHostSession -> Text
invitation :: Text, RemoteHostSession -> RHPendingSession
rhPendingSession :: RHPendingSession}
  | RHSessionPendingConfirmation {RemoteHostSession -> Text
sessionCode :: Text, RemoteHostSession -> TLS 'TServer
tls :: TLS 'TServer, rhPendingSession :: RHPendingSession}
  | RHSessionConfirmed {tls :: TLS 'TServer, rhPendingSession :: RHPendingSession}
  | RHSessionConnected
      { RemoteHostSession -> RCHostClient
rchClient :: RCHostClient,
        tls :: TLS 'TServer,
        RemoteHostSession -> RemoteHostClient
rhClient :: RemoteHostClient,
        RemoteHostSession -> Async ()
pollAction :: Async (),
        RemoteHostSession -> FilePath
storePath :: FilePath
      }

data RemoteHostSessionState
  = RHSStarting
  | RHSConnecting {RemoteHostSessionState -> Text
invitation :: Text}
  | RHSPendingConfirmation {RemoteHostSessionState -> Text
sessionCode :: Text}
  | RHSConfirmed {sessionCode :: Text}
  | RHSConnected {sessionCode :: Text}
  deriving (Int -> RemoteHostSessionState -> ShowS
[RemoteHostSessionState] -> ShowS
RemoteHostSessionState -> FilePath
(Int -> RemoteHostSessionState -> ShowS)
-> (RemoteHostSessionState -> FilePath)
-> ([RemoteHostSessionState] -> ShowS)
-> Show RemoteHostSessionState
forall a.
(Int -> a -> ShowS) -> (a -> FilePath) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> RemoteHostSessionState -> ShowS
showsPrec :: Int -> RemoteHostSessionState -> ShowS
$cshow :: RemoteHostSessionState -> FilePath
show :: RemoteHostSessionState -> FilePath
$cshowList :: [RemoteHostSessionState] -> ShowS
showList :: [RemoteHostSessionState] -> ShowS
Show)

rhsSessionState :: RemoteHostSession -> RemoteHostSessionState
rhsSessionState :: RemoteHostSession -> RemoteHostSessionState
rhsSessionState = \case
  RemoteHostSession
RHSessionStarting -> RemoteHostSessionState
RHSStarting
  RHSessionConnecting {Text
invitation :: RemoteHostSession -> Text
invitation :: Text
invitation} -> RHSConnecting {Text
invitation :: Text
invitation :: Text
invitation}
  RHSessionPendingConfirmation {TLS 'TServer
tls :: RemoteHostSession -> TLS 'TServer
tls :: TLS 'TServer
tls} -> RHSPendingConfirmation {sessionCode :: Text
sessionCode = TLS 'TServer -> Text
forall (p :: TransportPeer). TLS p -> Text
tlsSessionCode TLS 'TServer
tls}
  RHSessionConfirmed {TLS 'TServer
tls :: RemoteHostSession -> TLS 'TServer
tls :: TLS 'TServer
tls} -> RHSConfirmed {sessionCode :: Text
sessionCode = TLS 'TServer -> Text
forall (p :: TransportPeer). TLS p -> Text
tlsSessionCode TLS 'TServer
tls}
  RHSessionConnected {TLS 'TServer
tls :: RemoteHostSession -> TLS 'TServer
tls :: TLS 'TServer
tls} -> RHSConnected {sessionCode :: Text
sessionCode = TLS 'TServer -> Text
forall (p :: TransportPeer). TLS p -> Text
tlsSessionCode TLS 'TServer
tls}

tlsSessionCode :: TLS p -> Text
tlsSessionCode :: forall (p :: TransportPeer). TLS p -> Text
tlsSessionCode = ByteString -> Text
verificationCode (ByteString -> Text) -> (TLS p -> ByteString) -> TLS p -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. TLS p -> ByteString
forall (p :: TransportPeer). TLS p -> ByteString
tlsUniq

data RemoteProtocolError
  = -- | size prefix is malformed
    RPEInvalidSize
  | -- | failed to parse RemoteCommand or RemoteResponse
    RPEInvalidJSON {RemoteProtocolError -> FilePath
invalidJSON :: String}
  | RPEInvalidBody {RemoteProtocolError -> FilePath
invalidBody :: String}
  | PRESessionCode
  | RPEIncompatibleEncoding
  | RPEUnexpectedFile
  | RPENoFile
  | RPEFileSize
  | RPEFileDigest
  | RPEManySkippedIds Word32
  | PREEarlierId Word32
  | PREDuplicateId
  | -- | Wrong response received for the command sent
    RPEUnexpectedResponse {RemoteProtocolError -> Text
response :: Text}
  | -- | A file already exists in the destination position
    RPEStoredFileExists
  | PRERemoteControl {RemoteProtocolError -> RCErrorType
rcError :: RCErrorType}
  | RPEHTTP2 {RemoteProtocolError -> Text
http2Error :: Text}
  | RPEException {RemoteProtocolError -> Text
someException :: Text}
  deriving (Int -> RemoteProtocolError -> ShowS
[RemoteProtocolError] -> ShowS
RemoteProtocolError -> FilePath
(Int -> RemoteProtocolError -> ShowS)
-> (RemoteProtocolError -> FilePath)
-> ([RemoteProtocolError] -> ShowS)
-> Show RemoteProtocolError
forall a.
(Int -> a -> ShowS) -> (a -> FilePath) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> RemoteProtocolError -> ShowS
showsPrec :: Int -> RemoteProtocolError -> ShowS
$cshow :: RemoteProtocolError -> FilePath
show :: RemoteProtocolError -> FilePath
$cshowList :: [RemoteProtocolError] -> ShowS
showList :: [RemoteProtocolError] -> ShowS
Show, Show RemoteProtocolError
Typeable RemoteProtocolError
(Typeable RemoteProtocolError, Show RemoteProtocolError) =>
(RemoteProtocolError -> SomeException)
-> (SomeException -> Maybe RemoteProtocolError)
-> (RemoteProtocolError -> FilePath)
-> Exception RemoteProtocolError
SomeException -> Maybe RemoteProtocolError
RemoteProtocolError -> FilePath
RemoteProtocolError -> SomeException
forall e.
(Typeable e, Show e) =>
(e -> SomeException)
-> (SomeException -> Maybe e) -> (e -> FilePath) -> Exception e
$ctoException :: RemoteProtocolError -> SomeException
toException :: RemoteProtocolError -> SomeException
$cfromException :: SomeException -> Maybe RemoteProtocolError
fromException :: SomeException -> Maybe RemoteProtocolError
$cdisplayException :: RemoteProtocolError -> FilePath
displayException :: RemoteProtocolError -> FilePath
Exception)

instance AnyError RemoteProtocolError where
  fromSomeException :: SomeException -> RemoteProtocolError
fromSomeException = Text -> RemoteProtocolError
RPEException (Text -> RemoteProtocolError)
-> (SomeException -> Text) -> SomeException -> RemoteProtocolError
forall b c a. (b -> c) -> (a -> b) -> a -> c
. SomeException -> Text
forall a. Show a => a -> Text
tshow

type RemoteHostId = Int64

data RHKey = RHNew | RHId {RHKey -> RemoteHostId
remoteHostId :: RemoteHostId}
  deriving (RHKey -> RHKey -> Bool
(RHKey -> RHKey -> Bool) -> (RHKey -> RHKey -> Bool) -> Eq RHKey
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: RHKey -> RHKey -> Bool
== :: RHKey -> RHKey -> Bool
$c/= :: RHKey -> RHKey -> Bool
/= :: RHKey -> RHKey -> Bool
Eq, Eq RHKey
Eq RHKey =>
(RHKey -> RHKey -> Ordering)
-> (RHKey -> RHKey -> Bool)
-> (RHKey -> RHKey -> Bool)
-> (RHKey -> RHKey -> Bool)
-> (RHKey -> RHKey -> Bool)
-> (RHKey -> RHKey -> RHKey)
-> (RHKey -> RHKey -> RHKey)
-> Ord RHKey
RHKey -> RHKey -> Bool
RHKey -> RHKey -> Ordering
RHKey -> RHKey -> RHKey
forall a.
Eq a =>
(a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
$ccompare :: RHKey -> RHKey -> Ordering
compare :: RHKey -> RHKey -> Ordering
$c< :: RHKey -> RHKey -> Bool
< :: RHKey -> RHKey -> Bool
$c<= :: RHKey -> RHKey -> Bool
<= :: RHKey -> RHKey -> Bool
$c> :: RHKey -> RHKey -> Bool
> :: RHKey -> RHKey -> Bool
$c>= :: RHKey -> RHKey -> Bool
>= :: RHKey -> RHKey -> Bool
$cmax :: RHKey -> RHKey -> RHKey
max :: RHKey -> RHKey -> RHKey
$cmin :: RHKey -> RHKey -> RHKey
min :: RHKey -> RHKey -> RHKey
Ord, Int -> RHKey -> ShowS
[RHKey] -> ShowS
RHKey -> FilePath
(Int -> RHKey -> ShowS)
-> (RHKey -> FilePath) -> ([RHKey] -> ShowS) -> Show RHKey
forall a.
(Int -> a -> ShowS) -> (a -> FilePath) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> RHKey -> ShowS
showsPrec :: Int -> RHKey -> ShowS
$cshow :: RHKey -> FilePath
show :: RHKey -> FilePath
$cshowList :: [RHKey] -> ShowS
showList :: [RHKey] -> ShowS
Show)

-- | Storable/internal remote host data
data RemoteHost = RemoteHost
  { RemoteHost -> RemoteHostId
remoteHostId :: RemoteHostId,
    RemoteHost -> Text
hostDeviceName :: Text,
    RemoteHost -> FilePath
storePath :: FilePath,
    RemoteHost -> Maybe RCCtrlAddress
bindAddress_ :: Maybe RCCtrlAddress,
    RemoteHost -> Maybe Word16
bindPort_ :: Maybe Word16,
    RemoteHost -> RCHostPairing
hostPairing :: RCHostPairing
  }

-- | UI-accessible remote host information
data RemoteHostInfo = RemoteHostInfo
  { RemoteHostInfo -> RemoteHostId
remoteHostId :: RemoteHostId,
    RemoteHostInfo -> Text
hostDeviceName :: Text,
    RemoteHostInfo -> FilePath
storePath :: FilePath,
    RemoteHostInfo -> Maybe RCCtrlAddress
bindAddress_ :: Maybe RCCtrlAddress,
    RemoteHostInfo -> Maybe Word16
bindPort_ :: Maybe Word16,
    RemoteHostInfo -> Maybe RemoteHostSessionState
sessionState :: Maybe RemoteHostSessionState
  }
  deriving (Int -> RemoteHostInfo -> ShowS
[RemoteHostInfo] -> ShowS
RemoteHostInfo -> FilePath
(Int -> RemoteHostInfo -> ShowS)
-> (RemoteHostInfo -> FilePath)
-> ([RemoteHostInfo] -> ShowS)
-> Show RemoteHostInfo
forall a.
(Int -> a -> ShowS) -> (a -> FilePath) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> RemoteHostInfo -> ShowS
showsPrec :: Int -> RemoteHostInfo -> ShowS
$cshow :: RemoteHostInfo -> FilePath
show :: RemoteHostInfo -> FilePath
$cshowList :: [RemoteHostInfo] -> ShowS
showList :: [RemoteHostInfo] -> ShowS
Show)

type RemoteCtrlId = Int64

-- | Storable/internal remote controller data
data RemoteCtrl = RemoteCtrl
  { RemoteCtrl -> RemoteHostId
remoteCtrlId :: RemoteCtrlId,
    RemoteCtrl -> Text
ctrlDeviceName :: Text,
    RemoteCtrl -> RCCtrlPairing
ctrlPairing :: RCCtrlPairing
  }

remoteCtrlId' :: RemoteCtrl -> RemoteCtrlId
remoteCtrlId' :: RemoteCtrl -> RemoteHostId
remoteCtrlId' = RemoteCtrl -> RemoteHostId
remoteCtrlId

data PlatformEncoding
  = PESwift
  | PEKotlin
  deriving (Int -> PlatformEncoding -> ShowS
[PlatformEncoding] -> ShowS
PlatformEncoding -> FilePath
(Int -> PlatformEncoding -> ShowS)
-> (PlatformEncoding -> FilePath)
-> ([PlatformEncoding] -> ShowS)
-> Show PlatformEncoding
forall a.
(Int -> a -> ShowS) -> (a -> FilePath) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> PlatformEncoding -> ShowS
showsPrec :: Int -> PlatformEncoding -> ShowS
$cshow :: PlatformEncoding -> FilePath
show :: PlatformEncoding -> FilePath
$cshowList :: [PlatformEncoding] -> ShowS
showList :: [PlatformEncoding] -> ShowS
Show, PlatformEncoding -> PlatformEncoding -> Bool
(PlatformEncoding -> PlatformEncoding -> Bool)
-> (PlatformEncoding -> PlatformEncoding -> Bool)
-> Eq PlatformEncoding
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: PlatformEncoding -> PlatformEncoding -> Bool
== :: PlatformEncoding -> PlatformEncoding -> Bool
$c/= :: PlatformEncoding -> PlatformEncoding -> Bool
/= :: PlatformEncoding -> PlatformEncoding -> Bool
Eq)

localEncoding :: PlatformEncoding

#if defined(darwin_HOST_OS) && defined(swiftJSON)
localEncoding = PESwift
#else
localEncoding :: PlatformEncoding
localEncoding = PlatformEncoding
PEKotlin
#endif

data RemoteFile = RemoteFile
  { RemoteFile -> RemoteHostId
userId :: Int64,
    RemoteFile -> RemoteHostId
fileId :: Int64,
    RemoteFile -> Bool
sent :: Bool,
    RemoteFile -> CryptoFile
fileSource :: CryptoFile
  }
  deriving (Int -> RemoteFile -> ShowS
[RemoteFile] -> ShowS
RemoteFile -> FilePath
(Int -> RemoteFile -> ShowS)
-> (RemoteFile -> FilePath)
-> ([RemoteFile] -> ShowS)
-> Show RemoteFile
forall a.
(Int -> a -> ShowS) -> (a -> FilePath) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> RemoteFile -> ShowS
showsPrec :: Int -> RemoteFile -> ShowS
$cshow :: RemoteFile -> FilePath
show :: RemoteFile -> FilePath
$cshowList :: [RemoteFile] -> ShowS
showList :: [RemoteFile] -> ShowS
Show)

data CtrlAppInfo = CtrlAppInfo
  { CtrlAppInfo -> AppVersionRange
appVersionRange :: AppVersionRange,
    CtrlAppInfo -> Text
deviceName :: Text
  }
  deriving (Int -> CtrlAppInfo -> ShowS
[CtrlAppInfo] -> ShowS
CtrlAppInfo -> FilePath
(Int -> CtrlAppInfo -> ShowS)
-> (CtrlAppInfo -> FilePath)
-> ([CtrlAppInfo] -> ShowS)
-> Show CtrlAppInfo
forall a.
(Int -> a -> ShowS) -> (a -> FilePath) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> CtrlAppInfo -> ShowS
showsPrec :: Int -> CtrlAppInfo -> ShowS
$cshow :: CtrlAppInfo -> FilePath
show :: CtrlAppInfo -> FilePath
$cshowList :: [CtrlAppInfo] -> ShowS
showList :: [CtrlAppInfo] -> ShowS
Show)

data HostAppInfo = HostAppInfo
  { HostAppInfo -> AppVersion
appVersion :: AppVersion,
    HostAppInfo -> Text
deviceName :: Text,
    HostAppInfo -> PlatformEncoding
encoding :: PlatformEncoding,
    HostAppInfo -> Bool
encryptFiles :: Bool -- if the host encrypts files in app storage
  }

$(J.deriveJSON defaultJSON ''RemoteFile)

$(J.deriveJSON (sumTypeJSON $ dropPrefix "RPE") ''RemoteProtocolError)

$(J.deriveJSON (sumTypeJSON $ dropPrefix "RH") ''RHKey)

$(J.deriveJSON (enumJSON $ dropPrefix "PE") ''PlatformEncoding)

$(J.deriveJSON (sumTypeJSON $ dropPrefix "RHS") ''RemoteHostSessionState)

$(J.deriveJSON defaultJSON ''RemoteHostInfo)

$(J.deriveJSON defaultJSON ''CtrlAppInfo)

$(J.deriveJSON defaultJSON ''HostAppInfo)