mirror of
https://github.com/simplex-chat/simplex-chat.git
synced 2024-12-17 17:20:21 +01:00
Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| ec98ea051b | |||
| 435ea9a453 | |||
| 9ff11f886e |
+17
-17
@@ -17,7 +17,7 @@ _Please note_: when you change the servers in the app configuration, it only aff
|
||||
|
||||
## Installation
|
||||
|
||||
0. First, install `smp-server`:
|
||||
1. First, install `smp-server`:
|
||||
|
||||
- Manual deployment (see below)
|
||||
|
||||
@@ -28,7 +28,7 @@ _Please note_: when you change the servers in the app configuration, it only aff
|
||||
|
||||
Manual installation requires some preliminary actions:
|
||||
|
||||
0. Install binary:
|
||||
1. Install binary:
|
||||
|
||||
- Using offical binaries:
|
||||
|
||||
@@ -40,20 +40,20 @@ Manual installation requires some preliminary actions:
|
||||
|
||||
Please refer to [Build from source: Using your distribution](https://github.com/simplex-chat/simplexmq#using-your-distribution)
|
||||
|
||||
1. Create user and group for `smp-server`:
|
||||
2. Create user and group for `smp-server`:
|
||||
|
||||
```sh
|
||||
sudo useradd -m smp
|
||||
```
|
||||
|
||||
2. Create necessary directories and assign permissions:
|
||||
3. Create necessary directories and assign permissions:
|
||||
|
||||
```sh
|
||||
sudo mkdir -p /var/opt/simplex /etc/opt/simplex
|
||||
sudo chown smp:smp /var/opt/simplex /etc/opt/simplex
|
||||
```
|
||||
|
||||
3. Allow `smp-server` port in firewall:
|
||||
4. Allow `smp-server` port in firewall:
|
||||
|
||||
```sh
|
||||
# For Ubuntu
|
||||
@@ -63,7 +63,7 @@ Manual installation requires some preliminary actions:
|
||||
sudo firewall-cmd --reload
|
||||
```
|
||||
|
||||
4. **Optional** — If you're using distribution with `systemd`, create `/etc/systemd/system/smp-server.service` file with the following content:
|
||||
5. **Optional** — If you're using distribution with `systemd`, create `/etc/systemd/system/smp-server.service` file with the following content:
|
||||
|
||||
```sh
|
||||
[Unit]
|
||||
@@ -398,20 +398,20 @@ To import `csv` to `Grafana` one should:
|
||||
|
||||
2. Allow local mode by appending following:
|
||||
|
||||
```sh
|
||||
[plugin.marcusolsson-csv-datasource]
|
||||
allow_local_mode = true
|
||||
```
|
||||
```sh
|
||||
[plugin.marcusolsson-csv-datasource]
|
||||
allow_local_mode = true
|
||||
```
|
||||
|
||||
... to `/etc/grafana/grafana.ini`
|
||||
... to `/etc/grafana/grafana.ini`
|
||||
|
||||
3. Add a CSV data source:
|
||||
|
||||
- In the side menu, click the Configuration tab (cog icon)
|
||||
- Click Add data source in the top-right corner of the Data Sources tab
|
||||
- Enter "CSV" in the search box to find the CSV data source
|
||||
- Click the search result that says "CSV"
|
||||
- In URL, enter a file that points to CSV content
|
||||
- In the side menu, click the Configuration tab (cog icon)
|
||||
- Click Add data source in the top-right corner of the Data Sources tab
|
||||
- Enter "CSV" in the search box to find the CSV data source
|
||||
- Click the search result that says "CSV"
|
||||
- In URL, enter a file that points to CSV content
|
||||
|
||||
4. You're done! You should be able to create your own dashboard with statistics.
|
||||
|
||||
@@ -445,7 +445,7 @@ To update your smp-server to latest version, choose your installation method and
|
||||
- [Docker container](https://github.com/simplex-chat/simplexmq#using-docker)
|
||||
1. Stop and remove the container:
|
||||
```sh
|
||||
docker rm $(docker stop $(docker ps -a -q --filter ancestor=simplexchat/smp-server --format="{{.ID}}"))
|
||||
docker rm $(docker stop $(docker ps -a -q --filter ancestor=simplexchat/smp-server --format="\{\{.ID\}\}"))
|
||||
```
|
||||
2. Pull latest image:
|
||||
```sh
|
||||
|
||||
+1
-1
@@ -448,7 +448,7 @@ To update your XFTP server to latest version, choose your installation method an
|
||||
- [Docker container](https://github.com/simplex-chat/simplexmq#using-docker)
|
||||
1. Stop and remove the container:
|
||||
```sh
|
||||
docker rm $(docker stop $(docker ps -a -q --filter ancestor=simplexchat/xftp-server --format="{{.ID}}"))
|
||||
docker rm $(docker stop $(docker ps -a -q --filter ancestor=simplexchat/xftp-server --format="\{\{.ID\}\}"))
|
||||
```
|
||||
2. Pull latest image:
|
||||
```sh
|
||||
|
||||
+68
-21
@@ -1,3 +1,5 @@
|
||||
{-# LANGUAGE BangPatterns #-}
|
||||
{-# LANGUAGE CPP #-}
|
||||
{-# LANGUAGE DataKinds #-}
|
||||
{-# LANGUAGE DuplicateRecordFields #-}
|
||||
{-# LANGUAGE FlexibleContexts #-}
|
||||
@@ -15,6 +17,9 @@
|
||||
|
||||
module Simplex.Chat where
|
||||
|
||||
#if MIN_VERSION_base(4,18,0)
|
||||
import GHC.Conc.Sync (BlockReason (..), ThreadStatus (..), listThreads, threadLabel, threadStatus)
|
||||
#endif
|
||||
import Control.Applicative (optional, (<|>))
|
||||
import Control.Concurrent.STM (retry)
|
||||
import Control.Logger.Simple
|
||||
@@ -330,7 +335,7 @@ startChatController mainApp = do
|
||||
a1 <- async agentSubscriber
|
||||
a2 <-
|
||||
if mainApp
|
||||
then Just <$> async (subscribeUsers False users)
|
||||
then Just <$> async (labelMyThread "startChatController.subscribeUsers" >> subscribeUsers False users)
|
||||
else pure Nothing
|
||||
atomically . writeTVar s $ Just (a1, a2)
|
||||
when mainApp $ do
|
||||
@@ -561,8 +566,8 @@ processChatCommand' vr = \case
|
||||
chatWriteVar chatActivated True
|
||||
when restoreChat $ do
|
||||
users <- withStoreCtx' (Just "APIActivateChat, getUsers") getUsers
|
||||
void . forkIO $ subscribeUsers True users
|
||||
void . forkIO $ startFilesToReceive users
|
||||
void . forkIO $ labelMyThread "APIActivateChat.subscribeUsers" >> subscribeUsers True users
|
||||
void . forkIO $ labelMyThread "APIActivateChat.startFilesToReceive" >> startFilesToReceive users
|
||||
setAllExpireCIFlags True
|
||||
ok_
|
||||
APISuspendChat t -> do
|
||||
@@ -2008,6 +2013,7 @@ processChatCommand' vr = \case
|
||||
when (fileSize > toInteger maxFileSizeHard) $ throwChatError $ CEFileSize filePath
|
||||
(_, _, fileTransferMeta) <- xftpSndFileTransfer_ user file fileSize 1 Nothing
|
||||
pure CRSndStandaloneFileCreated {user, fileTransferMeta}
|
||||
APIStandaloneFileInfo FileDescriptionURI {clientData} -> pure . CRStandaloneFileInfo $ clientData >>= J.decodeStrict . encodeUtf8
|
||||
APIDownloadStandaloneFile userId uri file -> withUserId userId $ \user -> do
|
||||
ft <- receiveViaURI user uri file
|
||||
pure $ CRRcvStandaloneFileCreated user ft
|
||||
@@ -2024,6 +2030,10 @@ processChatCommand' vr = \case
|
||||
pure CRDebugLocks {chatLockName, agentLocks}
|
||||
GetAgentWorkers -> CRAgentWorkersSummary <$> withAgent getAgentWorkersSummary
|
||||
GetAgentWorkersDetails -> CRAgentWorkersDetails <$> withAgent getAgentWorkersDetails
|
||||
GetThreads -> do
|
||||
(threadsRunning, threadsBlocked, threadsBlockedConc, threadsDone) <- liftIO getThreadsSummary
|
||||
pure CRThreadsSummary {threadsRunning, threadsBlocked, threadsBlockedConc, threadsDone}
|
||||
GetThreadsDetails -> CRThreadsDetails <$> liftIO getThreadsDetails
|
||||
GetAgentStats -> CRAgentStats . map stat <$> withAgent getAgentStats
|
||||
where
|
||||
stat (AgentStatsKey {host, clientTs, cmd, res}, count) =
|
||||
@@ -2889,6 +2899,7 @@ deleteGroupLink_ user gInfo conn = do
|
||||
|
||||
agentSubscriber :: forall m. (MonadUnliftIO m, MonadReader ChatController m) => m ()
|
||||
agentSubscriber = do
|
||||
labelMyThread "agentSubscriber"
|
||||
q <- asks $ subQ . smpAgent
|
||||
l <- asks chatLock
|
||||
forever $ atomically (readTBQueue q) >>= void . process l
|
||||
@@ -3051,6 +3062,7 @@ subscribeUserConnections vr onlyNeeded agentBatchSubscribe user@User {userId} =
|
||||
forM_ sftRs $ \(ft@SndFileTransfer {fileId, fileStatus}, err_) -> do
|
||||
forM_ err_ $ toView . CRSndFileSubError user ft
|
||||
void . forkIO $ do
|
||||
labelMyThread "sndFileSubsToView"
|
||||
threadDelay 1000000
|
||||
l <- asks chatLock
|
||||
when (fileStatus == FSConnected) . unlessM (isFileActive fileId sndFiles) . withLock l "subscribe sendFileChunk" $
|
||||
@@ -3271,13 +3283,15 @@ processAgentMsgSndFile _corrId aFileId msg =
|
||||
Nothing -> do
|
||||
withAgent (`xftpDeleteSndFileInternal` aFileId)
|
||||
withStore' $ \db -> createExtraSndFTDescrs db user fileId (map fileDescrText rfds)
|
||||
case mapMaybe fileDescrURI rfds of
|
||||
[] -> case rfds of
|
||||
[] -> logError "File sent without receiver descriptions" -- should not happen
|
||||
(rfd : _) -> xftpSndFileRedirect user fileId rfd >>= toView . CRSndFileRedirectStartXFTP user ft
|
||||
uris -> do
|
||||
ft' <- maybe (pure ft) (\fId -> withStore $ \db -> getFileTransferMeta db user fId) xftpRedirectFor
|
||||
toView $ CRSndStandaloneFileComplete user ft' uris
|
||||
case rfds of
|
||||
[] -> sendFileError "no receiver descriptions" fileId vr ft
|
||||
rfd : _ -> case [fd | fd@(FD.ValidFileDescription FD.FileDescription {chunks = [_]}) <- rfds] of
|
||||
[] -> case xftpRedirectFor of
|
||||
Nothing -> xftpSndFileRedirect user fileId rfd >>= toView . CRSndFileRedirectStartXFTP user ft
|
||||
Just _ -> sendFileError "Prohibit chaining redirects" fileId vr ft
|
||||
rfds' -> do -- we have 1 chunk - use it as URI whether it is redirect or not
|
||||
ft' <- maybe (pure ft) (\fId -> withStore $ \db -> getFileTransferMeta db user fId) xftpRedirectFor
|
||||
toView $ CRSndStandaloneFileComplete user ft' $ map (decodeLatin1 . strEncode . FD.fileDescriptionURI) rfds'
|
||||
Just (AChatItem _ d cInfo _ci@ChatItem {meta = CIMeta {itemSharedMsgId = msgId_, itemDeleted}}) ->
|
||||
case (msgId_, itemDeleted) of
|
||||
(Just sharedMsgId, Nothing) -> do
|
||||
@@ -3319,19 +3333,11 @@ processAgentMsgSndFile _corrId aFileId msg =
|
||||
SFERR e
|
||||
| temporaryAgentError e ->
|
||||
throwChatError $ CEXFTPSndFile fileId (AgentSndFileId aFileId) e
|
||||
| otherwise -> do
|
||||
ci <- withStore $ \db -> do
|
||||
liftIO $ updateFileCancelled db user fileId CIFSSndError
|
||||
lookupChatItemByFileId db vr user fileId
|
||||
withAgent (`xftpDeleteSndFileInternal` aFileId)
|
||||
toView $ CRSndFileError user ci ft
|
||||
| otherwise ->
|
||||
sendFileError (tshow e) fileId vr ft
|
||||
where
|
||||
fileDescrText :: FilePartyI p => ValidFileDescription p -> T.Text
|
||||
fileDescrText = safeDecodeUtf8 . strEncode
|
||||
fileDescrURI :: ValidFileDescription 'FRecipient -> Maybe T.Text
|
||||
fileDescrURI vfd = if T.length uri < FD.qrSizeLimit then Just uri else Nothing
|
||||
where
|
||||
uri = decodeLatin1 . strEncode $ FD.fileDescriptionURI vfd
|
||||
sendFileDescription :: SndFileTransfer -> ValidFileDescription 'FRecipient -> SharedMsgId -> (ChatMsgEvent 'Json -> m (SndMessage, Int64)) -> m Int64
|
||||
sendFileDescription sft rfd msgId sendMsg = do
|
||||
let rfdText = fileDescrText rfd
|
||||
@@ -3346,6 +3352,14 @@ processAgentMsgSndFile _corrId aFileId msg =
|
||||
case L.nonEmpty fds of
|
||||
Just fds' -> loopSend fds'
|
||||
Nothing -> pure msgDeliveryId
|
||||
sendFileError :: Text -> Int64 -> VersionRange -> FileTransferMeta -> m ()
|
||||
sendFileError err fileId vr ft = do
|
||||
logError $ "Sent file error: " <> err
|
||||
ci <- withStore $ \db -> do
|
||||
liftIO $ updateFileCancelled db user fileId CIFSSndError
|
||||
lookupChatItemByFileId db vr user fileId
|
||||
withAgent (`xftpDeleteSndFileInternal` aFileId)
|
||||
toView $ CRSndFileError user ci ft
|
||||
|
||||
splitFileDescr :: ChatMonad m => RcvFileDescrText -> m (NonEmpty FileDescr)
|
||||
splitFileDescr rfdText = do
|
||||
@@ -6783,6 +6797,7 @@ chatCommandP =
|
||||
"/stop remote ctrl" $> StopRemoteCtrl,
|
||||
"/delete remote ctrl " *> (DeleteRemoteCtrl <$> A.decimal),
|
||||
"/_upload " *> (APIUploadStandaloneFile <$> A.decimal <* A.space <*> cryptoFileP),
|
||||
"/_download info " *> (APIStandaloneFileInfo <$> strP),
|
||||
"/_download " *> (APIDownloadStandaloneFile <$> A.decimal <* A.space <*> strP_ <*> cryptoFileP),
|
||||
("/quit" <|> "/q" <|> "/exit") $> QuitChat,
|
||||
("/version" <|> "/v") $> ShowVersion,
|
||||
@@ -6792,7 +6807,9 @@ chatCommandP =
|
||||
"/get subs" $> GetAgentSubs,
|
||||
"/get subs details" $> GetAgentSubsDetails,
|
||||
"/get workers" $> GetAgentWorkers,
|
||||
"/get workers details" $> GetAgentWorkersDetails
|
||||
"/get workers details" $> GetAgentWorkersDetails,
|
||||
"/get threads" $> GetThreads,
|
||||
"/get threads details" $> GetThreadsDetails
|
||||
]
|
||||
where
|
||||
choice = A.choice . map (\p -> p <* A.takeWhile (== ' ') <* A.endOfInput)
|
||||
@@ -6989,3 +7006,33 @@ xftpSndFileRedirect user ftId vfd = do
|
||||
|
||||
dummyFileDescr :: FileDescr
|
||||
dummyFileDescr = FileDescr {fileDescrText = "", fileDescrPartNo = 0, fileDescrComplete = False}
|
||||
|
||||
getThreadsSummary :: IO (Int, Int, Int, Int)
|
||||
getThreadsSummary = do
|
||||
#if MIN_VERSION_base(4,18,0)
|
||||
threads <- listThreads >>= mapM threadStatus
|
||||
pure $ foldl' byStatus (0, 0, 0, 0) threads
|
||||
where
|
||||
byStatus (!r, !b, !bc, !d) = \case
|
||||
ThreadRunning -> (r + 1, b, bc, d)
|
||||
ThreadDied -> (r, b, bc, d + 1)
|
||||
ThreadFinished -> (r, b, bc, d + 1)
|
||||
ThreadBlocked br -> case br of
|
||||
BlockedOnMVar -> (r, b, bc + 1, d)
|
||||
BlockedOnSTM -> (r, b, bc + 1, d)
|
||||
_ -> (r, b + 1, bc, d)
|
||||
#else
|
||||
getThreadsSummary = pure (0, 0, 0, 0)
|
||||
#endif
|
||||
|
||||
getThreadsDetails :: IO [[String]]
|
||||
#if MIN_VERSION_base(4,18,0)
|
||||
getThreadsDetails = do
|
||||
threads <- listThreads
|
||||
forM threads $ \tid -> do
|
||||
status <- threadStatus tid
|
||||
label <- threadLabel tid
|
||||
pure [drop 9 $ show tid, show status, show label]
|
||||
#else
|
||||
getThreadsDetails = pure []
|
||||
#endif
|
||||
|
||||
@@ -455,6 +455,7 @@ data ChatCommand
|
||||
| DeleteRemoteCtrl RemoteCtrlId -- Remove all local data associated with a remote controller session
|
||||
| APIUploadStandaloneFile UserId CryptoFile
|
||||
| APIDownloadStandaloneFile UserId FileDescriptionURI CryptoFile
|
||||
| APIStandaloneFileInfo FileDescriptionURI
|
||||
| QuitChat
|
||||
| ShowVersion
|
||||
| DebugLocks
|
||||
@@ -464,6 +465,8 @@ data ChatCommand
|
||||
| GetAgentSubsDetails
|
||||
| GetAgentWorkers
|
||||
| GetAgentWorkersDetails
|
||||
| GetThreads
|
||||
| GetThreadsDetails
|
||||
deriving (Show)
|
||||
|
||||
allowRemoteCommand :: ChatCommand -> Bool -- XXX: consider using Relay/Block/ForceLocal
|
||||
@@ -594,6 +597,7 @@ data ChatResponse
|
||||
| CRRcvFileAccepted {user :: User, chatItem :: AChatItem}
|
||||
| CRRcvFileAcceptedSndCancelled {user :: User, rcvFileTransfer :: RcvFileTransfer}
|
||||
| CRRcvFileDescrNotReady {user :: User, chatItem :: AChatItem}
|
||||
| CRStandaloneFileInfo {fileMeta :: Maybe J.Value}
|
||||
| CRRcvStandaloneFileCreated {user :: User, rcvFileTransfer :: RcvFileTransfer} -- returned by _download
|
||||
| CRRcvFileStart {user :: User, chatItem :: AChatItem} -- sent by chats
|
||||
| CRRcvFileProgressXFTP {user :: User, chatItem_ :: Maybe AChatItem, receivedSize :: Int64, totalSize :: Int64, rcvFileTransfer :: RcvFileTransfer}
|
||||
@@ -700,6 +704,8 @@ data ChatResponse
|
||||
| CRSQLResult {rows :: [Text]}
|
||||
| CRSlowSQLQueries {chatQueries :: [SlowSQLQuery], agentQueries :: [SlowSQLQuery]}
|
||||
| CRDebugLocks {chatLockName :: Maybe String, agentLocks :: AgentLocks}
|
||||
| CRThreadsSummary {threadsRunning :: Int, threadsBlocked :: Int, threadsBlockedConc :: Int, threadsDone :: Int}
|
||||
| CRThreadsDetails {threads :: [[String]]}
|
||||
| CRAgentStats {agentStats :: [[String]]}
|
||||
| CRAgentWorkersDetails {agentWorkersDetails :: AgentWorkersDetails}
|
||||
| CRAgentWorkersSummary {agentWorkersSummary :: AgentWorkersSummary}
|
||||
|
||||
@@ -218,6 +218,7 @@ responseToView hu@(currentRH, user_) ChatConfig {logLevel, showReactions, showRe
|
||||
CRSndFileError u (Just ci) _ -> ttyUser u $ uploadingFile "error" ci
|
||||
CRSndFileRcvCancelled u _ ft@SndFileTransfer {recipientDisplayName = c} ->
|
||||
ttyUser u [ttyContact c <> " cancelled receiving " <> sndFile ft]
|
||||
CRStandaloneFileInfo info_ -> maybe ["no file information in URI"] (\j -> [plain . LB.toStrict $ J.encode j]) info_
|
||||
CRContactConnecting u _ -> ttyUser u []
|
||||
CRContactConnected u ct userCustomProfile -> ttyUser u $ viewContactConnected ct userCustomProfile testView
|
||||
CRContactAnotherClient u c -> ttyUser u [ttyContact' c <> ": contact is connected to another client"]
|
||||
@@ -370,6 +371,8 @@ responseToView hu@(currentRH, user_) ChatConfig {logLevel, showReactions, showRe
|
||||
[ "agent workers details:",
|
||||
plain . LB.unpack $ J.encode agentWorkersDetails -- this would be huge, but copypastable when has its own line
|
||||
]
|
||||
CRThreadsSummary {threadsRunning, threadsBlocked, threadsBlockedConc, threadsDone} -> ["running: " <> sShow threadsRunning <> " blocked: " <> sShow threadsBlocked <> " waiting: " <> sShow threadsBlockedConc <> " done: " <> sShow threadsDone]
|
||||
CRThreadsDetails rows -> map (plain . intercalate ",") rows
|
||||
CRConnectionDisabled entity -> viewConnectionEntityDisabled entity
|
||||
CRAgentRcvQueueDeleted acId srv aqId err_ ->
|
||||
[ ("completed deleting rcv queue, agent connection id: " <> sShow acId)
|
||||
|
||||
@@ -13,6 +13,7 @@ import Control.Logger.Simple
|
||||
import qualified Data.Aeson as J
|
||||
import qualified Data.ByteString.Char8 as B
|
||||
import qualified Data.ByteString.Lazy.Char8 as LB
|
||||
import Network.HTTP.Types.URI (urlEncode)
|
||||
import Simplex.Chat (roundedFDCount)
|
||||
import Simplex.Chat.Controller (ChatConfig (..))
|
||||
import Simplex.Chat.Mobile.File
|
||||
@@ -52,7 +53,9 @@ chatFileTests = do
|
||||
it "should prohibit file transfers in groups based on preference" testProhibitFiles
|
||||
describe "file transfer over XFTP without chat items" $ do
|
||||
it "send and receive small standalone file" testXFTPStandaloneSmall
|
||||
it "send and receive small standalone file with extra information" testXFTPStandaloneSmallInfo
|
||||
it "send and receive large standalone file" testXFTPStandaloneLarge
|
||||
it "send and receive large standalone file with extra information" testXFTPStandaloneLargeInfo
|
||||
it "send and receive large standalone file using relative paths" testXFTPStandaloneRelativePaths
|
||||
xit "removes sent file from server" testXFTPStandaloneCancelSnd -- no error shown in tests
|
||||
it "removes received temporary files" testXFTPStandaloneCancelRcv
|
||||
@@ -848,11 +851,11 @@ testXFTPStandaloneSmall :: HasCallStack => FilePath -> IO ()
|
||||
testXFTPStandaloneSmall = testChat2 aliceProfile aliceDesktopProfile $ \src dst -> do
|
||||
withXFTPServer $ do
|
||||
logNote "sending"
|
||||
src ##> "/_upload 1 ./tests/fixtures/test.jpg"
|
||||
src <## "started standalone uploading file 1 (test.jpg)"
|
||||
src ##> "/_upload 1 ./tests/fixtures/logo.jpg"
|
||||
src <## "started standalone uploading file 1 (logo.jpg)"
|
||||
-- silent progress events
|
||||
threadDelay 250000
|
||||
src <## "file 1 (test.jpg) upload complete. download with:"
|
||||
src <## "file 1 (logo.jpg) upload complete. download with:"
|
||||
-- file description fits, enjoy the direct URIs
|
||||
_uri1 <- getTermLine src
|
||||
_uri2 <- getTermLine src
|
||||
@@ -860,13 +863,43 @@ testXFTPStandaloneSmall = testChat2 aliceProfile aliceDesktopProfile $ \src dst
|
||||
_uri4 <- getTermLine src
|
||||
|
||||
logNote "receiving"
|
||||
let dstFile = "./tests/tmp/test.jpg"
|
||||
let dstFile = "./tests/tmp/logo.jpg"
|
||||
dst ##> ("/_download 1 " <> uri3 <> " " <> dstFile)
|
||||
dst <## "started standalone receiving file 1 (test.jpg)"
|
||||
dst <## "started standalone receiving file 1 (logo.jpg)"
|
||||
-- silent progress events
|
||||
threadDelay 250000
|
||||
dst <## "completed standalone receiving file 1 (test.jpg)"
|
||||
srcBody <- B.readFile "./tests/fixtures/test.jpg"
|
||||
dst <## "completed standalone receiving file 1 (logo.jpg)"
|
||||
srcBody <- B.readFile "./tests/fixtures/logo.jpg"
|
||||
B.readFile dstFile `shouldReturn` srcBody
|
||||
|
||||
testXFTPStandaloneSmallInfo :: HasCallStack => FilePath -> IO ()
|
||||
testXFTPStandaloneSmallInfo = testChat2 aliceProfile aliceDesktopProfile $ \src dst -> do
|
||||
withXFTPServer $ do
|
||||
logNote "sending"
|
||||
src ##> "/_upload 1 ./tests/fixtures/logo.jpg"
|
||||
src <## "started standalone uploading file 1 (logo.jpg)"
|
||||
-- silent progress events
|
||||
threadDelay 250000
|
||||
src <## "file 1 (logo.jpg) upload complete. download with:"
|
||||
-- file description fits, enjoy the direct URIs
|
||||
_uri1 <- getTermLine src
|
||||
_uri2 <- getTermLine src
|
||||
uri3 <- getTermLine src
|
||||
_uri4 <- getTermLine src
|
||||
let uri = uri3 <> "&data=" <> B.unpack (urlEncode False . LB.toStrict . J.encode $ J.object ["secret" J..= J.String "*********"])
|
||||
|
||||
logNote "info"
|
||||
dst ##> ("/_download info " <> uri)
|
||||
dst <## "{\"secret\":\"*********\"}"
|
||||
|
||||
logNote "receiving"
|
||||
let dstFile = "./tests/tmp/logo.jpg"
|
||||
dst ##> ("/_download 1 " <> uri <> " " <> dstFile) -- download sucessfully discarded extra info
|
||||
dst <## "started standalone receiving file 1 (logo.jpg)"
|
||||
-- silent progress events
|
||||
threadDelay 250000
|
||||
dst <## "completed standalone receiving file 1 (logo.jpg)"
|
||||
srcBody <- B.readFile "./tests/fixtures/logo.jpg"
|
||||
B.readFile dstFile `shouldReturn` srcBody
|
||||
|
||||
testXFTPStandaloneLarge :: HasCallStack => FilePath -> IO ()
|
||||
@@ -896,6 +929,39 @@ testXFTPStandaloneLarge = testChat2 aliceProfile aliceDesktopProfile $ \src dst
|
||||
srcBody <- B.readFile "./tests/tmp/testfile.in"
|
||||
B.readFile dstFile `shouldReturn` srcBody
|
||||
|
||||
testXFTPStandaloneLargeInfo :: HasCallStack => FilePath -> IO ()
|
||||
testXFTPStandaloneLargeInfo = testChat2 aliceProfile aliceDesktopProfile $ \src dst -> do
|
||||
withXFTPServer $ do
|
||||
xftpCLI ["rand", "./tests/tmp/testfile.in", "17mb"] `shouldReturn` ["File created: " <> "./tests/tmp/testfile.in"]
|
||||
|
||||
logNote "sending"
|
||||
src ##> "/_upload 1 ./tests/tmp/testfile.in"
|
||||
src <## "started standalone uploading file 1 (testfile.in)"
|
||||
|
||||
-- silent progress events
|
||||
threadDelay 250000
|
||||
src <## "file 1 (testfile.in) uploaded, preparing redirect file 2"
|
||||
src <## "file 1 (testfile.in) upload complete. download with:"
|
||||
uri1 <- getTermLine src
|
||||
_uri2 <- getTermLine src
|
||||
_uri3 <- getTermLine src
|
||||
_uri4 <- getTermLine src
|
||||
let uri = uri1 <> "&data=" <> B.unpack (urlEncode False . LB.toStrict . J.encode $ J.object ["secret" J..= J.String "*********"])
|
||||
|
||||
logNote "info"
|
||||
dst ##> ("/_download info " <> uri)
|
||||
dst <## "{\"secret\":\"*********\"}"
|
||||
|
||||
logNote "receiving"
|
||||
let dstFile = "./tests/tmp/testfile.out"
|
||||
dst ##> ("/_download 1 " <> uri <> " " <> dstFile)
|
||||
dst <## "started standalone receiving file 1 (testfile.out)"
|
||||
-- silent progress events
|
||||
threadDelay 250000
|
||||
dst <## "completed standalone receiving file 1 (testfile.out)"
|
||||
srcBody <- B.readFile "./tests/tmp/testfile.in"
|
||||
B.readFile dstFile `shouldReturn` srcBody
|
||||
|
||||
testXFTPStandaloneCancelSnd :: HasCallStack => FilePath -> IO ()
|
||||
testXFTPStandaloneCancelSnd = testChat2 aliceProfile aliceDesktopProfile $ \src dst -> do
|
||||
withXFTPServer $ do
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
---
|
||||
layout: layouts/group_link.html
|
||||
title: "SimpleX Chat - Finney Forum group"
|
||||
description: "Join the group of attendees of Finney Forum 2024"
|
||||
groupLink: "https://simplex.chat/contact#/?v=1-4&smp=smp%3A%2F%2Fhpq7_4gGJiilmz5Rf-CswuU5kZGkm_zOIooSw6yALRg%3D%40smp5.simplex.im%2FTlom_0qzRaEWo_4cweE_hzj6KBmqXC8R%23%2F%3Fv%3D1-2%26dh%3DMCowBQYDK2VuAyEAZzyx3sm1tpGsYjXAOR2LxXD0ty1hlAR7Hg0fbCxEoig%253D%26srv%3Djjbyvoemxysm7qxap7m5d5m35jzv5qq6gnlv7s4rsn7tdwwmuqciwpid.onion&data=%7B%22type%22%3A%22group%22%2C%22groupLinkId%22%3A%22IfdftVGf9odVOQImmz1I9A%3D%3D%22%7D"
|
||||
groupLinkText: Open Finney Forum group link
|
||||
templateEngineOverride: njk
|
||||
---
|
||||
Reference in New Issue
Block a user