mirror of
https://github.com/simplex-chat/simplex-chat.git
synced 2026-04-26 15:18:01 +00:00
Export & import storage archive (#726)
* core: import and export of chat archive * export chat archive * import archive, support starting chat after it is stopped * test for maintenance mode * test/fix archive with files * prevent starting chat after chat database was deleted or imported * update simplexmq
This commit is contained in:
committed by
GitHub
parent
7590502f29
commit
f341e54128
@@ -41,6 +41,7 @@ import qualified Data.Text as T
|
||||
import Data.Time.Clock (UTCTime, diffUTCTime, getCurrentTime, nominalDiffTimeToSeconds)
|
||||
import Data.Time.LocalTime (getCurrentTimeZone, getZonedTime)
|
||||
import Data.Word (Word32)
|
||||
import Simplex.Chat.Archive
|
||||
import Simplex.Chat.Call
|
||||
import Simplex.Chat.Controller
|
||||
import Simplex.Chat.Markdown
|
||||
@@ -134,7 +135,8 @@ newChatController chatStore user cfg@ChatConfig {agentConfig = aCfg, tbqSize, de
|
||||
rcvFiles <- newTVarIO M.empty
|
||||
currentCalls <- atomically TM.empty
|
||||
filesFolder <- newTVarIO Nothing
|
||||
pure ChatController {activeTo, firstTime, currentUser, smpAgent, agentAsync, chatStore, idsDrg, inputQ, outputQ, notifyQ, chatLock, sndFiles, rcvFiles, currentCalls, config, sendNotification, filesFolder}
|
||||
chatStoreChanged <- newTVarIO False
|
||||
pure ChatController {activeTo, firstTime, currentUser, smpAgent, agentAsync, chatStore, chatStoreChanged, idsDrg, inputQ, outputQ, notifyQ, chatLock, sndFiles, rcvFiles, currentCalls, config, sendNotification, filesFolder}
|
||||
where
|
||||
resolveServers :: InitialAgentServers -> IO InitialAgentServers
|
||||
resolveServers ss@InitialAgentServers {smp = defaultSMPServers} = case nonEmpty smpServers of
|
||||
@@ -150,6 +152,7 @@ runChatController = race_ notificationSubscriber . agentSubscriber
|
||||
|
||||
startChatController :: (MonadUnliftIO m, MonadReader ChatController m) => User -> m (Async ())
|
||||
startChatController user = do
|
||||
asks smpAgent >>= resumeAgentClient
|
||||
s <- asks agentAsync
|
||||
readTVarIO s >>= maybe (start s) pure
|
||||
where
|
||||
@@ -194,13 +197,23 @@ processChatCommand = \case
|
||||
StartChat -> withUser' $ \user ->
|
||||
asks agentAsync >>= readTVarIO >>= \case
|
||||
Just _ -> pure CRChatRunning
|
||||
_ -> startChatController user $> CRChatStarted
|
||||
_ ->
|
||||
ifM
|
||||
(asks chatStoreChanged >>= readTVarIO)
|
||||
(throwChatError CEChatStoreChanged)
|
||||
(startChatController user $> CRChatStarted)
|
||||
APIStopChat -> do
|
||||
ask >>= stopChatController
|
||||
pure CRChatStopped
|
||||
ResubscribeAllConnections -> withUser (subscribeUserConnections resubscribeConnection) $> CRCmdOk
|
||||
SetFilesFolder filesFolder' -> withUser $ \_ -> do
|
||||
createDirectoryIfMissing True filesFolder'
|
||||
ff <- asks filesFolder
|
||||
atomically . writeTVar ff $ Just filesFolder'
|
||||
pure CRCmdOk
|
||||
APIExportArchive cfg -> checkChatStopped $ exportArchive cfg $> CRCmdOk
|
||||
APIImportArchive cfg -> checkChatStopped $ importArchive cfg >> setStoreChanged $> CRCmdOk
|
||||
APIDeleteStorage -> checkChatStopped $ deleteStorage >> setStoreChanged $> CRCmdOk
|
||||
APIGetChats withPCC -> CRApiChats <$> withUser (\user -> withStore $ \st -> getChatPreviews st user withPCC)
|
||||
APIGetChat (ChatRef cType cId) pagination -> withUser $ \user -> case cType of
|
||||
CTDirect -> CRApiChat . AChat SCTDirect <$> withStore (\st -> getDirectChat st user cId pagination)
|
||||
@@ -770,6 +783,10 @@ processChatCommand = \case
|
||||
CTDirect -> withStore $ \st -> getContactIdByName st userId name
|
||||
CTGroup -> withStore $ \st -> getGroupIdByName st user name
|
||||
_ -> throwChatError $ CECommandError "not supported"
|
||||
checkChatStopped :: m ChatResponse -> m ChatResponse
|
||||
checkChatStopped a = asks agentAsync >>= readTVarIO >>= maybe a (const $ throwChatError CEChatNotStopped)
|
||||
setStoreChanged :: m ()
|
||||
setStoreChanged = asks chatStoreChanged >>= atomically . (`writeTVar` True)
|
||||
getSentChatItemIdByText :: User -> ChatRef -> ByteString -> m Int64
|
||||
getSentChatItemIdByText user@User {userId, localDisplayName} (ChatRef cType cId) msg = case cType of
|
||||
CTDirect -> withStore $ \st -> getDirectChatItemIdByText st userId cId SMDSnd (safeDecodeUtf8 msg)
|
||||
@@ -2212,8 +2229,12 @@ chatCommandP =
|
||||
("/user " <|> "/u ") *> (CreateActiveUser <$> userProfile)
|
||||
<|> ("/user" <|> "/u") $> ShowActiveUser
|
||||
<|> "/_start" $> StartChat
|
||||
<|> "/_stop" $> APIStopChat
|
||||
<|> "/_resubscribe all" $> ResubscribeAllConnections
|
||||
<|> "/_files_folder " *> (SetFilesFolder <$> filePath)
|
||||
<|> "/_db export " *> (APIExportArchive <$> jsonP)
|
||||
<|> "/_db import " *> (APIImportArchive <$> jsonP)
|
||||
<|> "/_db delete" $> APIDeleteStorage
|
||||
<|> "/_get chats" *> (APIGetChats <$> (" pcc=on" $> True <|> " pcc=off" $> False <|> pure False))
|
||||
<|> "/_get chat " *> (APIGetChat <$> chatRefP <* A.space <*> chatPaginationP)
|
||||
<|> "/_get items count=" *> (APIGetChatItems <$> A.decimal)
|
||||
|
||||
Reference in New Issue
Block a user