1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258
|
/***
This file is part of snapcast
Copyright (C) 2014-2025 Johannes Pohl
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
***/
#pragma once
// local headers
#include "common/snap_exception.hpp"
#include "common/utils/string_utils.hpp"
// standard headers
#include <algorithm>
#include <cstdint>
#include <filesystem>
#include <memory>
#include <string>
#include <vector>
/// Server settings
struct ServerSettings
{
/// Launch settings
struct Server
{
/// Number of worker threads
int threads{-1};
/// PID file, if running as daemon
std::string pid_file{"/var/run/snapserver/pid"};
/// User when running as deaemon
std::string user{"snapserver"};
/// Group when running as deaemon
std::string group;
/// Server data dir
std::string data_dir;
/// Enable mDNS to publish services
bool mdns_enabled{true};
};
/// SSL settings
struct Ssl
{
/// Certificate file
std::filesystem::path certificate;
/// Private key file
std::filesystem::path certificate_key;
/// Password for encrypted key file
std::string key_password;
/// Verify client certificates
bool verify_clients = false;
/// Client CA certificates
std::vector<std::filesystem::path> client_certs;
/// @return if SSL is enabled
bool enabled() const
{
return !certificate.empty() && !certificate_key.empty();
}
};
/// Authorization settings
struct Authorization
{
/// c'tor
Authorization() = default;
/// Init with @p conf_roles and @p conf_users
void init(const std::vector<std::string>& conf_roles, const std::vector<std::string>& conf_users)
{
roles.clear();
users.clear();
for (const auto& role : conf_roles)
roles.emplace_back(std::make_shared<ServerSettings::Authorization::Role>(role));
auto empty_role = std::make_shared<ServerSettings::Authorization::Role>();
for (const auto& conf_user : conf_users)
{
users.emplace_back(conf_user);
ServerSettings::Authorization::User& user = users.back();
if (user.role_name.empty())
{
user.role = empty_role;
}
else
{
const auto& role_iter = std::find_if(roles.begin(), roles.end(), [&](const auto& role) { return role->role == user.role_name; });
if (role_iter != roles.end())
user.role = *role_iter;
}
if (user.role == nullptr)
throw SnapException("Role '" + user.role_name + "' for user '" + user.name + "' not found");
}
}
/// Role settings
struct Role
{
/// c'tor
Role() = default;
/// c'tor
explicit Role(const std::string& role_permissions)
{
std::string perm;
role = utils::string::split_left(role_permissions, ':', perm);
permissions = utils::string::split(perm, ',');
}
/// role name
std::string role;
/// permissions
std::vector<std::string> permissions;
};
/// User settings
struct User
{
/// c'tor
explicit User(const std::string& user_password_role)
{
std::string perm;
name = utils::string::split_left(user_password_role, ':', perm);
password = utils::string::split_right(perm, ':', role_name);
}
/// user name
std::string name;
/// password
std::string password;
/// role
std::string role_name;
/// role
std::shared_ptr<Role> role;
};
/// is auth enabled
bool enabled{false};
/// users
std::vector<User> users;
/// roles
std::vector<std::shared_ptr<Role>> roles;
};
/// HTTP settings
struct Http
{
/// enable HTTP server
bool enabled{true};
/// enable HTTPS
bool ssl_enabled{false};
/// HTTP port
size_t port{1780};
/// HTTPS port
size_t ssl_port{1788};
/// HTTP listen address
std::vector<std::string> bind_to_address{{"::"}};
/// HTTPS listen address
std::vector<std::string> ssl_bind_to_address{{"::"}};
/// doc root directory
std::string doc_root;
/// HTTP server host name
std::string host{"<hostname>"};
/// URL prefix when serving album art
std::string url_prefix;
/// Publish HTTP service via mDNS as '_snapcast-http._tcp'
bool publish_http{true};
/// Publish HTTPS service via mDNS as '_snapcast-https._tcp'
bool publish_https{true};
};
/// TCP control client settings
struct TcpControl
{
/// enable plain TCP control
bool enabled{true};
/// TCP port
size_t port{1705};
/// TCP listen addresses
std::vector<std::string> bind_to_address{{"::"}};
/// Publish TCP control service via mDNS as '_snapcast-ctrl._tcp'
bool publish{true};
};
/// TCP streaming client settings
struct TcpStream
{
/// enable plain TCP audio streaming
bool enabled{true};
/// TCP port
size_t port{1704};
/// TCP listen addresses
std::vector<std::string> bind_to_address{{"::"}};
/// Publish TCP streaming service via mDNS as '_snapcast._tcp'
bool publish{true};
};
/// Stream settings
struct Stream
{
/// Directory for stream plugins
std::filesystem::path plugin_dir{"/usr/share/snapserver/plug-ins"};
/// Directory for executable process stream sources
std::filesystem::path sandbox_dir{"/usr/share/snapserver/sandbox"};
/// Stream sources
std::vector<std::string> sources;
/// Default codec
std::string codec{"flac"};
/// Default end to end delay
int32_t bufferMs{1000};
/// Default sample format
std::string sampleFormat{"48000:16:2"};
/// Default read size for stream sources
size_t streamChunkMs{20};
/// Send audio to muted clients?
bool sendAudioToMutedClients{false};
};
/// Client settings
struct StreamingClient
{
/// Initial volume of new clients
uint16_t initialVolume{100};
};
/// Logging settings
struct Logging
{
/// log sink
std::string sink;
/// log filter
std::string filter{"*:info"};
};
Server server; ///< Server settings
Ssl ssl; ///< SSL settings
Authorization auth; ///< Auth settings
Http http; ///< HTTP settings
TcpControl tcp_control; ///< TCP-Control settings
TcpStream tcp_stream; ///< TCP-Stream settings
Stream stream; ///< Stream settings
StreamingClient streamingclient; ///< Client settings
Logging logging; ///< Logging settings
};
|