Skip to content

Commit 807caec

Browse files
committed
0.15.0 - Avatar Batching
1 parent 1a56037 commit 807caec

11 files changed

Lines changed: 783 additions & 857 deletions

File tree

Cargo.lock

Lines changed: 684 additions & 765 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 15 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "vrc-log"
3-
version = "0.14.2"
3+
version = "0.15.0"
44
edition = "2024"
55
license = "MIT"
66
readme = "README.md"
@@ -21,31 +21,33 @@ chrono = "0.4"
2121
colored = "3"
2222
crossterm = { version = "0.29", optional = true }
2323
derive-config = { version = "2", features = ["dirs", "toml"] }
24-
discord-presence = { version = "2", optional = true }
25-
downcast-rs = "2.0.2"
26-
flume = "0.12.0"
24+
discord-presence = { version = "3", optional = true }
25+
flume = "0.12"
2726
futures = "0.3"
28-
inquire = "0.8"
29-
itertools = "0.14.0"
27+
inquire = "0.9"
28+
itertools = "0.14"
3029
lazy-regex = "3"
3130
notify = "8"
3231
parking_lot = "0.12"
33-
reqwest = { version = "0.12", default-features = false, features = [
34-
"json",
35-
], optional = true }
36-
rusqlite = "0.37.0"
32+
reqwest = { version = "0.13", features = ["json", "query"], optional = true }
33+
rusqlite = "0.38"
3734
serde = { version = "1", features = ["derive"] }
3835
serde_json = "1"
3936
strum = { version = "0.27", features = ["derive"] }
4037
terminal-link = "0.1"
4138
time = { version = "0.3", features = ["macros"] }
4239
tokio = { version = "1", features = ["full"] }
43-
tokio-rusqlite-new = { version = "0.11", features = [
44-
"bundled",
45-
], optional = true }
40+
tokio-rusqlite-new = { version = "0.12", features = ["bundled"], optional = true }
4641
tracing = "0.1"
4742
tracing-subscriber = { version = "=0.3.19", features = ["env-filter", "time"] }
4843

