mirror of
https://github.com/matrix-construct/construct
synced 2024-05-20 03:43:47 +02:00
Compare commits
10 commits
dd6d17433e
...
55a73624d2
Author | SHA1 | Date | |
---|---|---|---|
55a73624d2 | |||
cab2b4c822 | |||
79f5e4fd8d | |||
4c06793980 | |||
ef27ae50dc | |||
6e7d63ce6d | |||
73a3a4cb35 | |||
b40c21545a | |||
b4e75dfdf0 | |||
ba6030f4ce |
14
.github/workflows/docker.yml
vendored
14
.github/workflows/docker.yml
vendored
|
@ -1,9 +1,8 @@
|
||||||
|
#
|
||||||
|
# Build docker images
|
||||||
|
#
|
||||||
name: Docker Images
|
name: Docker Images
|
||||||
|
|
||||||
env:
|
|
||||||
ctor_id: ${{ vars.DOCKER_ID }}
|
|
||||||
ctor_url: https://github.com/${{github.repository}}
|
|
||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches: [master]
|
branches: [master]
|
||||||
|
@ -15,7 +14,12 @@ concurrency:
|
||||||
group: ${{ github.ref }}
|
group: ${{ github.ref }}
|
||||||
cancel-in-progress: true
|
cancel-in-progress: true
|
||||||
|
|
||||||
|
env:
|
||||||
|
ctor_id: ${{ vars.DOCKER_ID }}
|
||||||
|
ctor_url: https://github.com/${{github.repository}}
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
|
# Build the base-feature intermediate images (cached and not shipped).
|
||||||
base:
|
base:
|
||||||
uses: ./.github/workflows/docker_prime.yml
|
uses: ./.github/workflows/docker_prime.yml
|
||||||
with:
|
with:
|
||||||
|
@ -26,6 +30,7 @@ jobs:
|
||||||
machines: ${{vars.DOCKER_MACHINES}}
|
machines: ${{vars.DOCKER_MACHINES}}
|
||||||
test: ${{contains(github.events.push.commits[0].message, '[ci test]')}}
|
test: ${{contains(github.events.push.commits[0].message, '[ci test]')}}
|
||||||
|
|
||||||
|
# Build the full-feature intermediate images (cached and not shipped).
|
||||||
full:
|
full:
|
||||||
uses: ./.github/workflows/docker_prime.yml
|
uses: ./.github/workflows/docker_prime.yml
|
||||||
needs: [base]
|
needs: [base]
|
||||||
|
@ -37,6 +42,7 @@ jobs:
|
||||||
machines: ${{vars.DOCKER_MACHINES}}
|
machines: ${{vars.DOCKER_MACHINES}}
|
||||||
test: ${{contains(github.events.push.commits[0].message, '[ci test]')}}
|
test: ${{contains(github.events.push.commits[0].message, '[ci test]')}}
|
||||||
|
|
||||||
|
# Build the leaf images (shipped and not cached)
|
||||||
built:
|
built:
|
||||||
needs: [base, full]
|
needs: [base, full]
|
||||||
runs-on: ${{matrix.machine}}
|
runs-on: ${{matrix.machine}}
|
||||||
|
|
22
.github/workflows/docker_prime.yml
vendored
22
.github/workflows/docker_prime.yml
vendored
|
@ -1,3 +1,9 @@
|
||||||
|
#
|
||||||
|
# Build intermediate images
|
||||||
|
#
|
||||||
|
# Called to build lower-layer images which other images depend on. These are
|
||||||
|
# cached for use by the next layer but not shipped to users.
|
||||||
|
#
|
||||||
name: Docker Images Prime
|
name: Docker Images Prime
|
||||||
|
|
||||||
on:
|
on:
|
||||||
|
@ -5,32 +11,38 @@ on:
|
||||||
inputs:
|
inputs:
|
||||||
id:
|
id:
|
||||||
type: string
|
type: string
|
||||||
|
description: Dockerhub acct/repo identity.
|
||||||
url:
|
url:
|
||||||
type: string
|
type: string
|
||||||
|
description: Git repository for checkout.
|
||||||
features:
|
features:
|
||||||
type: string
|
type: string
|
||||||
|
description: JSON array of feature-set names to build images for.
|
||||||
distros:
|
distros:
|
||||||
type: string
|
type: string
|
||||||
|
description: JSON array of operating system distros to build for.
|
||||||
machines:
|
machines:
|
||||||
type: string
|
type: string
|
||||||
|
description: JSON array of machines to build for.
|
||||||
test:
|
test:
|
||||||
type: boolean
|
type: boolean
|
||||||
default: false
|
default: false
|
||||||
required: false
|
required: false
|
||||||
|
description: Echo all docker commands rather than invoking them.
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: ${{github.workflow}}-${{inputs.features}}
|
||||||
|
cancel-in-progress: false
|
||||||
|
|
||||||
env:
|
env:
|
||||||
ctor_id: ${{inputs.id}}
|
ctor_id: ${{inputs.id}}
|
||||||
ctor_url: ${{inputs.url}}
|
ctor_url: ${{inputs.url}}
|
||||||
|
|
||||||
concurrency:
|
|
||||||
group: ${{github.run_id}}
|
|
||||||
cancel-in-progress: true
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
prime:
|
prime:
|
||||||
runs-on: ${{matrix.machine}}
|
runs-on: ${{matrix.machine}}
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: true
|
||||||
matrix:
|
matrix:
|
||||||
feature: ${{fromJSON(inputs.features)}}
|
feature: ${{fromJSON(inputs.features)}}
|
||||||
distro: ${{fromJSON(inputs.distros)}}
|
distro: ${{fromJSON(inputs.distros)}}
|
||||||
|
|
|
@ -131,7 +131,7 @@ build()
|
||||||
|
|
||||||
# Leaf build; unique to each iteration.
|
# Leaf build; unique to each iteration.
|
||||||
tag="$ctor_acct/$ctor_repo:${distro}-${feature}-built-${toolchain}-${machine}"
|
tag="$ctor_acct/$ctor_repo:${distro}-${feature}-built-${toolchain}-${machine}"
|
||||||
arg="$args -t $tag $BASEDIR/${dist_name}/built"
|
arg="$args --no-cache -t $tag $BASEDIR/${dist_name}/built"
|
||||||
eval "$cmd build $arg"
|
eval "$cmd build $arg"
|
||||||
if test $? -ne 0; then return 1; fi
|
if test $? -ne 0; then return 1; fi
|
||||||
if test $stage = "built"; then return 0; fi
|
if test $stage = "built"; then return 0; fi
|
||||||
|
|
|
@ -192,8 +192,8 @@ ircd::cl::envs
|
||||||
{ "default", "true" },
|
{ "default", "true" },
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
{ "name", "MESA_GLSL_CACHE_DISABLE" },
|
{ "name", "MESA_SHADER_CACHE_DISABLE" },
|
||||||
{ "default", "true" },
|
{ "default", "true" },
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
{ "name", "AMD_DEBUG" },
|
{ "name", "AMD_DEBUG" },
|
||||||
|
|
114
ircd/db.cc
114
ircd/db.cc
|
@ -2358,15 +2358,20 @@ ircd::db::seek(domain::const_iterator_base &it,
|
||||||
{
|
{
|
||||||
switch(p)
|
switch(p)
|
||||||
{
|
{
|
||||||
|
// This is inefficient as per RocksDB's prefix impl.
|
||||||
case pos::BACK:
|
case pos::BACK:
|
||||||
{
|
{
|
||||||
// This is inefficient as per RocksDB's prefix impl. unknown why
|
char buf[512];
|
||||||
// a seek to NEXT is still needed after walking back one.
|
string_view key;
|
||||||
|
assert(bool(it)); do
|
||||||
|
{
|
||||||
|
assert(size(it.it->key()) <= sizeof(buf));
|
||||||
|
key = string_view(buf, copy(buf, slice(it.it->key())));
|
||||||
|
}
|
||||||
while(seek(it, pos::NEXT));
|
while(seek(it, pos::NEXT));
|
||||||
if(seek(it, pos::PREV))
|
|
||||||
seek(it, pos::NEXT);
|
|
||||||
|
|
||||||
return bool(it);
|
assert(key);
|
||||||
|
return seek(it, key);
|
||||||
}
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -5003,24 +5008,23 @@ ircd::db::_seek(const vector_view<_read_op> &op,
|
||||||
namespace ircd::db
|
namespace ircd::db
|
||||||
{
|
{
|
||||||
static rocksdb::Iterator &_seek_(rocksdb::Iterator &, const pos &);
|
static rocksdb::Iterator &_seek_(rocksdb::Iterator &, const pos &);
|
||||||
static rocksdb::Iterator &_seek_(rocksdb::Iterator &, const string_view &);
|
static rocksdb::Iterator &_seek_(rocksdb::Iterator &, const string_view &, const bool lte);
|
||||||
static rocksdb::Iterator &_seek_lower_(rocksdb::Iterator &, const string_view &);
|
static bool _seek(database::column &, const pos &, const rocksdb::ReadOptions &, rocksdb::Iterator &it, const bool lte);
|
||||||
static rocksdb::Iterator &_seek_upper_(rocksdb::Iterator &, const string_view &);
|
static bool _seek(database::column &, const string_view &, const rocksdb::ReadOptions &, rocksdb::Iterator &it, const bool lte);
|
||||||
static bool _seek(database::column &, const pos &, const rocksdb::ReadOptions &, rocksdb::Iterator &it);
|
|
||||||
static bool _seek(database::column &, const string_view &, const rocksdb::ReadOptions &, rocksdb::Iterator &it);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<rocksdb::Iterator>
|
std::unique_ptr<rocksdb::Iterator>
|
||||||
ircd::db::seek(column &column,
|
ircd::db::seek(column &column,
|
||||||
const string_view &key,
|
const string_view &key,
|
||||||
const gopts &opts)
|
const gopts &opts,
|
||||||
|
const bool lte)
|
||||||
{
|
{
|
||||||
database &d(column);
|
database &d(column);
|
||||||
database::column &c(column);
|
database::column &c(column);
|
||||||
|
|
||||||
std::unique_ptr<rocksdb::Iterator> ret;
|
std::unique_ptr<rocksdb::Iterator> ret;
|
||||||
const auto ropts(make_opts(opts));
|
const auto ropts(make_opts(opts));
|
||||||
seek(c, key, ropts, ret);
|
seek(c, key, ropts, ret, lte);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5029,7 +5033,8 @@ bool
|
||||||
ircd::db::seek(database::column &c,
|
ircd::db::seek(database::column &c,
|
||||||
const pos &p,
|
const pos &p,
|
||||||
const rocksdb::ReadOptions &opts,
|
const rocksdb::ReadOptions &opts,
|
||||||
std::unique_ptr<rocksdb::Iterator> &it)
|
std::unique_ptr<rocksdb::Iterator> &it,
|
||||||
|
const bool lte)
|
||||||
{
|
{
|
||||||
const ctx::uninterruptible ui;
|
const ctx::uninterruptible ui;
|
||||||
const ctx::stack_usage_assertion sua;
|
const ctx::stack_usage_assertion sua;
|
||||||
|
@ -5041,31 +5046,33 @@ ircd::db::seek(database::column &c,
|
||||||
it.reset(d.d->NewIterator(opts, cf));
|
it.reset(d.d->NewIterator(opts, cf));
|
||||||
}
|
}
|
||||||
|
|
||||||
return _seek(c, p, opts, *it);
|
return _seek(c, p, opts, *it, lte);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
ircd::db::_seek(database::column &c,
|
ircd::db::_seek(database::column &c,
|
||||||
const string_view &p,
|
const string_view &p,
|
||||||
const rocksdb::ReadOptions &opts,
|
const rocksdb::ReadOptions &opts,
|
||||||
rocksdb::Iterator &it)
|
rocksdb::Iterator &it,
|
||||||
|
const bool lte)
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
util::timer timer{util::timer::nostart};
|
util::timer timer{util::timer::nostart};
|
||||||
if constexpr(RB_DEBUG_DB_SEEK)
|
if constexpr(RB_DEBUG_DB_SEEK)
|
||||||
timer = util::timer{};
|
timer = util::timer{};
|
||||||
|
|
||||||
_seek_(it, p);
|
_seek_(it, p, lte);
|
||||||
|
|
||||||
database &d(*c.d);
|
database &d(*c.d);
|
||||||
if constexpr(RB_DEBUG_DB_SEEK)
|
if constexpr(RB_DEBUG_DB_SEEK)
|
||||||
log::debug
|
log::debug
|
||||||
{
|
{
|
||||||
log, "[%s] %lu:%lu SEEK %s %s in %ld$us '%s'",
|
log, "[%s] %lu:%lu SEEK[%s] %s %s in %ld$us '%s'",
|
||||||
name(d),
|
name(d),
|
||||||
sequence(d),
|
sequence(d),
|
||||||
sequence(opts.snapshot),
|
sequence(opts.snapshot),
|
||||||
valid(it)? "VALID" : "INVALID",
|
lte? "LTE"_sv: "GTE"_sv,
|
||||||
|
valid(it)? "VALID"_sv: "INVALID"_sv,
|
||||||
it.status().ok()? "OK"s: it.status().ToString(),
|
it.status().ok()? "OK"s: it.status().ToString(),
|
||||||
timer.at<microseconds>().count(),
|
timer.at<microseconds>().count(),
|
||||||
name(c)
|
name(c)
|
||||||
|
@ -5078,11 +5085,12 @@ catch(const error &e)
|
||||||
const database &d(*c.d);
|
const database &d(*c.d);
|
||||||
log::critical
|
log::critical
|
||||||
{
|
{
|
||||||
log, "[%s][%s] %lu:%lu SEEK key :%s",
|
log, "[%s][%s] %lu:%lu SEEK[%s] key :%s",
|
||||||
name(d),
|
name(d),
|
||||||
name(c),
|
name(c),
|
||||||
sequence(d),
|
sequence(d),
|
||||||
sequence(opts.snapshot),
|
sequence(opts.snapshot),
|
||||||
|
lte? "LTE"_sv: "GTE"_sv,
|
||||||
e.what(),
|
e.what(),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -5093,7 +5101,8 @@ bool
|
||||||
ircd::db::_seek(database::column &c,
|
ircd::db::_seek(database::column &c,
|
||||||
const pos &p,
|
const pos &p,
|
||||||
const rocksdb::ReadOptions &opts,
|
const rocksdb::ReadOptions &opts,
|
||||||
rocksdb::Iterator &it)
|
rocksdb::Iterator &it,
|
||||||
|
const bool)
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
bool valid_it;
|
bool valid_it;
|
||||||
|
@ -5115,7 +5124,7 @@ try
|
||||||
sequence(d),
|
sequence(d),
|
||||||
sequence(opts.snapshot),
|
sequence(opts.snapshot),
|
||||||
reflect(p),
|
reflect(p),
|
||||||
valid_it? "VALID" : "INVALID",
|
valid_it? "VALID"_sv: "INVALID"_sv,
|
||||||
it.status().ok()? "OK"s: it.status().ToString(),
|
it.status().ok()? "OK"s: it.status().ToString(),
|
||||||
timer.at<microseconds>().count(),
|
timer.at<microseconds>().count(),
|
||||||
name(c)
|
name(c)
|
||||||
|
@ -5134,41 +5143,27 @@ catch(const error &e)
|
||||||
sequence(d),
|
sequence(d),
|
||||||
sequence(opts.snapshot),
|
sequence(opts.snapshot),
|
||||||
reflect(p),
|
reflect(p),
|
||||||
it.Valid()? "VALID" : "INVALID",
|
it.Valid()? "VALID"_sv: "INVALID"_sv,
|
||||||
e.what(),
|
e.what(),
|
||||||
};
|
};
|
||||||
|
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Seek to entry NOT GREATER THAN key. That is, equal to or less than key
|
|
||||||
rocksdb::Iterator &
|
|
||||||
ircd::db::_seek_lower_(rocksdb::Iterator &it,
|
|
||||||
const string_view &sv)
|
|
||||||
{
|
|
||||||
assert(!ctx::interruptible());
|
|
||||||
|
|
||||||
it.SeekForPrev(slice(sv));
|
|
||||||
return it;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Seek to entry NOT LESS THAN key. That is, equal to or greater than key
|
|
||||||
rocksdb::Iterator &
|
|
||||||
ircd::db::_seek_upper_(rocksdb::Iterator &it,
|
|
||||||
const string_view &sv)
|
|
||||||
{
|
|
||||||
assert(!ctx::interruptible());
|
|
||||||
|
|
||||||
it.Seek(slice(sv));
|
|
||||||
return it;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Defaults to _seek_upper_ because it has better support from RocksDB.
|
/// Defaults to _seek_upper_ because it has better support from RocksDB.
|
||||||
rocksdb::Iterator &
|
rocksdb::Iterator &
|
||||||
ircd::db::_seek_(rocksdb::Iterator &it,
|
ircd::db::_seek_(rocksdb::Iterator &it,
|
||||||
const string_view &sv)
|
const string_view &sv,
|
||||||
|
const bool lte)
|
||||||
{
|
{
|
||||||
return _seek_upper_(it, sv);
|
assert(!ctx::interruptible());
|
||||||
|
|
||||||
|
if(lte)
|
||||||
|
it.SeekForPrev(slice(sv));
|
||||||
|
else
|
||||||
|
it.Seek(slice(sv));
|
||||||
|
|
||||||
|
return it;
|
||||||
}
|
}
|
||||||
|
|
||||||
rocksdb::Iterator &
|
rocksdb::Iterator &
|
||||||
|
@ -5179,11 +5174,24 @@ ircd::db::_seek_(rocksdb::Iterator &it,
|
||||||
|
|
||||||
switch(p)
|
switch(p)
|
||||||
{
|
{
|
||||||
case pos::NEXT: it.Next(); break;
|
case pos::NEXT:
|
||||||
case pos::PREV: it.Prev(); break;
|
assert(valid(it));
|
||||||
case pos::FRONT: it.SeekToFirst(); break;
|
it.Next();
|
||||||
case pos::BACK: it.SeekToLast(); break;
|
break;
|
||||||
default:
|
|
||||||
|
case pos::PREV:
|
||||||
|
assert(valid(it));
|
||||||
|
it.Prev();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case pos::FRONT:
|
||||||
|
it.SeekToFirst();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case pos::BACK:
|
||||||
|
it.SeekToLast();
|
||||||
|
break;
|
||||||
|
|
||||||
case pos::END:
|
case pos::END:
|
||||||
{
|
{
|
||||||
it.SeekToLast();
|
it.SeekToLast();
|
||||||
|
@ -5192,6 +5200,10 @@ ircd::db::_seek_(rocksdb::Iterator &it,
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
assert(false);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return it;
|
return it;
|
||||||
|
|
|
@ -134,10 +134,8 @@ namespace ircd::db
|
||||||
static void valid_eq_or_throw(const rocksdb::Iterator &, const string_view &);
|
static void valid_eq_or_throw(const rocksdb::Iterator &, const string_view &);
|
||||||
|
|
||||||
// [GET] iterator seek suite
|
// [GET] iterator seek suite
|
||||||
template<class pos> static bool seek(database::column &, const pos &, const rocksdb::ReadOptions &, std::unique_ptr<rocksdb::Iterator> &it);
|
template<class pos> static bool seek(database::column &, const pos &, const rocksdb::ReadOptions &, std::unique_ptr<rocksdb::Iterator> &it, const bool lte = false);
|
||||||
static std::unique_ptr<rocksdb::Iterator> seek(column &, const gopts &);
|
static std::unique_ptr<rocksdb::Iterator> seek(column &, const string_view &key, const gopts &, const bool lte = false);
|
||||||
static std::unique_ptr<rocksdb::Iterator> seek(column &, const string_view &key, const gopts &);
|
|
||||||
static std::vector<row::value_type> seek(database &, const gopts &);
|
|
||||||
static std::pair<string_view, string_view> operator*(const rocksdb::Iterator &);
|
static std::pair<string_view, string_view> operator*(const rocksdb::Iterator &);
|
||||||
|
|
||||||
// [GET] read suite
|
// [GET] read suite
|
||||||
|
|
|
@ -13312,9 +13312,9 @@ console_cmd__user__read(opt &out, const string_view &line)
|
||||||
"user_id", "room_id", "limit"
|
"user_id", "room_id", "limit"
|
||||||
}};
|
}};
|
||||||
|
|
||||||
const m::user::id user_id
|
const auto user_id
|
||||||
{
|
{
|
||||||
param.at("user_id")
|
param.at("user_id", "*"_sv)
|
||||||
};
|
};
|
||||||
|
|
||||||
const auto room_id
|
const auto room_id
|
||||||
|
@ -13324,6 +13324,11 @@ console_cmd__user__read(opt &out, const string_view &line)
|
||||||
m::room::id::buf{}
|
m::room::id::buf{}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const bool all_users
|
||||||
|
{
|
||||||
|
param["user_id"] == "*"
|
||||||
|
};
|
||||||
|
|
||||||
const bool all_rooms
|
const bool all_rooms
|
||||||
{
|
{
|
||||||
param["room_id"] == "*"
|
param["room_id"] == "*"
|
||||||
|
@ -13340,14 +13345,9 @@ console_cmd__user__read(opt &out, const string_view &line)
|
||||||
param["room_id"] == "***"
|
param["room_id"] == "***"
|
||||||
};
|
};
|
||||||
|
|
||||||
size_t limit
|
ssize_t limit
|
||||||
{
|
{
|
||||||
param.at("limit", 32UL)
|
param.at("limit", 32L)
|
||||||
};
|
|
||||||
|
|
||||||
const m::user::room user_room
|
|
||||||
{
|
|
||||||
user_id
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const m::event::closure each_event{[&out]
|
const m::event::closure each_event{[&out]
|
||||||
|
@ -13411,19 +13411,35 @@ console_cmd__user__read(opt &out, const string_view &line)
|
||||||
out << std::endl;
|
out << std::endl;
|
||||||
}};
|
}};
|
||||||
|
|
||||||
if(all_rooms)
|
if(all_rooms && !all_users)
|
||||||
{
|
{
|
||||||
|
const m::user::room user_room
|
||||||
|
{
|
||||||
|
user_id
|
||||||
|
};
|
||||||
|
|
||||||
const m::room::state state
|
const m::room::state state
|
||||||
{
|
{
|
||||||
user_room
|
user_room
|
||||||
};
|
};
|
||||||
|
|
||||||
state.for_each("ircd.read", each_event);
|
state.for_each("ircd.read", m::event::closure_bool{[&each_event, &limit]
|
||||||
|
(const m::event &event)
|
||||||
|
{
|
||||||
|
each_event(event);
|
||||||
|
return --limit > 0;
|
||||||
|
}});
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(eye_track)
|
if(eye_track && !all_users)
|
||||||
{
|
{
|
||||||
|
const m::user::room user_room
|
||||||
|
{
|
||||||
|
user_id
|
||||||
|
};
|
||||||
|
|
||||||
const m::room::type type
|
const m::room::type type
|
||||||
{
|
{
|
||||||
user_room, "ircd.read"
|
user_room, "ircd.read"
|
||||||
|
@ -13440,14 +13456,19 @@ console_cmd__user__read(opt &out, const string_view &line)
|
||||||
if(likely(event.valid))
|
if(likely(event.valid))
|
||||||
each_event(event);
|
each_event(event);
|
||||||
|
|
||||||
return --limit;
|
return --limit > 0;
|
||||||
});
|
});
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(fully_read)
|
if(fully_read && !all_users)
|
||||||
{
|
{
|
||||||
|
const m::user::room user_room
|
||||||
|
{
|
||||||
|
user_id
|
||||||
|
};
|
||||||
|
|
||||||
const m::room::type type
|
const m::room::type type
|
||||||
{
|
{
|
||||||
user_room, "ircd.account_data!", { -1UL, -1UL }, true
|
user_room, "ircd.account_data!", { -1UL, -1UL }, true
|
||||||
|
@ -13468,29 +13489,55 @@ console_cmd__user__read(opt &out, const string_view &line)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
each_event(event);
|
each_event(event);
|
||||||
return --limit;
|
return --limit > 0;
|
||||||
});
|
});
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
const m::room::state::space space
|
if(!all_users)
|
||||||
{
|
{
|
||||||
user_room
|
const m::user::room user_room
|
||||||
};
|
|
||||||
|
|
||||||
space.for_each("ircd.read", room_id, [&each_event, &limit]
|
|
||||||
(const auto &type, const auto &state_key, const auto &depth, const auto &event_idx) -> bool
|
|
||||||
{
|
|
||||||
const m::event::fetch event
|
|
||||||
{
|
{
|
||||||
std::nothrow, event_idx
|
user_id
|
||||||
};
|
};
|
||||||
|
|
||||||
if(likely(event.valid))
|
const m::room::state::space space
|
||||||
each_event(event);
|
{
|
||||||
|
user_room
|
||||||
|
};
|
||||||
|
|
||||||
return --limit;
|
space.for_each("ircd.read", room_id, [&each_event, &limit]
|
||||||
|
(const auto &type, const auto &state_key, const auto &depth, const auto &event_idx) -> bool
|
||||||
|
{
|
||||||
|
const m::event::fetch event
|
||||||
|
{
|
||||||
|
std::nothrow, event_idx
|
||||||
|
};
|
||||||
|
|
||||||
|
if(likely(event.valid))
|
||||||
|
each_event(event);
|
||||||
|
|
||||||
|
return --limit > 0;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const m::events::range range
|
||||||
|
{
|
||||||
|
-1UL, 0UL
|
||||||
|
};
|
||||||
|
|
||||||
|
m::events::for_each(range, [&each_event, &limit]
|
||||||
|
(const m::event::idx &seq, const m::event &event)
|
||||||
|
{
|
||||||
|
if(json::get<"type"_>(event) != "ircd.read")
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if(!my(event))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
each_event(event);
|
||||||
|
return --limit > 0;
|
||||||
});
|
});
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -15058,7 +15105,7 @@ console_cmd__feds__head(opt &out, const string_view &line)
|
||||||
if(prev_event.valid)
|
if(prev_event.valid)
|
||||||
out << pretty_oneline(prev_event);
|
out << pretty_oneline(prev_event);
|
||||||
else
|
else
|
||||||
out << string_view{prev_event_id};
|
out << result.request->room_id << ' ' << prev_event_id;
|
||||||
|
|
||||||
out << std::endl;
|
out << std::endl;
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,7 +40,21 @@ struct command_result
|
||||||
string_view msgtype {"m.notice"};
|
string_view msgtype {"m.notice"};
|
||||||
};
|
};
|
||||||
|
|
||||||
conf::item<bool>
|
static conf::item<size_t>
|
||||||
|
watch_limit
|
||||||
|
{
|
||||||
|
{ "name", "ircd.m.command.watch.limit" },
|
||||||
|
{ "default", 256 },
|
||||||
|
};
|
||||||
|
|
||||||
|
static conf::item<bool>
|
||||||
|
watch_opers
|
||||||
|
{
|
||||||
|
{ "name", "ircd.m.command.watch.opers" },
|
||||||
|
{ "default", true },
|
||||||
|
};
|
||||||
|
|
||||||
|
static conf::item<bool>
|
||||||
command_typing
|
command_typing
|
||||||
{
|
{
|
||||||
{ "name", "ircd.m.command.typing" },
|
{ "name", "ircd.m.command.typing" },
|
||||||
|
@ -55,6 +69,30 @@ execute_command(const mutable_buffer &buf,
|
||||||
const m::event::id &reply_to,
|
const m::event::id &reply_to,
|
||||||
const bool public_response);
|
const bool public_response);
|
||||||
|
|
||||||
|
static void
|
||||||
|
watch_command(const m::user::id &user_id,
|
||||||
|
const m::room::id &room_id,
|
||||||
|
const m::event::id &reply_id,
|
||||||
|
const m::event::id &response_id,
|
||||||
|
const m::room::id &response_room,
|
||||||
|
const m::user::id &response_sender,
|
||||||
|
const string_view &response_type,
|
||||||
|
const string_view &cmd,
|
||||||
|
const bool &public_response,
|
||||||
|
const milliseconds &watch_delay);
|
||||||
|
|
||||||
|
static const json::value
|
||||||
|
undef_val
|
||||||
|
{
|
||||||
|
string_view{nullptr}, json::STRING
|
||||||
|
};
|
||||||
|
|
||||||
|
static const json::value
|
||||||
|
html_format
|
||||||
|
{
|
||||||
|
"org.matrix.custom.html", json::STRING
|
||||||
|
};
|
||||||
|
|
||||||
void
|
void
|
||||||
handle_command(const m::event &event,
|
handle_command(const m::event &event,
|
||||||
m::vm::eval &eval)
|
m::vm::eval &eval)
|
||||||
|
@ -105,6 +143,18 @@ try
|
||||||
if(!is_command)
|
if(!is_command)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
const json::string reply_to
|
||||||
|
{
|
||||||
|
content["reply_id"]
|
||||||
|
};
|
||||||
|
|
||||||
|
const auto reply_id
|
||||||
|
{
|
||||||
|
reply_to?
|
||||||
|
m::event::id::buf{reply_to}:
|
||||||
|
m::event::id::buf{}
|
||||||
|
};
|
||||||
|
|
||||||
// View of the command string without prefix
|
// View of the command string without prefix
|
||||||
string_view input
|
string_view input
|
||||||
{
|
{
|
||||||
|
@ -120,29 +170,43 @@ try
|
||||||
startswith(input, '!')
|
startswith(input, '!')
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if(public_response)
|
||||||
|
input = lstrip(input, '!');
|
||||||
|
|
||||||
|
const bool command_watch
|
||||||
|
{
|
||||||
|
startswith(input, "watch ")
|
||||||
|
&& (!watch_opers || is_oper(user))
|
||||||
|
};
|
||||||
|
|
||||||
|
milliseconds watch_delay {0ms};
|
||||||
|
if(command_watch)
|
||||||
|
{
|
||||||
|
const auto delay
|
||||||
|
{
|
||||||
|
lex_cast<float>(token(input, ' ', 1))
|
||||||
|
};
|
||||||
|
|
||||||
|
watch_delay = milliseconds
|
||||||
|
{
|
||||||
|
long(delay * 1000.0)
|
||||||
|
};
|
||||||
|
|
||||||
|
input = tokens_after(input, ' ', 1);
|
||||||
|
}
|
||||||
|
|
||||||
const string_view cmd
|
const string_view cmd
|
||||||
{
|
{
|
||||||
lstrip(input, '!')
|
input
|
||||||
};
|
|
||||||
|
|
||||||
const json::string reply_to
|
|
||||||
{
|
|
||||||
content["reply_id"]
|
|
||||||
};
|
|
||||||
|
|
||||||
const auto reply_id
|
|
||||||
{
|
|
||||||
reply_to?
|
|
||||||
m::event::id{reply_to}:
|
|
||||||
m::event::id{}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
log::debug
|
log::debug
|
||||||
{
|
{
|
||||||
m::log, "Server command from %s in %s public:%b replying:%s :%s",
|
m::log, "Server command from %s in %s public:%b watch:%ld replying:%s :%s",
|
||||||
string_view{room_id},
|
string_view{room_id},
|
||||||
string_view{user.user_id},
|
string_view{user.user_id},
|
||||||
public_response,
|
public_response,
|
||||||
|
watch_delay.count(),
|
||||||
string_view{reply_id}?: "false"_sv,
|
string_view{reply_id}?: "false"_sv,
|
||||||
cmd
|
cmd
|
||||||
};
|
};
|
||||||
|
@ -175,7 +239,7 @@ try
|
||||||
public_response? "m.room.message" : "ircd.cmd.result"
|
public_response? "m.room.message" : "ircd.cmd.result"
|
||||||
};
|
};
|
||||||
|
|
||||||
const auto &response_event_id
|
const auto &command_event_id
|
||||||
{
|
{
|
||||||
public_response?
|
public_response?
|
||||||
string_view{event_id}:
|
string_view{event_id}:
|
||||||
|
@ -192,16 +256,6 @@ try
|
||||||
alt?: "no alt text"_sv, json::STRING
|
alt?: "no alt text"_sv, json::STRING
|
||||||
};
|
};
|
||||||
|
|
||||||
static const json::value undef_val
|
|
||||||
{
|
|
||||||
string_view{nullptr}, json::STRING
|
|
||||||
};
|
|
||||||
|
|
||||||
static const json::value html_format
|
|
||||||
{
|
|
||||||
"org.matrix.custom.html", json::STRING
|
|
||||||
};
|
|
||||||
|
|
||||||
char relates_buf[576], reply_buf[288];
|
char relates_buf[576], reply_buf[288];
|
||||||
json::object in_reply_to, relates_to {json::empty_object};
|
json::object in_reply_to, relates_to {json::empty_object};
|
||||||
if(event_id)
|
if(event_id)
|
||||||
|
@ -219,16 +273,52 @@ try
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
m::send(response_room, response_sender, response_type,
|
const auto response_id
|
||||||
{
|
{
|
||||||
{ "msgtype", msgtype?: "m.notice" },
|
m::send(response_room, response_sender, response_type,
|
||||||
{ "format", html? html_format: undef_val },
|
{
|
||||||
{ "body", content_body },
|
{ "msgtype", msgtype?: "m.notice" },
|
||||||
{ "formatted_body", html? html_val: undef_val },
|
{ "format", html? html_format: undef_val },
|
||||||
{ "room_id", room_id },
|
{ "body", content_body },
|
||||||
{ "input", input },
|
{ "formatted_body", html? html_val: undef_val },
|
||||||
{ "m.relates_to", relates_to },
|
{ "room_id", room_id },
|
||||||
});
|
{ "input", cmd },
|
||||||
|
{ "m.relates_to", relates_to },
|
||||||
|
})
|
||||||
|
};
|
||||||
|
|
||||||
|
if(command_watch)
|
||||||
|
ctx::context
|
||||||
|
{
|
||||||
|
"watch", ctx::context::POST | ctx::context::DETACH,
|
||||||
|
[
|
||||||
|
user_id(m::user::id::buf(user.user_id)),
|
||||||
|
room_id(m::room::id::buf(room_id)),
|
||||||
|
reply_id(m::event::id::buf(reply_id)),
|
||||||
|
response_id(m::event::id::buf(response_id)),
|
||||||
|
response_room(m::room::id::buf(response_room)),
|
||||||
|
response_sender(m::user::id::buf(response_sender)),
|
||||||
|
response_type(std::string(response_type)),
|
||||||
|
cmd(std::string(cmd)),
|
||||||
|
public_response,
|
||||||
|
watch_delay
|
||||||
|
]
|
||||||
|
{
|
||||||
|
watch_command
|
||||||
|
(
|
||||||
|
user_id,
|
||||||
|
room_id,
|
||||||
|
reply_id,
|
||||||
|
response_id,
|
||||||
|
response_room,
|
||||||
|
response_sender,
|
||||||
|
response_type,
|
||||||
|
cmd,
|
||||||
|
public_response,
|
||||||
|
watch_delay
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
catch(const std::exception &e)
|
catch(const std::exception &e)
|
||||||
{
|
{
|
||||||
|
@ -258,6 +348,90 @@ catch(const std::exception &e)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
watch_command(const m::user::id &user_id,
|
||||||
|
const m::room::id &room_id,
|
||||||
|
const m::event::id &reply_id,
|
||||||
|
const m::event::id &response_id,
|
||||||
|
const m::room::id &response_room,
|
||||||
|
const m::user::id &response_sender,
|
||||||
|
const string_view &response_type,
|
||||||
|
const string_view &cmd,
|
||||||
|
const bool &public_response,
|
||||||
|
const milliseconds &watch_delay)
|
||||||
|
{
|
||||||
|
const auto annotation_id
|
||||||
|
{
|
||||||
|
public_response?
|
||||||
|
m::annotate(response_room, response_sender, response_id, "▶️"_sv):
|
||||||
|
m::event::id::buf{}
|
||||||
|
};
|
||||||
|
|
||||||
|
const unwind deannotate{[&]
|
||||||
|
{
|
||||||
|
if(annotation_id && !m::redacted(annotation_id))
|
||||||
|
m::redact(response_room, response_sender, annotation_id, "cleared");
|
||||||
|
}};
|
||||||
|
|
||||||
|
const unique_buffer<mutable_buffer> buf
|
||||||
|
{
|
||||||
|
56_KiB
|
||||||
|
};
|
||||||
|
|
||||||
|
for(size_t i(0); i < size_t(watch_limit); ++i)
|
||||||
|
{
|
||||||
|
sleep(watch_delay);
|
||||||
|
|
||||||
|
if(m::redacted(response_id))
|
||||||
|
break;
|
||||||
|
|
||||||
|
if(annotation_id && m::redacted(annotation_id))
|
||||||
|
break;
|
||||||
|
|
||||||
|
const auto &[html, alt, msgtype]
|
||||||
|
{
|
||||||
|
execute_command(buf, user_id, room_id, cmd, reply_id, public_response)
|
||||||
|
};
|
||||||
|
|
||||||
|
if(!html && !alt)
|
||||||
|
break;
|
||||||
|
|
||||||
|
const json::value html_val
|
||||||
|
{
|
||||||
|
html, json::STRING
|
||||||
|
};
|
||||||
|
|
||||||
|
const json::value content_body
|
||||||
|
{
|
||||||
|
alt?: "no alt text"_sv, json::STRING
|
||||||
|
};
|
||||||
|
|
||||||
|
m::send(response_room, response_sender, response_type,
|
||||||
|
{
|
||||||
|
{ "body", content_body },
|
||||||
|
{ "format", html? html_format: undef_val },
|
||||||
|
{ "formatted_body", html? html_val: undef_val },
|
||||||
|
{ "input", cmd },
|
||||||
|
{ "msgtype", msgtype?: "m.notice" },
|
||||||
|
{ "room_id", room_id },
|
||||||
|
{ "m.new_content", json::members
|
||||||
|
{
|
||||||
|
{ "body", content_body },
|
||||||
|
{ "format", html? html_format: undef_val },
|
||||||
|
{ "formatted_body", html? html_val: undef_val },
|
||||||
|
{ "input", cmd },
|
||||||
|
{ "msgtype", msgtype?: "m.notice" },
|
||||||
|
{ "room_id", room_id },
|
||||||
|
}},
|
||||||
|
{ "m.relates_to", json::members
|
||||||
|
{
|
||||||
|
{ "event_id", response_id },
|
||||||
|
{ "rel_type", "m.replace" },
|
||||||
|
}}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static command_result
|
static command_result
|
||||||
command__summarize(const mutable_buffer &buf,
|
command__summarize(const mutable_buffer &buf,
|
||||||
const m::user &user,
|
const m::user &user,
|
||||||
|
|
|
@ -848,6 +848,91 @@ github_markdown(unique_const_buffer &buf,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
github_hook_for_each(const string_view &repo,
|
||||||
|
const function_bool<json::object> &closure)
|
||||||
|
{
|
||||||
|
unique_const_buffer buf;
|
||||||
|
const json::array response
|
||||||
|
{
|
||||||
|
github_request
|
||||||
|
(
|
||||||
|
buf, "GET", repo, "hooks"
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
|
for(const json::object hook : response)
|
||||||
|
if(!closure(hook))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
github_hook_ping(const string_view &repo,
|
||||||
|
const string_view &hook)
|
||||||
|
{
|
||||||
|
unique_const_buffer buf;
|
||||||
|
github_request
|
||||||
|
(
|
||||||
|
buf, "POST", repo, "hooks/%s/pings",
|
||||||
|
hook
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
github_hook_ping(const string_view &repo)
|
||||||
|
{
|
||||||
|
github_hook_for_each(repo, [&repo]
|
||||||
|
(const json::object &hook)
|
||||||
|
{
|
||||||
|
const json::string id
|
||||||
|
{
|
||||||
|
hook["id"]
|
||||||
|
};
|
||||||
|
|
||||||
|
github_hook_ping(repo, id);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
github_hook_shot_for_each(const string_view &repo,
|
||||||
|
const string_view &hook,
|
||||||
|
const bool &redelivery,
|
||||||
|
const function_bool<json::object> &closure)
|
||||||
|
{
|
||||||
|
unique_const_buffer buf;
|
||||||
|
const json::array response
|
||||||
|
{
|
||||||
|
github_request
|
||||||
|
(
|
||||||
|
//TODO: pagination token
|
||||||
|
buf, "GET", repo, "hooks/%s/deliveries?per_page=100",
|
||||||
|
hook
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
|
for(const json::object shot : response)
|
||||||
|
if(!closure(shot))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
github_hook_shot_retry(const string_view &repo,
|
||||||
|
const string_view &hook,
|
||||||
|
const string_view &id)
|
||||||
|
{
|
||||||
|
unique_const_buffer buf;
|
||||||
|
github_request
|
||||||
|
(
|
||||||
|
buf, "POST", repo, "hooks/%s/deliveries/%s/attempts",
|
||||||
|
hook,
|
||||||
|
id
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
github_run_for_each_jobs(const string_view &repo,
|
github_run_for_each_jobs(const string_view &repo,
|
||||||
const string_view &run_id,
|
const string_view &run_id,
|
||||||
|
|
Loading…
Reference in a new issue