Compare commits
13 Commits
ddb0066733
...
master
Author | SHA1 | Date | |
---|---|---|---|
dd462b450e | |||
344af9dc4b | |||
b63bc1dd0f | |||
c5bf212ab9 | |||
41d86bfd8f | |||
82a0fc0d36 | |||
34908967aa | |||
b21acd4c99 | |||
ea63233452 | |||
09c09e1bb2 | |||
d9ee8f9dc4 | |||
158860e1b0 | |||
759cd414ab |
21
LICENSE
Normal file
21
LICENSE
Normal 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.
|
10
external/CMakeLists.txt
vendored
10
external/CMakeLists.txt
vendored
@ -2,16 +2,6 @@ cmake_minimum_required(VERSION 3.14...3.24 FATAL_ERROR)
|
||||
|
||||
include(FetchContent)
|
||||
|
||||
# TODO: move entt dep into solanaceae_contact
|
||||
if (NOT TARGET EnTT::EnTT)
|
||||
FetchContent_Declare(EnTT
|
||||
GIT_REPOSITORY https://github.com/skypjack/entt.git
|
||||
GIT_TAG v3.12.2
|
||||
EXCLUDE_FROM_ALL
|
||||
)
|
||||
FetchContent_MakeAvailable(EnTT)
|
||||
endif()
|
||||
|
||||
if (NOT TARGET solanaceae_util)
|
||||
FetchContent_Declare(solanaceae_util
|
||||
GIT_REPOSITORY https://github.com/Green-Sky/solanaceae_util.git
|
||||
|
@ -1,9 +1,14 @@
|
||||
cmake_minimum_required(VERSION 3.14...3.24 FATAL_ERROR)
|
||||
|
||||
add_library(plugin_bridge SHARED
|
||||
add_library(plugin_bridge MODULE
|
||||
./plugin_bridge.cpp
|
||||
)
|
||||
|
||||
set_target_properties(plugin_bridge PROPERTIES
|
||||
C_VISIBILITY_PRESET hidden
|
||||
)
|
||||
target_compile_definitions(plugin_bridge PUBLIC ENTT_API_IMPORT)
|
||||
|
||||
target_link_libraries(plugin_bridge PUBLIC
|
||||
solanaceae_plugin
|
||||
solanaceae_bridge
|
||||
|
@ -2,19 +2,22 @@
|
||||
|
||||
#include "../src/bridge.hpp"
|
||||
|
||||
#include <solanaceae/util/config_model.hpp>
|
||||
#include <solanaceae/contact/contact_store_i.hpp>
|
||||
#include <solanaceae/message3/message_command_dispatcher.hpp>
|
||||
|
||||
#include <memory>
|
||||
#include <limits>
|
||||
#include <iostream>
|
||||
|
||||
#define RESOLVE_INSTANCE(x) static_cast<x*>(solana_api->resolveInstance(#x))
|
||||
#define PROVIDE_INSTANCE(x, p, v) solana_api->provideInstance(#x, p, static_cast<x*>(v))
|
||||
|
||||
static std::unique_ptr<Bridge> g_bridge = nullptr;
|
||||
|
||||
constexpr const char* plugin_name = "Bridge";
|
||||
|
||||
extern "C" {
|
||||
|
||||
SOLANA_PLUGIN_EXPORT const char* solana_plugin_get_name(void) {
|
||||
return "Bridge";
|
||||
return plugin_name;
|
||||
}
|
||||
|
||||
SOLANA_PLUGIN_EXPORT uint32_t solana_plugin_get_version(void) {
|
||||
@ -22,59 +25,42 @@ SOLANA_PLUGIN_EXPORT uint32_t solana_plugin_get_version(void) {
|
||||
}
|
||||
|
||||
SOLANA_PLUGIN_EXPORT uint32_t solana_plugin_start(struct SolanaAPI* solana_api) {
|
||||
std::cout << "PLUGIN Bridge START()\n";
|
||||
std::cout << "PLUGIN " << plugin_name << " START()\n";
|
||||
|
||||
if (solana_api == nullptr) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
Contact3Registry* cr = nullptr;
|
||||
RegistryMessageModel* rmm = nullptr;
|
||||
ConfigModelI* conf = nullptr;
|
||||
MessageCommandDispatcher* mcd = nullptr;
|
||||
try {
|
||||
auto* cs = PLUG_RESOLVE_INSTANCE(ContactStore4I);
|
||||
auto* rmm = PLUG_RESOLVE_INSTANCE(RegistryMessageModelI);
|
||||
auto* conf = PLUG_RESOLVE_INSTANCE(ConfigModelI);
|
||||
|
||||
{ // make sure required types are loaded
|
||||
cr = RESOLVE_INSTANCE(Contact3Registry);
|
||||
rmm = RESOLVE_INSTANCE(RegistryMessageModel);
|
||||
conf = RESOLVE_INSTANCE(ConfigModelI);
|
||||
mcd = RESOLVE_INSTANCE(MessageCommandDispatcher);
|
||||
|
||||
if (cr == nullptr) {
|
||||
std::cerr << "PLUGIN Bridge missing Contact3Registry\n";
|
||||
return 2;
|
||||
}
|
||||
|
||||
if (rmm == nullptr) {
|
||||
std::cerr << "PLUGIN Bridge missing RegistryMessageModel\n";
|
||||
return 2;
|
||||
}
|
||||
|
||||
if (conf == nullptr) {
|
||||
std::cerr << "PLUGIN Bridge missing ConfigModelI\n";
|
||||
return 2;
|
||||
}
|
||||
|
||||
// missing mcd is no error
|
||||
}
|
||||
// optional dep
|
||||
auto* mcd = PLUG_RESOLVE_INSTANCE_OPT(MessageCommandDispatcher);
|
||||
|
||||
// static store, could be anywhere tho
|
||||
// construct with fetched dependencies
|
||||
g_bridge = std::make_unique<Bridge>(*cr, *rmm, *conf, mcd);
|
||||
g_bridge = std::make_unique<Bridge>(*cs, *rmm, *conf, mcd);
|
||||
|
||||
// register types
|
||||
PROVIDE_INSTANCE(Bridge, "Bridge", g_bridge.get());
|
||||
PLUG_PROVIDE_INSTANCE(Bridge, plugin_name, g_bridge.get());
|
||||
} catch (const ResolveException& e) {
|
||||
std::cerr << "PLUGIN " << plugin_name << " " << e.what << "\n";
|
||||
return 2;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
SOLANA_PLUGIN_EXPORT void solana_plugin_stop(void) {
|
||||
std::cout << "PLUGIN Bridge STOP()\n";
|
||||
std::cout << "PLUGIN " << plugin_name << " STOP()\n";
|
||||
|
||||
g_bridge.reset();
|
||||
}
|
||||
|
||||
SOLANA_PLUGIN_EXPORT float solana_plugin_tick(float delta) {
|
||||
g_bridge->iterate(delta);
|
||||
SOLANA_PLUGIN_EXPORT float solana_plugin_tick(float time_delta) {
|
||||
g_bridge->iterate(time_delta);
|
||||
|
||||
return std::numeric_limits<float>::max();
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
cmake_minimum_required(VERSION 3.9 FATAL_ERROR)
|
||||
cmake_minimum_required(VERSION 3.14...3.24 FATAL_ERROR)
|
||||
|
||||
add_library(solanaceae_bridge STATIC
|
||||
./bridge.hpp
|
||||
|
@ -2,6 +2,8 @@
|
||||
|
||||
#include <solanaceae/util/config_model.hpp>
|
||||
#include <solanaceae/util/utils.hpp>
|
||||
#include <solanaceae/util/time.hpp>
|
||||
#include <solanaceae/contact/contact_store_i.hpp>
|
||||
#include <solanaceae/contact/components.hpp>
|
||||
#include <solanaceae/message3/components.hpp>
|
||||
#include <solanaceae/message3/message_command_dispatcher.hpp>
|
||||
@ -9,12 +11,12 @@
|
||||
#include <iostream>
|
||||
|
||||
Bridge::Bridge(
|
||||
Contact3Registry& cr,
|
||||
RegistryMessageModel& rmm,
|
||||
ContactStore4I& cs,
|
||||
RegistryMessageModelI& rmm,
|
||||
ConfigModelI& conf,
|
||||
MessageCommandDispatcher* mcd
|
||||
) : _cr(cr), _rmm(rmm), _conf(conf), _mcd(mcd) {
|
||||
_rmm.subscribe(this, enumType::message_construct);
|
||||
) : _cs(cs), _rmm(rmm), _rmm_sr(_rmm.newSubRef(this)), _conf(conf), _mcd(mcd) {
|
||||
_rmm_sr.subscribe(RegistryMessageModel_Event::message_construct);
|
||||
|
||||
if (!_conf.has_bool("Bridge", "username_angle_brackets")) {
|
||||
_conf.set("Bridge", "username_angle_brackets", true);
|
||||
@ -37,7 +39,8 @@ Bridge::Bridge(
|
||||
auto& v_group = _vgroups.at(tmp_name_to_id.at(tmp_vgroup_str));
|
||||
|
||||
auto& new_vgc = v_group.contacts.emplace_back();
|
||||
new_vgc.c = {_cr, entt::null}; // this is annoying af
|
||||
//new_vgc.c = {}; // TODO: does this work here?
|
||||
new_vgc.c = _cs.contactHandle(entt::null);
|
||||
new_vgc.id = hex2bin(contact_id);
|
||||
}
|
||||
|
||||
@ -66,10 +69,10 @@ void Bridge::updateVGroups(void) {
|
||||
|
||||
if (!vgc.c.valid()) {
|
||||
// search
|
||||
auto view = _cr.view<Contact::Components::TagBig, Contact::Components::ID>();
|
||||
auto view = _cs.registry().view<Contact::Components::TagBig, Contact::Components::ID>();
|
||||
for (const auto c : view) {
|
||||
if (view.get<Contact::Components::ID>(c).data == vgc.id) {
|
||||
vgc.c = {_cr, c};
|
||||
vgc.c = _cs.contactHandle(c);
|
||||
std::cout << "Bridge: found contact for vgroup\n";
|
||||
break;
|
||||
}
|
||||
@ -95,15 +98,30 @@ void Bridge::registerCommands(void) {
|
||||
const auto contact_from = m.get<Message::Components::ContactFrom>().c;
|
||||
const auto contact_to = m.get<Message::Components::ContactTo>().c;
|
||||
|
||||
// TODO: if no vgroup name supplied
|
||||
ContactHandle4 group_contact;
|
||||
const VirtualGroups* vg = nullptr;
|
||||
|
||||
Contact3Handle group_contact;
|
||||
if (/*is public ?*/ _c_to_vg.count({_cr, contact_to})) {
|
||||
if (!params.empty()) { // vgroup_name supplied
|
||||
for (const auto& vg_it : _vgroups) {
|
||||
if (vg_it.vg_name == params) {
|
||||
vg = &vg_it;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (vg == nullptr) {
|
||||
_rmm.sendText(
|
||||
contact_from,
|
||||
"The supplied vgroup name does not exist!"
|
||||
);
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
if (/*is public ?*/ _c_to_vg.count(_cs.contactHandle(contact_to))) {
|
||||
// message was sent public in group
|
||||
group_contact = {_cr, contact_to};
|
||||
} else if (_cr.all_of<Contact::Components::Parent>(contact_from)) {
|
||||
group_contact = _cs.contactHandle(contact_to);
|
||||
} else if (_cs.registry().all_of<Contact::Components::Parent>(contact_from)) {
|
||||
// use parent of sender
|
||||
group_contact = {_cr, _cr.get<Contact::Components::Parent>(contact_from).parent};
|
||||
group_contact = _cs.contactHandle(_cs.registry().get<Contact::Components::Parent>(contact_from).parent);
|
||||
} else if (false /* parent of contact_to ? */) {
|
||||
}
|
||||
|
||||
@ -117,13 +135,16 @@ void Bridge::registerCommands(void) {
|
||||
}
|
||||
|
||||
assert(static_cast<bool>(group_contact));
|
||||
const auto& vg = _vgroups.at(_c_to_vg.at(group_contact));
|
||||
vg = &_vgroups.at(_c_to_vg.at(group_contact));
|
||||
}
|
||||
|
||||
assert(vg != nullptr);
|
||||
|
||||
_rmm.sendText(
|
||||
contact_from,
|
||||
"Contacts online in other bridged group(s) in vgroup '" + vg.vg_name + "'"
|
||||
"Contacts online in other bridged group(s) in vgroup '" + vg->vg_name + "'"
|
||||
);
|
||||
for (const auto& vgc : vg.contacts) {
|
||||
for (const auto& vgc : vg->contacts) {
|
||||
if (vgc.c == group_contact) {
|
||||
// skip self
|
||||
continue;
|
||||
@ -137,10 +158,12 @@ void Bridge::registerCommands(void) {
|
||||
"' id:" + bin2hex(vgc.id)
|
||||
);
|
||||
|
||||
const auto& cr = _cs.registry();
|
||||
|
||||
// for each sub contact
|
||||
for (const auto& sub_c : vgc.c.get<Contact::Components::ParentOf>().subs) {
|
||||
if (
|
||||
const auto* sub_cs = _cr.try_get<Contact::Components::ConnectionState>(sub_c);
|
||||
const auto* sub_cs = cr.try_get<Contact::Components::ConnectionState>(sub_c);
|
||||
sub_cs != nullptr && sub_cs->state == Contact::Components::ConnectionState::disconnected
|
||||
) {
|
||||
// skip offline
|
||||
@ -150,9 +173,9 @@ void Bridge::registerCommands(void) {
|
||||
_rmm.sendText(
|
||||
contact_from,
|
||||
" '" +
|
||||
(_cr.all_of<Contact::Components::Name>(sub_c) ? _cr.get<Contact::Components::Name>(sub_c).name : "<unk>") +
|
||||
(cr.all_of<Contact::Components::Name>(sub_c) ? cr.get<Contact::Components::Name>(sub_c).name : "<unk>") +
|
||||
"'" +
|
||||
(_cr.all_of<Contact::Components::ID>(sub_c) ? " id:" + bin2hex(vgc.id) : "")
|
||||
(cr.all_of<Contact::Components::ID>(sub_c) ? " id:" + bin2hex(cr.get<Contact::Components::ID>(sub_c).data) : "")
|
||||
);
|
||||
}
|
||||
|
||||
@ -174,7 +197,7 @@ void Bridge::registerCommands(void) {
|
||||
std::cout << "Bridge: registered commands\n";
|
||||
}
|
||||
|
||||
const Bridge::VirtualGroups* Bridge::findVGforContact(const Contact3Handle& c) {
|
||||
const Bridge::VirtualGroups* Bridge::findVGforContact(const ContactHandle4& c) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@ -192,20 +215,22 @@ bool Bridge::onEvent(const Message::Events::MessageConstruct& e) {
|
||||
}
|
||||
|
||||
if (e.e.all_of<Message::Components::Timestamp>()) {
|
||||
int64_t time_diff = int64_t(Message::getTimeMS()) - int64_t(e.e.get<Message::Components::Timestamp>().ts);
|
||||
int64_t time_diff = int64_t(getTimeMS()) - int64_t(e.e.get<Message::Components::Timestamp>().ts);
|
||||
if (time_diff > 5*1000*60) {
|
||||
return false; // message too old
|
||||
}
|
||||
}
|
||||
|
||||
const auto& cr = _cs.registry();
|
||||
|
||||
const auto contact_from = e.e.get<Message::Components::ContactFrom>().c;
|
||||
if (_cr.any_of<Contact::Components::TagSelfStrong, Contact::Components::TagSelfWeak>(contact_from)) {
|
||||
if (cr.any_of<Contact::Components::TagSelfStrong, Contact::Components::TagSelfWeak>(contact_from)) {
|
||||
return false; // skip own messages
|
||||
}
|
||||
|
||||
const auto contact_to = e.e.get<Message::Components::ContactTo>().c;
|
||||
// if e.e <contact to> is in c to vg
|
||||
const auto it = _c_to_vg.find(Contact3Handle{_cr, contact_to});
|
||||
const auto it = _c_to_vg.find(_cs.contactHandle(contact_to));
|
||||
if (it == _c_to_vg.cend()) {
|
||||
return false; // contact is not bridged
|
||||
}
|
||||
@ -220,8 +245,8 @@ bool Bridge::onEvent(const Message::Events::MessageConstruct& e) {
|
||||
from_str += "<";
|
||||
}
|
||||
|
||||
if (_cr.all_of<Contact::Components::Name>(contact_from)) {
|
||||
const auto& name = _cr.get<Contact::Components::Name>(contact_from).name;
|
||||
if (cr.all_of<Contact::Components::Name>(contact_from)) {
|
||||
const auto& name = cr.get<Contact::Components::Name>(contact_from).name;
|
||||
if (name.empty()) {
|
||||
from_str += "UNK";
|
||||
} else {
|
||||
@ -230,9 +255,9 @@ bool Bridge::onEvent(const Message::Events::MessageConstruct& e) {
|
||||
}
|
||||
|
||||
if (_conf.get_bool("Bridge", "username_id", vgroup.vg_name).value()) {
|
||||
if (_cr.all_of<Contact::Components::ID>(contact_from)) {
|
||||
if (cr.all_of<Contact::Components::ID>(contact_from)) {
|
||||
// copy
|
||||
auto id = _cr.get<Contact::Components::ID>(contact_from).data;
|
||||
auto id = cr.get<Contact::Components::ID>(contact_from).data;
|
||||
id.resize(3); // TODO:make size configurable
|
||||
|
||||
// TODO: make seperator configurable
|
||||
|
@ -1,6 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include <solanaceae/contact/contact_model3.hpp>
|
||||
#include <solanaceae/contact/fwd.hpp>
|
||||
#include <solanaceae/message3/registry_message_model.hpp>
|
||||
|
||||
#include <vector>
|
||||
@ -13,14 +13,15 @@ struct ConfigModelI;
|
||||
class MessageCommandDispatcher;
|
||||
|
||||
class Bridge : public RegistryMessageModelEventI {
|
||||
Contact3Registry& _cr;
|
||||
RegistryMessageModel& _rmm;
|
||||
ContactStore4I& _cs;
|
||||
RegistryMessageModelI& _rmm;
|
||||
RegistryMessageModelI::SubscriptionReference _rmm_sr;
|
||||
ConfigModelI& _conf;
|
||||
MessageCommandDispatcher* _mcd;
|
||||
|
||||
struct VirtualGroups {
|
||||
struct VContact {
|
||||
Contact3Handle c; // might be null
|
||||
ContactHandle4 c; // might be null
|
||||
std::vector<uint8_t> id; // if contact appears, we check
|
||||
};
|
||||
std::vector<VContact> contacts;
|
||||
@ -29,14 +30,16 @@ class Bridge : public RegistryMessageModelEventI {
|
||||
// TODO: cache settings here?
|
||||
};
|
||||
std::vector<VirtualGroups> _vgroups;
|
||||
std::map<Contact3Handle, size_t> _c_to_vg;
|
||||
std::map<ContactHandle4, size_t> _c_to_vg;
|
||||
|
||||
float _iterate_timer {0.f};
|
||||
|
||||
public:
|
||||
static constexpr const char* version {"1"};
|
||||
|
||||
Bridge(
|
||||
Contact3Registry& cr,
|
||||
RegistryMessageModel& rmm,
|
||||
ContactStore4I& cs,
|
||||
RegistryMessageModelI& rmm,
|
||||
ConfigModelI& conf,
|
||||
MessageCommandDispatcher* mcd = nullptr
|
||||
);
|
||||
@ -47,7 +50,7 @@ class Bridge : public RegistryMessageModelEventI {
|
||||
private:
|
||||
void updateVGroups(void);
|
||||
void registerCommands(void);
|
||||
const VirtualGroups* findVGforContact(const Contact3Handle& c);
|
||||
const VirtualGroups* findVGforContact(const ContactHandle4& c);
|
||||
|
||||
protected: // mm
|
||||
bool onEvent(const Message::Events::MessageConstruct& e) override;
|
||||
|
Reference in New Issue
Block a user