0
0
Fork 0
mirror of https://github.com/matrix-construct/construct synced 2024-12-26 15:33:54 +01:00

ircd: Mein conf.

This commit is contained in:
Jason Volk 2018-03-02 00:35:02 -08:00
parent 15ec746fc6
commit 97e593a77e
9 changed files with 250 additions and 100 deletions

84
include/ircd/conf.h Normal file
View file

@ -0,0 +1,84 @@
// Matrix Construct
//
// Copyright (C) Matrix Construct Developers, Authors & Contributors
// Copyright (C) 2016-2018 Jason Volk <jason@zemos.net>
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice is present in all copies. The
// full license for this software is available in the LICENSE file.
#pragma once
#define HAVE_IRCD_CONF_H
namespace ircd::conf
{
template<class T = void> struct item; // doesn't exist
template<class T> struct value; // abstraction for carrying item value
template<> struct item<void>; // base class of all conf items
template<> struct item<seconds>;
IRCD_EXCEPTION(ircd::error, error)
extern const std::string &config; //TODO: X
void init(const string_view &configfile);
}
/// Conf item base class. You don't create this directly; use one of the
/// derived templates instead.
template<>
struct ircd::conf::item<void>
:instance_list<ircd::conf::item<>>
{
json::strung feature_;
json::object feature;
string_view name;
virtual bool refresh();
item(const json::members &);
virtual ~item() noexcept;
};
/// Conf item value abstraction. If possible, the conf item will also
/// inherit from this template to deduplicate functionality between
/// conf items which contain similar classes of values.
template<class T>
struct ircd::conf::value
:conf::item<>
{
using value_type = T;
T _value;
std::function<bool (T &)> refresher;
operator const T &() const
{
return _value;
}
bool refresh() override
{
return refresher? refresher(_value) : false;
}
template<class U>
value(const json::members &memb, U&& t)
:conf::item<>{memb}
,_value{std::forward<U>(t)}
{}
value(const json::members &memb = {})
:conf::item<>{memb}
,_value{feature.get<T>("default", T{})}
{}
};
template<>
struct ircd::conf::item<ircd::seconds>
:conf::value<seconds>
{
using value_type = seconds;
using value::value;
};

View file

@ -82,7 +82,7 @@ struct ircd::m::keys
struct ircd::m::keys::init
{
json::object conf;
json::object config;
void certificate();
void signing();
@ -90,7 +90,7 @@ struct ircd::m::keys::init
public:
void bootstrap();
init(const json::object &conf);
init(const json::object &config);
~init() noexcept;
};

View file

