0
0
Fork 0
mirror of https://github.com/matrix-construct/construct synced 2024-11-29 10:12:39 +01:00

ircd:Ⓜ️:homeserver: Refactor conf related; patch self:: related; console cmds.

This commit is contained in:
Jason Volk 2019-10-04 12:48:54 -07:00
parent 08ea932c59
commit 6f798df65c
6 changed files with 497 additions and 522 deletions

View file

@ -43,6 +43,7 @@ struct ircd::m::homeserver
struct key;
struct cert;
struct opts;
struct conf;
/// Internal state; use m::my().
static homeserver *primary;
@ -60,6 +61,9 @@ struct ircd::m::homeserver
/// a user representing the server.
m::user::id::buf self;
/// Configuration
std::unique_ptr<struct conf> conf;
/// Loaded modules.
std::list<ircd::module> modules;
@ -91,15 +95,33 @@ struct ircd::m::homeserver::key
/// Current ed25519:ident string
std::string public_key_id;
key(const string_view &origin);
key(const struct opts &);
key() = default;
};
struct ircd::m::homeserver::cert
struct ircd::m::homeserver::conf
{
std::string tls_private_key_path;
std::string tls_public_key_path;
std::string tls_cert_path;
/// !conf:origin
m::room::id::buf room_id;
/// Convenience
m::room room;
/// Register the conf item init callback //TODO: XXX
decltype(ircd::conf::on_init)::callback item_init;
/// Register the !conf room item message hook.
hookfn<vm::eval &> conf_updated;
// Interface
bool get(const string_view &key, const std::function<void (const string_view &)> &) const;
event::id::buf set(const string_view &key, const string_view &val) const;
size_t defaults(const string_view &prefix = {}) const;
size_t load(const string_view &prefix = {}) const;
size_t store(const string_view &prefix = {}, const bool &force = false) const;
conf(const struct opts &);
};
struct ircd::m::homeserver::opts

View file

@ -18,9 +18,7 @@ namespace ircd::m::self
// Similar to my_host(), but the comparison is relaxed to allow port
// numbers to be a factor: myself.com:8448 input will match if a homeserver
// here has a network_name of myself.com. OTOH, myself.com:1234 (i.e some
// non-canonical port) can only match a homeserver here with the explicit
// name of myself.com:1234.
// here has a network_name of myself.com.
bool host(const string_view &);
// Alias for origin(my()); primary homeserver's network name

View file

@ -120,7 +120,6 @@ libircd_matrix_la_SOURCES += sync.cc
libircd_matrix_la_SOURCES += typing.cc
libircd_matrix_la_SOURCES += users.cc
libircd_matrix_la_SOURCES += users_servers.cc
libircd_matrix_la_SOURCES += conf.cc
libircd_matrix_la_SOURCES += error.cc
libircd_matrix_la_SOURCES += filter.cc
libircd_matrix_la_SOURCES += txn.cc

View file

