mirror of
https://github.com/badaix/snapcast.git
synced 2025-05-10 15:46:42 +02:00
Move --user command line setting into config file
This commit is contained in:
parent
446b22ac85
commit
e148d74772
10 changed files with 85 additions and 83 deletions
|
@ -767,8 +767,10 @@ inline void Value<T>::update_reference()
|
|||
{
|
||||
if (this->assign_to_)
|
||||
{
|
||||
if (this->is_set() || default_)
|
||||
*this->assign_to_ = value();
|
||||
if (!this->is_set() && default_)
|
||||
*this->assign_to_ = *default_;
|
||||
else if (this->is_set())
|
||||
*this->assign_to_ = values_.back();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
2
debian/snapclient.init
vendored
2
debian/snapclient.init
vendored
|
@ -26,7 +26,7 @@ SCRIPTNAME=/etc/init.d/$NAME
|
|||
|
||||
# Read configuration variable file if it is present
|
||||
[ -r /etc/default/$NAME ] && . /etc/default/$NAME
|
||||
SNAPCLIENT_OPTS="--daemon $SNAPCLIENT_OPTS"
|
||||
SNAPCLIENT_OPTS="--daemon --user $USERNAME:$USERNAME $SNAPCLIENT_OPTS"
|
||||
|
||||
if [ "$START_SNAPCLIENT" != "true" ] ; then
|
||||
exit 0
|
||||
|
|
|
@ -32,8 +32,8 @@ using namespace std;
|
|||
using json = nlohmann::json;
|
||||
|
||||
|
||||
ControlServer::ControlServer(boost::asio::io_context& io_context, const ServerSettings::TcpSettings& tcp_settings,
|
||||
const ServerSettings::HttpSettings& http_settings, ControlMessageReceiver* controlMessageReceiver)
|
||||
ControlServer::ControlServer(boost::asio::io_context& io_context, const ServerSettings::Tcp& tcp_settings, const ServerSettings::Http& http_settings,
|
||||
ControlMessageReceiver* controlMessageReceiver)
|
||||
: io_context_(io_context), tcp_settings_(tcp_settings), http_settings_(http_settings), controlMessageReceiver_(controlMessageReceiver)
|
||||
{
|
||||
}
|
||||
|
|
|
@ -43,14 +43,14 @@ using acceptor_ptr = std::unique_ptr<tcp::acceptor>;
|
|||
class ControlServer : public ControlMessageReceiver
|
||||
{
|
||||
public:
|
||||
ControlServer(boost::asio::io_context& io_context, const ServerSettings::TcpSettings& tcp_settings, const ServerSettings::HttpSettings& http_settings,
|
||||
ControlServer(boost::asio::io_context& io_context, const ServerSettings::Tcp& tcp_settings, const ServerSettings::Http& http_settings,
|
||||
ControlMessageReceiver* controlMessageReceiver = nullptr);
|
||||
virtual ~ControlServer();
|
||||
|
||||
void start();
|
||||
void stop();
|
||||
|
||||
/// Send a message to all connceted clients
|
||||
/// Send a message to all connected clients
|
||||
void send(const std::string& message, const ControlSession* excludeSession = nullptr);
|
||||
|
||||
/// Clients call this when they receive a message. Implementation of MessageReceiver::onMessageReceived
|
||||
|
@ -70,8 +70,8 @@ private:
|
|||
std::vector<acceptor_ptr> acceptor_http_;
|
||||
|
||||
boost::asio::io_context& io_context_;
|
||||
ServerSettings::TcpSettings tcp_settings_;
|
||||
ServerSettings::HttpSettings http_settings_;
|
||||
ServerSettings::Tcp tcp_settings_;
|
||||
ServerSettings::Http http_settings_;
|
||||
ControlMessageReceiver* controlMessageReceiver_;
|
||||
};
|
||||
|
||||
|
|
|
@ -99,7 +99,7 @@ std::string path_cat(boost::beast::string_view base, boost::beast::string_view p
|
|||
} // namespace
|
||||
|
||||
ControlSessionHttp::ControlSessionHttp(ControlMessageReceiver* receiver, boost::asio::io_context& ioc, tcp::socket&& socket,
|
||||
const ServerSettings::HttpSettings& settings)
|
||||
const ServerSettings::Http& settings)
|
||||
: ControlSession(receiver), socket_(std::move(socket)), settings_(settings), strand_(ioc)
|
||||
{
|
||||
LOG(DEBUG) << "ControlSessionHttp\n";
|
||||
|
|
|
@ -40,7 +40,7 @@ class ControlSessionHttp : public ControlSession, public std::enable_shared_from
|
|||
{
|
||||
public:
|
||||
/// ctor. Received message from the client are passed to MessageReceiver
|
||||
ControlSessionHttp(ControlMessageReceiver* receiver, boost::asio::io_context& ioc, tcp::socket&& socket, const ServerSettings::HttpSettings& settings);
|
||||
ControlSessionHttp(ControlMessageReceiver* receiver, boost::asio::io_context& ioc, tcp::socket&& socket, const ServerSettings::Http& settings);
|
||||
~ControlSessionHttp() override;
|
||||
void start() override;
|
||||
void stop() override;
|
||||
|
@ -74,7 +74,7 @@ protected:
|
|||
protected:
|
||||
tcp::socket socket_;
|
||||
beast::flat_buffer buffer_;
|
||||
ServerSettings::HttpSettings settings_;
|
||||
ServerSettings::Http settings_;
|
||||
boost::asio::io_context::strand strand_;
|
||||
std::deque<std::string> messages_;
|
||||
};
|
||||
|
|
|
@ -32,6 +32,11 @@
|
|||
# the pid file when running as daemon
|
||||
#pidfile = /var/run/snapserver/pid
|
||||
|
||||
# the user to run as when daemonized
|
||||
#user = snapserver
|
||||
# the group to run as when daemonized
|
||||
#group = snapserver
|
||||
|
||||
# directory where persistent data is stored (server.json)
|
||||
# if empty, data dir will be
|
||||
# - "/var/lib/snapserver/" when running as daemon
|
||||
|
|
|
@ -24,7 +24,16 @@
|
|||
|
||||
struct ServerSettings
|
||||
{
|
||||
struct HttpSettings
|
||||
struct Server
|
||||
{
|
||||
int threads{-1};
|
||||
std::string pid_file{"/var/run/snapserver/pid"};
|
||||
std::string user{"snapserver"};
|
||||
std::string group{""};
|
||||
std::string data_dir{""};
|
||||
};
|
||||
|
||||
struct Http
|
||||
{
|
||||
bool enabled{true};
|
||||
size_t port{1780};
|
||||
|
@ -32,14 +41,14 @@ struct ServerSettings
|
|||
std::string doc_root{""};
|
||||
};
|
||||
|
||||
struct TcpSettings
|
||||
struct Tcp
|
||||
{
|
||||
bool enabled{true};
|
||||
size_t port{1705};
|
||||
std::vector<std::string> bind_to_address{{"0.0.0.0"}};
|
||||
};
|
||||
|
||||
struct StreamSettings
|
||||
struct Stream
|
||||
{
|
||||
size_t port{1704};
|
||||
std::vector<std::string> pcmStreams;
|
||||
|
@ -57,9 +66,10 @@ struct ServerSettings
|
|||
std::string filter{"*:info"};
|
||||
};
|
||||
|
||||
HttpSettings http;
|
||||
TcpSettings tcp;
|
||||
StreamSettings stream;
|
||||
Server server;
|
||||
Http http;
|
||||
Tcp tcp;
|
||||
Stream stream;
|
||||
Logging logging;
|
||||
};
|
||||
|
||||
|
|
|
@ -25,9 +25,6 @@ Show version number
|
|||
Daemonize
|
||||
optional process priority [-20..19]
|
||||
.TP
|
||||
\fB--user arg\fR
|
||||
the user[:group] to run snapserver as when daemonized
|
||||
.TP
|
||||
\fB-c, --config arg (=/etc/snapserver.conf)\fR
|
||||
path to the configuration file
|
||||
.SH FILES
|
||||
|
|
|
@ -63,57 +63,57 @@ int main(int argc, char* argv[])
|
|||
#ifdef HAS_DAEMON
|
||||
int processPriority(0);
|
||||
auto daemonOption = op.add<Implicit<int>>("d", "daemon", "Daemonize\noptional process priority [-20..19]", 0, &processPriority);
|
||||
auto userValue = op.add<Value<string>>("", "user", "the user[:group] to run snapserver as when daemonized", "");
|
||||
#endif
|
||||
|
||||
op.add<Value<string>>("c", "config", "path to the configuration file", config_file, &config_file);
|
||||
|
||||
// debug settings
|
||||
OptionParser conf("");
|
||||
conf.add<Value<string>>("", "logging.sink", "log sink [null,system,stdout,stderr,file:<filename>]", settings.logging.sink, &settings.logging.sink);
|
||||
auto logfilterOption = conf.add<Value<string>>(
|
||||
"", "logging.filter",
|
||||
"log filter <tag>:<level>[,<tag>:<level>]* with tag = * or <log tag> and level = [trace,debug,info,notice,warning,error,fatal]",
|
||||
settings.logging.filter);
|
||||
OptionParser conf("Overridable config file options");
|
||||
|
||||
// stream settings
|
||||
conf.add<Value<size_t>>("", "stream.port", "Server port", settings.stream.port, &settings.stream.port);
|
||||
auto streamValue = conf.add<Value<string>>(
|
||||
"", "stream.stream", "URI of the PCM input stream.\nFormat: TYPE://host/path?name=NAME\n[&codec=CODEC]\n[&sampleformat=SAMPLEFORMAT]", pcmStream,
|
||||
&pcmStream);
|
||||
int num_threads = -1;
|
||||
conf.add<Value<int>>("", "server.threads", "number of server threads", num_threads, &num_threads);
|
||||
std::string pid_file = "/var/run/snapserver/pid";
|
||||
conf.add<Value<string>>("", "server.pidfile", "pid file when running as daemon", pid_file, &pid_file);
|
||||
std::string data_dir;
|
||||
conf.add<Implicit<string>>("", "server.datadir", "directory where persistent data is stored", data_dir, &data_dir);
|
||||
|
||||
conf.add<Value<string>>("", "stream.sampleformat", "Default sample format", settings.stream.sampleFormat, &settings.stream.sampleFormat);
|
||||
conf.add<Value<string>>("", "stream.codec", "Default transport codec\n(flac|ogg|opus|pcm)[:options]\nType codec:? to get codec specific options",
|
||||
settings.stream.codec, &settings.stream.codec);
|
||||
// deprecated: stream_buffer, use chunk_ms instead
|
||||
conf.add<Value<size_t>>("", "stream.stream_buffer", "Default stream read chunk size [ms]", settings.stream.streamChunkMs,
|
||||
&settings.stream.streamChunkMs);
|
||||
conf.add<Value<size_t>>("", "stream.chunk_ms", "Default stream read chunk size [ms]", settings.stream.streamChunkMs, &settings.stream.streamChunkMs);
|
||||
conf.add<Value<int>>("", "stream.buffer", "Buffer [ms]", settings.stream.bufferMs, &settings.stream.bufferMs);
|
||||
conf.add<Value<bool>>("", "stream.send_to_muted", "Send audio to muted clients", settings.stream.sendAudioToMutedClients,
|
||||
&settings.stream.sendAudioToMutedClients);
|
||||
auto stream_bind_to_address = conf.add<Value<string>>("", "stream.bind_to_address", "address for the server to listen on",
|
||||
settings.stream.bind_to_address.front(), &settings.stream.bind_to_address[0]);
|
||||
// server settings
|
||||
conf.add<Value<int>>("", "server.threads", "number of server threads", settings.server.threads, &settings.server.threads);
|
||||
conf.add<Value<string>>("", "server.pidfile", "pid file when running as daemon", settings.server.pid_file, &settings.server.pid_file);
|
||||
conf.add<Value<string>>("", "server.user", "the user to run as when daemonized", settings.server.user, &settings.server.user);
|
||||
conf.add<Implicit<string>>("", "server.group", "the group to run as when daemonized", settings.server.group, &settings.server.group);
|
||||
conf.add<Implicit<string>>("", "server.datadir", "directory where persistent data is stored", settings.server.data_dir, &settings.server.data_dir);
|
||||
|
||||
// HTTP RPC settings
|
||||
conf.add<Value<bool>>("", "http.enabled", "enable HTTP Json RPC (HTTP POST and websockets)", settings.http.enabled, &settings.http.enabled);
|
||||
conf.add<Value<size_t>>("", "http.port", "which port the server should listen to", settings.http.port, &settings.http.port);
|
||||
conf.add<Value<size_t>>("", "http.port", "which port the server should listen on", settings.http.port, &settings.http.port);
|
||||
auto http_bind_to_address = conf.add<Value<string>>("", "http.bind_to_address", "address for the server to listen on",
|
||||
settings.http.bind_to_address.front(), &settings.http.bind_to_address[0]);
|
||||
conf.add<Implicit<string>>("", "http.doc_root", "serve a website from the doc_root location", settings.http.doc_root, &settings.http.doc_root);
|
||||
|
||||
// TCP RPC settings
|
||||
conf.add<Value<bool>>("", "tcp.enabled", "enable TCP Json RPC)", settings.tcp.enabled, &settings.tcp.enabled);
|
||||
conf.add<Value<size_t>>("", "tcp.port", "which port the server should listen to", settings.tcp.port, &settings.tcp.port);
|
||||
conf.add<Value<size_t>>("", "tcp.port", "which port the server should listen on", settings.tcp.port, &settings.tcp.port);
|
||||
auto tcp_bind_to_address = conf.add<Value<string>>("", "tcp.bind_to_address", "address for the server to listen on",
|
||||
settings.tcp.bind_to_address.front(), &settings.tcp.bind_to_address[0]);
|
||||
|
||||
// stream settings
|
||||
auto stream_bind_to_address = conf.add<Value<string>>("", "stream.bind_to_address", "address for the server to listen on",
|
||||
settings.stream.bind_to_address.front(), &settings.stream.bind_to_address[0]);
|
||||
conf.add<Value<size_t>>("", "stream.port", "which port the server should listen on", settings.stream.port, &settings.stream.port);
|
||||
auto streamValue = conf.add<Value<string>>(
|
||||
"", "stream.stream", "URI of the PCM input stream.\nFormat: TYPE://host/path?name=NAME\n[&codec=CODEC]\n[&sampleformat=SAMPLEFORMAT]", pcmStream,
|
||||
&pcmStream);
|
||||
|
||||
conf.add<Value<string>>("", "stream.sampleformat", "Default sample format", settings.stream.sampleFormat, &settings.stream.sampleFormat);
|
||||
conf.add<Value<string>>("", "stream.codec", "Default transport codec\n(flac|ogg|opus|pcm)[:options]\nType codec:? to get codec specific options",
|
||||
settings.stream.codec, &settings.stream.codec);
|
||||
// deprecated: stream_buffer, use chunk_ms instead
|
||||
conf.add<Value<size_t>>("", "stream.stream_buffer", "Default stream read chunk size [ms], deprecated, use stream.chunk_ms instead",
|
||||
settings.stream.streamChunkMs, &settings.stream.streamChunkMs);
|
||||
conf.add<Value<size_t>>("", "stream.chunk_ms", "Default stream read chunk size [ms]", settings.stream.streamChunkMs, &settings.stream.streamChunkMs);
|
||||
conf.add<Value<int>>("", "stream.buffer", "Buffer [ms]", settings.stream.bufferMs, &settings.stream.bufferMs);
|
||||
conf.add<Value<bool>>("", "stream.send_to_muted", "Send audio to muted clients", settings.stream.sendAudioToMutedClients,
|
||||
&settings.stream.sendAudioToMutedClients);
|
||||
|
||||
// logging settings
|
||||
conf.add<Value<string>>("", "logging.sink", "log sink [null,system,stdout,stderr,file:<filename>]", settings.logging.sink, &settings.logging.sink);
|
||||
auto logfilterOption = conf.add<Value<string>>(
|
||||
"", "logging.filter",
|
||||
"log filter <tag>:<level>[,<tag>:<level>]* with tag = * or <log tag> and level = [trace,debug,info,notice,warning,error,fatal]",
|
||||
settings.logging.filter);
|
||||
|
||||
try
|
||||
{
|
||||
op.parse(argc, argv);
|
||||
|
@ -140,7 +140,7 @@ int main(int argc, char* argv[])
|
|||
}
|
||||
catch (const std::invalid_argument& e)
|
||||
{
|
||||
LOG(ERROR) << "Exception: " << e.what() << std::endl;
|
||||
cerr << "Exception: " << e.what() << std::endl;
|
||||
cout << "\n" << op << "\n";
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
@ -234,35 +234,23 @@ int main(int argc, char* argv[])
|
|||
std::unique_ptr<Daemon> daemon;
|
||||
if (daemonOption->is_set())
|
||||
{
|
||||
string user = "";
|
||||
string group = "";
|
||||
if (settings.server.user.empty())
|
||||
std::invalid_argument("user must not be empty");
|
||||
|
||||
if (userValue->is_set())
|
||||
{
|
||||
if (userValue->value().empty())
|
||||
std::invalid_argument("user must not be empty");
|
||||
if (settings.server.data_dir.empty())
|
||||
settings.server.data_dir = "/var/lib/snapserver";
|
||||
Config::instance().init(settings.server.data_dir, settings.server.user, settings.server.group);
|
||||
|
||||
vector<string> user_group = utils::string::split(userValue->value(), ':');
|
||||
user = user_group[0];
|
||||
if (user_group.size() > 1)
|
||||
group = user_group[1];
|
||||
}
|
||||
if (data_dir.empty())
|
||||
data_dir = "/var/lib/snapserver";
|
||||
Config::instance().init(data_dir, user, group);
|
||||
daemon.reset(new Daemon(user, group, pid_file));
|
||||
LOG(NOTICE) << "daemonizing" << std::endl;
|
||||
daemon->daemonize();
|
||||
if (processPriority < -20)
|
||||
processPriority = -20;
|
||||
else if (processPriority > 19)
|
||||
processPriority = 19;
|
||||
daemon = std::make_unique<Daemon>(settings.server.user, settings.server.group, settings.server.pid_file);
|
||||
processPriority = std::min(std::max(-20, processPriority), 19);
|
||||
if (processPriority != 0)
|
||||
setpriority(PRIO_PROCESS, 0, processPriority);
|
||||
LOG(NOTICE) << "daemonizing" << std::endl;
|
||||
daemon->daemonize();
|
||||
LOG(NOTICE) << "daemon started" << std::endl;
|
||||
}
|
||||
else
|
||||
Config::instance().init(data_dir);
|
||||
Config::instance().init(settings.server.data_dir);
|
||||
#else
|
||||
Config::instance().init();
|
||||
#endif
|
||||
|
@ -299,9 +287,9 @@ int main(int argc, char* argv[])
|
|||
auto streamServer = std::make_unique<StreamServer>(io_context, settings);
|
||||
streamServer->start();
|
||||
|
||||
if (num_threads < 0)
|
||||
num_threads = std::max(2, std::min(4, static_cast<int>(std::thread::hardware_concurrency())));
|
||||
LOG(INFO) << "number of threads: " << num_threads << ", hw threads: " << std::thread::hardware_concurrency() << "\n";
|
||||
if (settings.server.threads < 0)
|
||||
settings.server.threads = std::max(2, std::min(4, static_cast<int>(std::thread::hardware_concurrency())));
|
||||
LOG(INFO) << "number of threads: " << settings.server.threads << ", hw threads: " << std::thread::hardware_concurrency() << "\n";
|
||||
|
||||
// Construct a signal set registered for process termination.
|
||||
boost::asio::signal_set signals(io_context, SIGHUP, SIGINT, SIGTERM);
|
||||
|
@ -314,7 +302,7 @@ int main(int argc, char* argv[])
|
|||
});
|
||||
|
||||
std::vector<std::thread> threads;
|
||||
for (int n = 0; n < num_threads; ++n)
|
||||
for (int n = 0; n < settings.server.threads; ++n)
|
||||
threads.emplace_back([&] { io_context.run(); });
|
||||
|
||||
io_context.run();
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue