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

ircd: Various cleanup.

This commit is contained in:
Jason Volk 2017-03-20 19:30:07 -07:00
parent f1c5257201
commit 21db4baab3
9 changed files with 485 additions and 58 deletions

View file

@ -248,7 +248,7 @@ ircd::json::operator<(const obj::member &a, const string_view &b)
inline bool inline bool
ircd::json::operator!=(const obj::member &a, const string_view &b) ircd::json::operator!=(const obj::member &a, const string_view &b)
{ {
return string_view(a.first.string, a.first.len) == b; return string_view(a.first.string, a.first.len) != b;
} }
inline bool inline bool

View file

@ -29,11 +29,211 @@ namespace ircd {
namespace m { namespace m {
struct error struct error
:ircd::error :http::error
{ {
error(const json::doc &doc); template<class... args> error(const http::code &, const string_view &errcode, const char *const &fmt, args&&...);
error(const json::obj &obj); template<class... args> error(const string_view &errcode, const char *const &fmt, args&&...);
error(const http::code &, const json::doc &doc = {});
error(const http::code &, const json::obj &obj);
};
struct member
{
};
template<const char *const &name>
struct mem
:member
{
std::string value;
operator const std::string &() const { return value; }
mem(const json::obj &obj)
:value{obj[name]}
{}
mem(const json::doc &doc)
:value{doc[name]}
{}
mem() = default;
friend std::ostream &operator<<(std::ostream &s, const mem &m)
{
s << m.value;
return s;
}
};
struct session
{
static constexpr auto _user_id { "user_id" };
static constexpr auto _access_token { "access_token" };
static constexpr auto _home_server { "home_server" };
static constexpr auto _device_id { "device_id" };
mem<_user_id> user_id;
mem<_access_token> access_token;
mem<_home_server> home_server;
mem<_device_id> device_id;
session(const json::obj &obj)
:user_id{obj}
,access_token{obj}
,home_server{obj}
,device_id{obj}
{}
session() = default;
};
struct request
:json::obj
{
struct quote;
struct versions;
struct sync;
struct login;
string_view method;
string_view resource;
string_view access_token;
request(const string_view &method,
const string_view &resource,
std::initializer_list<json::obj::member> body = {})
:json::obj{std::move(body)}
,method{method}
,resource{resource}
{}
request(const string_view &method,
const string_view &resource,
const json::doc &content)
:json::obj{content}
,method{method}
,resource{resource}
{}
};
struct request::sync
:request
{
/*
bool full_state;
string_view since;
string_view filter;
string_view set_presence;
milliseconds timeout;
*/
sync(std::initializer_list<json::obj::member> body = {})
:request{"GET", "/_matrix/client/r0/sync", std::move(body)}
{}
};
struct request::login
:request
{
/*
string_view user;
string_view password;
*/
login(std::initializer_list<json::obj::member> body = {})
:request{"POST", "/_matrix/client/r0/login", std::move(body)}
{}
};
struct request::quote
:request
{
quote(const string_view &method,
const string_view &resource,
const json::doc &content)
:request{method, resource, content}
{}
};
struct client
:ircd::client
{
IRCD_EXCEPTION(ircd::error, error)
std::unique_ptr<session> sess;
// Synchronize server state
void sync(request::sync &r);
// Account login
session login(request::login &);
// Account registration
void reg(const string_view &user,
const string_view &pass,
const string_view &type = "m.login.dummy");
void quote(request::quote &);
client(const host_port &);
};
using doc_closure = std::function<void (const json::doc &)>;
using arr_closure = std::function<void (const json::arr &)>;
struct request::versions
:request
{
versions(client &, const doc_closure & = nullptr, std::initializer_list<json::obj::member> body = {});
}; };
} // namespace m } // namespace m
} // namespace ircd } // namespace ircd
inline
ircd::m::error::error(const http::code &c,
const json::obj &obj)
:http::error{c, std::string{obj}}
{}
inline
ircd::m::error::error(const http::code &c,
const json::doc &doc)
:http::error{c, std::string{doc}}
{}
template<class... args>
ircd::m::error::error(const string_view &errcode,
const char *const &fmt,
args&&... a)
:error
{
http::BAD_REQUEST, errcode, fmt, std::forward<args>(a)...
}{}
template<class... args>
ircd::m::error::error(const http::code &status,
const string_view &errcode,
const char *const &fmt,
args&&... a)
:http::error
{
status, [&]
{
char estr[256]; const auto estr_len
{
fmt::snprintf(estr, sizeof(estr), fmt, std::forward<args>(a)...)
};
return std::string
{
json::obj
{
{ "errcode", errcode },
{ "error", string_view(estr, estr_len) }
}
};
}()
}{}

View file

@ -44,8 +44,10 @@ struct resource
protected: protected:
decltype(resources)::const_iterator resources_it; decltype(resources)::const_iterator resources_it;
void call_method(client &, method &, resource::request &);
public: public:
void operator()(client &, parse::capstan &, const http::request::head &) const; void operator()(client &, parse::capstan &, const http::request::head &);
resource(const char *const &name, resource(const char *const &name,
const char *const &description = ""); const char *const &description = "");
@ -53,18 +55,25 @@ struct resource
virtual ~resource() noexcept; virtual ~resource() noexcept;
}; };
struct resource::response
{
response(client &, const json::doc &doc, const http::code &code = http::OK);
response(client &, const json::obj &obj, const http::code &code = http::OK);
response() = default;
~response() noexcept;
};
struct resource::request struct resource::request
:json::doc
{ {
const http::request::head &head; const http::request::head &head;
http::request::content &content; http::request::content &content;
request(const http::request::head &head, http::request::content &content)
:json::doc{content}
,head{head}
,content{content}
{}
};
struct resource::response
{
response(client &, const json::doc &doc, const http::code & = http::OK);
response(client &, const json::obj &obj, const http::code & = http::OK);
response() = default;
~response() noexcept;
}; };
struct resource::method struct resource::method

