0
0
Fork 0
mirror of https://github.com/matrix-construct/construct synced 2024-11-01 03:18:54 +01:00
construct/matrix/room_origins.cc
2019-09-27 19:35:26 -07:00

265 lines
4.5 KiB
C++

// Matrix Construct
//
// Copyright (C) Matrix Construct Developers, Authors & Contributors
// Copyright (C) 2016-2018 Jason Volk <jason@zemos.net>
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice is present in all copies. The
// full license for this software is available in the LICENSE file.
ircd::string_view
ircd::m::room::origins::random(const mutable_buffer &buf,
const closure_bool &proffer)
const
{
string_view ret;
const auto closure{[&buf, &proffer, &ret]
(const string_view &origin)
{
ret = { data(buf), copy(buf, origin) };
}};
random(closure, proffer);
return ret;
}
bool
ircd::m::room::origins::random(const closure &view,
const closure_bool &proffer)
const
{
return random(*this, view, proffer);
}
bool
ircd::m::room::origins::random(const origins &origins,
const closure &view,
const closure_bool &proffer)
{
bool ret{false};
const size_t max
{
origins.count()
};
if(unlikely(!max))
return ret;
auto select
{
ssize_t(rand::integer(0, max - 1))
};
const closure_bool closure{[&proffer, &view, &select]
(const string_view &origin)
{
if(select-- > 0)
return true;
// Test if this random selection is "ok" e.g. the callback allows the
// user to test a blacklist for this origin. Skip to next if not.
if(proffer && !proffer(origin))
{
++select;
return true;
}
view(origin);
return false;
}};
const auto iteration{[&origins, &closure, &ret]
{
ret = !origins.for_each(closure);
}};
// Attempt select on first iteration
iteration();
// If nothing was OK between the random int and the end of the iteration
// then start again and pick the first OK.
if(!ret && select >= 0)
iteration();
return ret;
}
bool
ircd::m::room::origins::empty()
const
{
return for_each(closure_bool{[]
(const string_view &)
{
// return false to break and return false.
return false;
}});
}
size_t
ircd::m::room::origins::count()
const
{
size_t ret{0};
for_each([&ret](const string_view &)
{
++ret;
});
return ret;
}
size_t
ircd::m::room::origins::count_error()
const
{
size_t ret{0};
for_each([&ret](const string_view &server)
{
ret += !ircd::empty(server::errmsg(server));
});
return ret;
}
size_t
ircd::m::room::origins::count_online()
const
{
ssize_t ret
{
0 - ssize_t(count_error())
};
for_each([&ret](const string_view &hostport)
{
ret += bool(server::exists(hostport));
});
assert(ret >= 0L);
return std::max(ret, 0L);
}
/// Tests if argument is the only origin in the room.
/// If a zero or more than one origins exist, returns false. If the only origin
/// in the room is the argument origin, returns true.
bool
ircd::m::room::origins::only(const string_view &origin)
const
{
ushort ret{2};
for_each(closure_bool{[&ret, &origin]
(const string_view &origin_) -> bool
{
if(origin == origin_)
ret = 1;
else
ret = 0;
return ret;
}});
return ret == 1;
}
bool
ircd::m::room::origins::has(const string_view &origin)
const
{
db::domain &index
{
dbs::room_joined
};
char querybuf[dbs::ROOM_JOINED_KEY_MAX_SIZE];
const auto query
{
dbs::room_joined_key(querybuf, room.room_id, origin)
};
auto it
{
index.begin(query)
};
if(!it)
return false;
const string_view &key
{
lstrip(it->first, "\0"_sv)
};
const string_view &key_origin
{
std::get<0>(dbs::room_joined_key(key))
};
return key_origin == origin;
}
void
ircd::m::room::origins::for_each(const closure &view)
const
{
for_each(closure_bool{[&view]
(const string_view &origin)
{
view(origin);
return true;
}});
}
bool
ircd::m::room::origins::for_each(const closure_bool &view)
const
{
string_view last;
char lastbuf[rfc1035::NAME_BUFSIZE];
return _for_each(*this, [&last, &lastbuf, &view]
(const string_view &key)
{
const string_view &origin
{
std::get<0>(dbs::room_joined_key(key))
};
if(origin == last)
return true;
if(!view(origin))
return false;
last = { lastbuf, copy(lastbuf, origin) };
return true;
});
}
bool
ircd::m::room::origins::_for_each(const origins &origins,
const closure_bool &view)
{
db::domain &index
{
dbs::room_joined
};
auto it
{
index.begin(origins.room.room_id)
};
for(; bool(it); ++it)
{
const string_view &key
{
lstrip(it->first, "\0"_sv)
};
if(!view(key))
return false;
}
return true;
}