@ -1,357 +0,0 @@
// 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::m
{
struct conf_room;
}
using namespace ircd;
extern "C" void default_conf(const string_view &prefix);
extern "C" void rehash_conf(const string_view &prefix, const bool &existing);
extern "C" void reload_conf();
extern "C" void refresh_conf();
static void init_conf_item(conf::item<> &);
struct ircd::m::conf_room
{
m::room::id::buf room_id
{
"conf", my_host()
};
m::room room
{
room_id
};
operator const m::room &() const
{
return room;
}
};
// This module registers with conf::on_init to be called back
// when a conf item is initialized; when this module is unloaded
// we have to unregister that listener using this state.
decltype(conf::on_init)::const_iterator
conf_on_init_iter
{
end(conf::on_init)
};
void conf_on_init()
{
conf_on_init_iter = conf::on_init.emplace(end(conf::on_init), init_conf_item);
reload_conf();
}
void conf_on_fini()
{
assert(conf_on_init_iter != end(conf::on_init));
conf::on_init.erase(conf_on_init_iter);
}
/// Set to false to quiet errors from a conf item failing to set
bool
item_error_log
{
true
};
extern "C" m::event::id::buf
set_conf_item(const m::user::id &sender,
const string_view &key,
const string_view &val)
{
if(conf::exists(key) && !conf::persists(key))
{
conf::set(key, val);
return {};
}
const m::conf_room conf_room;
return send(conf_room, sender, "ircd.conf.item", key,
{
{ "value", val }
});
}
extern "C" void
get_conf_item(const string_view &key,
const std::function<void (const string_view &)> &closure)
{
static const m::event::fetch::opts fopts
{
m::event::keys::include { "content" }
};
const m::conf_room conf_room;
const m::room::state state
{
conf_room, &fopts
};
state.get("ircd.conf.item", key, [&closure]
(const m::event &event)
{
const auto &value
{
unquote(at<"content"_>(event).at("value"))
};
closure(value);
});
}
static void
conf_updated(const m::event &event)
try
{
const auto &content
{
at<"content"_>(event)
};
const auto &key
{
at<"state_key"_>(event)
};
const string_view &value
{
unquote(content.at("value"))
};
if(run::level == run::level::START && !conf::exists(key))
return;
// Conf items marked with a persist=false property are not read from
// the conf room into the item, even if the value exists in the room.
if(conf::exists(key) && !conf::persists(key))
return;
log::debug
{
"Updating conf [%s] => %s", key, value
};
ircd::conf::set(key, value);
}
catch(const std::exception &e)
{
if(item_error_log)
log::error
{
"Failed to set conf item '%s' :%s",
json::get<"state_key"_>(event),
e.what()
};
}
static void
conf_updated(const m::event::idx &event_idx)
try
{
static const m::event::fetch::opts fopts
{
m::event::keys::include { "content", "state_key" }
};
const m::event::fetch event
{
event_idx, fopts
};
conf_updated(event);
}
catch(const std::exception &e)
{
if(item_error_log)
log::error
{
"Failed to set conf item by event_idx:%lu :%s",
event_idx,
e.what()
};
}
static void
handle_conf_updated(const m::event &event,
m::vm::eval &)
{
conf_updated(event);
}
m::hookfn<m::vm::eval &>
conf_updated_hook
{
handle_conf_updated,
{
{ "_site", "vm.effect" },
{ "room_id", "!conf" },
{ "type", "ircd.conf.item" },
}
};
static void
init_conf_items()
{
static const m::event::fetch::opts fopts
{
m::event::keys::include { "content", "state_key" }
};
const m::conf_room conf_room;
const m::room::state state
{
conf_room, &fopts
};
state.prefetch("ircd.conf.item");
state.for_each("ircd.conf.item", []
(const auto &, const auto &state_key, const auto &event_idx)
{
if(!conf::exists(state_key))
return true;
conf_updated(event_idx);
return true;
});
}
static void
init_conf_item(conf::item<> &item)
{
const m::conf_room conf_room;
const m::room::state state
{
conf_room
};
const auto &event_idx
{
state.get(std::nothrow, "ircd.conf.item", item.name)
};
if(!event_idx)
return;
conf_updated(event_idx);
}
static m::event::id::buf
create_conf_item(const string_view &key,
const conf::item<> &item)
try
{
thread_local char vbuf[4_KiB];
const string_view &val
{
item.get(vbuf)
};
return set_conf_item(m::me(), key, val);
}
catch(const std::exception &e)
{
if(item_error_log) log::error
{
"Failed to create conf item '%s' :%s",
key,
e.what()
};
return {};
}
static void
create_conf_room(const m::event &,
m::vm::eval &)
{
const m::conf_room conf_room;
m::create(conf_room.room_id, m::me());
//rehash_conf({}, true);
}
m::hookfn<m::vm::eval &>
create_conf_room_hook
{
create_conf_room,
{
{ "_site", "vm.effect" },
{ "room_id", "!ircd" },
{ "type", "m.room.create" },
}
};
void
rehash_conf(const string_view &prefix,
const bool &existing)
{
const m::conf_room conf_room;
const m::room::state state
{
conf_room
};
for(const auto &p : conf::items)
{
const auto &key{p.first};
if(prefix && !startswith(key, prefix))
continue;
const auto &item{p.second}; assert(item);
// Conf items marked with a persist=false property are not written
// to the conf room.
if(!item->feature.get("persist", true))
continue;
// Use the `existing` argument to toggle a force-overwrite
if(!existing)
if(state.has("ircd.conf.item", key))
continue;
create_conf_item(key, *item);
}
}
void
default_conf(const string_view &prefix)
{
for(const auto &p : conf::items)
{
const auto &key{p.first};
if(prefix && !startswith(key, prefix))
continue;
const auto &item{p.second}; assert(item);
const auto value
{
unquote(item->feature["default"])
};
conf::set(key, value);
}
}
void
reload_conf()
{
init_conf_items();
}
void
refresh_conf()
{
ircd::conf::reset();
}

