Compare commits

..

14 Commits

Author SHA1 Message Date
4fea965521 post contact4 fixes 2025-04-25 14:27:55 +02:00
d29f45dbd2 actually fix windows 2025-03-10 21:27:01 +01:00
981e8e3048 windows lean and mean 2025-03-10 21:20:18 +01:00
5ebeeef3c2 make contact store version visible 2025-03-10 20:57:38 +01:00
54bda18e7c port to contact4, still needs contact model interface impls 2025-03-10 20:35:27 +01:00
4d74826a95 Create LICENSE 2025-02-07 12:31:22 +01:00
3657634be5 time moved to utils 2025-01-07 16:08:00 +01:00
51a5e841a6 properly cleanup globals 2024-10-31 11:44:35 +01:00
e4eaf91a68 use sr 2024-10-24 14:56:26 +02:00
7973c7a320 parent for tree 2024-10-24 14:15:25 +02:00
f5cf44119b update to rmmi 2024-10-06 11:42:52 +02:00
d7280771ce reflect connection to server onto all contacts 2024-06-18 18:42:59 +02:00
ae817987c6 fix null deref and auto rejoin channels 2024-06-18 17:49:35 +02:00
3cb37e33a2 detect disconnect and reconnect (channels still missing) 2024-06-18 12:12:08 +02:00
10 changed files with 449 additions and 214 deletions

