Settings can be overwritten on command line

make pidfile and persistant data dir confgurable
This commit is contained in:
badaix 2020-02-25 23:40:23 +01:00
parent 0c25a7a42d
commit 7376c7709c
8 changed files with 45 additions and 21 deletions

View file

@ -191,6 +191,7 @@ int main(int argc, char** argv)
group = user_group[1]; group = user_group[1];
} }
daemon = std::make_unique<Daemon>(user, group, pidFile); daemon = std::make_unique<Daemon>(user, group, pidFile);
SLOG(NOTICE) << "daemonizing" << std::endl;
daemon->daemonize(); daemon->daemonize();
if (processPriority < -20) if (processPriority < -20)
processPriority = -20; processPriority = -20;

View file

@ -148,7 +148,7 @@ void Daemon::daemonize()
/// Try to lock file /// Try to lock file
if (lockf(pidFilehandle_, F_TLOCK, 0) == -1) if (lockf(pidFilehandle_, F_TLOCK, 0) == -1)
throw SnapException("Could not lock PID lock file \"" + pidfile_ + "\""); throw SnapException("Could not lock PID lock file \"" + pidfile_ + "\". Is the daemon already running?");
char str[10]; char str[10];
/// Get and format PID /// Get and format PID

View file

@ -338,6 +338,9 @@ public:
/// @param argv command line arguments /// @param argv command line arguments
void parse(int argc, const char* const argv[]); void parse(int argc, const char* const argv[]);
/// Delete all parsed options
void reset();
/// Produce a help message /// Produce a help message
/// @param max_attribute show options up to this level (optional, advanced, expert) /// @param max_attribute show options up to this level (optional, advanced, expert)
/// @return the help message /// @return the help message
@ -989,11 +992,6 @@ inline void OptionParser::parse(const std::string& ini_filename)
inline void OptionParser::parse(int argc, const char* const argv[]) inline void OptionParser::parse(int argc, const char* const argv[])
{ {
unknown_options_.clear();
non_option_args_.clear();
for (auto& opt : options_)
opt->clear();
for (int n = 1; n < argc; ++n) for (int n = 1; n < argc; ++n)
{ {
const std::string arg(argv[n]); const std::string arg(argv[n]);
@ -1094,6 +1092,15 @@ inline void OptionParser::parse(int argc, const char* const argv[])
} }
inline void OptionParser::reset()
{
unknown_options_.clear();
non_option_args_.clear();
for (auto& opt : options_)
opt->clear();
}
inline std::string OptionParser::help(const Attribute& max_attribute) const inline std::string OptionParser::help(const Attribute& max_attribute) const
{ {
ConsoleOptionPrinter option_printer(this); ConsoleOptionPrinter option_printer(this);

View file

@ -49,13 +49,13 @@ void Config::init(const std::string& root_directory, const std::string& user, co
else if (getenv("HOME") == nullptr) else if (getenv("HOME") == nullptr)
dir = "/var/lib/snapserver/"; dir = "/var/lib/snapserver/";
else else
dir = getenv("HOME"); dir = string(getenv("HOME")) + "/.config/snapserver/";
if (!dir.empty() && (dir.back() != '/')) if (!dir.empty() && (dir.back() != '/'))
dir += "/"; dir += "/";
if (dir.find("/var/lib/snapserver") == string::npos) // if (dir.find("/var/lib/snapserver") == string::npos)
dir += ".config/snapserver/"; // dir += ".config/snapserver/";
int status = utils::file::mkdirRecursive(dir.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH); int status = utils::file::mkdirRecursive(dir.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
if ((status != 0) && (errno != EEXIST)) if ((status != 0) && (errno != EEXIST))

View file

@ -25,6 +25,16 @@
# in case there are a couple of longer running tasks, such as encoding # in case there are a couple of longer running tasks, such as encoding
# multiple audio streams # multiple audio streams
#threads = -1 #threads = -1
# the pid file when running as daemon
#pidfile = /var/run/snapserver/pid
# directory where persistent data is stored (server.json)
# if empty, data dir will be
# - "/var/lib/snapserver/" when running as daemon
# - "$HOME/.config/snapserver/" when not running as daemon
#datadir =
# #
############################################################################### ###############################################################################
@ -99,7 +109,7 @@
# note that you need to have the librespot binary on your machine # note that you need to have the librespot binary on your machine
# sampleformat will be set to "44100:16:2" # sampleformat will be set to "44100:16:2"
# file: file:///<path/to/PCM/file>?name=<name> # file: file:///<path/to/PCM/file>?name=<name>
# process: process:///<path/to/process>?name=<name>[&wd_timeout=0][&log_stderr=false] # process: process:///<path/to/process>?name=<name>[&wd_timeout=0][&log_stderr=false][&params=<process arguments>]
# airplay: airplay:///<path/to/airplay>?name=<name>[&port=5000] # airplay: airplay:///<path/to/airplay>?name=<name>[&port=5000]
# note that you need to have the airplay binary on your machine # note that you need to have the airplay binary on your machine
# sampleformat will be set to "44100:16:2" # sampleformat will be set to "44100:16:2"

View file

@ -75,21 +75,25 @@ int main(int argc, char* argv[])
&settings.logging.debug_logfile); &settings.logging.debug_logfile);
// stream settings // stream settings
conf.add<Value<size_t>>("p", "stream.port", "Server port", settings.stream.port, &settings.stream.port); conf.add<Value<size_t>>("", "stream.port", "Server port", settings.stream.port, &settings.stream.port);
auto streamValue = conf.add<Value<string>>( auto streamValue = conf.add<Value<string>>(
"s", "stream.stream", "URI of the PCM input stream.\nFormat: TYPE://host/path?name=NAME\n[&codec=CODEC]\n[&sampleformat=SAMPLEFORMAT]", pcmStream, "", "stream.stream", "URI of the PCM input stream.\nFormat: TYPE://host/path?name=NAME\n[&codec=CODEC]\n[&sampleformat=SAMPLEFORMAT]", pcmStream,
&pcmStream); &pcmStream);
int num_threads = -1; int num_threads = -1;
conf.add<Value<int>>("", "server.threads", "number of server threads", num_threads, &num_threads); 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.sampleformat", "Default sample format", settings.stream.sampleFormat, &settings.stream.sampleFormat);
conf.add<Value<string>>("c", "stream.codec", "Default transport codec\n(flac|ogg|opus|pcm)[:options]\nType codec:? to get codec specific options", 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); settings.stream.codec, &settings.stream.codec);
// deprecated: stream_buffer, use chunk_ms instead // deprecated: stream_buffer, use chunk_ms instead
conf.add<Value<size_t>>("", "stream.stream_buffer", "Default stream read chunk size [ms]", settings.stream.streamChunkMs, conf.add<Value<size_t>>("", "stream.stream_buffer", "Default stream read chunk size [ms]", settings.stream.streamChunkMs,
&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<size_t>>("", "stream.chunk_ms", "Default stream read chunk size [ms]", settings.stream.streamChunkMs, &settings.stream.streamChunkMs);
conf.add<Value<int>>("b", "stream.buffer", "Buffer [ms]", settings.stream.bufferMs, &settings.stream.bufferMs); 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, conf.add<Value<bool>>("", "stream.send_to_muted", "Send audio to muted clients", settings.stream.sendAudioToMutedClients,
&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", auto stream_bind_to_address = conf.add<Value<string>>("", "stream.bind_to_address", "address for the server to listen on",
@ -108,12 +112,11 @@ int main(int argc, char* argv[])
auto tcp_bind_to_address = conf.add<Value<string>>("", "tcp.bind_to_address", "address for the server to listen on", 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]); settings.tcp.bind_to_address.front(), &settings.tcp.bind_to_address[0]);
// TODO: Should be possible to override settings on command line
try try
{ {
op.parse(argc, argv); op.parse(argc, argv);
conf.parse(config_file); conf.parse(config_file);
conf.parse(argc, argv);
if (tcp_bind_to_address->is_set()) if (tcp_bind_to_address->is_set())
{ {
settings.tcp.bind_to_address.clear(); settings.tcp.bind_to_address.clear();
@ -219,9 +222,11 @@ int main(int argc, char* argv[])
if (user_group.size() > 1) if (user_group.size() > 1)
group = user_group[1]; group = user_group[1];
} }
if (data_dir.empty())
Config::instance().init("/var/lib/snapserver", user, group); data_dir = "/var/lib/snapserver";
daemon.reset(new Daemon(user, group, "/var/run/snapserver/pid")); Config::instance().init(data_dir, user, group);
daemon.reset(new Daemon(user, group, pid_file));
SLOG(NOTICE) << "daemonizing" << std::endl;
daemon->daemonize(); daemon->daemonize();
if (processPriority < -20) if (processPriority < -20)
processPriority = -20; processPriority = -20;
@ -232,7 +237,7 @@ int main(int argc, char* argv[])
SLOG(NOTICE) << "daemon started" << std::endl; SLOG(NOTICE) << "daemon started" << std::endl;
} }
else else
Config::instance().init(); Config::instance().init(data_dir);
#else #else
Config::instance().init(); Config::instance().init();
#endif #endif

View file

@ -94,6 +94,7 @@ void StreamServer::onChunkRead(const PcmStream* pcmStream, msg::PcmChunk* chunk,
{ {
// LOG(INFO) << "onChunkRead (" << pcmStream->getName() << "): " << duration << "ms\n"; // LOG(INFO) << "onChunkRead (" << pcmStream->getName() << "): " << duration << "ms\n";
bool isDefaultStream(pcmStream == streamManager_->getDefaultStream().get()); bool isDefaultStream(pcmStream == streamManager_->getDefaultStream().get());
// wrap it into a unique_ptr to ensure that the memory will be freed
unique_ptr<msg::PcmChunk> chunk_ptr(chunk); unique_ptr<msg::PcmChunk> chunk_ptr(chunk);
std::ostringstream oss; std::ostringstream oss;

View file

@ -48,7 +48,7 @@ void StreamUri::parse(const std::string& streamUri)
uri = uri.substr(0, this->uri.length() - 1); uri = uri.substr(0, this->uri.length() - 1);
string decodedUri = strutils::uriDecode(uri); string decodedUri = strutils::uriDecode(uri);
LOG(DEBUG) << "StreamUri: " << decodedUri << "\n"; LOG(DEBUG) << "StreamUri decoded: " << decodedUri << "\n";
string tmp(decodedUri); string tmp(decodedUri);