Cleaner handling of messages

This commit is contained in:
rexy712 2019-03-22 15:47:44 -07:00
parent 720b65e33c
commit 908260cfe8
4 changed files with 151 additions and 126 deletions

View File

@ -60,36 +60,46 @@ namespace matrix{
struct video_info : public image_info{};
struct audio_info : public file_info{};
//enumerate message type but also give a string representation
class msgtype{
private:
const char* m_str;
const int m_num;
public:
msgtype(const char* s, int n):
constexpr msgtype(const char* s, int n):
m_str(s), m_num(n){}
msgtype(const msgtype&) = default;
constexpr msgtype(const msgtype&) = default;
~msgtype(void) = default;
msgtype& operator=(const msgtype&) = default;
constexpr msgtype& operator=(const msgtype&) = default;
bool operator==(const msgtype& m){
constexpr bool operator==(const msgtype& m){
return m_num == m.m_num;
}
bool operator!=(const msgtype& m){
constexpr bool operator!=(const msgtype& m){
return m_num != m.m_num;
}
const char* str(void)const{
constexpr const char* str(void)const{
return m_str;
}
constexpr operator int(void)const{
return m_num;
}
};
//class enumeration
struct msg{
inline static msgtype text = msgtype("text", 0);
inline static msgtype audio = msgtype("audio", 1);
inline static msgtype video = msgtype("video", 2);
inline static msgtype file = msgtype("file", 3);
inline static msgtype image = msgtype("image", 4);
inline static msgtype other = msgtype("other", 100);
private:
enum _types{
_text, _audio, _video, _file, _image, _other
};
public:
constexpr static msgtype text = msgtype("text", _text);
constexpr static msgtype audio = msgtype("audio", _audio);
constexpr static msgtype video = msgtype("video", _video);
constexpr static msgtype file = msgtype("file", _file);
constexpr static msgtype image = msgtype("image", _image);
constexpr static msgtype other = msgtype("other", _other);
static msgtype& from_str(const char* str){
constexpr static const msgtype& from_str(const char* str){
if(!strcmp(str, "m.text")){
return text;
}else if(!strcmp(str, "m.audio")){
@ -106,6 +116,15 @@ namespace matrix{
}
};
struct msg_info
{
const raii::rjp_string roomid;
const raii::rjp_string sender;
const msgtype type;
const raii::rjp_string body;
const raii::rjp_string eventid;
};
class bot
{
private:
@ -132,7 +151,7 @@ namespace matrix{
static constexpr const char* s_proto = "https://";
};
private:
raii::curler m_curl; //https access
mutable raii::curler m_curl; //https access
raii::string m_useragent; //useragent to identify our application
raii::string m_homeserver; //name of our homeserver
raii::rjp_string m_access_token; //authentication
@ -141,9 +160,7 @@ namespace matrix{
raii::rjp_string m_next_batch; //string which tracks where we are in the server history
std::function<void(const raii::string_base&,const raii::string_base&,msgtype,
const raii::string_base&,const raii::string_base&)>
m_message_callback;
std::function<void(const bot&,const msg_info&)> m_message_callback;
public:
bot(const auth_data& a, const raii::string_base& useragent);
@ -170,28 +187,28 @@ namespace matrix{
//networked getter
raii::rjp_string room_alias_to_id(const raii::string_base& alias);
std::vector<raii::rjp_string> list_rooms(void);
raii::rjp_string room_alias_to_id(const raii::string_base& alias)const;
std::vector<raii::rjp_string> list_rooms(void)const;
//other networked operations
raii::string create_room(const raii::string_base& name, const raii::string_base& alias);
raii::string create_room(const raii::string_base& name, const raii::string_base& alias)const;
//upload media
file_info upload_file(const raii::string_base& filename);
file_info upload_file(const raii::string_base& filename, const raii::string_base& alias);
image_info upload_image(const raii::string_base& filename);
image_info upload_image(const raii::string_base& filename, const raii::string_base& alias);
video_info upload_video(const raii::string_base& filename);
video_info upload_video(const raii::string_base& filename, const raii::string_base& alias);
audio_info upload_audio(const raii::string_base& filename);
audio_info upload_audio(const raii::string_base& filename, const raii::string_base& alias);
file_info upload_file(const raii::string_base& filename)const;
file_info upload_file(const raii::string_base& filename, const raii::string_base& alias)const;
image_info upload_image(const raii::string_base& filename)const;
image_info upload_image(const raii::string_base& filename, const raii::string_base& alias)const;
video_info upload_video(const raii::string_base& filename)const;
video_info upload_video(const raii::string_base& filename, const raii::string_base& alias)const;
audio_info upload_audio(const raii::string_base& filename)const;
audio_info upload_audio(const raii::string_base& filename, const raii::string_base& alias)const;
//send messages
raii::rjp_string send_image(const raii::string_base& room, const image_info& image);
raii::rjp_string send_video(const raii::string_base& room, const video_info& video);
raii::rjp_string send_message(const raii::string_base& room, const raii::string_base& text);
raii::rjp_string send_audio(const raii::string_base& room, const audio_info& audio);
raii::rjp_string send_file(const raii::string_base& room, const file_info& file);
raii::rjp_string send_image(const raii::string_base& room, const image_info& image)const;
raii::rjp_string send_video(const raii::string_base& room, const video_info& video)const;
raii::rjp_string send_message(const raii::string_base& room, const raii::string_base& text)const;
raii::rjp_string send_audio(const raii::string_base& room, const audio_info& audio)const;
raii::rjp_string send_file(const raii::string_base& room, const file_info& file)const;
template<class Func>
void set_sync_callback(Func&& f){
@ -201,18 +218,18 @@ namespace matrix{
void logout(void);
protected:
void _send_read_receipt(const raii::string_base& roomid, const raii::string_base& eventid);
raii::rjp_string _upload_file(raii::filerd& fp, const raii::curl_llist& header);
raii::rjp_string _send_message(const raii::string_base& room, const raii::string_base& msg);
void _send_read_receipt(const raii::string_base& roomid, const raii::string_base& eventid)const;
raii::rjp_string _upload_file(raii::filerd& fp, const raii::curl_llist& header)const;
raii::rjp_string _send_message(const raii::string_base& room, const raii::string_base& msg)const;
static size_t _post_reply_curl_callback(char* ptr, size_t size, size_t nmemb, void* userdata);
raii::string _get_curl(const raii::string_base& url);
raii::string _post_curl(const raii::string_base& postdata, const raii::string_base& url, const raii::curl_llist& header);
raii::string _put_curl(const raii::string_base& postdata, const raii::string_base& url, const raii::curl_llist& header);
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);
raii::rjp_string _get_and_find(const raii::string_base& url, const raii::string_base& search);
raii::rjp_string _curl_reply_search(const raii::string_base& reply, const raii::string_base& search);
void _set_curl_defaults(void);
raii::string _request_access_token(const auth_data& a);
raii::string _get_curl(const raii::string_base& url)const;
raii::string _post_curl(const raii::string_base& postdata, const raii::string_base& url, const raii::curl_llist& header)const;
raii::string _put_curl(const raii::string_base& postdata, const raii::string_base& url, const raii::curl_llist& header)const;
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;
void _set_curl_defaults(void)const;
raii::string _request_access_token(const auth_data& a)const;
void _acquire_access_token(const auth_data& a);
};

View File

@ -116,7 +116,6 @@ namespace raii{
char& operator[](size_t i);
const char& operator[](size_t i)const;
protected:
template<class Tup, size_t I = 0>
static void _assign(char* dest, Tup&& t, size_t offset){
@ -305,7 +304,14 @@ namespace raii{
}
template<class Str1, class Str2, typename std::enable_if<raii::detail::is_concrete_string<Str1>::value&&raii::detail::is_concrete_string<Str2>::value,void>::type* = nullptr>
bool operator==(Str1&& left, Str2&& right){
return left && right && left.length() == right.length() && !strcmp(left.get(), right.get());
}
template<class Str1, class Str2, typename std::enable_if<raii::detail::is_concrete_string<Str1>::value&&raii::detail::is_concrete_string<Str2>::value,void>::type* = nullptr>
bool operator!=(Str1&& left, Str2&& right){
return !(left == right);
}
template<class Right, typename std::enable_if<raii::detail::is_string<Right>::value,void>::type* = nullptr>
auto operator+(const char* left, Right&& right){

View File

@ -113,11 +113,11 @@ namespace matrix{
raii::string reply = _put_curl(raii::string("{\"avatar_url\":\"" + media_url + "\"}"), raii::string("https://" + m_homeserver + "/_matrix/client/r0/profile/" + m_curl.encode(m_userid) + "/avatar_url?access_token=" + m_access_token), raii::curl_llist());
}
raii::rjp_string bot::room_alias_to_id(const raii::string_base& alias){
raii::rjp_string bot::room_alias_to_id(const raii::string_base& alias)const{
auto tmp = m_curl.encode(alias, alias.length());
return _get_and_find(raii::string(m_urls.alias_lookup + tmp), "room_id"_ss);
}
std::vector<raii::rjp_string> bot::list_rooms(void){
std::vector<raii::rjp_string> bot::list_rooms(void)const{
std::vector<raii::rjp_string> ret;
raii::string reply = _get_curl(m_urls.room_list);
if(!reply)
@ -137,7 +137,7 @@ namespace matrix{
return ret;
}
raii::string bot::create_room(const raii::string_base& name, const raii::string_base& alias){
raii::string bot::create_room(const raii::string_base& name, const raii::string_base& alias)const{
raii::string postdata;
if(alias)
postdata = "{\"name\": \"" + raii::json_escape(name) + "\",\"room_alias_name\": \"" + raii::json_escape(alias) + "\"}";
@ -146,16 +146,16 @@ namespace matrix{
return _post_curl(postdata, m_urls.create_room, raii::curl_llist());
}
file_info bot::upload_file(const raii::string_base& filename){
file_info bot::upload_file(const raii::string_base& filename)const{
return upload_file(filename, raii::static_string());
}
file_info bot::upload_file(const raii::string_base& filename, const raii::string_base& alias){
file_info bot::upload_file(const raii::string_base& filename, const raii::string_base& alias)const{
raii::filerd fd(filename);
if(!fd) return {};
return file_info{_upload_file(fd, raii::curl_llist{}), alias ? alias : filename, {}, fd.length()};
}
image_info bot::upload_image(const raii::string_base& filename){
image_info bot::upload_image(const raii::string_base& filename)const{
return upload_image(filename, raii::static_string());
}
#ifdef HAS_FREEIMAGE
@ -198,7 +198,7 @@ namespace matrix{
}
return {};
}
image_info bot::upload_image(const raii::string_base& filename, const raii::string_base& alias){
image_info bot::upload_image(const raii::string_base& filename, const raii::string_base& alias)const{
image_info ret;
FREE_IMAGE_FORMAT type = fipImage::identifyFIF(filename.get());
ret.mimetype = FreeImage_GetFIFMimeType(type);
@ -228,16 +228,16 @@ namespace matrix{
}
#else //HAS_FREEIMAGE
image_info bot::upload_image(const raii::string_base& filename, const raii::string_base& alias){
image_info bot::upload_image(const raii::string_base& filename, const raii::string_base& alias)const{
image_info ret = {};
ret = upload_file(filename, alias);
return ret;
}
#endif //HAS_FREEIMAGE
video_info bot::upload_video(const raii::string_base& filename){
video_info bot::upload_video(const raii::string_base& filename)const{
return upload_video(filename, raii::static_string());
}
audio_info bot::upload_audio(const raii::string_base& filename){
audio_info bot::upload_audio(const raii::string_base& filename)const{
return upload_audio(filename, raii::static_string());
}
#ifdef HAS_FFMPEG
@ -324,7 +324,7 @@ namespace matrix{
return raii::string("video/" + raii::static_string(ctx->iformat->name, first - ctx->iformat->name));
return raii::string("video/" + raii::static_string(ctx->iformat->name));
}
video_info bot::upload_video(const raii::string_base& filename, const raii::string_base& alias){
video_info bot::upload_video(const raii::string_base& filename, const raii::string_base& alias)const{
video_info ret = {};
libav::fmt::input_context in(filename);
@ -372,7 +372,7 @@ namespace matrix{
ret.filename = alias ? alias : filename;
return ret;
}
audio_info bot::upload_audio(const raii::string_base& filename, const raii::string_base& alias){
audio_info bot::upload_audio(const raii::string_base& filename, const raii::string_base& alias)const{
audio_info ret = {};
libav::fmt::input_context in(filename);
@ -389,31 +389,31 @@ namespace matrix{
return ret;
}
#else //HAS_FFMPEG
video_info bot::upload_video(const raii::string_base& filename, const raii::string_base& alias){
video_info bot::upload_video(const raii::string_base& filename, const raii::string_base& alias)const{
video_info ret = {};
ret = upload_file(filename, alias);
return ret;
}
audio_info bot::upload_audio(const raii::string_base& filename, const raii::string_base& alias){
audio_info bot::upload_audio(const raii::string_base& filename, const raii::string_base& alias)const{
audio_info ret = {};
ret = upload_file(filename, alias);
return ret;
}
#endif //HAS_FFMPEG
raii::rjp_string bot::send_file(const raii::string_base& room, const file_info& file){
raii::rjp_string bot::send_file(const raii::string_base& room, const file_info& file)const{
return _send_message(room, detail::_file_body(file));
}
raii::rjp_string bot::send_image(const raii::string_base& room, const image_info& image){
raii::rjp_string bot::send_image(const raii::string_base& room, const image_info& image)const{
return _send_message(room, detail::_image_body(image));
}
raii::rjp_string bot::send_video(const raii::string_base& room, const video_info& video){
raii::rjp_string bot::send_video(const raii::string_base& room, const video_info& video)const{
return _send_message(room, detail::_video_body(video));
}
raii::rjp_string bot::send_audio(const raii::string_base& room, const audio_info& audio){
raii::rjp_string bot::send_audio(const raii::string_base& room, const audio_info& audio)const{
return _send_message(room, detail::_audio_body(audio));
}
raii::rjp_string bot::send_message(const raii::string_base& room, const raii::string_base& text){
raii::rjp_string bot::send_message(const raii::string_base& room, const raii::string_base& text)const{
return _send_message(room, detail::_message_body(text));
}
void bot::logout(void){
@ -450,19 +450,21 @@ namespace matrix{
res = rjp_search_member(res.value, "events", 0);
if(!res.value) continue;
for(RJP_value* event = rjp_get_element(res.value);event;event = rjp_next_element(event)){
RJP_search_res sender = rjp_search_member(event, "sender", 0);
if(!sender.value) continue;
raii::rjp_string sender_str = sender.value;
if(sender_str == m_userid) continue;
res = rjp_search_member(event, "content", 0);
if(!res.value) continue;
RJP_search_res msg = rjp_search_member(res.value, "msgtype", 0);
if(!msg.value) continue;
RJP_search_res body = rjp_search_member(res.value, "body", 0);
if(!body.value) continue;
RJP_search_res sender = rjp_search_member(event, "sender", 0);
if(!sender.value) continue;
res = rjp_search_member(event, "event_id", 0);
if(!res.value) continue;
raii::rjp_string room_str = rjp_member_name(roomid);
raii::rjp_string eventid_str = res.value;
m_message_callback(room_str, raii::rjp_string(sender.value), msg::from_str(rjp_value_string(msg.value)), raii::rjp_string(body.value), eventid_str);
m_message_callback(*this, msg_info{room_str, sender_str, msg::from_str(rjp_value_string(msg.value)), raii::rjp_string(body.value), eventid_str});
_send_read_receipt(room_str, eventid_str);
}
}
@ -476,11 +478,11 @@ namespace matrix{
Internal functions
********************************/
void bot::_send_read_receipt(const raii::string_base& roomid, const raii::string_base& eventid){
void bot::_send_read_receipt(const raii::string_base& roomid, const raii::string_base& eventid)const{
raii::string url = "https://" + m_homeserver + "/_matrix/client/r0/rooms/" + m_curl.encode(roomid) + "/receipt/m.read/" + m_curl.encode(eventid) + "?access_token=" + m_access_token;
_post_curl(""_ss, url, raii::curl_llist());
}
raii::rjp_string bot::_upload_file(raii::filerd& fp, const raii::curl_llist& header){
raii::rjp_string bot::_upload_file(raii::filerd& fp, const raii::curl_llist& header)const{
raii::string fileurl;
m_curl.postreq();
m_curl.setopt(CURLOPT_POSTFIELDS, NULL);
@ -506,7 +508,7 @@ namespace matrix{
return res.value;
}
raii::rjp_string bot::_send_message(const raii::string_base& room, const raii::string_base& msg){
raii::rjp_string bot::_send_message(const raii::string_base& room, const raii::string_base& msg)const{
raii::rjp_string reply = _post_and_find(
msg,
raii::string("https://" + m_homeserver + "/_matrix/client/r0/rooms/" + m_curl.encode(room) + "/send/m.room.message?access_token=" + m_access_token),
@ -520,7 +522,7 @@ namespace matrix{
return size*nmemb;
}
raii::string bot::_get_curl(const raii::string_base& url){
raii::string bot::_get_curl(const raii::string_base& url)const{
raii::string reply;
m_curl.getreq();
m_curl.seturl(url);
@ -532,7 +534,7 @@ namespace matrix{
return {};
return reply;
}
raii::string bot::_post_curl(const raii::string_base& postdata, const raii::string_base& url, const raii::curl_llist& header){
raii::string bot::_post_curl(const raii::string_base& postdata, const raii::string_base& url, const raii::curl_llist& header)const{
raii::string reply;
m_curl.postreq();
m_curl.setopt(CURLOPT_POSTFIELDS, postdata.get());
@ -559,7 +561,7 @@ namespace matrix{
src->data += to_copy;
return to_copy;
}
raii::string bot::_put_curl(const raii::string_base& putdata, const raii::string_base& url, const raii::curl_llist& header){
raii::string bot::_put_curl(const raii::string_base& putdata, const raii::string_base& url, const raii::curl_llist& header)const{
raii::string reply;
put_data data{putdata.get(), putdata.length()};
m_curl.putreq();
@ -580,20 +582,20 @@ namespace matrix{
return reply;
}
raii::rjp_string bot::_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::curl_llist& header, const raii::string_base& target)const
{
raii::string reply = _post_curl(data, url, header);
if(!reply)
return {};
return _curl_reply_search(reply, target);
}
raii::rjp_string bot::_get_and_find(const raii::string_base& url, const raii::string_base& target){
raii::rjp_string bot::_get_and_find(const raii::string_base& url, const raii::string_base& target)const{
raii::string reply = _get_curl(url);
if(!reply)
return {};
return _curl_reply_search(reply, target);
}
raii::rjp_string bot::_curl_reply_search(const raii::string_base& reply, const raii::string_base& target){
raii::rjp_string bot::_curl_reply_search(const raii::string_base& reply, const raii::string_base& target)const{
raii::rjp_ptr root(rjp_parse(reply));
if(!root)
return {};
@ -602,7 +604,7 @@ namespace matrix{
return {};
return raii::rjp_string(res.value);
}
void bot::_set_curl_defaults(void){
void bot::_set_curl_defaults(void)const{
m_curl.setopt(CURLOPT_BUFFERSIZE, 102400L);
m_curl.setopt(CURLOPT_NOPROGRESS, 1L);
m_curl.setuseragent(m_useragent);
@ -612,7 +614,7 @@ namespace matrix{
m_curl.setopt(CURLOPT_TCP_KEEPALIVE, 1L);
m_curl.setopt(CURLOPT_FAILONERROR, 1L);
}
raii::string bot::_request_access_token(const auth_data& a){
raii::string bot::_request_access_token(const auth_data& a)const{
CURLcode result;
raii::string postdata("{\"type\":\"m.login.password\", \"user\":\"" + raii::json_escape(a.bot_name) + "\", \"password\":\"" + raii::json_escape(a.bot_pass) + "\"}");
raii::string reply;

File diff suppressed because one or more lines are too long