@ -61,7 +61,7 @@ namespace ircd
struct ircd::m::init
{
json::object conf;
json::object config;
void bootstrap();
void listeners();

View file

@ -183,7 +183,7 @@ namespace ircd
constexpr size_t BUFSIZE { 512 };
extern const enum runlevel &runlevel;
extern const std::string &conf;
extern const std::string &config;
extern bool debugmode; ///< Toggle; available only ifdef RB_DEBUG
std::string demangle(const std::string &symbol);
@ -218,6 +218,7 @@ namespace ircd
#include "http.h"
#include "fmt.h"
#include "magics.h"
#include "conf.h"
#include "fs/fs.h"
#include "ios.h"
#include "ctx/ctx.h"

View file

@ -78,6 +78,7 @@ libircd_la_SOURCES = \
logger.cc \
info.cc \
sodium.cc \
conf.cc \
rfc1459.cc \
rand.cc \
hash.cc \

135
ircd/conf.cc Normal file
View file

@ -0,0 +1,135 @@
// Matrix Construct
//
// Copyright (C) Matrix Construct Developers, Authors & Contributors
// Copyright (C) 2016-2018 Jason Volk <jason@zemos.net>
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice is present in all copies. The
// full license for this software is available in the LICENSE file.
namespace ircd::conf
{
std::string _config;
static std::string read_json_file(string_view filename);
}
//TODO: X
decltype(ircd::conf::config)
ircd::conf::config
{
_config
};
// The configuration file is a user-converted Synapse homeserver.yaml
// converted into JSON. The configuration file is only truly necessary
// the first time IRCd is ever run. It does not have to be passed again
// to subsequent executions of IRCd if the database can be found. If
// the database is found, data passed in the configfile will be used
// to override the databased values. In this case, the complete config
// is not required to be specified in the file; only what is present
// will be used to override.
//
// *NOTE* This expects *canonical JSON* right now. That means converting
// your homeserver.yaml may be a two step process: 1. YAML to JSON, 2.
// whitespace-stripping the JSON. Tools to do both of these things are
// first hits in a google search.
void
ircd::conf::init(const string_view &filename)
{
_config = read_json_file(filename);
}
//
// item
//
template<>
decltype(ircd::instance_list<ircd::conf::item<>>::list)
ircd::instance_list<ircd::conf::item<>>::list
{};
/// Conf item abstract constructor.
ircd::conf::item<void>::item(const json::members &opts)
:feature_
{
opts
}
,feature
{
feature_
}
,name
{
feature.has("name")? unquote(feature["name"]) : "<unnamed>"_sv
}
{
}
ircd::conf::item<void>::~item()
noexcept
{
}
bool
ircd::conf::item<void>::refresh()
{
return false;
}
//
// misc
//
std::string
ircd::conf::read_json_file(string_view filename)
try
{
if(!filename.empty())
log::debug
{
"User supplied a configuration file path: `%s'", filename
};
if(filename.empty())
filename = fs::CPATH;
if(!fs::exists(filename))
return {};
std::string read
{
fs::read(filename)
};
// ensure any trailing cruft is removed to not set off the validator
if(endswith(read, '\n'))
read.pop_back();
if(endswith(read, '\r'))
read.pop_back();
// grammar check; throws on error
json::valid(read);
const json::object object{read};
const size_t key_count{object.count()};
log::info
{
"Using configuration from: `%s': JSON object with %zu members in %zu bytes",
filename,
key_count,
read.size()
};
return read;
}
catch(const std::exception &e)
{
log::error
{
"Configuration @ `%s': %s", filename, e.what()
};
throw;
}

View file

@ -20,13 +20,9 @@ namespace ircd
boost::asio::io_context *ios; // user's io service
struct strand *strand; // libircd event serializer
std::string _conf; // JSON read from configfile
const std::string &conf{_conf}; // Observer for conf data
ctx::ctx *main_context; // Main program loop
bool debugmode; // meaningful ifdef RB_DEBUG
std::string read_conf(std::string file);
void set_runlevel(const enum runlevel &);
void at_main_exit() noexcept;
void main();
@ -87,30 +83,16 @@ try
// Saves the user's runlevel_changed callback which we invoke.
ircd::runlevel_changed = std::move(runlevel_changed);
// The log is available, but it is console-only until conf opens files.
// The log is available. but it is console-only until conf opens files.
log::init();
log::mark("READY");
// The conf supplied by the user is read in; see: ircd::conf.
conf::init(configfile);
// This starts off the log with library information.
info::init();
// The configuration file is a user-converted Synapse homeserver.yaml
// converted into JSON. The configuration file is only truly meaningful
// the first time IRCd is ever run. Subsequently, only the database must
// be found. Real configuration is stored in the !config channel.
//
// This subroutine reads a file either at the user-supplied path or the
// default path specified in ircd::fs, vets for basic syntax issues, and
// then returns a string of JSON (the file's contents). The validity of
// the actual configuration is not known until specific subsystems are
// init'ed later.
//
// *NOTE* This expects *canonical JSON* right now. That means converting
// your homeserver.yaml may be a two step process: 1. YAML to JSON, 2.
// whitespace-stripping the JSON. Tools to do both of these things are
// first hits in a google search.
ircd::_conf = read_conf(configfile);
// Setup the main context, which is a new stack executing the function
// ircd::main(). The main_context is the first ircd::ctx to be spawned
// and will be the last to finish.
@ -362,56 +344,3 @@ ircd::reflect(const enum runlevel &level)
return "??????";
}
std::string
ircd::read_conf(std::string filename)
try
{
if(!filename.empty())
log::debug
{
"User supplied a configuration file path: `%s'", filename
};
if(filename.empty())
filename = fs::CPATH;
if(!fs::exists(filename))
return {};
std::string read
{
fs::read(filename)
};
// ensure any trailing cruft is removed to not set off the validator
if(endswith(read, '\n'))
read.pop_back();
if(endswith(read, '\r'))
read.pop_back();
// grammar check; throws on error
json::valid(read);
const json::object object{read};
const size_t key_count{object.count()};
log::info
{
"Using configuration from: `%s': JSON object with %zu members in %zu bytes",
filename,
key_count,
read.size()
};
return read;
}
catch(const std::exception &e)
{
log::error
{
"Configuration @ `%s': %s", filename, e.what()
};
throw;
}