View file

@ -171,7 +171,6 @@ struct line {};
#include "rfc1459.h" #include "rfc1459.h"
#include "json.h" #include "json.h"
#include "http.h" #include "http.h"
#include "matrix.h"
#include "fmt.h" #include "fmt.h"
#include "path.h" #include "path.h"
#include "ctx.h" #include "ctx.h"
@ -183,3 +182,4 @@ struct line {};
#include "js.h" #include "js.h"
#include "client.h" #include "client.h"
#include "mods.h" #include "mods.h"
#include "matrix.h"

View file

@ -41,10 +41,11 @@ libircd_la_SOURCES = \
fmt.cc \ fmt.cc \
db.cc \ db.cc \
locale.cc \ locale.cc \
json.cc \
http.cc \ http.cc \
json.cc \
matrix.cc \ matrix.cc \
parse.cc parse.cc \
conf.cc
if JS if JS
libircd_la_SOURCES += \ libircd_la_SOURCES += \

View file

@ -181,6 +181,7 @@ ircd::read_closure(client &client)
{ {
try try
{ {
const char *const got(start);
read(client, start, stop); read(client, start, stop);
} }
catch(const boost::system::system_error &e) catch(const boost::system::system_error &e)
@ -317,7 +318,7 @@ try
string(remote_addr(client)).c_str(), string(remote_addr(client)).c_str(),
std::string(head.resource).c_str()); std::string(head.resource).c_str());
const auto &resource(*resource::resources.at(head.resource)); auto &resource(*resource::resources.at(head.resource));
resource(client, pc, head); resource(client, pc, head);
} }
catch(const std::out_of_range &e) catch(const std::out_of_range &e)

24
ircd/conf.cc Normal file
View file