View file

@ -177,26 +177,25 @@ ircd::m::homeserver::homeserver(const struct opts *const &opts)
}
,opts{[this, &opts]
{
//TODO: xxx
primary = primary?: this;
primary = primary?: this; //TODO: xxx
return opts;
}()}
,key
{
std::make_unique<struct key>(opts->origin)
std::make_unique<struct key>(*opts)
}
,database
{
std::make_shared<dbs::init>(opts->server_name, std::string{})
}
,rooms
{
{ "ircd", opts->origin },
std::make_shared<dbs::init>(opts->server_name)
}
,self
{
"ircd", opts->origin
}
,conf
{
std::make_unique<struct conf>(*opts)
}
,modules
{
begin(matrix::module_names), end(matrix::module_names)
@ -223,7 +222,7 @@ noexcept
}
//
// homeserver::keys
// homeserver::key
//
/*
@ -305,14 +304,10 @@ ircd::m::self::init::federation_ed25519()
}
*/
//
// create_my_key
//
ircd::m::homeserver::key::key(const string_view &origin)
ircd::m::homeserver::key::key(const struct opts &opts)
:secret_key_path
{
(("%s.ed25519"_snstringf, rfc3986::DOMAIN_BUFSIZE + 16UL), origin)
(("%s.ed25519"_snstringf, rfc3986::DOMAIN_BUFSIZE + 16UL), opts.origin)
}
,secret_key
{
@ -374,62 +369,321 @@ ircd::m::homeserver::key::key(const string_view &origin)
*/
}
///////////////////////////////////////////////////////////////////////////////
//
// m/self.h
// homeserver::conf
//
ircd::string_view
ircd::m::self::my_host()
namespace ircd::m
{
return origin(my());
static bool load_conf_item(const event &);
static bool load_conf_item(const event::idx &);
static size_t load_conf_items(const room &, const string_view &prefix);
static void handle_conf_room_hook(const event &, vm::eval &);
static void handle_item_init(const room &, conf::item<> &);
}
bool
ircd::m::self::host(const string_view &other)
//
// homeserver::conf::conf
//
ircd::m::homeserver::conf::conf(const struct opts &opts)
:room_id
{
const net::hostport other_host{other};
for(const auto &[my_network, hs_p] : homeserver::map)
"conf", opts.origin
}
,room
{
room_id
}
,item_init
{
ircd::conf::on_init, [this](ircd::conf::item<> &item)
{
// port() is 0 when the origin has no port (and implies 8448)
const auto port
handle_item_init(room, item);
}
}
,conf_updated
{
handle_conf_room_hook,
{
{ "_site", "vm.effect" },
{ "room_id", room_id },
{ "type", "ircd.conf.item" },
}
}
{
}
size_t
ircd::m::homeserver::conf::store(const string_view &prefix,
const bool &force)
const
{
size_t ret(0);
for(const auto &[key, item] : ircd::conf::items) try
{
if(prefix && !startswith(key, prefix))
continue;
// Conf items marked with a persist=false property are not written
// to the conf room; regardless of force=true
if(!item->feature.get("persist", true))
continue;
thread_local char buf[4_KiB];
const auto &val
{
net::port(net::hostport(my_network))
item->get(buf)
};
// If my_host has a port number, then the argument must also have the
// same port number.
if(port && my_network == other)
return true;
else if(port)
bool dup{false}, exists{false};
if(!force)
get(key, [&exists, &dup, &val](const string_view &val_)
{
exists = true;
dup = val == val_;
});
// No reason to store the same value
if(!force && dup)
continue;
/// If my_host has no port number, then the argument can have port
/// 8448 or no port number, which will initialize net::hostport.port to
/// the "canon_port" of 8448.
assert(net::canon_port == 8448);
if(net::port(other_host) != net::canon_port)
const json::string &default_value
{
item->feature["default"]
};
// When the !conf room has nothing for a key, and this store request
// is asking us to write the default value, that is rejected here.
if(!force && !exists && val == default_value)
continue;
/// Both myself and input are using 8448; now the name has to match.
if(my_network != host(other_host))
continue;
return true;
set(key, val);
ret++;
}
catch(const std::exception &e)
{
log::error
{
"Failed to create conf item '%s' :%s",
key,
e.what()
};
}
return false;
return ret;
}
size_t
ircd::m::homeserver::conf::load(const string_view &prefix)
const
{
return load_conf_items(room, prefix);
}
size_t
ircd::m::homeserver::conf::defaults(const string_view &prefix)
const
{
size_t ret(0);
for(const auto &[key, item] : ircd::conf::items)
{
if(prefix && !startswith(key, prefix))
continue;
assert(item);
const json::string &default_value
{
item->feature["default"]
};
ret += ircd::conf::set(key, default_value);
}
return ret;
}
ircd::m::event::id::buf
ircd::m::homeserver::conf::set(const string_view &key,
const string_view &val)
const
{
// Branch for conf items that do not persist. We don't send a message to
// the conf room to update them; the value is put directly into the item.
if(ircd::conf::exists(key) && !ircd::conf::persists(key))
{
ircd::conf::set(key, val);
return {};
}
const m::user::id::buf sender
{
"ircd", room_id.hostname()
};
return send(room, sender, "ircd.conf.item", key, json::members
{
{ "value", val }
});
}
bool
ircd::m::self::my_host(const string_view &name)
ircd::m::homeserver::conf::get(const string_view &key,
const std::function<void (const string_view &)> &closure)
const
{
const auto it
const auto &event_idx
{
homeserver::map.find(name)
room.get("ircd.conf.item", key)
};
return it != end(homeserver::map);
return m::get(std::nothrow, event_idx, "content", [&closure]
(const json::object &content)
{
const json::string &value
{
content["value"]
};
closure(value);
});
}
void
ircd::m::handle_item_init(const room &room,
conf::item<> &item)
{
const auto event_idx
{
room.get(std::nothrow, "ircd.conf.item", item.name)
};
if(!event_idx)
return;
load_conf_item(event_idx);
}
void
ircd::m::handle_conf_room_hook(const event &event,
vm::eval &eval)
{
if(!homeserver::primary)
return;
assert(homeserver::primary->conf);
const m::room::id &primary_room
{
homeserver::primary->conf->room_id
};
// Only the primary homeserver controls the global conf items.
if(json::get<"room_id"_>(event) != primary_room)
return;
load_conf_item(event);
}
size_t
ircd::m::load_conf_items(const m::room &room,
const string_view &prefix)
{
const m::room::state state
{
room
};
state.for_each("ircd.conf.item", [&prefix]
(const auto &, const auto &state_key, const auto &event_idx)
{
static const m::event::fetch::opts fopts
{
m::event::keys::include { "content", "state_key" }
};
if(prefix && !startswith(state_key, prefix))
return true;
m::prefetch(event_idx, fopts);
return true;
});
size_t ret(0);
state.for_each("ircd.conf.item", [&ret, &prefix]
(const auto &, const auto &state_key, const auto &event_idx)
{
if(prefix && !startswith(state_key, prefix))
return true;
if(!conf::exists(state_key))
return true;
ret += load_conf_item(event_idx);
return true;
});
return ret;
}
bool
ircd::m::load_conf_item(const m::event::idx &event_idx)
{
static const m::event::fetch::opts fopts
{
m::event::keys::include { "content", "state_key" }
};
const m::event::fetch event
{
event_idx, std::nothrow, fopts
};
return event.valid && load_conf_item(event);
}
bool
ircd::m::load_conf_item(const m::event &event)
try
{
const auto &key
{
at<"state_key"_>(event)
};
const auto &content
{
at<"content"_>(event)
};
const json::string &value
{
content.get("value")
};
// Conf items marked with a persist=false property are not read from
// the conf room into the item, even if the value exists in the room.
if(conf::exists(key) && !conf::persists(key))
return false;
log::debug
{
"Updating conf [%s] => [%s]", key, value
};
ircd::conf::set(key, value);
return true;
}
catch(const std::exception &e)
{
log::error
{
"Failed to set conf item '%s' :%s",
json::get<"state_key"_>(event),
e.what()
};
return false;
}
//
@ -464,49 +718,10 @@ ircd::m::signoff(homeserver &homeserver)
presence::set(homeserver.self, "offline", offline_status_msg);
}
/*
//
// init
// bootstrap
//
ircd::m::self::init::init()
try
{
// Sanity check that these are valid hostname strings. This was likely
// already checked, so these validators will simply throw without very
// useful error messages if invalid strings ever make it this far.
ircd_user_id = {"ircd", origin};
m::me = {ircd_user_id};
ircd_room_id = {"ircd", origin};
m::my_room = {ircd_room_id};
if(origin == "localhost")
log::warning
{
"The origin is configured or has defaulted to 'localhost'"
};
}
catch(const std::exception &e)
{
log::critical
{
m::log, "Failed to init self origin[%s] servername[%s]",
origin,
servername,
};
throw;
}
static const auto self_init{[]
{
ircd::m::self::init();
return true;
}()};
*/
void
ircd::m::bootstrap(homeserver &homeserver)
try
@ -583,6 +798,25 @@ try
{ "topic", "The daemon's den." }
});
const m::room::id::buf conf_room_id
{
"conf", origin(homeserver)
};
const m::room conf_room
{
conf_room_id
};
if(!exists(conf_room))
create(conf_room, me);
if(!conf_room.has("m.room.name",""))
send(conf_room, me, "m.room.name", "",
{
{ "name", "Server Configuration" }
});
const m::room::id::buf tokens_room_id
{
"tokens", origin(homeserver)
@ -616,3 +850,81 @@ catch(const std::exception &e)
e.what()
};
}
///////////////////////////////////////////////////////////////////////////////
//
// m/self.h
//
//
// !!! DEPRECATED !!!
//
// These items are being replaced, but their widespread use throughout the
// codebase is keeping them here for now.
//
namespace ircd::m::self
{
static bool match(const net::hostport &a, const net::hostport &b) noexcept;
}
/// Get network name (origin) of the primary homeserver. Use of this function
/// is discouraged, though it's not marked as deprecated to reduce warnings
/// for now until an actual effort is made to eliminate all callsites. Instead
/// of using this function, try to obtain a more specific homeserver instance
/// being hosted from this server based on the context of the callsite.
ircd::string_view
ircd::m::self::my_host()
{
return origin(my());
}
bool
ircd::m::self::my_host(const string_view &name)
{
const auto it
{
homeserver::map.find(name)
};
return it != end(homeserver::map);
}
/// Determine if argument string is one of my homeserver's network names. This
/// is not a simple string comparison; strings postfixed with port :8448 are
/// compared equal to strings without a port.
bool
ircd::m::self::host(const string_view &other)
{
assert(net::canon_port == 8448);
const net::hostport other_host{other};
for(const auto &[my_network, hs_p] : homeserver::map)
if(match(my_network, other))
return true;
return false;
}
bool
ircd::m::self::match(const net::hostport &a,
const net::hostport &b)
noexcept
{
// port() is 0 when the origin has no port (and implies 8448)
const auto my_port
{
port(a)?: 8448
};
// If my_host has a non-canonical port number, then the argument must
// also have the same port number, or there is no possible match.
if(my_port != net::canon_port)
return my_port == port(b) && host(a) == host(b);
// Since my host is on the canonical port, if other host has some
// different port number, there is no possible match.
if(port(b) != net::canon_port)
return false;
// Both myself and input are using 8448; now the name has to match.
return host(a) == host(b);
}

