2019-03-19 04:30:04 +01:00
|
|
|
#include "swarm.h"
|
|
|
|
#include "http_connection.h"
|
|
|
|
|
|
|
|
#include "service_node.h"
|
|
|
|
|
|
|
|
#include <boost/log/trivial.hpp>
|
|
|
|
|
|
|
|
namespace loki {
|
|
|
|
|
2019-03-19 04:47:55 +01:00
|
|
|
static bool swarm_exists(const all_swarms_t& all_swarms,
|
|
|
|
const swarm_id_t& swarm) {
|
2019-03-19 04:30:04 +01:00
|
|
|
|
2019-03-19 04:47:55 +01:00
|
|
|
const auto it = std::find_if(
|
|
|
|
all_swarms.begin(), all_swarms.end(),
|
|
|
|
[&swarm](const SwarmInfo& si) { return si.swarm_id == swarm; });
|
2019-03-19 04:30:04 +01:00
|
|
|
|
|
|
|
return it != all_swarms.end();
|
|
|
|
}
|
|
|
|
|
|
|
|
Swarm::~Swarm() = default;
|
|
|
|
|
|
|
|
SwarmEvents Swarm::update_swarms(const all_swarms_t& swarms) {
|
|
|
|
|
|
|
|
/// TODO: need a fast check that the swarms are the same and exit early
|
|
|
|
|
|
|
|
SwarmEvents events = {};
|
|
|
|
|
|
|
|
swarm_id_t our_swarm_idx = UINT32_MAX;
|
|
|
|
|
|
|
|
/// Find us:
|
|
|
|
for (auto swarm_idx = 0u; swarm_idx < swarms.size(); ++swarm_idx) {
|
|
|
|
|
|
|
|
const auto& snodes = swarms[swarm_idx].snodes;
|
|
|
|
|
|
|
|
for (auto node_idx = 0u; node_idx < snodes.size(); ++node_idx) {
|
|
|
|
|
2019-03-21 00:19:50 +01:00
|
|
|
if (our_address == snodes[node_idx]) {
|
2019-03-19 04:30:04 +01:00
|
|
|
our_swarm_idx = swarm_idx;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
const auto& our_swarm = swarms[our_swarm_idx].snodes;
|
|
|
|
|
|
|
|
if (our_swarm_idx == UINT32_MAX) {
|
|
|
|
BOOST_LOG_TRIVIAL(error) << "ERROR: WE ARE NOT IN ANY SWARM";
|
|
|
|
return events;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (swarm_peers_.empty()) {
|
|
|
|
|
|
|
|
assert(cur_swarm_id_ == UINT64_MAX);
|
|
|
|
|
2019-03-19 04:47:55 +01:00
|
|
|
BOOST_LOG_TRIVIAL(info)
|
|
|
|
<< "EVENT: started SN in swarm: " << our_swarm_idx;
|
2019-03-19 04:30:04 +01:00
|
|
|
|
|
|
|
} else {
|
|
|
|
|
2019-03-19 04:47:55 +01:00
|
|
|
/// Are we in a new swarm?
|
2019-03-19 04:30:04 +01:00
|
|
|
if (cur_swarm_id_ != swarms[our_swarm_idx].swarm_id) {
|
|
|
|
|
2019-03-19 04:47:55 +01:00
|
|
|
BOOST_LOG_TRIVIAL(info) << "EVENT: got moved into a new swarm: "
|
|
|
|
<< swarms[our_swarm_idx].swarm_id;
|
2019-03-19 04:30:04 +01:00
|
|
|
|
|
|
|
/// Check that our old swarm still exists
|
|
|
|
if (!swarm_exists(swarms, cur_swarm_id_)) {
|
|
|
|
|
2019-03-19 04:47:55 +01:00
|
|
|
BOOST_LOG_TRIVIAL(info)
|
|
|
|
<< "EVENT: our old swarm got DISSOLVED!";
|
2019-03-19 04:30:04 +01:00
|
|
|
events.decommissioned = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-03-21 06:51:03 +01:00
|
|
|
/// don't bother checking the rest
|
|
|
|
if (!events.decommissioned) {
|
2019-03-19 04:30:04 +01:00
|
|
|
|
2019-03-21 06:51:03 +01:00
|
|
|
/// See if anyone joined our swarm
|
|
|
|
for (auto& sn : our_swarm) {
|
2019-03-19 04:30:04 +01:00
|
|
|
|
2019-03-25 00:35:21 +01:00
|
|
|
auto it =
|
|
|
|
std::find(swarm_peers_.begin(), swarm_peers_.end(), sn);
|
2019-03-21 06:51:03 +01:00
|
|
|
|
|
|
|
if (it == swarm_peers_.end()) {
|
2019-03-25 00:35:21 +01:00
|
|
|
BOOST_LOG_TRIVIAL(info)
|
|
|
|
<< "EVENT: detected new SN: " << to_string(sn);
|
2019-03-21 06:51:03 +01:00
|
|
|
events.new_snodes.push_back(sn);
|
|
|
|
}
|
2019-03-19 04:30:04 +01:00
|
|
|
}
|
|
|
|
|
2019-03-21 06:51:03 +01:00
|
|
|
/// See if there are any new swarms
|
2019-03-19 04:30:04 +01:00
|
|
|
|
2019-03-21 06:51:03 +01:00
|
|
|
for (const auto& swarm_info : swarms) {
|
2019-03-19 04:30:04 +01:00
|
|
|
|
2019-03-21 06:51:03 +01:00
|
|
|
bool found = false;
|
2019-03-19 04:30:04 +01:00
|
|
|
|
2019-03-21 06:51:03 +01:00
|
|
|
for (const auto& prev_si : all_cur_swarms_) {
|
2019-03-19 04:30:04 +01:00
|
|
|
|
2019-03-21 06:51:03 +01:00
|
|
|
if (prev_si.swarm_id == swarm_info.swarm_id) {
|
|
|
|
found = true;
|
|
|
|
break;
|
|
|
|
}
|
2019-03-19 04:30:04 +01:00
|
|
|
}
|
|
|
|
|
2019-03-21 06:51:03 +01:00
|
|
|
if (!found) {
|
2019-03-25 00:35:21 +01:00
|
|
|
BOOST_LOG_TRIVIAL(info) << "EVENT: detected a new swarm: "
|
|
|
|
<< swarm_info.swarm_id;
|
2019-03-21 06:51:03 +01:00
|
|
|
events.new_swarms.push_back(swarm_info.swarm_id);
|
|
|
|
}
|
2019-03-19 04:30:04 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// NOTE: need to be careful and make sure we don't miss any
|
|
|
|
/// swarm update (e.g. if we don't update frequently enough)
|
|
|
|
|
|
|
|
cur_swarm_id_ = swarms[our_swarm_idx].swarm_id;
|
|
|
|
all_cur_swarms_ = swarms;
|
|
|
|
swarm_peers_ = our_swarm;
|
|
|
|
|
|
|
|
return events;
|
|
|
|
}
|
|
|
|
|
2019-03-19 04:47:55 +01:00
|
|
|
swarm_id_t get_swarm_by_pk(const std::vector<SwarmInfo>& all_swarms,
|
2019-03-22 06:47:18 +01:00
|
|
|
const std::string& pk) {
|
2019-03-19 04:30:04 +01:00
|
|
|
|
|
|
|
// TODO: handle errors
|
|
|
|
// TODO: get rid of allocations?
|
|
|
|
|
2019-03-28 05:33:41 +01:00
|
|
|
std::string pk0_str = std::string(pk.c_str() + 2, 16);
|
|
|
|
std::string pk1_str = std::string(pk.c_str() + 2 + 16, 16);
|
|
|
|
std::string pk2_str = std::string(pk.c_str() + 2 + 32, 16);
|
|
|
|
std::string pk3_str = std::string(pk.c_str() + 2 + 48, 16);
|
2019-03-19 04:30:04 +01:00
|
|
|
|
|
|
|
uint64_t pk0 = std::stoull(pk0_str, 0, 16);
|
|
|
|
uint64_t pk1 = std::stoull(pk1_str, 0, 16);
|
|
|
|
uint64_t pk2 = std::stoull(pk2_str, 0, 16);
|
|
|
|
uint64_t pk3 = std::stoull(pk3_str, 0, 16);
|
|
|
|
|
|
|
|
uint64_t res = pk0 ^ pk1 ^ pk2 ^ pk3;
|
|
|
|
|
|
|
|
swarm_id_t cur_best = 0;
|
|
|
|
uint64_t cur_min = std::numeric_limits<uint64_t>::max();
|
|
|
|
|
|
|
|
for (const auto& si : all_swarms) {
|
|
|
|
|
2019-03-19 04:47:55 +01:00
|
|
|
uint64_t dist =
|
|
|
|
(si.swarm_id > res) ? (si.swarm_id - res) : (res - si.swarm_id);
|
2019-03-19 04:30:04 +01:00
|
|
|
if (dist < cur_min) {
|
|
|
|
cur_best = si.swarm_id;
|
|
|
|
cur_min = dist;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// handle special case
|
|
|
|
|
|
|
|
if (res > all_swarms[0].swarm_id) {
|
2019-03-19 04:47:55 +01:00
|
|
|
uint64_t dist =
|
|
|
|
std::numeric_limits<uint64_t>::max() - res + all_swarms[0].swarm_id;
|
2019-03-19 04:30:04 +01:00
|
|
|
|
|
|
|
if (dist < cur_min) {
|
|
|
|
return all_swarms[0].swarm_id;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return cur_best;
|
|
|
|
}
|
|
|
|
|
2019-03-21 00:19:50 +01:00
|
|
|
std::vector<sn_record_t> Swarm::other_nodes() const {
|
2019-03-19 04:30:04 +01:00
|
|
|
|
2019-03-21 00:19:50 +01:00
|
|
|
std::vector<sn_record_t> result;
|
2019-03-19 04:30:04 +01:00
|
|
|
|
|
|
|
for (auto& swarm : swarm_peers_) {
|
2019-03-21 00:19:50 +01:00
|
|
|
if (swarm != our_address) {
|
2019-03-19 04:30:04 +01:00
|
|
|
result.push_back(swarm);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2019-03-19 04:47:55 +01:00
|
|
|
} // namespace loki
|