docs: add Hosting your own Chat Relay guide (#7272)

* docs: add Hosting your own Chat Relay guide

* cli: run headless relay without a terminal

--headless (no -e) now runs via simplexChatCore instead of the terminal
UI, so the relay runs as a systemd service without a TTY (withTerminal
requires one). Drains the event queue logging only errors, and sets
stdout to line-buffering so logs reach the journal.

* docs/chat-relay: debounce service

* Apply suggestions from code review

Co-authored-by: Evgeny <evgeny@poberezkin.com>

---------

Co-authored-by: Evgeny <evgeny@poberezkin.com>
This commit is contained in:
sh
2026-07-17 17:09:38 +01:00
committed by GitHub
co-authored by Evgeny
parent 27da94e11d
commit a81baebed5
3 changed files with 273 additions and 2 deletions
+13 -2
View File
@@ -18,6 +18,7 @@ import Simplex.Chat.View (ChatResponseEvent, smpProxyModeStr)
import Simplex.Messaging.Client (NetworkConfig (..), SocksMode (..))
import System.Directory (getAppUserDataDirectory)
import System.Exit (exitFailure)
import System.IO (BufferMode (..), hSetBuffering, stdout)
import System.Terminal (withTerminal)
simplexChatCLI :: ChatConfig -> Maybe (ServiceName -> ChatConfig -> ChatOpts -> IO ()) -> IO ()
@@ -27,19 +28,29 @@ simplexChatCLI cfg server_ = do
simplexChatCLI' cfg opts server_
simplexChatCLI' :: ChatConfig -> ChatOpts -> Maybe (ServiceName -> ChatConfig -> ChatOpts -> IO ()) -> IO ()
simplexChatCLI' cfg opts@ChatOpts {chatCmd, chatCmdLog, chatCmdDelay, chatServerPort} server_ = do
simplexChatCLI' cfg opts@ChatOpts {chatCmd, chatCmdLog, chatCmdDelay, chatServerPort, coreOptions = CoreChatOpts {headless}} server_ = do
if null chatCmd
then case chatServerPort of
Just chatPort -> case server_ of
Just server -> server chatPort cfg opts
Nothing -> putStrLn "Not allowed to run as a WebSockets server" >> exitFailure
_ -> runCLI
_
| headless -> do
hSetBuffering stdout LineBuffering
welcome cfg opts
simplexChatCore cfg opts runHeadless
| otherwise -> runCLI
else simplexChatCore cfg opts runCommand
where
runCLI = do
welcome cfg opts
t <- withTerminal pure
simplexChatTerminal cfg opts t
runHeadless user cc = forever $ do
(rh, r) <- atomically $ readTBQueue $ outputQ cc
case r of
Left _ -> printResponseEvent (rh, Just user) cfg r
Right _ -> pure ()
runCommand user cc = do
when (chatCmdLog /= CCLNone) . void . forkIO . forever $ do
(_, r) <- atomically . readTBQueue $ outputQ cc