View file

@ -1643,14 +1643,14 @@ console_cmd__conf__list(opt &out, const string_view &line)
};
thread_local char val[4_KiB];
for(const auto &item : conf::items)
for(const auto &[key, item_p] : conf::items)
{
if(prefix && !startswith(item.first, prefix))
if(prefix && !startswith(key, prefix))
continue;
out
<< std::setw(64) << std::left << std::setfill('_') << item.first
<< " " << item.second->get(val)
<< std::setw(64) << std::left << std::setfill('_') << key
<< " " << item_p->get(val)
<< std::endl;
}
@ -1663,11 +1663,6 @@ console_cmd__conf(opt &out, const string_view &line)
return console_cmd__conf__list(out, line);
}
extern "C" ircd::m::event::id::buf
set_conf_item(const ircd::m::user::id &,
const ircd::string_view &key,
const ircd::string_view &val);
bool
console_cmd__conf__set(opt &out, const string_view &line)
{
@ -1688,7 +1683,7 @@ console_cmd__conf__set(opt &out, const string_view &line)
const auto event_id
{
set_conf_item(m::me(), key, val)
m::my().conf->set(key, val)
};
out << event_id << " <- " << key << " = " << val << std::endl;
@ -1732,15 +1727,9 @@ console_cmd__conf__rehash(opt &out, const string_view &line)
{
const params param{line, " ",
{
"prefix", "force"
"prefix"
}};
using prototype = void (const string_view &, const bool &);
static mods::import<prototype> rehash_conf
{
"conf", "rehash_conf"
};
string_view prefix
{
param.at("prefix", "*"_sv)
@ -1749,18 +1738,18 @@ console_cmd__conf__rehash(opt &out, const string_view &line)
if(prefix == "*")
prefix = string_view{};
const bool force
const auto stored
{
param["force"] == "force"
m::my().conf->store(prefix)
};
rehash_conf(prefix, force);
out << "Saved runtime conf items"
<< (prefix? " with the prefix "_sv : string_view{})
<< (prefix? prefix : string_view{})
<< " from the current state into !conf:" << my_host()
<< std::endl;
out
<< "Saved runtime conf items"
<< (prefix? " with the prefix "_sv : string_view{})
<< (prefix? prefix : string_view{})
<< " from the current state into "
<< m::my().conf->room_id
<< std::endl;
return true;
}
@ -1773,47 +1762,66 @@ console_cmd__conf__default(opt &out, const string_view &line)
"prefix"
}};
using prototype = void (const string_view &);
static mods::import<prototype> default_conf
const auto &prefix
{
"conf", "default_conf"
param["prefix"]
};
string_view prefix
const auto defaulted
{
param.at("prefix", "*"_sv)
m::my().conf->defaults(prefix)
};
if(prefix == "*")
prefix = string_view{};
default_conf(prefix);
out << "Set runtime conf items"
<< (prefix? " with the prefix "_sv : string_view{})
<< (prefix? prefix : string_view{})
<< " to their default value."
<< std::endl
<< "Note: These values must be saved with the rehash command"
<< " to survive a restart/reload."
<< std::endl;
out
<< "Set "
<< defaulted
<< " runtime conf items"
<< (prefix? " with the prefix "_sv : string_view{})
<< (prefix? prefix : string_view{})
<< " to their default value."
<< std::endl
<< "Note: These values must be saved with the rehash command"
<< " to survive a restart/reload."
<< std::endl;
return true;
}
bool
console_cmd__conf__reload(opt &out, const string_view &line)
console_cmd__conf__load(opt &out, const string_view &line)
{
using prototype = void ();
static mods::import<prototype> reload_conf
const params param{line, " ",
{
"conf", "reload_conf"
"room_id", "prefix"
}};
const auto &room_id
{
startswith(param["room_id"], '!')?
param["room_id"]:
m::my().conf->room_id
};
reload_conf();
out << "Updated any runtime conf items"
<< " from the current state in !conf:" << my_host()
<< std::endl;
const auto &prefix
{
startswith(param["room_id"], '!')?
param["prefix"]:
param["room_id"]
};
// TODO: interface for room_id
const auto loaded
{
m::my().conf->load(prefix)
};
out
<< "Updated "
<< loaded
<< " runtime conf items from the current state in "
<< room_id
<< std::endl;
return true;
}
@ -1821,13 +1829,7 @@ console_cmd__conf__reload(opt &out, const string_view &line)
bool
console_cmd__conf__reset(opt &out, const string_view &line)
{
using prototype = void ();
static mods::import<prototype> refresh_conf
{
"conf", "refresh_conf"
};
refresh_conf();
ircd::conf::reset();
out << "All conf items which execute code upon a change"
<< " have done so with the latest runtime value."
<< std::endl;
@ -5881,8 +5883,16 @@ console_cmd__resource(opt &out, const string_view &line)
}
//
// me
//
//
bool
console_cmd__me(opt &out, const string_view &line)
{
out << m::me() << std::endl;
out << m::public_key_id(m::my()) << std::endl;
return true;
}
//
// key
@ -5901,15 +5911,6 @@ console_cmd__key(opt &out, const string_view &line)
param["server_name"]
};
// information on my current key
if(!server_name)
{
out << "origin: " << m::my_host() << std::endl;
out << "public key ID: " << m::public_key_id(m::my()) << std::endl;
//out << "public key base64: " << m::self::public_key_b64 << std::endl;
return true;
}
// keys cached for server by param.
m::keys::cache::for_each(server_name, [&out]
(const m::keys &keys)