{-# LANGUAGE DuplicateRecordFields #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE NamedFieldPuns #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE TemplateHaskell #-}

module Simplex.FileTransfer.Types
  ( RcvFileId,
    SndFileId,
    FileHeader (..),
    DBRcvFileId,
    RcvFile (..),
    RcvFileStatus (..),
    RcvFileChunk (..),
    RcvFileChunkReplica (..),
    RcvFileRedirect (..),
    DBSndFileId,
    SndFile (..),
    SndFileStatus (..),
    SndFileChunk (..),
    NewSndChunkReplica (..),
    SndFileChunkReplica (..),
    SndFileReplicaStatus (..),
    DeletedSndChunkReplica (..),
    SentRecipientReplica (..),
    FileErrorType (..),
    authTagSize,
    sndFileEncPath,
    sndChunkSize,
  ) where

import qualified Data.Aeson.TH as J
import qualified Data.Attoparsec.ByteString.Char8 as A
import Data.ByteString.Char8 (ByteString)
import Data.Int (Int64)
import Data.Text (Text)
import qualified Data.Text as T
import Data.Text.Encoding (encodeUtf8)
import Data.Word (Word32)
import Simplex.FileTransfer.Client (XFTPChunkSpec (..))
import Simplex.FileTransfer.Description
import Simplex.Messaging.Agent.Store.DB (FromField (..), ToField (..), fromTextField_)
import qualified Simplex.Messaging.Crypto as C
import Simplex.Messaging.Crypto.File (CryptoFile (..))
import Simplex.Messaging.Encoding
import Simplex.Messaging.Encoding.String
import Simplex.Messaging.Parsers
import Simplex.Messaging.Protocol (XFTPServer)
import System.FilePath ((</>))

type RcvFileId = ByteString -- Agent entity ID

type SndFileId = ByteString -- Agent entity ID

authTagSize :: Int64
authTagSize :: Int64
authTagSize = Int -> Int64
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
C.authTagSize

-- fileExtra is added to allow header extension in future versions
data FileHeader = FileHeader
  { FileHeader -> Text
fileName :: Text,
    FileHeader -> Maybe Text
fileExtra :: Maybe Text
  }
  deriving (FileHeader -> FileHeader -> Bool
(FileHeader -> FileHeader -> Bool)
-> (FileHeader -> FileHeader -> Bool) -> Eq FileHeader
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: FileHeader -> FileHeader -> Bool
== :: FileHeader -> FileHeader -> Bool
$c/= :: FileHeader -> FileHeader -> Bool
/= :: FileHeader -> FileHeader -> Bool
Eq, Int -> FileHeader -> ShowS
[FileHeader] -> ShowS
FileHeader -> String
(Int -> FileHeader -> ShowS)
-> (FileHeader -> String)
-> ([FileHeader] -> ShowS)
-> Show FileHeader
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> FileHeader -> ShowS
showsPrec :: Int -> FileHeader -> ShowS
$cshow :: FileHeader -> String
show :: FileHeader -> String
$cshowList :: [FileHeader] -> ShowS
showList :: [FileHeader] -> ShowS
Show)

instance Encoding FileHeader where
  smpEncode :: FileHeader -> ByteString
smpEncode FileHeader {Text
$sel:fileName:FileHeader :: FileHeader -> Text
fileName :: Text
fileName, Maybe Text
$sel:fileExtra:FileHeader :: FileHeader -> Maybe Text
fileExtra :: Maybe Text
fileExtra} = (Text, Maybe Text) -> ByteString
forall a. Encoding a => a -> ByteString
smpEncode (Text
fileName, Maybe Text
fileExtra)
  smpP :: Parser FileHeader
smpP = do
    (Text
fileName, Maybe Text
fileExtra) <- Parser (Text, Maybe Text)
forall a. Encoding a => Parser a
smpP
    FileHeader -> Parser FileHeader
forall a. a -> Parser ByteString a
forall (f :: * -> *) a. Applicative f => a -> f a
pure FileHeader {Text
$sel:fileName:FileHeader :: Text
fileName :: Text
fileName, Maybe Text
$sel:fileExtra:FileHeader :: Maybe Text
fileExtra :: Maybe Text
fileExtra}

type DBRcvFileId = Int64

data RcvFile = RcvFile
  { RcvFile -> Int64
rcvFileId :: DBRcvFileId,
    RcvFile -> ByteString
rcvFileEntityId :: RcvFileId,
    RcvFile -> Int64
userId :: Int64,
    RcvFile -> FileSize Int64
size :: FileSize Int64,
    RcvFile -> FileDigest
digest :: FileDigest,
    RcvFile -> SbKey
key :: C.SbKey,
    RcvFile -> CbNonce
nonce :: C.CbNonce,
    RcvFile -> FileSize Word32
chunkSize :: FileSize Word32,
    RcvFile -> Maybe RcvFileRedirect
redirect :: Maybe RcvFileRedirect,
    RcvFile -> [RcvFileChunk]
chunks :: [RcvFileChunk],
    RcvFile -> String
prefixPath :: FilePath,
    RcvFile -> Maybe String
tmpPath :: Maybe FilePath,
    RcvFile -> CryptoFile
saveFile :: CryptoFile,
    RcvFile -> RcvFileStatus
status :: RcvFileStatus,
    RcvFile -> Bool
deleted :: Bool
  }
  deriving (Int -> RcvFile -> ShowS
[RcvFile] -> ShowS
RcvFile -> String
(Int -> RcvFile -> ShowS)
-> (RcvFile -> String) -> ([RcvFile] -> ShowS) -> Show RcvFile
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> RcvFile -> ShowS
showsPrec :: Int -> RcvFile -> ShowS
$cshow :: RcvFile -> String
show :: RcvFile -> String
$cshowList :: [RcvFile] -> ShowS
showList :: [RcvFile] -> ShowS
Show)

data RcvFileStatus
  = RFSReceiving
  | RFSReceived
  | RFSDecrypting
  | RFSComplete
  | RFSError
  deriving (RcvFileStatus -> RcvFileStatus -> Bool
(RcvFileStatus -> RcvFileStatus -> Bool)
-> (RcvFileStatus -> RcvFileStatus -> Bool) -> Eq RcvFileStatus
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: RcvFileStatus -> RcvFileStatus -> Bool
== :: RcvFileStatus -> RcvFileStatus -> Bool
$c/= :: RcvFileStatus -> RcvFileStatus -> Bool
/= :: RcvFileStatus -> RcvFileStatus -> Bool
Eq, Int -> RcvFileStatus -> ShowS
[RcvFileStatus] -> ShowS
RcvFileStatus -> String
(Int -> RcvFileStatus -> ShowS)
-> (RcvFileStatus -> String)
-> ([RcvFileStatus] -> ShowS)
-> Show RcvFileStatus
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> RcvFileStatus -> ShowS
showsPrec :: Int -> RcvFileStatus -> ShowS
$cshow :: RcvFileStatus -> String
show :: RcvFileStatus -> String
$cshowList :: [RcvFileStatus] -> ShowS
showList :: [RcvFileStatus] -> ShowS
Show)

instance FromField RcvFileStatus where fromField :: FieldParser RcvFileStatus
fromField = (Text -> Maybe RcvFileStatus) -> FieldParser RcvFileStatus
forall a. Typeable a => (Text -> Maybe a) -> Field -> Ok a
fromTextField_ Text -> Maybe RcvFileStatus
forall a. TextEncoding a => Text -> Maybe a
textDecode

instance ToField RcvFileStatus where toField :: RcvFileStatus -> SQLData
toField = Text -> SQLData
forall a. ToField a => a -> SQLData
toField (Text -> SQLData)
-> (RcvFileStatus -> Text) -> RcvFileStatus -> SQLData
forall b c a. (b -> c) -> (a -> b) -> a -> c
. RcvFileStatus -> Text
forall a. TextEncoding a => a -> Text
textEncode

instance TextEncoding RcvFileStatus where
  textDecode :: Text -> Maybe RcvFileStatus
textDecode = \case
    Text
"receiving" -> RcvFileStatus -> Maybe RcvFileStatus
forall a. a -> Maybe a
Just RcvFileStatus
RFSReceiving
    Text
"received" -> RcvFileStatus -> Maybe RcvFileStatus
forall a. a -> Maybe a
Just RcvFileStatus
RFSReceived
    Text
"decrypting" -> RcvFileStatus -> Maybe RcvFileStatus
forall a. a -> Maybe a
Just RcvFileStatus
RFSDecrypting
    Text
"complete" -> RcvFileStatus -> Maybe RcvFileStatus
forall a. a -> Maybe a
Just RcvFileStatus
RFSComplete
    Text
"error" -> RcvFileStatus -> Maybe RcvFileStatus
forall a. a -> Maybe a
Just RcvFileStatus
RFSError
    Text
_ -> Maybe RcvFileStatus
forall a. Maybe a
Nothing
  textEncode :: RcvFileStatus -> Text
textEncode = \case
    RcvFileStatus
RFSReceiving -> Text
"receiving"
    RcvFileStatus
RFSReceived -> Text
"received"
    RcvFileStatus
RFSDecrypting -> Text
"decrypting"
    RcvFileStatus
RFSComplete -> Text
"complete"
    RcvFileStatus
RFSError -> Text
"error"

data RcvFileChunk = RcvFileChunk
  { RcvFileChunk -> Int64
rcvFileId :: DBRcvFileId,
    RcvFileChunk -> ByteString
rcvFileEntityId :: RcvFileId,
    RcvFileChunk -> Int64
userId :: Int64,
    RcvFileChunk -> Int64
rcvChunkId :: Int64,
    RcvFileChunk -> Int
chunkNo :: Int,
    RcvFileChunk -> FileSize Word32
chunkSize :: FileSize Word32,
    RcvFileChunk -> FileDigest
digest :: FileDigest,
    RcvFileChunk -> [RcvFileChunkReplica]
replicas :: [RcvFileChunkReplica],
    RcvFileChunk -> String
fileTmpPath :: FilePath,
    RcvFileChunk -> Maybe String
chunkTmpPath :: Maybe FilePath
  }
  deriving (Int -> RcvFileChunk -> ShowS
[RcvFileChunk] -> ShowS
RcvFileChunk -> String
(Int -> RcvFileChunk -> ShowS)
-> (RcvFileChunk -> String)
-> ([RcvFileChunk] -> ShowS)
-> Show RcvFileChunk
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> RcvFileChunk -> ShowS
showsPrec :: Int -> RcvFileChunk -> ShowS
$cshow :: RcvFileChunk -> String
show :: RcvFileChunk -> String
$cshowList :: [RcvFileChunk] -> ShowS
showList :: [RcvFileChunk] -> ShowS
Show)

data RcvFileChunkReplica = RcvFileChunkReplica
  { RcvFileChunkReplica -> Int64
rcvChunkReplicaId :: Int64,
    RcvFileChunkReplica -> XFTPServer
server :: XFTPServer,
    RcvFileChunkReplica -> ChunkReplicaId
replicaId :: ChunkReplicaId,
    RcvFileChunkReplica -> APrivateAuthKey
replicaKey :: C.APrivateAuthKey,
    RcvFileChunkReplica -> Bool
received :: Bool,
    RcvFileChunkReplica -> Maybe Int64
delay :: Maybe Int64,
    RcvFileChunkReplica -> Int
retries :: Int
  }
  deriving (Int -> RcvFileChunkReplica -> ShowS
[RcvFileChunkReplica] -> ShowS
RcvFileChunkReplica -> String
(Int -> RcvFileChunkReplica -> ShowS)
-> (RcvFileChunkReplica -> String)
-> ([RcvFileChunkReplica] -> ShowS)
-> Show RcvFileChunkReplica
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> RcvFileChunkReplica -> ShowS
showsPrec :: Int -> RcvFileChunkReplica -> ShowS
$cshow :: RcvFileChunkReplica -> String
show :: RcvFileChunkReplica -> String
$cshowList :: [RcvFileChunkReplica] -> ShowS
showList :: [RcvFileChunkReplica] -> ShowS
Show)

data RcvFileRedirect = RcvFileRedirect
  { RcvFileRedirect -> Int64
redirectDbId :: DBRcvFileId,
    RcvFileRedirect -> ByteString
redirectEntityId :: RcvFileId,
    RcvFileRedirect -> RedirectFileInfo
redirectFileInfo :: RedirectFileInfo
  }
  deriving (Int -> RcvFileRedirect -> ShowS
[RcvFileRedirect] -> ShowS
RcvFileRedirect -> String
(Int -> RcvFileRedirect -> ShowS)
-> (RcvFileRedirect -> String)
-> ([RcvFileRedirect] -> ShowS)
-> Show RcvFileRedirect
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> RcvFileRedirect -> ShowS
showsPrec :: Int -> RcvFileRedirect -> ShowS
$cshow :: RcvFileRedirect -> String
show :: RcvFileRedirect -> String
$cshowList :: [RcvFileRedirect] -> ShowS
showList :: [RcvFileRedirect] -> ShowS
Show)

-- Sending files

type DBSndFileId = Int64

data SndFile = SndFile
  { SndFile -> Int64
sndFileId :: DBSndFileId,
    SndFile -> ByteString
sndFileEntityId :: SndFileId,
    SndFile -> Int64
userId :: Int64,
    SndFile -> Int
numRecipients :: Int,
    SndFile -> Maybe FileDigest
digest :: Maybe FileDigest,
    SndFile -> SbKey
key :: C.SbKey,
    SndFile -> CbNonce
nonce :: C.CbNonce,
    SndFile -> [SndFileChunk]
chunks :: [SndFileChunk],
    SndFile -> CryptoFile
srcFile :: CryptoFile,
    SndFile -> Maybe String
prefixPath :: Maybe FilePath,
    SndFile -> SndFileStatus
status :: SndFileStatus,
    SndFile -> Bool
deleted :: Bool,
    SndFile -> Maybe RedirectFileInfo
redirect :: Maybe RedirectFileInfo
  }
  deriving (Int -> SndFile -> ShowS
[SndFile] -> ShowS
SndFile -> String
(Int -> SndFile -> ShowS)
-> (SndFile -> String) -> ([SndFile] -> ShowS) -> Show SndFile
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> SndFile -> ShowS
showsPrec :: Int -> SndFile -> ShowS
$cshow :: SndFile -> String
show :: SndFile -> String
$cshowList :: [SndFile] -> ShowS
showList :: [SndFile] -> ShowS
Show)

sndFileEncPath :: FilePath -> FilePath
sndFileEncPath :: ShowS
sndFileEncPath String
prefixPath = String
prefixPath String -> ShowS
</> String
"xftp.encrypted"

data SndFileStatus
  = SFSNew -- db record created
  | SFSEncrypting -- encryption started
  | SFSEncrypted -- encryption complete
  | SFSUploading -- all chunk replicas are created on servers
  | SFSComplete -- all chunk replicas are uploaded
  | SFSError -- permanent error
  deriving (SndFileStatus -> SndFileStatus -> Bool
(SndFileStatus -> SndFileStatus -> Bool)
-> (SndFileStatus -> SndFileStatus -> Bool) -> Eq SndFileStatus
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: SndFileStatus -> SndFileStatus -> Bool
== :: SndFileStatus -> SndFileStatus -> Bool
$c/= :: SndFileStatus -> SndFileStatus -> Bool
/= :: SndFileStatus -> SndFileStatus -> Bool
Eq, Int -> SndFileStatus -> ShowS
[SndFileStatus] -> ShowS
SndFileStatus -> String
(Int -> SndFileStatus -> ShowS)
-> (SndFileStatus -> String)
-> ([SndFileStatus] -> ShowS)
-> Show SndFileStatus
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> SndFileStatus -> ShowS
showsPrec :: Int -> SndFileStatus -> ShowS
$cshow :: SndFileStatus -> String
show :: SndFileStatus -> String
$cshowList :: [SndFileStatus] -> ShowS
showList :: [SndFileStatus] -> ShowS
Show)

instance FromField SndFileStatus where fromField :: FieldParser SndFileStatus
fromField = (Text -> Maybe SndFileStatus) -> FieldParser SndFileStatus
forall a. Typeable a => (Text -> Maybe a) -> Field -> Ok a
fromTextField_ Text -> Maybe SndFileStatus
forall a. TextEncoding a => Text -> Maybe a
textDecode

instance ToField SndFileStatus where toField :: SndFileStatus -> SQLData
toField = Text -> SQLData
forall a. ToField a => a -> SQLData
toField (Text -> SQLData)
-> (SndFileStatus -> Text) -> SndFileStatus -> SQLData
forall b c a. (b -> c) -> (a -> b) -> a -> c
. SndFileStatus -> Text
forall a. TextEncoding a => a -> Text
textEncode

instance TextEncoding SndFileStatus where
  textDecode :: Text -> Maybe SndFileStatus
textDecode = \case
    Text
"new" -> SndFileStatus -> Maybe SndFileStatus
forall a. a -> Maybe a
Just SndFileStatus
SFSNew
    Text
"encrypting" -> SndFileStatus -> Maybe SndFileStatus
forall a. a -> Maybe a
Just SndFileStatus
SFSEncrypting
    Text
"encrypted" -> SndFileStatus -> Maybe SndFileStatus
forall a. a -> Maybe a
Just SndFileStatus
SFSEncrypted
    Text
"uploading" -> SndFileStatus -> Maybe SndFileStatus
forall a. a -> Maybe a
Just SndFileStatus
SFSUploading
    Text
"complete" -> SndFileStatus -> Maybe SndFileStatus
forall a. a -> Maybe a
Just SndFileStatus
SFSComplete
    Text
"error" -> SndFileStatus -> Maybe SndFileStatus
forall a. a -> Maybe a
Just SndFileStatus
SFSError
    Text
_ -> Maybe SndFileStatus
forall a. Maybe a
Nothing
  textEncode :: SndFileStatus -> Text
textEncode = \case
    SndFileStatus
SFSNew -> Text
"new"
    SndFileStatus
SFSEncrypting -> Text
"encrypting"
    SndFileStatus
SFSEncrypted -> Text
"encrypted"
    SndFileStatus
SFSUploading -> Text
"uploading"
    SndFileStatus
SFSComplete -> Text
"complete"
    SndFileStatus
SFSError -> Text
"error"

data SndFileChunk = SndFileChunk
  { SndFileChunk -> Int64
sndFileId :: DBSndFileId,
    SndFileChunk -> ByteString
sndFileEntityId :: SndFileId,
    SndFileChunk -> Int64
userId :: Int64,
    SndFileChunk -> Int
numRecipients :: Int,
    SndFileChunk -> Int64
sndChunkId :: Int64,
    SndFileChunk -> Int
chunkNo :: Int,
    SndFileChunk -> XFTPChunkSpec
chunkSpec :: XFTPChunkSpec,
    SndFileChunk -> String
filePrefixPath :: FilePath,
    SndFileChunk -> FileDigest
digest :: FileDigest,
    SndFileChunk -> [SndFileChunkReplica]
replicas :: [SndFileChunkReplica]
  }
  deriving (Int -> SndFileChunk -> ShowS
[SndFileChunk] -> ShowS
SndFileChunk -> String
(Int -> SndFileChunk -> ShowS)
-> (SndFileChunk -> String)
-> ([SndFileChunk] -> ShowS)
-> Show SndFileChunk
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> SndFileChunk -> ShowS
showsPrec :: Int -> SndFileChunk -> ShowS
$cshow :: SndFileChunk -> String
show :: SndFileChunk -> String
$cshowList :: [SndFileChunk] -> ShowS
showList :: [SndFileChunk] -> ShowS
Show)

sndChunkSize :: SndFileChunk -> Word32
sndChunkSize :: SndFileChunk -> Word32
sndChunkSize SndFileChunk {$sel:chunkSpec:SndFileChunk :: SndFileChunk -> XFTPChunkSpec
chunkSpec = XFTPChunkSpec {Word32
chunkSize :: Word32
$sel:chunkSize:XFTPChunkSpec :: XFTPChunkSpec -> Word32
chunkSize}} = Word32
chunkSize

data NewSndChunkReplica = NewSndChunkReplica
  { NewSndChunkReplica -> XFTPServer
server :: XFTPServer,
    NewSndChunkReplica -> ChunkReplicaId
replicaId :: ChunkReplicaId,
    NewSndChunkReplica -> APrivateAuthKey
replicaKey :: C.APrivateAuthKey,
    NewSndChunkReplica -> [(ChunkReplicaId, APrivateAuthKey)]
rcvIdsKeys :: [(ChunkReplicaId, C.APrivateAuthKey)]
  }
  deriving (Int -> NewSndChunkReplica -> ShowS
[NewSndChunkReplica] -> ShowS
NewSndChunkReplica -> String
(Int -> NewSndChunkReplica -> ShowS)
-> (NewSndChunkReplica -> String)
-> ([NewSndChunkReplica] -> ShowS)
-> Show NewSndChunkReplica
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> NewSndChunkReplica -> ShowS
showsPrec :: Int -> NewSndChunkReplica -> ShowS
$cshow :: NewSndChunkReplica -> String
show :: NewSndChunkReplica -> String
$cshowList :: [NewSndChunkReplica] -> ShowS
showList :: [NewSndChunkReplica] -> ShowS
Show)

data SndFileChunkReplica = SndFileChunkReplica
  { SndFileChunkReplica -> Int64
sndChunkReplicaId :: Int64,
    SndFileChunkReplica -> XFTPServer
server :: XFTPServer,
    SndFileChunkReplica -> ChunkReplicaId
replicaId :: ChunkReplicaId,
    SndFileChunkReplica -> APrivateAuthKey
replicaKey :: C.APrivateAuthKey,
    SndFileChunkReplica -> [(ChunkReplicaId, APrivateAuthKey)]
rcvIdsKeys :: [(ChunkReplicaId, C.APrivateAuthKey)],
    SndFileChunkReplica -> SndFileReplicaStatus
replicaStatus :: SndFileReplicaStatus,
    SndFileChunkReplica -> Maybe Int64
delay :: Maybe Int64,
    SndFileChunkReplica -> Int
retries :: Int
  }
  deriving (Int -> SndFileChunkReplica -> ShowS
[SndFileChunkReplica] -> ShowS
SndFileChunkReplica -> String
(Int -> SndFileChunkReplica -> ShowS)
-> (SndFileChunkReplica -> String)
-> ([SndFileChunkReplica] -> ShowS)
-> Show SndFileChunkReplica
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> SndFileChunkReplica -> ShowS
showsPrec :: Int -> SndFileChunkReplica -> ShowS
$cshow :: SndFileChunkReplica -> String
show :: SndFileChunkReplica -> String
$cshowList :: [SndFileChunkReplica] -> ShowS
showList :: [SndFileChunkReplica] -> ShowS
Show)

data SndFileReplicaStatus
  = SFRSCreated
  | SFRSUploaded
  deriving (SndFileReplicaStatus -> SndFileReplicaStatus -> Bool
(SndFileReplicaStatus -> SndFileReplicaStatus -> Bool)
-> (SndFileReplicaStatus -> SndFileReplicaStatus -> Bool)
-> Eq SndFileReplicaStatus
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: SndFileReplicaStatus -> SndFileReplicaStatus -> Bool
== :: SndFileReplicaStatus -> SndFileReplicaStatus -> Bool
$c/= :: SndFileReplicaStatus -> SndFileReplicaStatus -> Bool
/= :: SndFileReplicaStatus -> SndFileReplicaStatus -> Bool
Eq, Int -> SndFileReplicaStatus -> ShowS
[SndFileReplicaStatus] -> ShowS
SndFileReplicaStatus -> String
(Int -> SndFileReplicaStatus -> ShowS)
-> (SndFileReplicaStatus -> String)
-> ([SndFileReplicaStatus] -> ShowS)
-> Show SndFileReplicaStatus
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> SndFileReplicaStatus -> ShowS
showsPrec :: Int -> SndFileReplicaStatus -> ShowS
$cshow :: SndFileReplicaStatus -> String
show :: SndFileReplicaStatus -> String
$cshowList :: [SndFileReplicaStatus] -> ShowS
showList :: [SndFileReplicaStatus] -> ShowS
Show)

instance FromField SndFileReplicaStatus where fromField :: FieldParser SndFileReplicaStatus
fromField = (Text -> Maybe SndFileReplicaStatus)
-> FieldParser SndFileReplicaStatus
forall a. Typeable a => (Text -> Maybe a) -> Field -> Ok a
fromTextField_ Text -> Maybe SndFileReplicaStatus
forall a. TextEncoding a => Text -> Maybe a
textDecode

instance ToField SndFileReplicaStatus where toField :: SndFileReplicaStatus -> SQLData
toField = Text -> SQLData
forall a. ToField a => a -> SQLData
toField (Text -> SQLData)
-> (SndFileReplicaStatus -> Text)
-> SndFileReplicaStatus
-> SQLData
forall b c a. (b -> c) -> (a -> b) -> a -> c
. SndFileReplicaStatus -> Text
forall a. TextEncoding a => a -> Text
textEncode

instance TextEncoding SndFileReplicaStatus where
  textDecode :: Text -> Maybe SndFileReplicaStatus
textDecode = \case
    Text
"created" -> SndFileReplicaStatus -> Maybe SndFileReplicaStatus
forall a. a -> Maybe a
Just SndFileReplicaStatus
SFRSCreated
    Text
"uploaded" -> SndFileReplicaStatus -> Maybe SndFileReplicaStatus
forall a. a -> Maybe a
Just SndFileReplicaStatus
SFRSUploaded
    Text
_ -> Maybe SndFileReplicaStatus
forall a. Maybe a
Nothing
  textEncode :: SndFileReplicaStatus -> Text
textEncode = \case
    SndFileReplicaStatus
SFRSCreated -> Text
"created"
    SndFileReplicaStatus
SFRSUploaded -> Text
"uploaded"

data DeletedSndChunkReplica = DeletedSndChunkReplica
  { DeletedSndChunkReplica -> Int64
deletedSndChunkReplicaId :: Int64,
    DeletedSndChunkReplica -> Int64
userId :: Int64,
    DeletedSndChunkReplica -> XFTPServer
server :: XFTPServer,
    DeletedSndChunkReplica -> ChunkReplicaId
replicaId :: ChunkReplicaId,
    DeletedSndChunkReplica -> APrivateAuthKey
replicaKey :: C.APrivateAuthKey,
    DeletedSndChunkReplica -> FileDigest
chunkDigest :: FileDigest,
    DeletedSndChunkReplica -> Maybe Int64
delay :: Maybe Int64,
    DeletedSndChunkReplica -> Int
retries :: Int
  }
  deriving (Int -> DeletedSndChunkReplica -> ShowS
[DeletedSndChunkReplica] -> ShowS
DeletedSndChunkReplica -> String
(Int -> DeletedSndChunkReplica -> ShowS)
-> (DeletedSndChunkReplica -> String)
-> ([DeletedSndChunkReplica] -> ShowS)
-> Show DeletedSndChunkReplica
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> DeletedSndChunkReplica -> ShowS
showsPrec :: Int -> DeletedSndChunkReplica -> ShowS
$cshow :: DeletedSndChunkReplica -> String
show :: DeletedSndChunkReplica -> String
$cshowList :: [DeletedSndChunkReplica] -> ShowS
showList :: [DeletedSndChunkReplica] -> ShowS
Show)

data SentRecipientReplica = SentRecipientReplica
  { SentRecipientReplica -> Int
chunkNo :: Int,
    SentRecipientReplica -> XFTPServer
server :: XFTPServer,
    SentRecipientReplica -> Int
rcvNo :: Int,
    SentRecipientReplica -> ChunkReplicaId
replicaId :: ChunkReplicaId,
    SentRecipientReplica -> APrivateAuthKey
replicaKey :: C.APrivateAuthKey,
    SentRecipientReplica -> FileDigest
digest :: FileDigest,
    SentRecipientReplica -> FileSize Word32
chunkSize :: FileSize Word32
  }

data FileErrorType
  = -- | cannot proceed with download from not approved relays without proxy
    NOT_APPROVED
  | -- | max file size exceeded
    SIZE
  | -- | bad redirect data
    REDIRECT {FileErrorType -> String
redirectError :: String}
  | -- | file crypto error
    FILE_IO {FileErrorType -> String
fileIOError :: String}
  | -- | file not found or was deleted
    NO_FILE
  deriving (FileErrorType -> FileErrorType -> Bool
(FileErrorType -> FileErrorType -> Bool)
-> (FileErrorType -> FileErrorType -> Bool) -> Eq FileErrorType
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: FileErrorType -> FileErrorType -> Bool
== :: FileErrorType -> FileErrorType -> Bool
$c/= :: FileErrorType -> FileErrorType -> Bool
/= :: FileErrorType -> FileErrorType -> Bool
Eq, Int -> FileErrorType -> ShowS
[FileErrorType] -> ShowS
FileErrorType -> String
(Int -> FileErrorType -> ShowS)
-> (FileErrorType -> String)
-> ([FileErrorType] -> ShowS)
-> Show FileErrorType
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> FileErrorType -> ShowS
showsPrec :: Int -> FileErrorType -> ShowS
$cshow :: FileErrorType -> String
show :: FileErrorType -> String
$cshowList :: [FileErrorType] -> ShowS
showList :: [FileErrorType] -> ShowS
Show)

instance StrEncoding FileErrorType where
  strP :: Parser FileErrorType
strP =
    (Char -> Bool) -> Parser ByteString
A.takeTill (Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
== Char
' ')
      Parser ByteString
-> (ByteString -> Parser FileErrorType) -> Parser FileErrorType
forall a b.
Parser ByteString a
-> (a -> Parser ByteString b) -> Parser ByteString b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \case
        ByteString
"NOT_APPROVED" -> FileErrorType -> Parser FileErrorType
forall a. a -> Parser ByteString a
forall (f :: * -> *) a. Applicative f => a -> f a
pure FileErrorType
NOT_APPROVED
        ByteString
"SIZE" -> FileErrorType -> Parser FileErrorType
forall a. a -> Parser ByteString a
forall (f :: * -> *) a. Applicative f => a -> f a
pure FileErrorType
SIZE
        ByteString
"REDIRECT" -> String -> FileErrorType
REDIRECT (String -> FileErrorType)
-> Parser ByteString String -> Parser FileErrorType
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> (Parser Char
A.space Parser Char -> Parser ByteString String -> Parser ByteString String
forall a b.
Parser ByteString a -> Parser ByteString b -> Parser ByteString b
forall (f :: * -> *) a b. Applicative f => f a -> f b -> f b
*> Parser ByteString String
textP)
        ByteString
"FILE_IO" -> String -> FileErrorType
FILE_IO (String -> FileErrorType)
-> Parser ByteString String -> Parser FileErrorType
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> (Parser Char
A.space Parser Char -> Parser ByteString String -> Parser ByteString String
forall a b.
Parser ByteString a -> Parser ByteString b -> Parser ByteString b
forall (f :: * -> *) a b. Applicative f => f a -> f b -> f b
*> Parser ByteString String
textP)
        ByteString
"NO_FILE" -> FileErrorType -> Parser FileErrorType
forall a. a -> Parser ByteString a
forall (f :: * -> *) a. Applicative f => a -> f a
pure FileErrorType
NO_FILE
        ByteString
_ -> String -> Parser FileErrorType
forall a. String -> Parser ByteString a
forall (m :: * -> *) a. MonadFail m => String -> m a
fail String
"bad FileErrorType"
  strEncode :: FileErrorType -> ByteString
strEncode = \case
    FileErrorType
NOT_APPROVED -> ByteString
"NOT_APPROVED"
    FileErrorType
SIZE -> ByteString
"SIZE"
    REDIRECT String
e -> ByteString
"REDIRECT " ByteString -> ByteString -> ByteString
forall a. Semigroup a => a -> a -> a
<> Text -> ByteString
encodeUtf8 (String -> Text
T.pack String
e)
    FILE_IO String
e -> ByteString
"FILE_IO " ByteString -> ByteString -> ByteString
forall a. Semigroup a => a -> a -> a
<> Text -> ByteString
encodeUtf8 (String -> Text
T.pack String
e)
    FileErrorType
NO_FILE -> ByteString
"NO_FILE"

$(J.deriveJSON (sumTypeJSON id) ''FileErrorType)