#include "notification.h" #include #include #include #include "codes.h" #include "client.h" namespace twitter { notification::type notification::getType() const { return _type; } notification::notification(const client& tclient, std::string data) { const user& current_user = tclient.getUser(); nlohmann::json json; try { json = nlohmann::json::parse(data); } catch (const std::invalid_argument& error) { std::throw_with_nested(invalid_response(data)); } try { if (!json["in_reply_to_status_id"].is_null()) { _type = type::tweet; new(&_tweet) tweet(tclient, data); } else if (!json["event"].is_null()) { std::string event = json["event"]; user source(tclient, json["source"].dump()); user target(tclient, json["target"].dump()); if (event == "user_update") { _type = type::update_user; new(&_user) user(source); } else if (event == "block") { _type = type::block; new(&_user) user(target); } else if (event == "unblock") { _type = type::unblock; new(&_user) user(target); } else if (event == "favorite") { new(&_user_and_tweet._tweet) tweet(tclient, json["target_object"].dump()); if (current_user == source) { _type = type::favorite; new(&_user_and_tweet._user) user(target); } else { _type = type::favorited; new(&_user_and_tweet._user) user(source); } } else if (event == "unfavorite") { new(&_user_and_tweet._tweet) tweet(tclient, json["target_object"].dump()); if (current_user == source) { _type = type::unfavorite; new(&_user_and_tweet._user) user(target); } else { _type = type::unfavorited; new(&_user_and_tweet._user) user(source); } } else if (event == "follow") { if (current_user == source) { _type = type::follow; new(&_user) user(target); } else { _type = type::followed; new(&_user) user(source); } } else if (event == "unfollow") { _type = type::unfollow; new(&_user) user(target); } else if (event == "list_created") { _type = type::list_created; new(&_list) list(json["target_object"].dump()); } else if (event == "list_destroyed") { _type = type::list_destroyed; new(&_list) list(json["target_object"].dump()); } else if (event == "list_updated") { _type = type::list_updated; new(&_list) list(json["target_object"].dump()); } else if (event == "list_member_added") { new(&_user_and_list._list) list(json["target_object"].dump()); if (current_user == source) { _type = type::list_add; new(&_user_and_list._user) user(target); } else { _type = type::list_added; new(&_user_and_list._user) user(source); } } else if (event == "list_member_removed") { new(&_user_and_list._list) list(json["target_object"].dump()); if (current_user == source) { _type = type::list_remove; new(&_user_and_list._user) user(target); } else { _type = type::list_removed; new(&_user_and_list._user) user(source); } } else if (event == "list_member_subscribe") { new(&_user_and_list._list) list(json["target_object"].dump()); if (current_user == source) { _type = type::list_subscribe; new(&_user_and_list._user) user(target); } else { _type = type::list_subscribed; new(&_user_and_list._user) user(source); } } else if (event == "list_member_unsubscribe") { new(&_user_and_list._list) list(json["target_object"].dump()); if (current_user == source) { _type = type::list_unsubscribe; new(&_user_and_list._user) user(target); } else { _type = type::list_unsubscribed; new(&_user_and_list._user) user(source); } } else if (event == "quoted_tweet") { _type = type::quoted; new(&_user_and_tweet._user) user(source); new(&_user_and_tweet._tweet) tweet(tclient, json["target_object"].dump()); } } else if (!json["warning"].is_null()) { new(&_warning) std::string(json["warning"]["message"].get()); auto warning_code = json["warning"]["code"].get(); if (warning_code == "FALLING_BEHIND") { _type = type::stall; } else if (warning_code == "FOLLOWS_OVER_LIMIT") { _type = type::follow_limit; } else { _type = type::unknown_warning; } } else if (!json["delete"].is_null()) { _type = type::deletion; _user_id_and_tweet_id._tweet_id = json["delete"]["status"]["id"].get(); _user_id_and_tweet_id._user_id = json["delete"]["status"]["user_id"].get(); } else if (!json["scrub_geo"].is_null()) { _type = type::scrub_location; _user_id_and_tweet_id._tweet_id = json["scrub_geo"]["up_to_status_id"].get(); _user_id_and_tweet_id._user_id = json["scrub_geo"]["user_id"].get(); } else if (!json["limit"].is_null()) { _type = type::limit; _limit = json["limit"]["track"].get(); } else if (!json["status_withheld"].is_null()) { _type = type::withhold_status; _withhold_status._user_id = json["status_withheld"]["user_id"].get(); _withhold_status._tweet_id = json["status_withheld"]["id"].get(); new(&_withhold_status._countries) std::vector(); for (auto s : json["status_withheld"]["withheld_in_countries"]) { _withhold_status._countries.push_back(s); } } else if (!json["user_withheld"].is_null()) { _type = type::withhold_user; _withhold_user._user_id = json["user_withheld"]["id"].get(); new(&_withhold_user._countries) std::vector(); for (auto s : json["user_withheld"]["withheld_in_countries"]) { _withhold_user._countries.push_back(s); } } else if (!json["disconnect"].is_null()) { _type = type::disconnect; switch (json["disconnect"]["code"].get()) { case 1: _disconnect = disconnect_code::shutdown; break; case 2: _disconnect = disconnect_code::duplicate; break; case 4: _disconnect = disconnect_code::stall; break; case 5: _disconnect = disconnect_code::normal; break; case 6: _disconnect = disconnect_code::token_revoked; break; case 7: _disconnect = disconnect_code::admin_logout; break; case 9: _disconnect = disconnect_code::limit; break; case 10: _disconnect = disconnect_code::exception; break; case 11: _disconnect = disconnect_code::broker; break; case 12: _disconnect = disconnect_code::load; break; default: _disconnect = disconnect_code::unknown; } } else if (!json["friends"].is_null()) { _type = type::friends; new(&_friends) std::set(std::begin(json["friends"]), std::end(json["friends"])); } else if (!json["direct_message"].is_null()) { _type = type::direct; new(&_direct_message) direct_message(json["direct_message"].dump()); } else { _type = type::unknown; } } catch (const std::domain_error& error) { std::throw_with_nested(invalid_response(data)); } } notification::notification(notification&& other) { _type = other._type; switch (_type) { case type::tweet: { new(&_tweet) tweet(std::move(other._tweet)); break; } case type::update_user: case type::block: case type::unblock: case type::follow: case type::followed: case type::unfollow: { new(&_user) user(std::move(other._user)); break; } case type::favorite: case type::favorited: case type::unfavorite: case type::unfavorited: case type::quoted: { new(&_user_and_tweet._user) user(std::move(other._user_and_tweet._user)); new(&_user_and_tweet._tweet) tweet(std::move(other._user_and_tweet._tweet)); break; } case type::list_created: case type::list_destroyed: case type::list_updated: { new(&_list) list(std::move(other._list)); break; } case type::list_add: case type::list_added: case type::list_remove: case type::list_removed: case type::list_subscribe: case type::list_subscribed: case type::list_unsubscribe: case type::list_unsubscribed: { new(&_user_and_list._user) user(std::move(other._user_and_list._user)); new(&_user_and_list._list) list(std::move(other._user_and_list._list)); break; } case type::stall: case type::follow_limit: case type::unknown_warning: { new(&_warning) std::string(std::move(other._warning)); break; } case type::deletion: case type::scrub_location: { _user_id_and_tweet_id._user_id = other._user_id_and_tweet_id._user_id; _user_id_and_tweet_id._tweet_id = other._user_id_and_tweet_id._tweet_id; break; } case type::limit: { _limit = other._limit; break; } case type::withhold_status: { _withhold_status._user_id = other._withhold_status._user_id; _withhold_status._tweet_id = other._withhold_status._tweet_id; new(&_withhold_status._countries) std::vector(std::move(other._withhold_status._countries)); break; } case type::withhold_user: { _withhold_user._user_id = other._withhold_user._user_id; new(&_withhold_user._countries) std::vector(std::move(other._withhold_user._countries)); break; } case type::disconnect: { _disconnect = other._disconnect; break; } case type::friends: { new(&_friends) std::set(std::move(other._friends)); break; } case type::direct: { new(&_direct_message) direct_message(std::move(other._direct_message)); break; } case type::unknown: case type::invalid: { break; } } } notification& notification::operator=(notification&& other) { this->~notification(); _type = other._type; switch (_type) { case type::tweet: { new(&_tweet) tweet(std::move(other._tweet)); break; } case type::update_user: case type::block: case type::unblock: case type::follow: case type::followed: case type::unfollow: { new(&_user) user(std::move(other._user)); break; } case type::favorite: case type::favorited: case type::unfavorite: case type::unfavorited: case type::quoted: { new(&_user_and_tweet._user) user(std::move(other._user_and_tweet._user)); new(&_user_and_tweet._tweet) tweet(std::move(other._user_and_tweet._tweet)); break; } case type::list_created: case type::list_destroyed: case type::list_updated: { new(&_list) list(std::move(other._list)); break; } case type::list_add: case type::list_added: case type::list_remove: case type::list_removed: case type::list_subscribe: case type::list_subscribed: case type::list_unsubscribe: case type::list_unsubscribed: { new(&_user_and_list._user) user(std::move(other._user_and_list._user)); new(&_user_and_list._list) list(std::move(other._user_and_list._list)); break; } case type::stall: case type::follow_limit: case type::unknown_warning: { new(&_warning) std::string(std::move(other._warning)); break; } case type::deletion: case type::scrub_location: { _user_id_and_tweet_id._user_id = other._user_id_and_tweet_id._user_id; _user_id_and_tweet_id._tweet_id = other._user_id_and_tweet_id._tweet_id; break; } case type::limit: { _limit = other._limit; break; } case type::withhold_status: { _withhold_status._user_id = other._withhold_status._user_id; _withhold_status._tweet_id = other._withhold_status._tweet_id; new(&_withhold_status._countries) std::vector(std::move(other._withhold_status._countries)); break; } case type::withhold_user: { _withhold_user._user_id = other._withhold_user._user_id; new(&_withhold_user._countries) std::vector(std::move(other._withhold_user._countries)); break; } case type::disconnect: { _disconnect = other._disconnect; break; } case type::friends: { new(&_friends) std::set(std::move(other._friends)); break; } case type::direct: { new(&_direct_message) direct_message(std::move(other._direct_message)); break; } case type::invalid: case type::unknown: { break; } } return *this; } notification::~notification() { switch (_type) { case type::tweet: { _tweet.~tweet(); break; } case type::update_user: case type::block: case type::unblock: case type::follow: case type::followed: case type::unfollow: { _user.~user(); break; } case type::favorite: case type::favorited: case type::unfavorite: case type::unfavorited: case type::quoted: { _user_and_tweet._user.~user(); _user_and_tweet._tweet.~tweet(); break; } case type::list_created: case type::list_destroyed: case type::list_updated: { _list.~list(); break; } case type::list_add: case type::list_added: case type::list_remove: case type::list_removed: case type::list_subscribe: case type::list_subscribed: case type::list_unsubscribe: case type::list_unsubscribed: { _user_and_list._user.~user(); _user_and_list._list.~list(); break; } case type::stall: case type::follow_limit: case type::unknown_warning: { using string_type = std::string; _warning.~string_type(); break; } case type::withhold_status: { using list_type = std::vector; _withhold_status._countries.~list_type(); break; } case type::withhold_user: { using list_type = std::vector; _withhold_user._countries.~list_type(); break; } case type::friends: { using list_type = std::set; _friends.~list_type(); break; } case type::direct: { _direct_message.~direct_message(); break; } case type::deletion: case type::scrub_location: case type::limit: case type::disconnect: case type::unknown: case type::invalid: { break; } } } const tweet& notification::getTweet() const { switch (_type) { case type::tweet: { return _tweet; } case type::favorite: case type::favorited: case type::unfavorite: case type::unfavorited: case type::quoted: { return _user_and_tweet._tweet; } default: { assert(false); } } } const user& notification::getUser() const { switch (_type) { case type::update_user: case type::block: case type::unblock: case type::follow: case type::followed: case type::unfollow: { return _user; } case type::favorite: case type::favorited: case type::unfavorite: case type::unfavorited: case type::quoted: { return _user_and_tweet._user; } case type::list_add: case type::list_added: case type::list_remove: case type::list_removed: case type::list_subscribe: case type::list_subscribed: case type::list_unsubscribe: case type::list_unsubscribed: { return _user_and_list._user; } default: { assert(false); } } } const list& notification::getList() const { switch (_type) { case type::list_created: case type::list_destroyed: case type::list_updated: { return _list; } case type::list_add: case type::list_added: case type::list_remove: case type::list_removed: case type::list_subscribe: case type::list_subscribed: case type::list_unsubscribe: case type::list_unsubscribed: { return _user_and_list._list; } default: { assert(false); } } } tweet_id notification::getTweetID() const { switch (_type) { case type::deletion: case type::scrub_location: { return _user_id_and_tweet_id._tweet_id; } case type::withhold_status: { return _withhold_status._tweet_id; } default: { assert(false); } } } user_id notification::getUserID() const { switch (_type) { case type::deletion: case type::scrub_location: { return _user_id_and_tweet_id._user_id; } case type::withhold_status: { return _withhold_status._user_id; } case type::withhold_user: { return _withhold_user._user_id; } default: { assert(false); } } } const std::vector& notification::getCountries() const { switch (_type) { case type::withhold_status: { return _withhold_status._countries; } case type::withhold_user: { return _withhold_user._countries; } default: { assert(false); } } } disconnect_code notification::getDisconnectCode() const { assert(_type == type::disconnect); return _disconnect; } const std::set& notification::getFriends() const { assert(_type == type::friends); return _friends; } const direct_message& notification::getDirectMessage() const { assert(_type == type::direct); return _direct_message; } int notification::getLimit() const { assert(_type == type::limit); return _limit; } const std::string& notification::getWarning() const { switch (_type) { case type::stall: case type::follow_limit: case type::unknown_warning: { return _warning; } default: { assert(false); } } } };