44+
[dev-dependencies]
45+
criterion = "0.8"
46+
reqwest = "0.13"
47+
tempfile = "3"
48+
tokio = { version = "1", features = ["full"] }
49+
uuid = { version = "1", features = ["v4"] }
50+
4951
[target.'cfg(windows)'.dependencies]
5052
windows = { version = "0.62", features = [
5153
"Win32_Foundation",
@@ -62,7 +64,6 @@ default = [
6264
"vrcdb",
6365
"vrcwb",
6466
"title",
65-
"rustls-tls",
6667
]
6768

6869
# VRChat Avatar Database Providers
@@ -76,9 +77,6 @@ vrcwb = ["dep:reqwest", "discord"]
7677
discord = ["dep:discord-presence", "dep:cached"]
7778
title = ["dep:crossterm"]
7879

79-
native-tls = ["reqwest/native-tls"]
80-
rustls-tls = ["reqwest/rustls-tls"]
81-
8280
[[bench]]
8381
name = "cache_bench"
8482
harness = false
@@ -87,7 +85,6 @@ harness = false
8785
name = "cache_disk_bench"
8886
harness = false
8987

90-
9188
# https://github.com/johnthagen/min-sized-rust
9289
[profile.release]
9390
strip = true # Automatically strip symbols from the binary.
@@ -102,11 +99,3 @@ nursery = { level = "warn", priority = -1 }
10299
cargo = { level = "warn", priority = -1 }
103100
multiple_crate_versions = "allow"
104101
similar_names = "allow"
105-
106-
[dev-dependencies]
107-
criterion = "0.8.1"
108-
httptest = "0.16.3"
109-
reqwest = "0.12"
110-
tempfile = "3.23.0"
111-
tokio = { version = "1", features = ["full"] }
112-
uuid = { version = "1.19.0", features = ["v4"] }

src/main.rs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,15 +10,16 @@ use crossterm::{execute, terminal::SetTitle};
1010
use derive_config::{ConfigError, DeriveTomlConfig};
1111
use notify::PollWatcher;
1212
use terminal_link::Link;
13-
use time::{UtcOffset, macros::format_description};
13+
use time::{macros::format_description, UtcOffset};
1414
use tokio::signal;
1515
use tracing::level_filters::LevelFilter;
16-
use tracing_subscriber::{EnvFilter, fmt::time::OffsetTime};
16+
use tracing_subscriber::{fmt::time::OffsetTime, EnvFilter};
1717
use vrc_log::{
18-
CARGO_PKG_HOMEPAGE, provider,
19-
provider::{ProviderKind, avtrdb::AvtrDBActor, prelude::*},
18+
provider,
19+
provider::{avtrdb::AvtrDBActor, prelude::*, ProviderKind},
2020
settings::Settings,
2121
vrchat::{VRCHAT_AMP_PATH, VRCHAT_LOW_PATH},
22+
CARGO_PKG_HOMEPAGE,
2223
};
2324

2425
/* Watchers will stop working if they get dropped. */

src/process.rs

Lines changed: 45 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,56 +1,70 @@
1-
use std::sync::Arc;
2-
3-
use crate::print_colorized;
4-
use crate::provider::Provider;
1+
use std::{collections::HashMap, sync::Arc};
52

63
#[cfg(feature = "cache")]
74
use crate::cache;
5+
use crate::{print_colorized, provider::Provider};
86

97
#[cfg(feature = "cache")]
108
pub async fn process_with_cache<I: IntoIterator<Item = String>>(
119
providers: Vec<Arc<Box<dyn Provider>>>,
1210
cache: &cache::Cache,
1311
avatar_ids: I,
1412
) -> anyhow::Result<()> {
15-
let checked_ids = cache.check_all_ids(avatar_ids).await?;
13+
let checked_ids = cache
14+
.check_all_ids(avatar_ids)
15+
.await?
16+
.into_iter()
17+
.collect::<Vec<_>>();
1618

1719
let (tx, rx) = flume::unbounded();
20+
let checked_ids = Arc::new(checked_ids);
21+
let mut base_bits = HashMap::new();
1822

19-
for (id, provider_bits) in checked_ids {
20-
print_colorized(&id);
23+
for (id, provider_bits) in checked_ids.iter() {
24+
print_colorized(id);
25+
base_bits.insert(id.clone(), *provider_bits);
26+
}
2127

22-
for p in providers
23-
.iter()
24-
.filter(|provider| provider_bits & provider.kind() as u32 == 0)
25-
{
26-
let p = p.clone();
27-
let id_clone = id.clone();
28-
let tx_clone = tx.clone();
29-
tokio::spawn(async move {
30-
let kind = p.kind();
31-
match p.send_avatar_id(&id_clone).await {
28+
for provider in &providers {
29+
let provider = provider.clone();
30+
let tx_clone = tx.clone();
31+
let checked_ids = checked_ids.clone();
32+
tokio::spawn(async move {
33+
let kind = provider.kind();
34+
let kind_bit = kind as u32;
35+
for (id, provider_bits) in checked_ids.iter() {
36+
if provider_bits & kind_bit != 0 {
37+
continue;
38+
}
39+
match provider.send_avatar_id(id).await {
3240
Ok(success) => {
3341
if success {
3442
info!("^ Successfully Submitted to {kind}");
35-
let _ = tx_clone
36-
.send_async((id_clone, provider_bits | kind as u32))
37-
.await;
43+
let _ = tx_clone.send_async((id.clone(), kind_bit)).await;
3844
}
3945
}
4046
Err(err) => {
4147
error!("^ Failed to submit to {kind}: {err}");
4248
}
4349
}
44-
});
45-
}
50+
}
51+
});
4652
}
4753

4854
drop(tx);
4955

50-
let mut buffer = Vec::new();
56+
let mut updated_bits = HashMap::new();
5157

52-
while let Ok(msg) = rx.recv_async().await {
53-
buffer.push(msg);
58+
while let Ok((id, kind_bit)) = rx.recv_async().await {
59+
let entry = updated_bits.entry(id).or_insert(0);
60+
*entry |= kind_bit;
61+
}
62+
63+
let mut buffer = Vec::new();
64+
for (id, bits) in base_bits {
65+
if let Some(add_bits) = updated_bits.get(&id) {
66+
buffer.push((id, bits | add_bits));
67+
}
5468
}
5569

5670
cache.store_avatar_ids_with_providers(buffer).await
@@ -90,19 +104,20 @@ pub async fn process_without_cache<I: IntoIterator<Item = String>>(
90104

91105
#[cfg(test)]
92106
mod tests {
93-
use crate::provider::ProviderKind;
107+
use std::sync::Arc;
94108

95-
use super::*;
96109
use anyhow::Result;
97110
use async_trait::async_trait;
98-
use std::sync::Arc;
99111
use strum::IntoEnumIterator;
100112
use tokio::sync::Mutex;
101113

114+
use super::*;
115+
use crate::provider::ProviderKind;
116+
102117
#[derive(Clone)]
103118
struct MockProvider {
104-
kind: ProviderKind,
105-
sent: Arc<Mutex<Vec<String>>>,
119+
kind: ProviderKind,
120+
sent: Arc<Mutex<Vec<String>>>,
106121
succeed: bool,
107122
}
108123

src/provider/avtrdb.rs

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use std::time::Duration;
22

3-
use anyhow::{Result, bail};
3+
use anyhow::{bail, Result};
44
use colored::{Color, Colorize};
55
use flume::{Receiver, Sender};
66
use reqwest::{Client, StatusCode, Url};
@@ -10,9 +10,9 @@ use terminal_link::Link;
1010
use tokio::time::Instant;
1111

1212
use crate::{
13-
USER_AGENT,
1413
provider::{Provider, ProviderKind},
1514
settings::Settings,
15+
USER_AGENT,
1616
};
1717

1818
const INGEST_BASE_URL: &str = "https://api.avtrdb.com/v3/";
@@ -31,13 +31,13 @@ pub struct AvtrDB {
3131
}
3232

3333
pub struct AvtrDBActor<'s> {
34-
settings: &'s Settings,
35-
client: Client,
36-
buffer: Vec<String>,
37-
base_url: String,
38-
channel: Receiver<String>,
34+
settings: &'s Settings,
35+
client: Client,
36+
buffer: Vec<String>,
37+
base_url: String,
38+
channel: Receiver<String>,
3939
flush_interval: Duration,
40-
last_flush: Instant,
40+
last_flush: Instant,
4141
}
4242

4343
impl<'s> AvtrDBActor<'s> {
@@ -177,8 +177,8 @@ impl AvtrDB {
177177
#[allow(dead_code)]
178178
struct IngestResponse {
179179
avatars_enqueued: u64,
180-
invalid_ids: u64,
181-
ticket: String,
180+
invalid_ids: u64,
181+
ticket: String,
182182
}
183183

184184
#[async_trait::async_trait]

src/provider/mod.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,16 +24,16 @@ pub enum ProviderKind {
2424
#[cfg(feature = "nsvr")]
2525
#[strum(to_string = "NSVR - NekoSune Community")]
2626
#[serde(alias = "VRCDS")]
27-
NSVR = 1 << 1,
27+
NSVR = 1 << 1,
2828
#[cfg(feature = "paw")]
2929
#[strum(to_string = "PAW - Puppy's Avatar World")]
30-
PAW = 1 << 2,
30+
PAW = 1 << 2,
3131
#[cfg(feature = "vrcdb")]
3232
#[strum(to_string = "VRCDB - Avatar Search")]
33-
VRCDB = 1 << 3,
33+
VRCDB = 1 << 3,
3434
#[cfg(feature = "vrcwb")]
3535
#[strum(to_string = "VRCWB - World Balancer")]
36-
VRCWB = 1 << 4,
36+
VRCWB = 1 << 4,
3737
}
3838

3939
#[async_trait]

src/provider/nsvr.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,21 @@
11
use std::time::Duration;
22

3-
use anyhow::{Result, bail};
3+
use anyhow::{bail, Result};
44
use async_trait::async_trait;
55
use reqwest::{Client, StatusCode};
66
use serde_json::json;
77

88
use crate::{
9-
USER_AGENT,
109
provider::{Provider, ProviderKind},
1110
settings::Settings,
11+
USER_AGENT,
1212
};
1313

1414
const URL: &str = "https://avtr.nekosunevr.co.uk/v1/vrchat/avatars/store/putavatarExternal";
1515

1616
pub struct NSVR<'s> {
1717
settings: &'s Settings,
18-
client: Client,
18+
client: Client,
1919
}
2020

2121
impl<'s> NSVR<'s> {

src/provider/paw.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
11
use std::time::Duration;
22

3-
use anyhow::{Result, bail};
3+
use anyhow::{bail, Result};
44
use async_trait::async_trait;
55
use reqwest::{Client, StatusCode};
66
use serde::Deserialize;
77
use serde_json::Value;
88

99
use crate::{
10-
USER_AGENT,
1110
provider::{Provider, ProviderKind},
1211
settings::Settings,
12+
USER_AGENT,
1313
};
1414

1515
const URL: &str = "https://paw-api.amelia.fun/update";
@@ -31,9 +31,9 @@ impl Paw {
3131
#[allow(dead_code)]
3232
struct PawResponse {
3333
success: bool,
34-
code: u16,
35-
result: Option<Value>,
36-
avatar: Option<Value>,
34+
code: u16,
35+
result: Option<Value>,
36+
avatar: Option<Value>,
3737
}
3838

3939
#[async_trait]

src/provider/vrcdb.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,21 @@
11
use std::time::Duration;
22

3-
use anyhow::{Result, bail};
3+
use anyhow::{bail, Result};
44
use async_trait::async_trait;
55
use reqwest::{Client, StatusCode};
66
use serde_json::json;
77

88
use crate::{
9-
USER_AGENT,
109
provider::{Provider, ProviderKind},
1110
settings::Settings,
11+
USER_AGENT,
1212
};
1313

1414
const URL: &str = "https://search.bs002.de/api/Avatar/putavatar";
1515

1616
pub struct VrcDB<'s> {
1717
settings: &'s Settings,
18-
client: Client,
18+
client: Client,
1919
}
2020

2121
impl<'s> VrcDB<'s> {

0 commit comments

Comments
 (0)