0
0
Fork 0
mirror of https://github.com/matrix-construct/construct synced 2024-07-06 10:38:37 +02:00
construct/ircd/m/m.cc

462 lines
9.9 KiB
C++
Raw Normal View History

2018-02-04 03:22:01 +01:00
// 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.
2017-11-16 02:37:09 +01:00
2017-11-30 20:44:23 +01:00
#include <ircd/m/m.h>
2017-11-16 02:37:09 +01:00
namespace ircd::m
{
struct log::log log
{
"matrix", 'm'
};
std::map<std::string, ircd::module> modules;
std::list<ircd::net::listener> listeners;
2017-11-16 02:37:09 +01:00
static void leave_ircd_room();
static void join_ircd_room();
}
const ircd::m::user::id::buf
ircd_user_id
{
"ircd", ircd::my_host() //TODO: hostname
};
ircd::m::user
ircd::m::me
{
ircd_user_id
};
const ircd::m::room::id::buf
ircd_room_id
{
"ircd", ircd::my_host()
};
ircd::m::room
ircd::m::my_room
{
ircd_room_id
};
const ircd::m::room::id::buf
control_room_id
{
"control", ircd::my_host()
};
ircd::m::room
ircd::m::control
{
control_room_id
};
//
// init
//
ircd::m::init::init()
try
:conf
2017-11-16 02:37:09 +01:00
{
ircd::conf
2017-11-16 02:37:09 +01:00
}
,_keys
2017-11-16 02:37:09 +01:00
{
conf
2017-11-16 02:37:09 +01:00
}
{
modules();
if(db::sequence(*dbs::events) == 0)
bootstrap();
2017-11-16 02:37:09 +01:00
listeners();
2017-11-16 02:37:09 +01:00
join_ircd_room();
}
catch(const m::error &e)
{
log.error("%s %s", e.what(), e.content);
throw;
}
catch(const std::exception &e)
{
log.error("%s", e.what());
throw;
2017-11-16 02:37:09 +01:00
}
ircd::m::init::~init()
noexcept try
{
leave_ircd_room();
m::listeners.clear();
m::modules.clear();
2017-11-16 02:37:09 +01:00
}
catch(const m::error &e)
{
log.critical("%s %s", e.what(), e.content);
ircd::terminate();
2017-11-16 02:37:09 +01:00
}
void
ircd::m::init::modules()
{
const string_view prefixes[]
{
"m_", "client_", "key_", "federation_", "media_"
};
for(const auto &name : mods::available())
if(startswith_any(name, std::begin(prefixes), std::end(prefixes)))
m::modules.emplace(name, name);
m::modules.emplace("root"s, "root"s);
}
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);
}
void
ircd::m::init::listeners()
{
const json::array listeners
{
conf["listeners"]
};
if(m::listeners.empty())
init_listener(conf, {});
else
for(const json::object opts : listeners)
init_listener(conf, opts);
}
static void
ircd::m::init_listener(const json::object &conf,
const json::object &opts)
{
const json::array binds
{
opts["bind_addresses"]
};
if(binds.empty())
init_listener(conf, opts, "0.0.0.0");
else
for(const auto &bindaddr : binds)
init_listener(conf, opts, unquote(bindaddr));
}
static void
ircd::m::init_listener(const json::object &conf,
const json::object &opts,
const string_view &host)
{
const json::array resources
{
opts["resources"]
};
// resources has multiple names with different configs which are being
// ignored :-/
const std::string name{"Matrix"s};
// 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"] },
}};
m::listeners.emplace_back(options);
2017-11-16 02:37:09 +01:00
}
void
ircd::m::init::bootstrap()
2017-11-16 02:37:09 +01:00
{
assert(dbs::events);
assert(db::sequence(*dbs::events) == 0);
2017-11-16 02:37:09 +01:00
ircd::log::notice
(
"This appears to be your first time running IRCd because the events "
"database is empty. I will be bootstrapping it with initial events now..."
);
create(user::users, me.user_id);
me.activate();
2017-11-16 02:37:09 +01:00
create(my_room, me.user_id);
send(my_room, me.user_id, "m.room.name", "",
{
{ "name", "IRCd's Room" }
});
send(my_room, me.user_id, "m.room.topic", "",
{
{ "topic", "The daemon's den." }
});
2017-11-16 02:37:09 +01:00
create(control, me.user_id);
join(control, me.user_id);
send(control, me.user_id, "m.room.name", "",
{
{ "name", "Control Room" }
});
send(user::users, me.user_id, "m.room.name", "",
{
{ "name", "Users" }
});
create(user::tokens, me.user_id);
send(user::tokens, me.user_id, "m.room.name", "",
{
{ "name", "User Tokens" }
});
_keys.bootstrap();
2017-11-16 02:37:09 +01:00
message(control, me.user_id, "Welcome to the control room.");
message(control, me.user_id, "I am the daemon. You can talk to me in this room by highlighting me.");
}
bool
ircd::m::self::host(const string_view &s)
{
return s == host();
}
ircd::string_view
ircd::m::self::host()
{
return "zemos.net"; //me.user_id.host();
}
void
ircd::m::join_ircd_room()
try
{
join(my_room, me.user_id);
}
catch(const m::ALREADY_MEMBER &e)
{
log.warning("IRCd did not shut down correctly...");
}
void
ircd::m::leave_ircd_room()
{
leave(my_room, me.user_id);
}
///////////////////////////////////////////////////////////////////////////////
//
// m/room.h
//
ircd::m::room
ircd::m::create(const id::room &room_id,
const id::user &creator,
const string_view &type)
{
using prototype = room (const id::room &, const id::user &, const string_view &);
static import<prototype> function
{
"client_createroom", "createroom__type"
};
return function(room_id, creator, type);
}
ircd::m::room
ircd::m::create(const id::room &room_id,
const id::user &creator,
const id::room &parent,
const string_view &type)
{
using prototype = room (const id::room &, const id::user &, const id::room &, const string_view &);
static import<prototype> function
{
"client_createroom", "createroom__parent_type"
};
return function(room_id, creator, parent, type);
}
ircd::m::event::id::buf
ircd::m::join(const room &room,
const id::user &user_id)
{
using prototype = event::id::buf (const m::room &, const id::user &);
static import<prototype> function
{
"client_rooms", "join__room_user"
};
return function(room, user_id);
}
ircd::m::event::id::buf
ircd::m::leave(const room &room,
const id::user &user_id)
{
using prototype = event::id::buf (const m::room &, const id::user &);
static import<prototype> function
{
"client_rooms", "leave__room_user"
};
return function(room, user_id);
}
ircd::m::event::id::buf
ircd::m::redact(const room &room,
const id::user &sender,
const id::event &event_id,
const string_view &reason)
{
using prototype = event::id::buf (const m::room &, const id::user &, const id::event &, const string_view &);
static import<prototype> function
{
"client_rooms", "redact__"
};
return function(room, sender, event_id, reason);
}
ircd::m::event::id::buf
ircd::m::message(const room &room,
const m::id::user &sender,
const string_view &body,
const string_view &msgtype)
{
return message(room, sender,
{
{ "body", { body, json::STRING } },
{ "msgtype", { msgtype, json::STRING } },
});
}
ircd::m::event::id::buf
ircd::m::message(const room &room,
const m::id::user &sender,
const json::members &contents)
{
return send(room, sender, "m.room.message", contents);
}
ircd::m::event::id::buf
ircd::m::send(const room &room,
const m::id::user &sender,
const string_view &type,
const string_view &state_key,
const json::members &contents)
{
json::iov _content;
json::iov::push content[contents.size()];
return send(room, sender, type, state_key, make_iov(_content, content, contents.size(), contents));
}
ircd::m::event::id::buf
ircd::m::send(const room &room,
const m::id::user &sender,
const string_view &type,
const string_view &state_key,
const json::object &contents)
{
json::iov _content;
json::iov::push content[contents.size()];
return send(room, sender, type, state_key, make_iov(_content, content, contents.size(), contents));
}
ircd::m::event::id::buf
ircd::m::send(const room &room,
const m::id::user &sender,
const string_view &type,
const string_view &state_key,
const json::iov &content)
{
using prototype = event::id::buf (const m::room &, const id::user &, const string_view &, const string_view &, const json::iov &);
static import<prototype> function
{
"client_rooms", "state__iov"
};
return function(room, sender, type, state_key, content);
}
ircd::m::event::id::buf
ircd::m::send(const room &room,
const m::id::user &sender,
const string_view &type,
const json::members &contents)
{
json::iov _content;
json::iov::push content[contents.size()];
return send(room, sender, type, make_iov(_content, content, contents.size(), contents));
}
ircd::m::event::id::buf
ircd::m::send(const room &room,
const m::id::user &sender,
const string_view &type,
const json::object &contents)
{
json::iov _content;
json::iov::push content[contents.count()];
return send(room, sender, type, make_iov(_content, content, contents.count(), contents));
}
ircd::m::event::id::buf
ircd::m::send(const room &room,
const m::id::user &sender,
const string_view &type,
const json::iov &content)
{
using prototype = event::id::buf (const m::room &, const id::user &, const string_view &, const json::iov &);
static import<prototype> function
{
"client_rooms", "send__iov"
};
return function(room, sender, type, content);
}
ircd::m::event::id::buf
ircd::m::commit(const room &room,
json::iov &event,
const json::iov &contents)
{
using prototype = event::id::buf (const m::room &, json::iov &, const json::iov &);
static import<prototype> function
{
"client_rooms", "commit__iov_iov"
};
return function(room, event, contents);
}