diff --git a/include/matrix/connection.hpp b/include/matrix/connection.hpp index ead864c..7c8bca8 100644 --- a/include/matrix/connection.hpp +++ b/include/matrix/connection.hpp @@ -23,7 +23,9 @@ #include "raii/string.hpp" #include "raii/rjp_string.hpp" #include "raii/binary.hpp" +#include "raii/rjp_ptr.hpp" #include "matrix/session_info.hpp" +#include "matrix/netreturn.hpp" #include //shared_ptr namespace matrix{ @@ -92,7 +94,11 @@ namespace matrix{ raii::rjp_string _post_and_find(const raii::string_base& data, const raii::string_base& url, const raii::curl_llist& header, const raii::string_base& target)const; raii::rjp_string _get_and_find(const raii::string_base& url, const raii::string_base& search)const; raii::rjp_string _curl_reply_search(const raii::string_base& reply, const raii::string_base& search)const; + raii::rjp_string _curl_reply_search(const raii::rjp_ptr& root, const raii::string_base& search)const; void _set_curl_defaults(const raii::string_base& useragent)const; + static netreturn_base _create_netreturn(const raii::string_base& mxjson, int httpstatus); + static netreturn_base _create_netreturn(const raii::rjp_ptr& root, int httpstatus); + }; } diff --git a/include/matrix/netreturn.hpp b/include/matrix/netreturn.hpp new file mode 100644 index 0000000..451798b --- /dev/null +++ b/include/matrix/netreturn.hpp @@ -0,0 +1,87 @@ +/** + This file is a part of rexy's matrix client + Copyright (C) 2019 rexy712 + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero 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 Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . +*/ + +#ifndef MATRIX_NETRETURN_HPP +#define MATRIX_NETRETURN_HPP + +#include "raii/rjp_string.hpp" +#include //std::forward + +namespace matrix{ + + class netreturn_base + { + protected: + raii::rjp_string m_error = {}; + raii::rjp_string m_errorcode = {}; + int m_http_error = 200; + + public: + constexpr netreturn_base(void) = default; + netreturn_base(const raii::rjp_string& error, const raii::rjp_string& errorcode, int httpstatus); + netreturn_base(const raii::rjp_string& error, raii::rjp_string&& errorcode, int httpstatus); + netreturn_base(raii::rjp_string&& error, const raii::rjp_string& errorcode, int httpstatus); + netreturn_base(raii::rjp_string&& error, raii::rjp_string&& errorcode, int httpstatus); + operator bool(void)const; + const raii::rjp_string mxerror(void)const; + const raii::rjp_string mxerrorcode(void)const; + int httpstatus(void)const; + }; + template + class netreturn : public netreturn_base + { + public: + using value_type = Retval; + private: + Retval m_ret = {}; + public: + constexpr netreturn(void) = default; + template + netreturn(Str1&& error, Str2&& errorcode, int httpcode, Val&& val = Val()): + netreturn_base(std::forward(error), std::forward(errorcode), httpcode), + m_ret(std::forward(val)){} + netreturn(netreturn_base&& n): + netreturn_base(std::move(n)){} + netreturn(const netreturn_base& n): + netreturn_base(n){} + Retval& value(void){ + return m_ret; + } + const Retval& value(void)const{ + return m_ret; + } + }; + template<> + class netreturn : public netreturn_base + { + public: + using value_type = void; + + public: + template + netreturn(Str1&& error, Str2&& errorcode, int httpcode): + netreturn_base(std::forward(error), std::forward(errorcode), httpcode){} + netreturn(netreturn_base&& n): + netreturn_base(std::move(n)){} + netreturn(const netreturn_base& n): + netreturn_base(n){} + }; + +} + +#endif diff --git a/include/matrix/roomcxn.hpp b/include/matrix/roomcxn.hpp index 4f96fe0..d35d45a 100644 --- a/include/matrix/roomcxn.hpp +++ b/include/matrix/roomcxn.hpp @@ -25,6 +25,7 @@ #include "raii/rjp_string.hpp" #include "matrix/room_url_list.hpp" #include "matrix/iterable.hpp" +#include "matrix/netreturn.hpp" #include @@ -48,40 +49,48 @@ namespace matrix{ roomcxn& operator=(roomcxn&&) = default; //membership - bool join_room(void)const; - bool leave_room(void)const; - [[deprecated("Use client::join_room instead")]] - bool accept_invite(void)const; - [[deprecated("Use client::leave_room instead")]] - bool reject_invite(void)const; - std::vector members(void)const; + netreturn join(void)const; + netreturn leave(void)const; + [[deprecated("Use roomcxn::join_room instead")]] + netreturn accept_invite(void)const; + [[deprecated("Use roomcxn::leave_room instead")]] + netreturn reject_invite(void)const; + netreturn> members(void)const; + + //member management + netreturn invite(const raii::string_base& userid); + [[deprecated("Use roomcxn::kick instead")]] + netreturn uninvite(const raii::string_base& userid, const raii::string_base& reason = raii::string()); + netreturn kick(const raii::string_base& userid, const raii::string_base& reason = raii::string()); + netreturn ban(const raii::string_base& userid, const raii::string_base& reason = raii::string()); + netreturn unban(const raii::string_base& userid); //sending events - raii::rjp_string send_custom_event(const raii::string_base& event, const raii::string_base& eventtype)const; - raii::rjp_string send_message(const raii::string_base& text)const; - raii::rjp_string send_file(const uploaded_file& file)const; - raii::rjp_string send_image(const uploaded_image& image)const; - raii::rjp_string send_video(const uploaded_video& video)const; - raii::rjp_string send_audio(const uploaded_audio& audio)const; - bool send_typing(bool active, int timeout = 5000)const; - bool send_read_receipt(const raii::string_base& eventid)const; + netreturn send_custom_event(const raii::string_base& event, const raii::string_base& eventtype)const; + netreturn send_message(const raii::string_base& text)const; + netreturn send_file(const uploaded_file& file)const; + netreturn send_image(const uploaded_image& image)const; + netreturn send_video(const uploaded_video& video)const; + netreturn send_audio(const uploaded_audio& audio)const; + netreturn send_typing(bool active, int timeout = 5000)const; + netreturn send_read_receipt(const raii::string_base& eventid)const; - raii::rjp_string redact_event(const raii::string_base& eventid, const raii::string_base& reason)const; - raii::rjp_string redact_event(const raii::string_base& eventid)const; + netreturn redact_event(const raii::string_base& eventid, const raii::string_base& reason)const; + netreturn redact_event(const raii::string_base& eventid)const; //recieve events - sync::roomcxn_message_event_list get_events_forward(int amount); - sync::roomcxn_message_event_list get_events_backward(int amount); - sync::roomcxn_message_event_list get_events_forward(int amount, const raii::string_base& from, const raii::string_base& to); - sync::roomcxn_message_event_list get_events_backward(int amount, const raii::string_base& from, const raii::string_base& to); + netreturn get_events_forward(int amount); + netreturn get_events_backward(int amount); + netreturn get_events_forward(int amount, const raii::string_base& from, const raii::string_base& to); + netreturn get_events_backward(int amount, const raii::string_base& from, const raii::string_base& to); //meta stuff void regenerate_urls(void); - raii::rjp_string upgrade(int version)const; + netreturn upgrade(int version)const; private: - sync::roomcxn_message_event_list _get_events(int amount, raii::static_string direction, const raii::string_base& from, const raii::string_base& to); - raii::rjp_string _send_message(const raii::string_base& msg)const; + netreturn _get_events(int amount, raii::static_string direction, const raii::string_base& from, const raii::string_base& to); + netreturn _send_message(const raii::string_base& msg)const; }; } diff --git a/src/matrix/connection.cpp b/src/matrix/connection.cpp index 672338a..b7e82ae 100644 --- a/src/matrix/connection.cpp +++ b/src/matrix/connection.cpp @@ -171,12 +171,16 @@ namespace matrix{ } raii::rjp_string connection::_curl_reply_search(const raii::string_base& reply, const raii::string_base& target)const{ raii::rjp_ptr root(rjp_parse(reply)); + return _curl_reply_search(root, target); + } + raii::rjp_string connection::_curl_reply_search(const raii::rjp_ptr& root, const raii::string_base& target)const{ if(!root) return {}; RJP_search_res res = rjp_search_member(root.get(), target.get(), 0); if(rjp_value_type(res.value) != json_string) return {}; return raii::rjp_string(res.value); + } void connection::_set_curl_defaults(const raii::string_base& useragent)const{ #ifdef _WIN32 @@ -192,5 +196,18 @@ namespace matrix{ m_curl.setopt(CURLOPT_TCP_KEEPALIVE, 1L); m_curl.setopt(CURLOPT_FAILONERROR, 1L); } + netreturn_base connection::_create_netreturn(const raii::string_base& mxjson, int httpstatus){ + if(!mxjson) + return netreturn_base(""_ss, ""_ss, httpstatus); + raii::rjp_ptr root(rjp_parse(mxjson.get())); + return _create_netreturn(root, httpstatus); + } + netreturn_base connection::_create_netreturn(const raii::rjp_ptr& root, int httpstatus){ + if(!root) + return netreturn_base("Invalid JSON"_ss, "Invalid JSON"_ss, -1); + raii::rjp_string error = rjp_search_member(root.get(), "error", 0).value; + raii::rjp_string errorcode = rjp_search_member(root.get(), "errorcode", 0).value; + return netreturn_base(std::move(error), std::move(errorcode), httpstatus); + } } diff --git a/src/matrix/netreturn.cpp b/src/matrix/netreturn.cpp new file mode 100644 index 0000000..01bbdb8 --- /dev/null +++ b/src/matrix/netreturn.cpp @@ -0,0 +1,42 @@ +/** + This file is a part of rexy's matrix client + Copyright (C) 2019 rexy712 + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero 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 Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . +*/ + +#include "matrix/netreturn.hpp" +namespace matrix{ + + netreturn_base::netreturn_base(const raii::rjp_string& error, const raii::rjp_string& errorcode, int httpstatus): + m_error(error), m_errorcode(errorcode), m_http_error(httpstatus){} + netreturn_base::netreturn_base(const raii::rjp_string& error, raii::rjp_string&& errorcode, int httpstatus): + m_error(error), m_errorcode(std::move(errorcode)), m_http_error(httpstatus){} + netreturn_base::netreturn_base(raii::rjp_string&& error, const raii::rjp_string& errorcode, int httpstatus): + m_error(std::move(error)), m_errorcode(errorcode), m_http_error(httpstatus){} + netreturn_base::netreturn_base(raii::rjp_string&& error, raii::rjp_string&& errorcode, int httpstatus): + m_error(std::move(error)), m_errorcode(std::move(errorcode)), m_http_error(httpstatus){} + netreturn_base::operator bool(void)const{ + return m_http_error > 299; + } + const raii::rjp_string netreturn_base::mxerror(void)const{ + return m_error; + } + const raii::rjp_string netreturn_base::mxerrorcode(void)const{ + return m_errorcode; + } + int netreturn_base::httpstatus(void)const{ + return m_http_error; + } +} diff --git a/src/matrix/roomcxn.cpp b/src/matrix/roomcxn.cpp index c4cea39..a7a3c0d 100644 --- a/src/matrix/roomcxn.cpp +++ b/src/matrix/roomcxn.cpp @@ -34,111 +34,155 @@ namespace matrix{ m_roomid(std::move(roomid)), m_urls(ses->homeserver, ses->access_token, m_curl.encode(m_roomid), ses->userid){} - bool roomcxn::join_room(void)const{ - return _post_curl(raii::string(), m_urls.join_room(), raii::curl_llist()); + netreturn roomcxn::join(void)const{ + raii::string response = _post_curl(raii::string(), m_urls.join_room(), raii::curl_llist()); + return _create_netreturn(response, http_status()); } - bool roomcxn::leave_room(void)const{ - return _post_curl(raii::string(), m_urls.leave_room(), raii::curl_llist()); + netreturn roomcxn::leave(void)const{ + raii::string response = _post_curl(raii::string(), m_urls.leave_room(), raii::curl_llist()); + return _create_netreturn(response, http_status()); } - bool roomcxn::accept_invite(void)const{ - return join_room(); + netreturn roomcxn::accept_invite(void)const{ + return join(); } - bool roomcxn::reject_invite(void)const{ - return leave_room(); + netreturn roomcxn::reject_invite(void)const{ + return leave(); } - std::vector roomcxn::members(void)const{ - std::vector retval; + netreturn> roomcxn::members(void)const{ + netreturn> retval; raii::string resp = _get_curl(m_urls.room_members()); - if(!resp) return {}; + if(!resp) return _create_netreturn(resp, http_status()); raii::rjp_ptr root(rjp_parse(resp.get())); - if(!root) return {}; + if(!root) return _create_netreturn(root, http_status()); RJP_search_res res = rjp_search_member(root.get(), "joined", 0); - if(!res.value) return{}; + if(!res.value) return _create_netreturn(root, http_status()); for(RJP_value* mem = rjp_get_member(res.value);mem;mem = rjp_next_member(mem)){ raii::rjp_string tmp = raii::rjp_string_from_key(mem); - retval.emplace_back(std::move(tmp)); + retval.value().emplace_back(std::move(tmp)); } return retval; } - - raii::rjp_string roomcxn::send_custom_event(const raii::string_base& event, const raii::string_base& eventtype)const{ - return _post_and_find( - event, - m_urls.send(m_ses->homeserver, m_ses->access_token, m_curl.encode(m_roomid), eventtype), - raii::curl_llist(), - "event_id"_ss); + netreturn roomcxn::invite(const raii::string_base& userid){ + raii::string json("{\"user_id\":\"" + userid + "\"}"); + printf("%s\n", json.get()); + raii::string response = _post_curl(json, m_urls.invite(), raii::curl_llist()); + return _create_netreturn(response, http_status()); } - raii::rjp_string roomcxn::send_message(const raii::string_base& text)const{ + netreturn roomcxn::uninvite(const raii::string_base& userid, const raii::string_base& reason){ + return kick(userid, reason); + } + netreturn roomcxn::kick(const raii::string_base& userid, const raii::string_base& reason){ + raii::string response; + if(reason){ + response = _post_curl(raii::string("{\"user_id\":\"" + userid + "\",\"reason\":\"" + reason + "\"}"), m_urls.kick(), raii::curl_llist()); + }else{ + response = _post_curl(raii::string("{\"user_id\":\"" + userid + "\"}"), m_urls.kick(), raii::curl_llist()); + } + return _create_netreturn(response, http_status()); + } + netreturn roomcxn::ban(const raii::string_base& userid, const raii::string_base& reason){ + raii::string response; + if(reason){ + response = _post_curl(raii::string("{\"user_id\":\"" + userid + "\",\"reason\":\"" + reason + "\"}"), m_urls.ban(), raii::curl_llist()); + }else{ + response = _post_curl(raii::string("{\"user_id\":\"" + userid + "\"}"), m_urls.ban(), raii::curl_llist()); + } + return _create_netreturn(response, http_status()); + } + netreturn roomcxn::unban(const raii::string_base& userid){ + raii::string response = _post_curl(raii::string("{\"user_id\":\"" + userid + "\"}"), m_urls.unban(), raii::curl_llist()); + return _create_netreturn(response, http_status()); + } + + + netreturn roomcxn::send_custom_event(const raii::string_base& event, const raii::string_base& eventtype)const{ + raii::string reply = _post_curl(event, m_urls.send(m_ses->homeserver, m_ses->access_token, m_curl.encode(m_roomid), eventtype), raii::curl_llist()); + if(!reply) + return _create_netreturn(reply, http_status()); + + raii::rjp_ptr root(rjp_parse(reply)); + netreturn retval = _create_netreturn(root, http_status()); + retval.value() = _curl_reply_search(root, "event_id"_ss); + return retval; + } + netreturn roomcxn::send_message(const raii::string_base& text)const{ return _send_message(detail::_message_body(text)); } - raii::rjp_string roomcxn::send_file(const uploaded_file& file)const{ + netreturn roomcxn::send_file(const uploaded_file& file)const{ return _send_message(detail::_file_body(file)); } - raii::rjp_string roomcxn::send_image(const uploaded_image& image)const{ + netreturn roomcxn::send_image(const uploaded_image& image)const{ return _send_message(detail::_image_body(image)); } - raii::rjp_string roomcxn::send_video(const uploaded_video& video)const{ + netreturn roomcxn::send_video(const uploaded_video& video)const{ return _send_message(detail::_video_body(video)); } - raii::rjp_string roomcxn::send_audio(const uploaded_audio& audio)const{ + netreturn roomcxn::send_audio(const uploaded_audio& audio)const{ return _send_message(detail::_audio_body(audio)); } - bool roomcxn::send_typing(bool active, int timeout)const{ + netreturn roomcxn::send_typing(bool active, int timeout)const{ if(active) - return _put_curl(raii::string("{\"timeout\":" + raii::itostr(timeout) + ",\"typing\":true}"), m_urls.typing(), raii::curl_llist()); + return _create_netreturn(_put_curl(raii::string("{\"timeout\":" + raii::itostr(timeout) + ",\"typing\":true}"), m_urls.typing(), raii::curl_llist()), http_status()); else - return _put_curl("{\"typing\":false}"_ss, m_urls.typing(), raii::curl_llist()); + return _create_netreturn(_put_curl("{\"typing\":false}"_ss, m_urls.typing(), raii::curl_llist()), http_status()); } - bool roomcxn::send_read_receipt(const raii::string_base& eventid)const{ - return _post_curl(""_ss, m_urls.read_receipt(m_ses->homeserver, m_ses->access_token, m_curl.encode(m_roomid), m_curl.encode(eventid)), raii::curl_llist()); + netreturn roomcxn::send_read_receipt(const raii::string_base& eventid)const{ + return _create_netreturn(_post_curl(""_ss, m_urls.read_receipt(m_ses->homeserver, m_ses->access_token, m_curl.encode(m_roomid), m_curl.encode(eventid)), raii::curl_llist()), http_status()); } - raii::rjp_string roomcxn::redact_event(const raii::string_base& eventid, const raii::string_base& reason)const{ - auto ret = _put_curl(raii::string("{\"reason\":\"" + reason + "\"}"), m_urls.redact(m_ses->homeserver, m_ses->access_token, m_curl.encode(m_roomid), m_curl.encode(eventid)), raii::curl_llist()); - if(!ret) return {}; + netreturn roomcxn::redact_event(const raii::string_base& eventid, const raii::string_base& reason)const{ + raii::string ret = _put_curl(raii::string("{\"reason\":\"" + reason + "\"}"), m_urls.redact(m_ses->homeserver, m_ses->access_token, m_curl.encode(m_roomid), m_curl.encode(eventid)), raii::curl_llist()); + if(!ret) return _create_netreturn(ret, http_status()); raii::rjp_ptr root(rjp_parse(ret.get())); - if(!root) return {}; - - RJP_search_res res = rjp_search_member(root.get(), "event_id", 0); - if(!res.value) return {}; - return raii::rjp_string(res.value); + netreturn retval = _create_netreturn(root, http_status()); + retval.value() = _curl_reply_search(root, "event_id"_ss); + return retval; } - raii::rjp_string roomcxn::redact_event(const raii::string_base& eventid)const{ + netreturn roomcxn::redact_event(const raii::string_base& eventid)const{ return redact_event(eventid, "No reason given"_ss); } - sync::roomcxn_message_event_list roomcxn::_get_events(int amount, raii::static_string direction, const raii::string_base& from, const raii::string_base& to){ + netreturn roomcxn::_get_events(int amount, raii::static_string direction, const raii::string_base& from, const raii::string_base& to){ raii::string reply = _get_curl(m_urls.messages(m_ses->homeserver, m_ses->access_token, m_curl.encode(m_roomid), from, to, direction, amount)); - if(!reply) return {}; + if(!reply) return _create_netreturn(reply, http_status()); raii::rjp_ptr root(rjp_parse(reply.get())); - if(!root.get()) return {}; + if(!root.get()) _create_netreturn(root, http_status()); + + netreturn retval = _create_netreturn(root, http_status()); RJP_value* chunk = rjp_search_member(root.get(), "chunk", 0).value; - if(!chunk) return {}; - return sync::roomcxn_message_event_list(root, rjp_get_element(chunk), m_roomid); + if(!chunk) return retval; + retval.value() = sync::roomcxn_message_event_list(root, rjp_get_element(chunk), m_roomid); + return retval; } - sync::roomcxn_message_event_list roomcxn::get_events_forward(int amount){ + netreturn roomcxn::get_events_forward(int amount){ return _get_events(amount, "f"_ss, ""_ss, ""_ss); } - sync::roomcxn_message_event_list roomcxn::get_events_backward(int amount){ + netreturn roomcxn::get_events_backward(int amount){ return _get_events(amount, "b"_ss, ""_ss, ""_ss); } - sync::roomcxn_message_event_list roomcxn::get_events_forward(int amount, const raii::string_base& from, const raii::string_base& to){ + netreturn roomcxn::get_events_forward(int amount, const raii::string_base& from, const raii::string_base& to){ return _get_events(amount, "f"_ss, from, to); } - sync::roomcxn_message_event_list roomcxn::get_events_backward(int amount, const raii::string_base& from, const raii::string_base& to){ + netreturn roomcxn::get_events_backward(int amount, const raii::string_base& from, const raii::string_base& to){ return _get_events(amount, "b"_ss, from, to); } void roomcxn::regenerate_urls(void){ m_urls.repopulate(m_ses->homeserver, m_ses->access_token, m_ses->userid, m_roomid); } - raii::rjp_string roomcxn::upgrade(int version)const{ - return _post_and_find(raii::string("{\"new_version\":\""_ss + raii::itostr(version) + "\"}"_ss), m_urls.upgrade(), raii::curl_llist(), "replacement_room"_ss); + netreturn roomcxn::upgrade(int version)const{ + raii::string reply = _post_curl(raii::string("{\"new_version\":\""_ss + raii::itostr(version) + "\"}"_ss), m_urls.upgrade(), raii::curl_llist()); + if(!reply) return _create_netreturn(reply, http_status()); + raii::rjp_ptr root(rjp_parse(reply)); + netreturn retval = _create_netreturn(root, http_status()); + if(!root) return retval; + retval.value() = _curl_reply_search(root, "event_id"_ss); + return retval; } - raii::rjp_string roomcxn::_send_message(const raii::string_base& msg)const{ + netreturn roomcxn::_send_message(const raii::string_base& msg)const{ return send_custom_event(msg, "m.room.message"_ss); } } diff --git a/src/test.cpp b/src/test.cpp index 1a1c476..b8b8e45 100644 --- a/src/test.cpp +++ b/src/test.cpp @@ -73,8 +73,8 @@ int main(){ auto syn = ses.spawn_syncer(); auto client = ses.spawn_client(); - auto room = client.spawn_room("!roomid:matrix.org"_ss); - auto reply = room.get_events_backward(5); + auto room = client.spawn_room("!IaZlRZWhZiNMMsiZRl:rexy712.chickenkiller.com"_ss); + auto reply = std::move(room.get_events_backward(5).value()); printf("%s\n", reply.start_token().get()); printf("%s\n", reply.end_token().get()); for(auto event : reply){