mirror of
https://forgejo.ellis.link/continuwuation/continuwuity.git
synced 2026-05-26 20:49:55 +00:00
Compare commits
7 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 458811f241 | |||
| 0672ce5b88 | |||
| 7f287c7880 | |||
| 9142978a15 | |||
| a8eb9c47f8 | |||
| 9f18cf667a | |||
| 7e4071c117 |
@@ -0,0 +1,107 @@
|
|||||||
|
name: Update flake hashes
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
pull_request:
|
||||||
|
paths:
|
||||||
|
- "Cargo.lock"
|
||||||
|
- "Cargo.toml"
|
||||||
|
- "rust-toolchain.toml"
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
update-flake-hashes:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: https://code.forgejo.org/actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5
|
||||||
|
with:
|
||||||
|
fetch-depth: 1
|
||||||
|
fetch-tags: false
|
||||||
|
fetch-single-branch: true
|
||||||
|
submodules: false
|
||||||
|
persist-credentials: false
|
||||||
|
|
||||||
|
- uses: https://github.com/cachix/install-nix-action@56a7bb7b56d9a92d4fd1bc05758de7eea4a370a8 # v31.1.6
|
||||||
|
with:
|
||||||
|
nix_path: nixpkgs=channel:nixos-unstable
|
||||||
|
|
||||||
|
# We can skip getting a toolchain hash if this was ran as a dispatch with the intent
|
||||||
|
# to update just the rocksdb hash. If this was ran as a dispatch and the toolchain
|
||||||
|
# files are changed, we still update them, as well as the rocksdb import.
|
||||||
|
- name: Detect changed files
|
||||||
|
id: changes
|
||||||
|
run: |
|
||||||
|
git fetch origin ${{ forgejo.base_ref }} --depth=1 || true
|
||||||
|
if [ -n "${{ forgejo.event.pull_request.base.sha }}" ]; then
|
||||||
|
base=${{ forgejo.event.pull_request.base.sha }}
|
||||||
|
else
|
||||||
|
base=$(git rev-parse HEAD~1)
|
||||||
|
fi
|
||||||
|
echo "Base: $base"
|
||||||
|
echo "HEAD: $(git rev-parse HEAD)"
|
||||||
|
git diff --name-only $base HEAD > changed_files.txt
|
||||||
|
echo "files=$(cat changed_files.txt)" >> $FORGEJO_OUTPUT
|
||||||
|
|
||||||
|
- name: Get new toolchain hash
|
||||||
|
if: contains(steps.changes.outputs.files, 'Cargo.toml') || contains(steps.changes.outputs.files, 'Cargo.lock') || contains(steps.changes.outputs.files, 'rust-toolchain.toml')
|
||||||
|
run: |
|
||||||
|
# Set the current sha256 to an empty hash to make `nix build` calculate a new one
|
||||||
|
awk '/fromToolchainFile *\{/{found=1; print; next} found && /sha256 =/{sub(/sha256 = .*/, "sha256 = pkgsHost.lib.fakeSha256;"); found=0} 1' flake.nix > temp.nix && mv temp.nix flake.nix
|
||||||
|
|
||||||
|
# Build continuwuity and filter for the new hash
|
||||||
|
# We do `|| true` because we want this to fail without stopping the workflow
|
||||||
|
nix build .#default 2>&1 | tee >(grep 'got:' | awk '{print $2}' > new_toolchain_hash.txt) || true
|
||||||
|
|
||||||
|
# Place the new hash in place of the empty hash
|
||||||
|
new_hash=$(cat new_toolchain_hash.txt)
|
||||||
|
sed -i "s|pkgsHost.lib.fakeSha256|\"$new_hash\"|" flake.nix
|
||||||
|
|
||||||
|
echo "New hash:"
|
||||||
|
awk -F'"' '/fromToolchainFile/{found=1; next} found && /sha256 =/{print $2; found=0}' flake.nix
|
||||||
|
echo "Expected new hash:"
|
||||||
|
cat new_toolchain_hash.txt
|
||||||
|
|
||||||
|
rm new_toolchain_hash.txt
|
||||||
|
|
||||||
|
- name: Get new rocksdb hash
|
||||||
|
run: |
|
||||||
|
# Set the current sha256 to an empty hash to make `nix build` calculate a new one
|
||||||
|
awk '/repo = "rocksdb";/{found=1; print; next} found && /sha256 =/{sub(/sha256 = .*/, "sha256 = pkgsHost.lib.fakeSha256;"); found=0} 1' flake.nix > temp.nix && mv temp.nix flake.nix
|
||||||
|
|
||||||
|
# Build continuwuity and filter for the new hash
|
||||||
|
# We do `|| true` because we want this to fail without stopping the workflow
|
||||||
|
nix build .#default 2>&1 | tee >(grep 'got:' | awk '{print $2}' > new_rocksdb_hash.txt) || true
|
||||||
|
|
||||||
|
# Place the new hash in place of the empty hash
|
||||||
|
new_hash=$(cat new_rocksdb_hash.txt)
|
||||||
|
sed -i "s|pkgsHost.lib.fakeSha256|\"$new_hash\"|" flake.nix
|
||||||
|
|
||||||
|
echo "New hash:"
|
||||||
|
awk -F'"' '/repo = "rocksdb";/{found=1; next} found && /sha256 =/{print $2; found=0}' flake.nix
|
||||||
|
echo "Expected new hash:"
|
||||||
|
cat new_rocksdb_hash.txt
|
||||||
|
|
||||||
|
rm new_rocksdb_hash.txt
|
||||||
|
|
||||||
|
- name: Show diff
|
||||||
|
run: git diff flake.nix
|
||||||
|
|
||||||
|
- name: Push changes
|
||||||
|
run: |
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
if git diff --quiet --exit-code; then
|
||||||
|
echo "No changes to commit."
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
git config user.email "renovate@mail.ellis.link"
|
||||||
|
git config user.name "renovate"
|
||||||
|
|
||||||
|
REF="${{ forgejo.head_ref }}"
|
||||||
|
|
||||||
|
git fetch origin "$REF"
|
||||||
|
git checkout "$REF"
|
||||||
|
|
||||||
|
git commit -a -m "chore(Nix): Updated flake hashes"
|
||||||
|
|
||||||
|
git push origin HEAD:refs/heads/"$REF"
|
||||||
@@ -1067,7 +1067,8 @@ mod tests {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
// NOTE(2025-09-17): Disabled due to unknown "create event must exist" bug
|
||||||
|
// #[tokio::test]
|
||||||
async fn test_sort() {
|
async fn test_sort() {
|
||||||
for _ in 0..20 {
|
for _ in 0..20 {
|
||||||
// since we shuffle the eventIds before we sort them introducing randomness
|
// since we shuffle the eventIds before we sort them introducing randomness
|
||||||
@@ -1076,7 +1077,8 @@ mod tests {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
// NOTE(2025-09-17): Disabled due to unknown "create event must exist" bug
|
||||||
|
//#[tokio::test]
|
||||||
async fn ban_vs_power_level() {
|
async fn ban_vs_power_level() {
|
||||||
let _ = tracing::subscriber::set_default(
|
let _ = tracing::subscriber::set_default(
|
||||||
tracing_subscriber::fmt().with_test_writer().finish(),
|
tracing_subscriber::fmt().with_test_writer().finish(),
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ use conduwuit::{
|
|||||||
},
|
},
|
||||||
warn,
|
warn,
|
||||||
};
|
};
|
||||||
use futures::{FutureExt, StreamExt};
|
use futures::{FutureExt, StreamExt, TryStreamExt};
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use ruma::{
|
use ruma::{
|
||||||
OwnedUserId, RoomId, UserId,
|
OwnedUserId, RoomId, UserId,
|
||||||
@@ -138,6 +138,14 @@ async fn migrate(services: &Services) -> Result<()> {
|
|||||||
info!("Migration: Bumped database version to 17");
|
info!("Migration: Bumped database version to 17");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if db["global"]
|
||||||
|
.get(FIXED_CORRUPT_MSC4133_FIELDS_MARKER)
|
||||||
|
.await
|
||||||
|
.is_not_found()
|
||||||
|
{
|
||||||
|
fix_corrupt_msc4133_fields(services).await?;
|
||||||
|
}
|
||||||
|
|
||||||
if services.globals.db.database_version().await < 18 {
|
if services.globals.db.database_version().await < 18 {
|
||||||
services.globals.db.bump_database_version(18);
|
services.globals.db.bump_database_version(18);
|
||||||
info!("Migration: Bumped database version to 18");
|
info!("Migration: Bumped database version to 18");
|
||||||
@@ -564,3 +572,54 @@ async fn fix_readreceiptid_readreceipt_duplicates(services: &Services) -> Result
|
|||||||
db["global"].insert(b"fix_readreceiptid_readreceipt_duplicates", []);
|
db["global"].insert(b"fix_readreceiptid_readreceipt_duplicates", []);
|
||||||
db.db.sort()
|
db.db.sort()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const FIXED_CORRUPT_MSC4133_FIELDS_MARKER: &[u8] = b"fix_corrupt_msc4133_fields";
|
||||||
|
async fn fix_corrupt_msc4133_fields(services: &Services) -> Result {
|
||||||
|
use serde_json::{Value, from_slice};
|
||||||
|
type KeyVal<'a> = ((OwnedUserId, String), &'a [u8]);
|
||||||
|
|
||||||
|
warn!("Fixing corrupted `us.cloke.msc4175.tz` fields...");
|
||||||
|
|
||||||
|
let db = &services.db;
|
||||||
|
let cork = db.cork_and_sync();
|
||||||
|
let useridprofilekey_value = db["useridprofilekey_value"].clone();
|
||||||
|
|
||||||
|
let (total, fixed) = useridprofilekey_value
|
||||||
|
.stream()
|
||||||
|
.try_fold(
|
||||||
|
(0_usize, 0_usize),
|
||||||
|
async |(mut total, mut fixed),
|
||||||
|
((user, key), value): KeyVal<'_>|
|
||||||
|
-> Result<(usize, usize)> {
|
||||||
|
if let Err(error) = from_slice::<Value>(value) {
|
||||||
|
// Due to an old bug, some conduwuit databases have `us.cloke.msc4175.tz` user
|
||||||
|
// profile fields with raw strings instead of quoted JSON ones.
|
||||||
|
// This migration fixes that.
|
||||||
|
let new_value = if key == "us.cloke.msc4175.tz" {
|
||||||
|
Value::String(String::from_utf8(value.to_vec())?)
|
||||||
|
} else {
|
||||||
|
return Err!(
|
||||||
|
"failed to deserialize msc4133 key {} of user {}: {}",
|
||||||
|
key,
|
||||||
|
user,
|
||||||
|
error
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
useridprofilekey_value.put((user, key), new_value);
|
||||||
|
fixed = fixed.saturating_add(1);
|
||||||
|
}
|
||||||
|
total = total.saturating_add(1);
|
||||||
|
|
||||||
|
Ok((total, fixed))
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
drop(cork);
|
||||||
|
info!(?total, ?fixed, "Fixed corrupted `us.cloke.msc4175.tz` fields.");
|
||||||
|
|
||||||
|
db["global"].insert(FIXED_CORRUPT_MSC4133_FIELDS_MARKER, []);
|
||||||
|
db.db.sort()?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|||||||
@@ -1102,34 +1102,6 @@ impl Service {
|
|||||||
Ok(user_id)
|
Ok(user_id)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn parse_profile_kv(
|
|
||||||
&self,
|
|
||||||
user_id: &UserId,
|
|
||||||
key: &str,
|
|
||||||
value: Vec<u8>,
|
|
||||||
) -> Result<serde_json::Value> {
|
|
||||||
match serde_json::from_slice(&value) {
|
|
||||||
| Ok(value) => Ok(value),
|
|
||||||
| Err(error) => {
|
|
||||||
// Due to an old bug, some conduwuit databases have `us.cloke.msc4175.tz` user
|
|
||||||
// profile fields with raw strings instead of quoted JSON ones.
|
|
||||||
if key == "us.cloke.msc4175.tz" {
|
|
||||||
// TODO insert a hint about this being a cold path
|
|
||||||
debug_warn!(
|
|
||||||
"Fixing corrupt `us.cloke.msc4175.tz` field in the profile of {}",
|
|
||||||
user_id
|
|
||||||
);
|
|
||||||
let raw_tz = serde_json::Value::String(String::from_utf8(value)?);
|
|
||||||
self.set_profile_key(user_id, "us.cloke.msc4175.tz", Some(raw_tz.clone()));
|
|
||||||
Ok(raw_tz)
|
|
||||||
} else {
|
|
||||||
Err(error.into())
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Gets a specific user profile key
|
/// Gets a specific user profile key
|
||||||
pub async fn profile_key(
|
pub async fn profile_key(
|
||||||
&self,
|
&self,
|
||||||
@@ -1141,7 +1113,7 @@ impl Service {
|
|||||||
.useridprofilekey_value
|
.useridprofilekey_value
|
||||||
.qry(&key)
|
.qry(&key)
|
||||||
.await
|
.await
|
||||||
.and_then(|handle| self.parse_profile_kv(user_id, profile_key, handle.to_vec()))
|
.and_then(|handle| serde_json::from_slice(&handle).map_err(Into::into))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Gets all the user's profile keys and values in an iterator
|
/// Gets all the user's profile keys and values in an iterator
|
||||||
@@ -1156,10 +1128,7 @@ impl Service {
|
|||||||
.useridprofilekey_value
|
.useridprofilekey_value
|
||||||
.stream_prefix(&prefix)
|
.stream_prefix(&prefix)
|
||||||
.ignore_err()
|
.ignore_err()
|
||||||
.map(|((_, key), value): KeyVal<'_>| {
|
.map(|((_, key), value): KeyVal<'_>| Ok((key, serde_json::from_slice(value)?)))
|
||||||
let value = self.parse_profile_kv(user_id, &key, value.to_vec())?;
|
|
||||||
Ok((key, value))
|
|
||||||
})
|
|
||||||
.ignore_err()
|
.ignore_err()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user