View file

@ -52,8 +52,8 @@ ircd::m::self::tls_cert_der_sha256_b64
// init
//
ircd::m::keys::init::init(const json::object &conf)
:conf{conf}
ircd::m::keys::init::init(const json::object &config)
:config{config}
{
certificate();
signing();
@ -114,7 +114,7 @@ ircd::m::keys::init::signing()
{
const std::string sk_file
{
unquote(conf.get("signing_key_path", "construct.sk"))
unquote(config.get("signing_key_path", "construct.sk"))
};
if(fs::exists(sk_file))

View file

@ -66,13 +66,13 @@ ircd::m::control
ircd::m::init::init()
try
:conf
:config
{
ircd::conf
ircd::conf::config //TODO: X
}
,_keys
{
conf
this->config
}
{
modules();
@ -123,8 +123,8 @@ ircd::m::init::modules()
namespace ircd::m
{
static void init_listener(const json::object &conf, const json::object &opts, const string_view &bindaddr);
static void init_listener(const json::object &conf, const json::object &opts);
static void init_listener(const json::object &config, const json::object &opts, const string_view &bindaddr);
static void init_listener(const json::object &config, const json::object &opts);
}
void
@ -132,18 +132,18 @@ ircd::m::init::listeners()
{
const json::array listeners
{
conf["listeners"]
config["listeners"]
};
if(m::listeners.empty())
init_listener(conf, {});
init_listener(config, {});
else
for(const json::object opts : listeners)
init_listener(conf, opts);
init_listener(config, opts);
}
static void
ircd::m::init_listener(const json::object &conf,
ircd::m::init_listener(const json::object &config,
const json::object &opts)
{
const json::array binds
@ -152,14 +152,14 @@ ircd::m::init_listener(const json::object &conf,
};
if(binds.empty())
init_listener(conf, opts, "0.0.0.0");
init_listener(config, opts, "0.0.0.0");
else
for(const auto &bindaddr : binds)
init_listener(conf, opts, unquote(bindaddr));
init_listener(config, opts, unquote(bindaddr));
}
static void
ircd::m::init_listener(const json::object &conf,
ircd::m::init_listener(const json::object &config,
const json::object &opts,
const string_view &host)
{
@ -175,12 +175,12 @@ ircd::m::init_listener(const json::object &conf,
// Translate synapse options to our options (which reflect asio::ssl)
const json::strung options{json::members
{
{ "name", name },
{ "host", host },
{ "port", opts.get("port", 8448L) },
{ "ssl_certificate_file_pem", conf["tls_certificate_path"] },
{ "ssl_private_key_file_pem", conf["tls_private_key_path"] },
{ "ssl_tmp_dh_file", conf["tls_dh_params_path"] },
{ "name", name },
{ "host", host },
{ "port", opts.get("port", 8448L) },
{ "ssl_certificate_file_pem", config["tls_certificate_path"] },
{ "ssl_private_key_file_pem", config["tls_private_key_path"] },
{ "ssl_tmp_dh_file", config["tls_dh_params_path"] },
}};
m::listeners.emplace_back(options);