21
LICENSE Normal file
View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2025 Erik Scholz
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@ -1,5 +1,7 @@
#include <solanaceae/plugin/solana_plugin_v1.h> #include <solanaceae/plugin/solana_plugin_v1.h>
#include <solanaceae/contact/contact_store_i.hpp>
#include <solanaceae/ircclient/ircclient.hpp> #include <solanaceae/ircclient/ircclient.hpp>
#include <solanaceae/ircclient_contacts/ircclient_contact_model.hpp> #include <solanaceae/ircclient_contacts/ircclient_contact_model.hpp>
#include <solanaceae/ircclient_messages/ircclient_message_manager.hpp> #include <solanaceae/ircclient_messages/ircclient_message_manager.hpp>
@ -34,15 +36,15 @@ SOLANA_PLUGIN_EXPORT uint32_t solana_plugin_start(struct SolanaAPI* solana_api)
} }
try { try {
auto* cr = PLUG_RESOLVE_INSTANCE_VERSIONED(Contact3Registry, "1"); auto* cs = PLUG_RESOLVE_INSTANCE(ContactStore4I);
auto* rmm = PLUG_RESOLVE_INSTANCE(RegistryMessageModel); auto* rmm = PLUG_RESOLVE_INSTANCE(RegistryMessageModelI);
auto* conf = PLUG_RESOLVE_INSTANCE(ConfigModelI); auto* conf = PLUG_RESOLVE_INSTANCE(ConfigModelI);
// static store, could be anywhere tho // static store, could be anywhere tho
// construct with fetched dependencies // construct with fetched dependencies
g_ircc = std::make_unique<IRCClient1>(*conf); g_ircc = std::make_unique<IRCClient1>(*conf);
g_ircccm = std::make_unique<IRCClientContactModel>(*cr, *conf, *g_ircc); g_ircccm = std::make_unique<IRCClientContactModel>(*cs, *conf, *g_ircc);
g_irccmm = std::make_unique<IRCClientMessageManager>(*rmm, *cr, *conf, *g_ircc, *g_ircccm); g_irccmm = std::make_unique<IRCClientMessageManager>(*rmm, *cs, *conf, *g_ircc, *g_ircccm);
// register types // register types
PLUG_PROVIDE_INSTANCE(IRCClient1, plugin_name, g_ircc.get()); PLUG_PROVIDE_INSTANCE(IRCClient1, plugin_name, g_ircc.get());
@ -59,14 +61,13 @@ SOLANA_PLUGIN_EXPORT uint32_t solana_plugin_start(struct SolanaAPI* solana_api)
SOLANA_PLUGIN_EXPORT void solana_plugin_stop(void) { SOLANA_PLUGIN_EXPORT void solana_plugin_stop(void) {
std::cout << "PLUGIN " << plugin_name << " STOP()\n"; std::cout << "PLUGIN " << plugin_name << " STOP()\n";
g_irccmm.reset();
g_ircccm.reset();
g_ircc.reset(); g_ircc.reset();
} }
SOLANA_PLUGIN_EXPORT float solana_plugin_tick(float delta) { SOLANA_PLUGIN_EXPORT float solana_plugin_tick(float delta) {
(void)delta; return g_ircc->iterate(delta);
g_ircc->iterate(); // TODO: return interval, respect dcc etc
return 1.f; // expect atleast once per sec
} }
} // extern C } // extern C

View File

@ -8,6 +8,7 @@ add_library(solanaceae_ircclient
) )
target_include_directories(solanaceae_ircclient PUBLIC .) target_include_directories(solanaceae_ircclient PUBLIC .)
target_compile_definitions(solanaceae_ircclient PRIVATE WIN32_LEAN_AND_MEAN NOMINMAX)
target_compile_features(solanaceae_ircclient PRIVATE cxx_std_20) target_compile_features(solanaceae_ircclient PRIVATE cxx_std_20)
target_compile_features(solanaceae_ircclient INTERFACE cxx_std_17) target_compile_features(solanaceae_ircclient INTERFACE cxx_std_17)
target_link_libraries(solanaceae_ircclient PUBLIC target_link_libraries(solanaceae_ircclient PUBLIC
@ -27,6 +28,7 @@ add_library(solanaceae_ircclient_contacts
) )
target_include_directories(solanaceae_ircclient_contacts PUBLIC .) target_include_directories(solanaceae_ircclient_contacts PUBLIC .)
target_compile_definitions(solanaceae_ircclient_contacts PRIVATE WIN32_LEAN_AND_MEAN NOMINMAX)
target_compile_features(solanaceae_ircclient_contacts PRIVATE cxx_std_20) target_compile_features(solanaceae_ircclient_contacts PRIVATE cxx_std_20)
target_compile_features(solanaceae_ircclient_contacts INTERFACE cxx_std_17) target_compile_features(solanaceae_ircclient_contacts INTERFACE cxx_std_17)
target_link_libraries(solanaceae_ircclient_contacts PUBLIC target_link_libraries(solanaceae_ircclient_contacts PUBLIC
@ -43,6 +45,7 @@ add_library(solanaceae_ircclient_messages
) )
target_include_directories(solanaceae_ircclient_messages PUBLIC .) target_include_directories(solanaceae_ircclient_messages PUBLIC .)
target_compile_definitions(solanaceae_ircclient_messages PRIVATE WIN32_LEAN_AND_MEAN NOMINMAX)
target_compile_features(solanaceae_ircclient_messages PRIVATE cxx_std_20) target_compile_features(solanaceae_ircclient_messages PRIVATE cxx_std_20)
target_compile_features(solanaceae_ircclient_messages INTERFACE cxx_std_17) target_compile_features(solanaceae_ircclient_messages INTERFACE cxx_std_17)
target_link_libraries(solanaceae_ircclient_messages PUBLIC target_link_libraries(solanaceae_ircclient_messages PUBLIC

View File

@ -26,6 +26,7 @@ void IRCClient1::on_event_numeric(irc_session_t* session, unsigned int event, co
auto ircc = static_cast<IRCClient1*>(irc_get_ctx(session)); auto ircc = static_cast<IRCClient1*>(irc_get_ctx(session));
ircc->dispatch(IRCClient_Event::NUMERIC, IRCClient::Events::Numeric{event, origin, params_view}); ircc->dispatch(IRCClient_Event::NUMERIC, IRCClient::Events::Numeric{event, origin, params_view});
ircc->_event_fired = true;
} }
IRCClient1::IRCClient1( IRCClient1::IRCClient1(
@ -77,7 +78,111 @@ IRCClient1::IRCClient1(
irc_option_set(_irc_session, LIBIRC_OPTION_STRIPNICKS); irc_option_set(_irc_session, LIBIRC_OPTION_STRIPNICKS);
irc_option_set(_irc_session, LIBIRC_OPTION_SSL_NO_VERIFY); // why irc_option_set(_irc_session, LIBIRC_OPTION_SSL_NO_VERIFY); // why
connectSession();
}
IRCClient1::~IRCClient1(void) {
irc_destroy_session(_irc_session);
}
// tmp
void IRCClient1::run(void) {
if (irc_run(_irc_session) != 0) {
std::cerr << "error failed to run: " << irc_strerror(irc_errno(_irc_session)) << "\n";
}
}
float IRCClient1::iterate(float delta) {
//if ( session->state != LIBIRC_STATE_CONNECTING )
//{
//session->lasterror = LIBIRC_ERR_STATE;
//return 1;
//}
if (!irc_is_connected(_irc_session)) {
if (_try_connecting_state) {
// try to connect, every 20sec
_try_connecting_cooldown -= delta;
if (_try_connecting_cooldown <= 0.f) {
std::cerr << "IRCC: trying to connect\n";
connectSession();
}
} else {
std::cerr << "IRCC error: not connected, trying to reconnect\n";
dispatch(IRCClient_Event::DISCONNECT, IRCClient::Events::Disconnect{});
connectSession(); // potentially enters trying phase
}
return 0.5f;
}
_event_fired = false;
struct timeval tv;
fd_set in_set, out_set;
int maxfd = 0;
//tv.tv_usec = 20000; // 20ms
tv.tv_usec = 1000; // 1ms
tv.tv_sec = 0;
// Init sets
FD_ZERO(&in_set);
FD_ZERO(&out_set);
if (irc_add_select_descriptors(_irc_session, &in_set, &out_set, &maxfd) != 0) {
std::cerr << "IRCC error: adding select descriptors\n";
}
if (select(maxfd + 1, &in_set, &out_set, 0, &tv) < 0) {
std::cerr << "IRCC error: select returned error\n";
#if 0
if (socket_error() == EINTR) {
//continue;
return;
}
#endif
//session->lasterror = LIBIRC_ERR_TERMINATED;
//return 1;
return 0.1f;
}
if (irc_process_select_descriptors(_irc_session, &in_set, &out_set) != 0) {
std::cerr << "IRCC error: processing socket select\n";
//return 1;
}
// TODO: handle dcc
if (_event_fired) {
return 0.1f;
} else {
return 1.f;
}
}
irc_session_t* IRCClient1::getSession(void) {
return _irc_session;
}
const std::string_view IRCClient1::getServerName(void) const {
return _server_name;
}
void IRCClient1::join(std::string_view channel) {
assert(false && "implement me");
}
void IRCClient1::connectSession(void) {
_try_connecting_state = true;
_try_connecting_cooldown = 20.f;
// reset connection
// only closes potentially open sockets and sets state to init
// nothing else is touched
irc_disconnect(_irc_session);
// TODO: do we need to set this every time?
if (!_conf.has_string("IRCClient", "server")) { if (!_conf.has_string("IRCClient", "server")) {
std::cerr << "IRCC error: no irc server in config!!\n"; std::cerr << "IRCC error: no irc server in config!!\n";
throw std::runtime_error("missing server in config"); throw std::runtime_error("missing server in config");
@ -111,70 +216,14 @@ IRCClient1::IRCClient1(
} }
if (irc_connect(_irc_session, server.c_str(), port, nullptr, nick.c_str(), username.c_str(), realname.c_str()) != 0) { if (irc_connect(_irc_session, server.c_str(), port, nullptr, nick.c_str(), username.c_str(), realname.c_str()) != 0) {
std::cerr << "error failed to connect: (" << irc_errno(_irc_session) << ") " << irc_strerror(irc_errno(_irc_session)) << "\n"; std::cerr << "IRCC error: failed to connect: (" << irc_errno(_irc_session) << ") " << irc_strerror(irc_errno(_irc_session)) << "\n";
throw std::runtime_error("failed to connect to irc");
}
}
IRCClient1::~IRCClient1(void) { irc_disconnect(_irc_session);
irc_destroy_session(_irc_session);
}
// tmp //throw std::runtime_error("failed to connect to irc");
void IRCClient1::run(void) {
if (irc_run(_irc_session) != 0) {
std::cerr << "error failed to run: " << irc_strerror(irc_errno(_irc_session)) << "\n";
}
}
void IRCClient1::iterate(void) {
//if ( session->state != LIBIRC_STATE_CONNECTING )
//{
//session->lasterror = LIBIRC_ERR_STATE;
//return 1;
//}
if (!irc_is_connected(_irc_session)) {
return; return;
} }
struct timeval tv; _try_connecting_state = false;
fd_set in_set, out_set;
int maxfd = 0;
//tv.tv_usec = 20000; // 20ms
tv.tv_usec = 1000; // 1ms
tv.tv_sec = 0;
// Init sets
FD_ZERO (&in_set);
FD_ZERO (&out_set);
irc_add_select_descriptors(_irc_session, &in_set, &out_set, &maxfd);
if (select(maxfd + 1, &in_set, &out_set, 0, &tv) < 0)
{
#if 0
if (socket_error() == EINTR) {
//continue;
return;
}
#endif
//session->lasterror = LIBIRC_ERR_TERMINATED;
//return 1;
return;
}
if (irc_process_select_descriptors(_irc_session, &in_set, &out_set)) {
//return 1;
}
} }
irc_session_t* IRCClient1::getSession(void) {
return _irc_session;
}
const std::string_view IRCClient1::getServerName(void) const {
return _server_name;
}

View File

@ -110,6 +110,11 @@ namespace IRCClient::Events {
std::vector<std::string_view> params; std::vector<std::string_view> params;
}; };
struct Disconnect {
// TODO: reason
// this is not a libircclient event (bad lib)
};
} // Events } // Events
enum class IRCClient_Event : uint32_t { enum class IRCClient_Event : uint32_t {
@ -135,6 +140,8 @@ enum class IRCClient_Event : uint32_t {
UNKNOWN, UNKNOWN,
DISCONNECT,
MAX MAX
}; };
@ -162,6 +169,7 @@ struct IRCClientEventI {
virtual bool onEvent(const IRCClient::Events::CTCP_Rep&) { return false; } virtual bool onEvent(const IRCClient::Events::CTCP_Rep&) { return false; }
virtual bool onEvent(const IRCClient::Events::CTCP_Action&) { return false; } virtual bool onEvent(const IRCClient::Events::CTCP_Action&) { return false; }
virtual bool onEvent(const IRCClient::Events::Unknown&) { return false; } virtual bool onEvent(const IRCClient::Events::Unknown&) { return false; }
virtual bool onEvent(const IRCClient::Events::Disconnect&) { return false; }
}; };
using IRCClientEventProviderI = EventProviderI<IRCClientEventI>; using IRCClientEventProviderI = EventProviderI<IRCClientEventI>;
@ -170,7 +178,11 @@ using IRCClientEventProviderI = EventProviderI<IRCClientEventI>;
class IRCClient1 : public IRCClientEventProviderI { class IRCClient1 : public IRCClientEventProviderI {
ConfigModelI& _conf; ConfigModelI& _conf;
irc_session_t* _irc_session = nullptr; irc_session_t* _irc_session {nullptr};
bool _try_connecting_state {false};
float _try_connecting_cooldown {0.f};
bool _event_fired {false};
std::string _server_name; // name of the irc network this iirc is connected to std::string _server_name; // name of the irc network this iirc is connected to
@ -181,9 +193,10 @@ class IRCClient1 : public IRCClientEventProviderI {
~IRCClient1(void); ~IRCClient1(void);
// tmp // tmp
void run(void); void run(void);
void iterate(void); float iterate(float delta);
// raw access // raw access
irc_session_t* getSession(void); irc_session_t* getSession(void);
@ -193,17 +206,23 @@ class IRCClient1 : public IRCClientEventProviderI {
// join // join
void join(std::string_view channel); void join(std::string_view channel);
private:
// connects an already existing session
void connectSession(void);
private: // callbacks for libircclient private: // callbacks for libircclient
static void on_event_numeric(irc_session_t* session, unsigned int event, const char* origin, const char** params, unsigned int count); static void on_event_numeric(irc_session_t* session, unsigned int event, const char* origin, const char** params, unsigned int count);
template<IRCClient_Event event_type_enum, typename EventType> template<IRCClient_Event event_type_enum, typename EventType>
static void on_event_generic_new(irc_session_t* session, const char* event, const char* origin, const char** params, unsigned int count) { static void on_event_generic_new(irc_session_t* session, const char* event, const char* origin, const char** params, unsigned int count) {
assert(session != nullptr);
std::vector<std::string_view> params_view; std::vector<std::string_view> params_view;
for (size_t i = 0; i < count; i++) { for (size_t i = 0; i < count; i++) {
params_view.push_back(params[i]); params_view.push_back(params[i]);
} }
std::cout << "IRC: event " << event << " " << origin << "\n"; std::cout << "IRC: event '" << (event?event:"<nullptr>") << "' o:" << (origin?origin:"<nullptr>") << "\n";
#if 0 #if 0
if (std::string_view{event} == "ACTION") { if (std::string_view{event} == "ACTION") {
@ -219,7 +238,9 @@ class IRCClient1 : public IRCClientEventProviderI {
auto* ircc = static_cast<IRCClient1*>(irc_get_ctx(session)); auto* ircc = static_cast<IRCClient1*>(irc_get_ctx(session));
assert(ircc != nullptr); assert(ircc != nullptr);
ircc->dispatch(event_type_enum, EventType{origin, params_view}); // hack if origin is null
ircc->dispatch(event_type_enum, EventType{origin?origin:"<nullptr>", params_view});
ircc->_event_fired = true;
} }
}; };

View File

@ -2,12 +2,16 @@
#include "./components.hpp" #include "./components.hpp"
#include <solanaceae/contact/contact_store_i.hpp>
#include <solanaceae/contact/components.hpp> #include <solanaceae/contact/components.hpp>
#include <solanaceae/util/utils.hpp> #include <solanaceae/util/utils.hpp>
#include <libirc_rfcnumeric.h> #include <libirc_rfcnumeric.h>
#include <libircclient.h> #include <libircclient.h>
#include <entt/entity/registry.hpp>
#include <entt/entity/handle.hpp>
#include <sodium/crypto_hash_sha256.h> #include <sodium/crypto_hash_sha256.h>
#include <cstdint> #include <cstdint>
@ -16,20 +20,24 @@
#include <iostream> #include <iostream>
IRCClientContactModel::IRCClientContactModel( IRCClientContactModel::IRCClientContactModel(
Contact3Registry& cr, ContactStore4I& cs,
ConfigModelI& conf, ConfigModelI& conf,
IRCClient1& ircc IRCClient1& ircc
) : _cr(cr), _conf(conf), _ircc(ircc) { ) : _cs(cs), _conf(conf), _ircc(ircc), _ircc_sr(_ircc.newSubRef(this)) {
_ircc.subscribe(this, IRCClient_Event::CONNECT); _ircc_sr
.subscribe(IRCClient_Event::CONNECT)
_ircc.subscribe(this, IRCClient_Event::NUMERIC); .subscribe(IRCClient_Event::NUMERIC)
_ircc.subscribe(this, IRCClient_Event::JOIN); .subscribe(IRCClient_Event::JOIN)
_ircc.subscribe(this, IRCClient_Event::PART); .subscribe(IRCClient_Event::PART)
_ircc.subscribe(this, IRCClient_Event::TOPIC); .subscribe(IRCClient_Event::TOPIC)
_ircc.subscribe(this, IRCClient_Event::QUIT); .subscribe(IRCClient_Event::QUIT)
_ircc.subscribe(this, IRCClient_Event::CTCP_REQ); .subscribe(IRCClient_Event::CTCP_REQ)
.subscribe(IRCClient_Event::DISCONNECT)
;
// dont create server self etc until connect event comes // dont create server self etc until connect event comes
@ -58,6 +66,18 @@ void IRCClientContactModel::join(const std::string& channel) {
} }
} }
bool IRCClientContactModel::addContact(Contact4 c) {
return false;
}
bool IRCClientContactModel::acceptRequest(Contact4 c, std::string_view self_name, std::string_view password) {
return false;
}
bool IRCClientContactModel::leave(Contact4 c, std::string_view reason) {
return false;
}
std::vector<uint8_t> IRCClientContactModel::getHash(std::string_view value) { std::vector<uint8_t> IRCClientContactModel::getHash(std::string_view value) {
assert(!value.empty()); assert(!value.empty());
@ -83,33 +103,35 @@ std::vector<uint8_t> IRCClientContactModel::getIDHash(std::string_view name) {
return getHash(data); return getHash(data);
} }
Contact3Handle IRCClientContactModel::getC(std::string_view channel) { ContactHandle4 IRCClientContactModel::getC(std::string_view channel) {
const auto server_name = _ircc.getServerName(); const auto server_name = _ircc.getServerName();
const auto& cr = _cs.registry();
// TODO: this needs a better way // TODO: this needs a better way
for (const auto e : _cr.view<Contact::Components::IRC::ServerName, Contact::Components::IRC::ChannelName>()) { for (const auto e : cr.view<Contact::Components::IRC::ServerName, Contact::Components::IRC::ChannelName>()) {
if (_cr.get<Contact::Components::IRC::ServerName>(e).name == server_name && _cr.get<Contact::Components::IRC::ChannelName>(e).name == channel) { if (cr.get<Contact::Components::IRC::ServerName>(e).name == server_name && cr.get<Contact::Components::IRC::ChannelName>(e).name == channel) {
return {_cr, e}; return _cs.contactHandle(e);
} }
} }
return {_cr, entt::null}; return {};
} }
Contact3Handle IRCClientContactModel::getU(std::string_view nick) { ContactHandle4 IRCClientContactModel::getU(std::string_view nick) {
const auto server_name = _ircc.getServerName(); const auto server_name = _ircc.getServerName();
const auto& cr = _cs.registry();
// TODO: this needs a better way // TODO: this needs a better way
for (const auto e : _cr.view<Contact::Components::IRC::ServerName, Contact::Components::IRC::UserName>()) { for (const auto e : cr.view<Contact::Components::IRC::ServerName, Contact::Components::IRC::UserName>()) {
if (_cr.get<Contact::Components::IRC::ServerName>(e).name == server_name && _cr.get<Contact::Components::IRC::UserName>(e).name == nick) { if (cr.get<Contact::Components::IRC::ServerName>(e).name == server_name && cr.get<Contact::Components::IRC::UserName>(e).name == nick) {
return {_cr, e}; return _cs.contactHandle(e);
} }
} }
return {_cr, entt::null}; return {};
} }
Contact3Handle IRCClientContactModel::getCU(std::string_view name) { ContactHandle4 IRCClientContactModel::getCU(std::string_view name) {
if (name.empty()) { if (name.empty()) {
return {_cr, entt::null}; return {};
} }
static constexpr std::string_view channel_prefixes{ static constexpr std::string_view channel_prefixes{
@ -133,63 +155,59 @@ bool IRCClientContactModel::onEvent(const IRCClient::Events::Connect& e) {
_server_hash = getHash(_ircc.getServerName()); _server_hash = getHash(_ircc.getServerName());
_connected = true; _connected = true;
{ // server auto& cr = _cs.registry();
if (!_cr.valid(_server)) {
// check for empty contact by id
for (const auto e : _cr.view<Contact::Components::ID>()) {
if (_cr.get<Contact::Components::ID>(e).data == _server_hash) {
_server = e;
break;
}
}
if (!_cr.valid(_server)) { bool server_contact_created {false};
_server = _cr.create(); { // server
_cr.emplace_or_replace<Contact::Components::ID>(_server, _server_hash); if (!cr.valid(_server)) {
// check for empty contact by id
_server = _cs.getOneContactByID(ByteSpan{_server_hash});
if (!cr.valid(_server)) {
_server = cr.create();
server_contact_created = true;
cr.emplace_or_replace<Contact::Components::ID>(_server, _server_hash);
} }
} }
_cr.emplace_or_replace<Contact::Components::ContactModel>(_server, this); cr.emplace_or_replace<Contact::Components::ContactModel>(_server, this);
_cr.emplace_or_replace<Contact::Components::IRC::ServerName>(_server, std::string{_ircc.getServerName()}); // really? cr.emplace_or_replace<Contact::Components::IRC::ServerName>(_server, std::string{_ircc.getServerName()}); // really?
_cr.emplace_or_replace<Contact::Components::Name>(_server, std::string{_ircc.getServerName()}); // TODO: add special string? cr.emplace_or_replace<Contact::Components::Name>(_server, std::string{_ircc.getServerName()}); // TODO: add special string?
// does this make sense ? // does this make sense ?
_cr.emplace_or_replace<Contact::Components::ConnectionState>(_server, Contact::Components::ConnectionState::State::direct); cr.emplace_or_replace<Contact::Components::ConnectionState>(_server, Contact::Components::ConnectionState::State::direct);
_cr.emplace_or_replace<Contact::Components::TagBig>(_server); cr.emplace_or_replace<Contact::Components::TagBig>(_server);
// the server connection is also the root contact (ircccm only handles 1 server 1 user) // the server connection is also the root contact (ircccm only handles 1 server 1 user)
_cr.emplace_or_replace<Contact::Components::TagRoot>(_server); cr.emplace_or_replace<Contact::Components::TagRoot>(_server);
// TODO: should this be its own node instead? or should the server node be created on construction? // TODO: should this be its own node instead? or should the server node be created on construction?
} }
bool self_contact_created {false};
{ // self { // self
if (!_cr.valid(_self)) { if (!cr.valid(_self)) {
// TODO: this can create self with peexisting id // TODO: this can create self with peexisting id
if (!e.params.empty()) { if (!e.params.empty()) {
const auto self_hash = getIDHash(e.params.front()); const auto self_hash = getIDHash(e.params.front());
// check for empty contact by id // check for empty contact by id
for (const auto e : _cr.view<Contact::Components::ID>()) { _server = _cs.getOneContactByID(_server, ByteSpan{self_hash});
if (_cr.get<Contact::Components::ID>(e).data == self_hash) {
_self = e;
break;
}
}
} }
if (!_cr.valid(_self)) { if (!cr.valid(_self)) {
_self = _cr.create(); _self = cr.create();
self_contact_created = true;
} }
} }
_cr.emplace_or_replace<Contact::Components::ContactModel>(_self, this); cr.emplace_or_replace<Contact::Components::ContactModel>(_self, this);
_cr.emplace_or_replace<Contact::Components::Parent>(_self, _server); cr.emplace_or_replace<Contact::Components::Parent>(_self, _server);
_cr.emplace_or_replace<Contact::Components::TagSelfStrong>(_self); cr.emplace_or_replace<Contact::Components::TagSelfStrong>(_self);
_cr.emplace_or_replace<Contact::Components::IRC::ServerName>(_self, std::string{_ircc.getServerName()}); // really? cr.emplace_or_replace<Contact::Components::IRC::ServerName>(_self, std::string{_ircc.getServerName()}); // really?
if (!e.params.empty()) { if (!e.params.empty()) {
_cr.emplace_or_replace<Contact::Components::IRC::UserName>(_self, std::string{e.params.front()}); cr.emplace_or_replace<Contact::Components::IRC::UserName>(_self, std::string{e.params.front()});
_cr.emplace_or_replace<Contact::Components::Name>(_self, std::string{e.params.front()}); cr.emplace_or_replace<Contact::Components::Name>(_self, std::string{e.params.front()});
// make id hash(hash(ServerName)+UserName) // make id hash(hash(ServerName)+UserName)
// or irc name format, but those might cause collisions // or irc name format, but those might cause collisions
_cr.emplace_or_replace<Contact::Components::ID>(_self, getIDHash(e.params.front())); cr.emplace_or_replace<Contact::Components::ID>(_self, getIDHash(e.params.front()));
#if 0 #if 0
std::cout << "### created self with" std::cout << "### created self with"
@ -201,14 +219,34 @@ bool IRCClientContactModel::onEvent(const IRCClient::Events::Connect& e) {
#endif #endif
} }
_cr.emplace_or_replace<Contact::Components::ConnectionState>(_self, Contact::Components::ConnectionState::State::direct); cr.emplace_or_replace<Contact::Components::ConnectionState>(_self, Contact::Components::ConnectionState::State::direct);
// add self to server // add self to server
_cr.emplace_or_replace<Contact::Components::Self>(_server, _self); cr.emplace_or_replace<Contact::Components::Self>(_server, _self);
} }
// check for preexisting channels,
// since this might be a reconnect
// and reissue joins
cr.view<Contact::Components::IRC::ServerName, Contact::Components::IRC::ChannelName>().each([this](const auto c, const auto& sn_c, const auto& cn_c) {
// HACK: by name
// should be by parent instead
if (sn_c.name != _ircc.getServerName()) {
return;
}
// TODO: implement join lol
irc_cmd_join(
_ircc.getSession(),
cn_c.name.c_str(),
""
);
});
// join queued // join queued
// TODO: merge with above
while (!_join_queue.empty()) { while (!_join_queue.empty()) {
// TODO: implement join lol
irc_cmd_join( irc_cmd_join(
_ircc.getSession(), _ircc.getSession(),
_join_queue.front().c_str(), _join_queue.front().c_str(),
@ -217,6 +255,18 @@ bool IRCClientContactModel::onEvent(const IRCClient::Events::Connect& e) {
_join_queue.pop(); _join_queue.pop();
} }
if (server_contact_created) {
_cs.throwEventConstruct(_server);
} else {
_cs.throwEventUpdate(_server);
}
if (self_contact_created) {
_cs.throwEventConstruct(_self);
} else {
_cs.throwEventUpdate(_self);
}
return false; return false;
} }
@ -244,7 +294,7 @@ bool IRCClientContactModel::onEvent(const IRCClient::Events::Numeric& e) {
const auto& channel_name = e.params.at(2); const auto& channel_name = e.params.at(2);
auto channel = getC(channel_name); auto channel = getC(channel_name);
if (!channel.valid()) { if (!static_cast<bool>(channel)) {
std::cerr << "IRCCCM error: name list for unknown channel\n"; std::cerr << "IRCCCM error: name list for unknown channel\n";
return false; return false;
} }
@ -295,17 +345,15 @@ bool IRCClientContactModel::onEvent(const IRCClient::Events::Numeric& e) {
//std::cout << "u: " << user_str << "\n"; //std::cout << "u: " << user_str << "\n";
auto user = getU(user_str); auto user = getU(user_str);
if (!user.valid()) { bool user_throw_event {false};
bool user_created {false};
if (!static_cast<bool>(user)) {
const auto user_hash = getIDHash(user_str); const auto user_hash = getIDHash(user_str);
// check for empty contact by id // check for empty contact by id
for (const auto e : _cr.view<Contact::Components::ID>()) { user = _cs.getOneContactByID(_server, ByteSpan{user_hash});
if (_cr.get<Contact::Components::ID>(e).data == user_hash) { if (!static_cast<bool>(user)) {
user = {_cr, e}; user = _cs.contactHandle(_cs.registry().create());
break; user_created = true;
}
}
if (!user.valid()) {
user = {_cr, _cr.create()};
user.emplace_or_replace<Contact::Components::ID>(user_hash); user.emplace_or_replace<Contact::Components::ID>(user_hash);
} }
@ -315,11 +363,15 @@ bool IRCClientContactModel::onEvent(const IRCClient::Events::Numeric& e) {
// add to channel? // add to channel?
user.emplace_or_replace<Contact::Components::IRC::UserName>(std::string{user_str}); user.emplace_or_replace<Contact::Components::IRC::UserName>(std::string{user_str});
user.emplace_or_replace<Contact::Components::Name>(std::string{user_str}); user.emplace_or_replace<Contact::Components::Name>(std::string{user_str});
user_throw_event = true;
} }
if (user.entity() != _self) { if (user.entity() != _self) {
user.emplace_or_replace<Contact::Components::ConnectionState>(Contact::Components::ConnectionState::State::cloud); user.emplace_or_replace<Contact::Components::ConnectionState>(Contact::Components::ConnectionState::State::cloud);
user.emplace_or_replace<Contact::Components::Self>(_self); user.emplace_or_replace<Contact::Components::Self>(_self);
user_throw_event = true;
} }
{ // add user to channel { // add user to channel
@ -327,6 +379,15 @@ bool IRCClientContactModel::onEvent(const IRCClient::Events::Numeric& e) {
if (std::find(channel_user_list.begin(), channel_user_list.end(), user) == channel_user_list.end()) { if (std::find(channel_user_list.begin(), channel_user_list.end(), user) == channel_user_list.end()) {
//std::cout << "!!!!!!!! new user in channel!\n"; //std::cout << "!!!!!!!! new user in channel!\n";
channel_user_list.push_back(user); channel_user_list.push_back(user);
user_throw_event = true;
}
}
if (user_throw_event) {
if (user_created) {
_cs.throwEventConstruct(user);
} else {
_cs.throwEventUpdate(user);
} }
} }
} }
@ -357,13 +418,14 @@ bool IRCClientContactModel::onEvent(const IRCClient::Events::Numeric& e) {
const auto channel_name = e.params.at(1); const auto channel_name = e.params.at(1);
auto channel = getC(channel_name); auto channel = getC(channel_name);
if (!channel.valid()) { if (!static_cast<bool>(channel)) {
std::cerr << "IRCCCM error: topic for unknown channel\n"; std::cerr << "IRCCCM error: topic for unknown channel\n";
return false; return false;
} }
const auto topic = e.params.at(2); const auto topic = e.params.at(2);
channel.emplace_or_replace<Contact::Components::StatusText>(std::string{topic}).fillFirstLineLength(); channel.emplace_or_replace<Contact::Components::StatusText>(std::string{topic}).fillFirstLineLength();
_cs.throwEventUpdate(channel);
} }
return false; return false;
} }
@ -377,22 +439,23 @@ bool IRCClientContactModel::onEvent(const IRCClient::Events::Join& e) {
//std::cout << "JOIN!!!! " << e.origin << " in " << joined_channel_name << "\n"; //std::cout << "JOIN!!!! " << e.origin << " in " << joined_channel_name << "\n";
auto& cr = _cs.registry();
bool channel_created {false};
auto channel = getC(e.params.front()); auto channel = getC(e.params.front());
if (!channel.valid()) { if (!static_cast<bool>(channel)) {
const auto channel_hash = getIDHash(joined_channel_name); const auto channel_hash = getIDHash(joined_channel_name);
// check for empty contact by id // check for empty contact by id
for (const auto e : _cr.view<Contact::Components::ID>()) { channel = _cs.getOneContactByID(_server, ByteSpan{channel_hash});
if (_cr.get<Contact::Components::ID>(e).data == channel_hash) { if (!static_cast<bool>(channel)) {
channel = {_cr, e}; //channel = {_cr, _cr.create()};
break; channel = _cs.contactHandle(cr.create());
} channel_created = true;
}
if (!channel.valid()) {
channel = {_cr, _cr.create()};
channel.emplace_or_replace<Contact::Components::ID>(channel_hash); channel.emplace_or_replace<Contact::Components::ID>(channel_hash);
} }
channel.emplace_or_replace<Contact::Components::ContactModel>(this); channel.emplace_or_replace<Contact::Components::ContactModel>(this);
channel.emplace_or_replace<Contact::Components::Parent>(_server); channel.emplace_or_replace<Contact::Components::Parent>(_server);
cr.get_or_emplace<Contact::Components::ParentOf>(_server).subs.push_back(channel);
channel.emplace_or_replace<Contact::Components::ParentOf>(); // start empty channel.emplace_or_replace<Contact::Components::ParentOf>(); // start empty
channel.emplace_or_replace<Contact::Components::IRC::ServerName>(std::string{_ircc.getServerName()}); channel.emplace_or_replace<Contact::Components::IRC::ServerName>(std::string{_ircc.getServerName()});
channel.emplace_or_replace<Contact::Components::IRC::ChannelName>(std::string{joined_channel_name}); channel.emplace_or_replace<Contact::Components::IRC::ChannelName>(std::string{joined_channel_name});
@ -400,27 +463,30 @@ bool IRCClientContactModel::onEvent(const IRCClient::Events::Join& e) {
std::cout << "IRCCCM: joined '" << joined_channel_name << "' id:" << bin2hex(channel.get<Contact::Components::ID>().data) << "\n"; std::cout << "IRCCCM: joined '" << joined_channel_name << "' id:" << bin2hex(channel.get<Contact::Components::ID>().data) << "\n";
channel.emplace_or_replace<Contact::Components::ConnectionState>(Contact::Components::ConnectionState::State::cloud);
channel.emplace_or_replace<Contact::Components::TagBig>(); channel.emplace_or_replace<Contact::Components::TagBig>();
channel.emplace_or_replace<Contact::Components::TagGroup>(); channel.emplace_or_replace<Contact::Components::TagGroup>();
// add self to channel // add self to channel
channel.emplace_or_replace<Contact::Components::Self>(_self); channel.emplace_or_replace<Contact::Components::Self>(_self);
} }
channel.emplace_or_replace<Contact::Components::ConnectionState>(Contact::Components::ConnectionState::State::cloud);
if (channel_created) {
_cs.throwEventConstruct(channel);
} else {
_cs.throwEventUpdate(channel);
}
auto user = getU(e.origin); auto user = getU(e.origin);
if (!user.valid()) { bool user_throw_event {false};
bool user_created {false};
if (!static_cast<bool>(user)) {
const auto user_hash = getIDHash(e.origin); const auto user_hash = getIDHash(e.origin);
// check for empty contact by id // check for empty contact by id
for (const auto e : _cr.view<Contact::Components::ID>()) { user = _cs.getOneContactByID(_server, ByteSpan{user_hash});
if (_cr.get<Contact::Components::ID>(e).data == user_hash) { if (!static_cast<bool>(user)) {
user = {_cr, e}; user = _cs.contactHandle(cr.create());
break; user_created = true;
}
}
if (!user.valid()) {
user = {_cr, _cr.create()};
user.emplace_or_replace<Contact::Components::ID>(user_hash); user.emplace_or_replace<Contact::Components::ID>(user_hash);
std::cerr << "IRCCCM error: had to create joining user (self?)\n"; std::cerr << "IRCCCM error: had to create joining user (self?)\n";
} }
@ -433,16 +499,28 @@ bool IRCClientContactModel::onEvent(const IRCClient::Events::Join& e) {
user.emplace_or_replace<Contact::Components::IRC::UserName>(std::string{e.origin}); user.emplace_or_replace<Contact::Components::IRC::UserName>(std::string{e.origin});
user.emplace_or_replace<Contact::Components::Name>(std::string{e.origin}); user.emplace_or_replace<Contact::Components::Name>(std::string{e.origin});
user_throw_event = true;
// ???
std::cout << "### created self(?) with" std::cout << "### created self(?) with"
<< " ircn:" << _cr.get<Contact::Components::IRC::UserName>(_self).name << " ircn:" << cr.get<Contact::Components::IRC::UserName>(_self).name
<< " ircsn:" << _cr.get<Contact::Components::IRC::ServerName>(_self).name << " ircsn:" << cr.get<Contact::Components::IRC::ServerName>(_self).name
<< " id:" << bin2hex(_cr.get<Contact::Components::ID>(_self).data) << " id:" << bin2hex(cr.get<Contact::Components::ID>(_self).data)
<< "\n"; << "\n";
} }
if (user.entity() != _self) { if (user.entity() != _self) {
user.emplace_or_replace<Contact::Components::ConnectionState>(Contact::Components::ConnectionState::State::cloud); user.emplace_or_replace<Contact::Components::ConnectionState>(Contact::Components::ConnectionState::State::cloud);
user.emplace_or_replace<Contact::Components::Self>(_self); user.emplace_or_replace<Contact::Components::Self>(_self);
user_throw_event = true;
}
if (user_throw_event) {
if (user_created) {
_cs.throwEventConstruct(user);
} else {
_cs.throwEventUpdate(user);
}
} }
{ // add user to channel { // add user to channel
@ -450,6 +528,7 @@ bool IRCClientContactModel::onEvent(const IRCClient::Events::Join& e) {
if (std::find(channel_user_list.begin(), channel_user_list.end(), user) == channel_user_list.end()) { if (std::find(channel_user_list.begin(), channel_user_list.end(), user) == channel_user_list.end()) {
//std::cout << "!!!!!!!! new user in channel!\n"; //std::cout << "!!!!!!!! new user in channel!\n";
channel_user_list.push_back(user); channel_user_list.push_back(user);
_cs.throwEventUpdate(channel);
} }
} }
@ -464,7 +543,7 @@ bool IRCClientContactModel::onEvent(const IRCClient::Events::Part& e) {
// e.origin // is the parting user // e.origin // is the parting user
auto user = getU(e.origin); auto user = getU(e.origin);
if (!user.valid()) { if (!static_cast<bool>(user)) {
// ignoring unknown users, might be caused by a bug // ignoring unknown users, might be caused by a bug
std::cerr << "ignoring unknown users, might be caused by a bug\n"; std::cerr << "ignoring unknown users, might be caused by a bug\n";
return false; return false;
@ -472,7 +551,7 @@ bool IRCClientContactModel::onEvent(const IRCClient::Events::Part& e) {
// e.params.front() is the channel // e.params.front() is the channel
auto channel = getC(e.params.front()); auto channel = getC(e.params.front());
if (!channel.valid()) { if (!static_cast<bool>(channel)) {
// ignoring unknown channel, might be caused by a bug // ignoring unknown channel, might be caused by a bug
std::cerr << "ignoring unknown channel, might be caused by a bug\n"; std::cerr << "ignoring unknown channel, might be caused by a bug\n";
return false; return false;
@ -483,11 +562,14 @@ bool IRCClientContactModel::onEvent(const IRCClient::Events::Part& e) {
if (auto it = std::find(channel_user_list.begin(), channel_user_list.end(), user); it != channel_user_list.end()) { if (auto it = std::find(channel_user_list.begin(), channel_user_list.end(), user); it != channel_user_list.end()) {
//std::cout << "!!!!!!!! removing user from channel!\n"; //std::cout << "!!!!!!!! removing user from channel!\n";
channel_user_list.erase(it); channel_user_list.erase(it);
_cs.throwEventUpdate(channel);
} else { } else {
//std::cout << "!!!!!!!! unknown user leaving channel!\n"; //std::cout << "!!!!!!!! unknown user leaving channel!\n";
} }
} }
_cs.throwEventUpdate(user); // ??
return false; return false;
} }
@ -504,13 +586,14 @@ bool IRCClientContactModel::onEvent(const IRCClient::Events::Topic& e) {
const auto channel_name = e.params.at(0); const auto channel_name = e.params.at(0);
auto channel = getC(channel_name); auto channel = getC(channel_name);
if (!channel.valid()) { if (!static_cast<bool>(channel)) {
std::cerr << "IRCCCM error: new topic for unknown channel\n"; std::cerr << "IRCCCM error: new topic for unknown channel\n";
return false; return false;
} }
const auto topic = e.params.at(1); const auto topic = e.params.at(1);
channel.emplace_or_replace<Contact::Components::StatusText>(std::string{topic}).fillFirstLineLength(); channel.emplace_or_replace<Contact::Components::StatusText>(std::string{topic}).fillFirstLineLength();
_cs.throwEventUpdate(channel);
return false; return false;
} }
@ -520,7 +603,7 @@ bool IRCClientContactModel::onEvent(const IRCClient::Events::Quit& e) {
// e.params.front() is the quit reason // e.params.front() is the quit reason
auto user = getU(e.origin); auto user = getU(e.origin);
if (!user.valid()) { if (!static_cast<bool>(user)) {
// ignoring unknown users, might be caused by a bug // ignoring unknown users, might be caused by a bug
return false; return false;
} }
@ -531,6 +614,8 @@ bool IRCClientContactModel::onEvent(const IRCClient::Events::Quit& e) {
// should we remove the user from the channel? // should we remove the user from the channel?
_cs.throwEventUpdate(user);
return false; return false;
} }
@ -545,3 +630,36 @@ bool IRCClientContactModel::onEvent(const IRCClient::Events::CTCP_Req& e) {
return false; return false;
} }
bool IRCClientContactModel::onEvent(const IRCClient::Events::Disconnect&) {
_connected = false;
auto& cr = _cs.registry();
if (!cr.valid(_server)) {
// skip if where already offline
return false;
}
cr.get<Contact::Components::ConnectionState>(_server).state = Contact::Components::ConnectionState::disconnected;
// HACK: by name
ContactHandle4 server;
cr.view<Contact::Components::IRC::ServerName, Contact::Components::ConnectionState>().each([this, &server](const auto c, const auto& sn_c, auto&) {
// HACK: by name
// should be by parent instead
if (sn_c.name != _ircc.getServerName()) {
return;
}
server = _cs.contactHandle(c);
});
if (!static_cast<bool>(server)) {
return false;
}
server.get_or_emplace<Contact::Components::ConnectionState>().state = Contact::Components::ConnectionState::disconnected;
_cs.throwEventUpdate(server);
return false;
}

View File

@ -1,10 +1,12 @@
#pragma once #pragma once
#include <solanaceae/contact/contact_model3.hpp> #include <solanaceae/contact/contact_model4.hpp>
#include <solanaceae/util/config_model.hpp> #include <solanaceae/util/config_model.hpp>
#include <solanaceae/ircclient/ircclient.hpp> #include <solanaceae/ircclient/ircclient.hpp>
#include <entt/entity/entity.hpp>
#include <vector> #include <vector>
#include <string> #include <string>
#include <queue> #include <queue>
@ -12,24 +14,25 @@
#include <iostream> // tmp #include <iostream> // tmp
class IRCClientContactModel : public IRCClientEventI, public ContactModel3I { class IRCClientContactModel : public IRCClientEventI, public ContactModel4I {
Contact3Registry& _cr; ContactStore4I& _cs;
ConfigModelI& _conf; ConfigModelI& _conf;
IRCClient1& _ircc; IRCClient1& _ircc;
IRCClient1::SubscriptionReference _ircc_sr;
// cm needs the connect event to happen // cm needs the connect event to happen
bool _connected {false}; bool _connected {false};
std::vector<uint8_t> _server_hash; // cached for id gen std::vector<uint8_t> _server_hash; // cached for id gen
Contact3 _server = entt::null; Contact4 _server {entt::null};
Contact3 _self = entt::null; Contact4 _self {entt::null};
// used if not connected // used if not connected
std::queue<std::string> _join_queue; std::queue<std::string> _join_queue;
public: public:
IRCClientContactModel( IRCClientContactModel(
Contact3Registry& cr, ContactStore4I& cs,
ConfigModelI& conf, ConfigModelI& conf,
IRCClient1& ircc IRCClient1& ircc
); );
@ -38,6 +41,11 @@ class IRCClientContactModel : public IRCClientEventI, public ContactModel3I {
void join(const std::string& channel); void join(const std::string& channel);
protected: // interface
bool addContact(Contact4 c) override;
bool acceptRequest(Contact4 c, std::string_view self_name, std::string_view password) override;
bool leave(Contact4 c, std::string_view reason) override;
private: private:
// just the hash algo // just the hash algo
std::vector<uint8_t> getHash(std::string_view value); std::vector<uint8_t> getHash(std::string_view value);
@ -48,10 +56,10 @@ class IRCClientContactModel : public IRCClientEventI, public ContactModel3I {
// eg: hash(hash(ServerName)+ChannelName) // eg: hash(hash(ServerName)+ChannelName)
std::vector<uint8_t> getIDHash(std::string_view name); std::vector<uint8_t> getIDHash(std::string_view name);
Contact3Handle getC(std::string_view channel); ContactHandle4 getC(std::string_view channel);
Contact3Handle getU(std::string_view nick); ContactHandle4 getU(std::string_view nick);
// user or channel using channel prefix // user or channel using channel prefix
Contact3Handle getCU(std::string_view name); ContactHandle4 getCU(std::string_view name);
private: // ircclient private: // ircclient
bool onEvent(const IRCClient::Events::Connect& e) override; bool onEvent(const IRCClient::Events::Connect& e) override;
@ -61,4 +69,5 @@ class IRCClientContactModel : public IRCClientEventI, public ContactModel3I {
bool onEvent(const IRCClient::Events::Topic& e) override; bool onEvent(const IRCClient::Events::Topic& e) override;
bool onEvent(const IRCClient::Events::Quit& e) override; bool onEvent(const IRCClient::Events::Quit& e) override;
bool onEvent(const IRCClient::Events::CTCP_Req&) override; bool onEvent(const IRCClient::Events::CTCP_Req&) override;
bool onEvent(const IRCClient::Events::Disconnect&) override;
}; };

View File

@ -1,8 +1,11 @@
#include "./ircclient_message_manager.hpp" #include "./ircclient_message_manager.hpp"
#include <solanaceae/util/time.hpp>
#include <solanaceae/ircclient_contacts/components.hpp> #include <solanaceae/ircclient_contacts/components.hpp>
#include <solanaceae/contact/components.hpp> #include <solanaceae/contact/components.hpp>
#include <solanaceae/contact/contact_store_i.hpp>
#include <solanaceae/message3/components.hpp> #include <solanaceae/message3/components.hpp>
#include <solanaceae/message3/registry_message_model.hpp> #include <solanaceae/message3/registry_message_model.hpp>
@ -17,26 +20,28 @@
#include <iostream> #include <iostream>
IRCClientMessageManager::IRCClientMessageManager( IRCClientMessageManager::IRCClientMessageManager(
RegistryMessageModel& rmm, RegistryMessageModelI& rmm,
Contact3Registry& cr, ContactStore4I& cs,
ConfigModelI& conf, ConfigModelI& conf,
IRCClient1& ircc, IRCClient1& ircc,
IRCClientContactModel& ircccm IRCClientContactModel& ircccm
) : _rmm(rmm), _cr(cr), _conf(conf), _ircc(ircc), _ircccm(ircccm) { ) : _rmm(rmm), _rmm_sr(_rmm.newSubRef(this)), _cs(cs), _conf(conf), _ircc(ircc), _ircc_sr(_ircc.newSubRef(this)), _ircccm(ircccm) {
_ircc.subscribe(this, IRCClient_Event::CHANNEL); _ircc_sr
_ircc.subscribe(this, IRCClient_Event::PRIVMSG); .subscribe(IRCClient_Event::CHANNEL)
_ircc.subscribe(this, IRCClient_Event::NOTICE); .subscribe(IRCClient_Event::PRIVMSG)
_ircc.subscribe(this, IRCClient_Event::CHANNELNOTICE); .subscribe(IRCClient_Event::NOTICE)
_ircc.subscribe(this, IRCClient_Event::CTCP_ACTION); .subscribe(IRCClient_Event::CHANNELNOTICE)
.subscribe(IRCClient_Event::CTCP_ACTION)
;
_rmm.subscribe(this, RegistryMessageModel_Event::send_text); _rmm_sr.subscribe(RegistryMessageModel_Event::send_text);
} }
IRCClientMessageManager::~IRCClientMessageManager(void) { IRCClientMessageManager::~IRCClientMessageManager(void) {
} }
bool IRCClientMessageManager::processMessage(Contact3Handle from, Contact3Handle to, std::string_view message_text, bool action) { bool IRCClientMessageManager::processMessage(ContactHandle4 from, ContactHandle4 to, std::string_view message_text, bool action) {
const uint64_t ts = Message::getTimeMS(); const uint64_t ts = getTimeMS();
Message3Registry* reg_ptr = nullptr; Message3Registry* reg_ptr = nullptr;
if (to.all_of<Contact::Components::TagSelfStrong>()) { if (to.all_of<Contact::Components::TagSelfStrong>()) {
@ -77,8 +82,10 @@ bool IRCClientMessageManager::processMessage(Contact3Handle from, Contact3Handle
return false; return false;
} }
bool IRCClientMessageManager::sendText(const Contact3 c, std::string_view message, bool action) { bool IRCClientMessageManager::sendText(const Contact4 c, std::string_view message, bool action) {
if (!_cr.valid(c)) { const auto& cr = _cs.registry();
if (!cr.valid(c)) {
return false; return false;
} }
@ -86,23 +93,23 @@ bool IRCClientMessageManager::sendText(const Contact3 c, std::string_view messag
return false; // TODO: empty messages allowed? return false; // TODO: empty messages allowed?
} }
const uint64_t ts = Message::getTimeMS(); const uint64_t ts = getTimeMS();
if (_cr.all_of<Contact::Components::TagSelfStrong>(c)) { if (cr.all_of<Contact::Components::TagSelfStrong>(c)) {
return false; // message to self? not with irc return false; // message to self? not with irc
} }
// test for contact irc specific components // test for contact irc specific components
// TODO: what about commands and server messages? // TODO: what about commands and server messages?
if (!_cr.any_of<Contact::Components::IRC::UserName, Contact::Components::IRC::ChannelName>(c)) { if (!cr.any_of<Contact::Components::IRC::UserName, Contact::Components::IRC::ChannelName>(c)) {
return false; return false;
} }
std::string to_str; std::string to_str;
if (_cr.all_of<Contact::Components::IRC::UserName>(c)) { if (cr.all_of<Contact::Components::IRC::UserName>(c)) {
to_str = _cr.get<Contact::Components::IRC::UserName>(c).name; to_str = cr.get<Contact::Components::IRC::UserName>(c).name;
} else { } else {
to_str = _cr.get<Contact::Components::IRC::ChannelName>(c).name; to_str = cr.get<Contact::Components::IRC::ChannelName>(c).name;
} }
auto* reg_ptr = _rmm.get(c); auto* reg_ptr = _rmm.get(c);
@ -110,7 +117,7 @@ bool IRCClientMessageManager::sendText(const Contact3 c, std::string_view messag
return false; // nope return false; // nope
} }
if (!_cr.all_of<Contact::Components::Self>(c)) { if (!cr.all_of<Contact::Components::Self>(c)) {
std::cerr << "IRCCMM error: cant get self\n"; std::cerr << "IRCCMM error: cant get self\n";
return false; return false;
} }
@ -141,7 +148,7 @@ bool IRCClientMessageManager::sendText(const Contact3 c, std::string_view messag
} }
} }
const Contact3 c_self = _cr.get<Contact::Components::Self>(c).self; const Contact4 c_self = cr.get<Contact::Components::Self>(c).self;
auto new_msg = Message3Handle{*reg_ptr, reg_ptr->create()}; auto new_msg = Message3Handle{*reg_ptr, reg_ptr->create()};
@ -174,14 +181,14 @@ bool IRCClientMessageManager::onEvent(const IRCClient::Events::Channel& e) {
// e.origin is sender // e.origin is sender
auto sender = _ircccm.getU(e.origin); // assuming its always a user // aka ContactFrom auto sender = _ircccm.getU(e.origin); // assuming its always a user // aka ContactFrom
if (!sender.valid()) { if (!static_cast<bool>(sender)) {
std::cerr << "IRCCMM error: channel event unknown sender\n"; std::cerr << "IRCCMM error: channel event unknown sender\n";
return false; return false;
} }
// e.params.at(0) is channel // e.params.at(0) is channel
auto channel = _ircccm.getC(e.params.at(0)); // aka ContactTo auto channel = _ircccm.getC(e.params.at(0)); // aka ContactTo
if (!channel.valid()) { if (!static_cast<bool>(channel)) {
std::cerr << "IRCCMM error: channel event unknown channel\n"; std::cerr << "IRCCMM error: channel event unknown channel\n";
return false; return false;
} }
@ -200,14 +207,14 @@ bool IRCClientMessageManager::onEvent(const IRCClient::Events::PrivMSG& e) {
// e.origin is sender // e.origin is sender
auto from = _ircccm.getU(e.origin); // assuming its always a user // aka ContactFrom auto from = _ircccm.getU(e.origin); // assuming its always a user // aka ContactFrom
if (!from.valid()) { if (!static_cast<bool>(from)) {
std::cerr << "IRCCMM error: privmsg event unknown sender\n"; std::cerr << "IRCCMM error: privmsg event unknown sender\n";
return false; return false;
} }
// e.params.at(0) is receiver (us?) // e.params.at(0) is receiver (us?)
auto to = _ircccm.getU(e.params.at(0)); // aka ContactTo auto to = _ircccm.getU(e.params.at(0)); // aka ContactTo
if (!to.valid()) { if (!static_cast<bool>(to)) {
std::cerr << "IRCCMM error: privmsg event unknown channel\n"; std::cerr << "IRCCMM error: privmsg event unknown channel\n";
return false; return false;
} }
@ -252,14 +259,14 @@ bool IRCClientMessageManager::onEvent(const IRCClient::Events::ChannelNotice& e)
// e.origin is sending user (probably) // e.origin is sending user (probably)
auto from = _ircccm.getU(e.origin); auto from = _ircccm.getU(e.origin);
if (!from.valid()) { if (!static_cast<bool>(from)) {
std::cerr << "IRCCMM error: channel notice event unknown sender\n"; std::cerr << "IRCCMM error: channel notice event unknown sender\n";
return false; return false;
} }
// e.params.at(0) is channel // e.params.at(0) is channel
auto to = _ircccm.getC(e.params.at(0)); auto to = _ircccm.getC(e.params.at(0));
if (!to.valid()) { if (!static_cast<bool>(to)) {
std::cerr << "IRCCMM error: unknown receiver\n"; std::cerr << "IRCCMM error: unknown receiver\n";
return false; return false;
} }
@ -278,14 +285,14 @@ bool IRCClientMessageManager::onEvent(const IRCClient::Events::CTCP_Action& e) {
// e.origin is sender // e.origin is sender
auto from = _ircccm.getU(e.origin); // assuming its always a user // aka ContactFrom auto from = _ircccm.getU(e.origin); // assuming its always a user // aka ContactFrom
if (!from.valid()) { if (!static_cast<bool>(from)) {
std::cerr << "IRCCMM error: channel event unknown sender\n"; std::cerr << "IRCCMM error: channel event unknown sender\n";
return false; return false;
} }
// e.params.at(0) is receiver (self if pm or channel if channel) // e.params.at(0) is receiver (self if pm or channel if channel)
auto receiver = _ircccm.getCU(e.params.at(0)); auto receiver = _ircccm.getCU(e.params.at(0));
if (!receiver.valid()) { if (!static_cast<bool>(receiver)) {
std::cerr << "IRCCMM error: unknown receiver\n"; std::cerr << "IRCCMM error: unknown receiver\n";
return false; return false;
} }

View File

@ -6,16 +6,18 @@
class IRCClientMessageManager : public IRCClientEventI, public RegistryMessageModelEventI { class IRCClientMessageManager : public IRCClientEventI, public RegistryMessageModelEventI {
protected: protected:
RegistryMessageModel& _rmm; RegistryMessageModelI& _rmm;
Contact3Registry& _cr; RegistryMessageModelI::SubscriptionReference _rmm_sr;
ContactStore4I& _cs;
ConfigModelI& _conf; ConfigModelI& _conf;
IRCClient1& _ircc; IRCClient1& _ircc;
IRCClient1::SubscriptionReference _ircc_sr;
IRCClientContactModel& _ircccm; IRCClientContactModel& _ircccm;
public: public:
IRCClientMessageManager( IRCClientMessageManager(
RegistryMessageModel& rmm, RegistryMessageModelI& rmm,
Contact3Registry& cr, ContactStore4I& cs,
ConfigModelI& conf, ConfigModelI& conf,
IRCClient1& ircc, IRCClient1& ircc,
IRCClientContactModel& ircccm IRCClientContactModel& ircccm
@ -27,10 +29,10 @@ class IRCClientMessageManager : public IRCClientEventI, public RegistryMessageMo
using IRCClientEventI::onEvent; using IRCClientEventI::onEvent;
using RegistryMessageModelEventI::onEvent; using RegistryMessageModelEventI::onEvent;
private: private:
bool processMessage(Contact3Handle from, Contact3Handle to, std::string_view message_text, bool action); bool processMessage(ContactHandle4 from, ContactHandle4 to, std::string_view message_text, bool action);
private: // mm3 private: // mm3
bool sendText(const Contact3 c, std::string_view message, bool action = false) override; bool sendText(const Contact4 c, std::string_view message, bool action = false) override;
private: // ircclient private: // ircclient
bool onEvent(const IRCClient::Events::Channel& e) override; bool onEvent(const IRCClient::Events::Channel& e) override;

View File

@ -1,6 +1,7 @@
#include <chrono>
#include <solanaceae/util/simple_config_model.hpp> #include <solanaceae/util/simple_config_model.hpp>
#include <solanaceae/contact/contact_model3.hpp> #include <solanaceae/contact/contact_model3.hpp>
#include <solanaceae/message3/registry_message_model.hpp> #include <solanaceae/message3/registry_message_model_impl.hpp>
#include <solanaceae/ircclient/ircclient.hpp> #include <solanaceae/ircclient/ircclient.hpp>
#include <solanaceae/ircclient_contacts/ircclient_contact_model.hpp> #include <solanaceae/ircclient_contacts/ircclient_contact_model.hpp>
#include <solanaceae/ircclient_messages/ircclient_message_manager.hpp> #include <solanaceae/ircclient_messages/ircclient_message_manager.hpp>
@ -9,6 +10,8 @@
#include <iostream> #include <iostream>
#include <string_view> #include <string_view>
#include <thread>
#include <chrono>
int main(void) { int main(void) {
SimpleConfigModel conf; SimpleConfigModel conf;
@ -19,7 +22,7 @@ int main(void) {
conf.set("IRCClient", "autojoin", "#green_testing", true); conf.set("IRCClient", "autojoin", "#green_testing", true);
Contact3Registry cr; Contact3Registry cr;
RegistryMessageModel rmm{cr}; RegistryMessageModelImpl rmm{cr};
IRCClient1 ircc{conf}; IRCClient1 ircc{conf};
@ -29,7 +32,8 @@ int main(void) {
//ircccm.join("#green_testing"); //ircccm.join("#green_testing");
while (irc_is_connected(ircc.getSession())) { while (irc_is_connected(ircc.getSession())) {
ircc.iterate(); ircc.iterate(0.005f);
std::this_thread::sleep_for(std::chrono::milliseconds(5));
} }
return 0; return 0;