@ -0,0 +1,24 @@
/*
* Copyright (C) 2017 Charybdis Development Team
* Copyright (C) 2017 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.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
namespace ircd {
} // namespace ircd

View file

@ -22,30 +22,193 @@
namespace ircd { namespace ircd {
namespace m { namespace m {
db::handle accounts;
} // namespace m } // namespace m
} // namespace ircd } // namespace ircd
void ircd::m::client::client(const host_port &host_port)
ircd::test(const string_view &what) :ircd::client{host_port}
try
{ {
const auto tok(tokens(what, " ")); }
const std::string method(tok.at(2));
const std::string rcontent(tok.size() >= 5? tok.at(4) : string_view{});
char url[256] {0}; ircd::m::request::versions::versions(client &client,
snprintf(url, sizeof(url), "/_matrix/client/%s", std::string(tok.at(3)).c_str()); const doc_closure &closure,
std::initializer_list<json::obj::member> body)
const std::string host{tok.at(0)}; :request
const auto port(lex_cast<uint16_t>(tok.at(1))); {
ircd::client client "GET", "/_matrix/client/versions", std::move(body)
}
{
const auto handle([&](const http::code &code,
const json::doc &doc)
{ {
{ host, port } switch(code)
{
case http::OK:
if(closure)
closure(doc);
break;
default:
throw m::error(code, doc);
}
});
char buf[1024];
parse::buffer pb{buf};
parse::capstan pc{pb, read_closure(client)};
const auto handler([&pc, &handle]
(const http::response::head &head)
{
const http::response::content content{pc, head};
const auto status(http::status(head.status));
const json::doc doc{content};
handle(status, doc);
});
http::request
{
host(remote_addr(client)), method, resource, std::string(*this), write_closure(client),
{
{ "Content-Type"s, "application/json"s }
}
};
http::response
{
pc, nullptr, handler
};
}
void
ircd::m::client::reg(const string_view &user,
const string_view &pass,
const string_view &type)
{
const json::obj auth
{
{ "type", type }
};
const json::obj obj
{
{ "password", pass },
{ "username", user },
{ "auth", &auth },
};
const auto handle([&](const http::code &code,
const json::doc &doc)
{
switch(code)
{
case http::OK:
std::cout << "OK!" << std::endl;
std::cout << doc << std::endl;
break;
default:
throw m::error(code, doc);
}
});
char buf[4096];
parse::buffer pb{buf};
parse::capstan pc{pb, read_closure(*this)};
const auto handler([&pc, &handle]
(const http::response::head &head)
{
const http::response::content content{pc, head};
const auto status(http::status(head.status));
const json::doc doc{content};
handle(status, doc);
});
http::request
{
host(remote_addr(*this)), "POST"s, "/_matrix/client/r0/register"s, std::string(obj), write_closure(*this),
{
{ "Content-Type"s, "application/json"s }
}
};
http::response
{
pc, nullptr, handler
};
}
ircd::m::session
ircd::m::client::login(request::login &r)
{
session ret;
const auto handle([&](const http::code &code,
const json::doc &doc)
{
switch(code)
{
case http::OK:
ret = json::obj{doc};
this->sess.reset(new session{doc});
break;
default:
throw m::error(code, doc);
}
});
char buf[4096];
parse::buffer pb{buf};
parse::capstan pc{pb, read_closure(*this)};
const auto handler([&pc, &handle]
(const http::response::head &head)
{
const http::response::content content{pc, head};
const auto status(http::status(head.status));
const json::doc doc{content};
handle(status, doc);
});
http::request
{
host(remote_addr(*this)), r.method, r.resource, std::string(r), write_closure(*this),
{
{ "Content-Type"s, "application/json"s }
}
};
http::response
{
pc, nullptr, handler
};
return ret;
}
void
ircd::m::client::sync(request::sync &r)
{
if(!sess)
throw error("No active session");
static const auto urlfmt
{
"%s?access_token=%s"
};
char url[1024]; const auto urllen
{
fmt::snprintf(url, sizeof(url), urlfmt, r.resource, string(sess->access_token))
}; };
http::request http::request
{ {
host, method, url, rcontent, write_closure(client), host(remote_addr(*this)), r.method, url, {}, write_closure(*this),
{ {
{ "Content-Type"s, "application/json"s } { "Content-Type"s, "application/json"s }
} }
@ -53,33 +216,34 @@ try
char buf[4096]; char buf[4096];
parse::buffer pb{buf}; parse::buffer pb{buf};
parse::capstan pc{pb, read_closure(client)}; parse::capstan pc{pb, read_closure(*this)};
http::response http::response
{ {
pc, nullptr, [&pc](const auto &head) pc, nullptr, [this, &pc](const auto &head)
{ {
http::response::content content{pc, head}; http::response::content content
const json::doc cdoc{content}; {
pc, head
};
for(const auto &member : cdoc) switch(http::status(head.status))
std::cout << member.first << " --> " << member.second << std::endl; {
case http::OK:
{
const json::obj d(content, true);
const json::arr a(d["account_data.events[0]"]);
std::cout << a << std::endl;
break;
}
default:
throw m::error(http::status(head.status), json::doc(content));
}
} }
}; };
} }
catch(const std::exception &e)
{
log::error("test: %s", e.what());
throw;
}
ircd::m::error::error(const json::obj &obj) void
:ircd::error{generate_skip} ircd::m::client::quote(request::quote &r)
{ {
serialize(obj, begin(buf), end(buf));
}
ircd::m::error::error(const json::doc &doc)
:ircd::error{generate_skip}
{
print(buf, sizeof(buf), doc);
} }

View file

@ -56,20 +56,39 @@ void
ircd::resource::operator()(client &client, ircd::resource::operator()(client &client,
parse::capstan &pc, parse::capstan &pc,
const http::request::head &head) const http::request::head &head)
const try try
{ {
const auto &method(*methods.at(head.method)); auto &method(*methods.at(head.method));
http::request::content content{pc, head}; http::request::content content{pc, head};
resource::request request resource::request request
{ {
head, content head, content
}; };
method(client, request); call_method(client, method, request);
} }
catch(const std::out_of_range &e) catch(const std::out_of_range &e)
{ {
throw http::error(http::METHOD_NOT_ALLOWED); throw http::error
{
http::METHOD_NOT_ALLOWED
};
}
void
ircd::resource::call_method(client &client,
method &method,
resource::request &request)
try
{
method(client, request);
}
catch(const json::error &e)
{
throw m::error
{
"M_BAD_JSON", "Required JSON field: %s", e.what()
};
} }
ircd::resource::method::method(struct resource &resource, ircd::resource::method::method(struct resource &resource,
@ -99,11 +118,20 @@ noexcept
} }
ircd::resource::response::response(client &client, ircd::resource::response::response(client &client,
const json::obj &doc, const json::obj &obj,
const http::code &code) const http::code &code)
try
{ {
char cbuf[1024]; char cbuf[1024], *out(cbuf);
response(client, serialize(doc, cbuf, cbuf + sizeof(cbuf)), code); const auto doc(serialize(obj, out, cbuf + sizeof(cbuf)));
response(client, doc, code);
}
catch(const json::error &e)
{
throw m::error
{
http::INTERNAL_SERVER_ERROR, "M_NOT_JSON", "Generator Protection: %s", e.what()
};
} }
ircd::resource::response::response(client &client, ircd::resource::response::response(client &client,