uwu
This commit is contained in:
parent
581c16a8b2
commit
7b512e78d5
|
@ -120,8 +120,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "bfd4d1b31faaa3a89d7934dbded3111da0d2ef28e3ebccdb4f0179f5929d1ef1"
|
||||
dependencies = [
|
||||
"iana-time-zone",
|
||||
"js-sys",
|
||||
"num-integer",
|
||||
"num-traits",
|
||||
"time",
|
||||
"wasm-bindgen",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
|
@ -364,7 +367,7 @@ checksum = "4eb1a864a501629691edf6c15a593b7a51eebaa1e8468e9ddc623de7c9b58ec6"
|
|||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"wasi",
|
||||
"wasi 0.11.0+wasi-snapshot-preview1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -663,7 +666,7 @@ checksum = "57ee1c23c7c63b0c9250c339ffdc69255f110b298b901b9f6c82547b7b87caaf"
|
|||
dependencies = [
|
||||
"libc",
|
||||
"log",
|
||||
"wasi",
|
||||
"wasi 0.11.0+wasi-snapshot-preview1",
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
|
@ -1032,6 +1035,7 @@ version = "0.1.0"
|
|||
dependencies = [
|
||||
"anyhow",
|
||||
"base64",
|
||||
"chrono",
|
||||
"rand",
|
||||
"serde",
|
||||
"serde_yaml",
|
||||
|
@ -1281,6 +1285,17 @@ dependencies = [
|
|||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "time"
|
||||
version = "0.1.44"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6db9e6914ab8b1ae1c260a4ae7a49b6c5611b40328a735b21862567685e73255"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"wasi 0.10.0+wasi-snapshot-preview1",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tinyvec"
|
||||
version = "1.6.0"
|
||||
|
@ -1599,6 +1614,12 @@ dependencies = [
|
|||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasi"
|
||||
version = "0.10.0+wasi-snapshot-preview1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f"
|
||||
|
||||
[[package]]
|
||||
name = "wasi"
|
||||
version = "0.11.0+wasi-snapshot-preview1"
|
||||
|
|
|
@ -8,6 +8,7 @@ edition = "2021"
|
|||
[dependencies]
|
||||
anyhow = "1"
|
||||
base64 = "0.13"
|
||||
chrono = "0.4"
|
||||
rand = "0.8"
|
||||
serde = { version = "1", features = ["derive"] }
|
||||
serde_yaml = "0.9"
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
alter table users
|
||||
add column extra integer not null default 0;
|
|
@ -155,6 +155,7 @@ words:
|
|||
- Allagan tomestone
|
||||
- gil
|
||||
- scrip
|
||||
- third-party tool
|
||||
|
||||
- name: Battle Tactics
|
||||
words:
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
use serde::{Deserialize, Serialize};
|
||||
use sqlx::types::chrono::NaiveDateTime;
|
||||
use uuid::Uuid;
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
|
@ -31,6 +32,8 @@ pub struct RetrievedMessage {
|
|||
pub positive_votes: i32,
|
||||
pub negative_votes: i32,
|
||||
pub user_vote: i64,
|
||||
#[serde(skip)]
|
||||
pub created: NaiveDateTime,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize)]
|
||||
|
|
|
@ -30,7 +30,7 @@ pub fn routes(state: Arc<State>) -> BoxedFilter<(impl Reply, )> {
|
|||
.boxed()
|
||||
}
|
||||
|
||||
pub fn get_id(state: Arc<State>) -> BoxedFilter<(i64, )> {
|
||||
pub fn get_id(state: Arc<State>) -> BoxedFilter<((i64, i64), )> {
|
||||
warp::cookie("access_token")
|
||||
.or(warp::header("x-api-key"))
|
||||
.unify()
|
||||
|
@ -40,13 +40,13 @@ pub fn get_id(state: Arc<State>) -> BoxedFilter<(i64, )> {
|
|||
let hashed = crate::util::hash(&access_token);
|
||||
let id = sqlx::query!(
|
||||
// language=sqlite
|
||||
"select id from users where auth = ?",
|
||||
"select id, extra from users where auth = ?",
|
||||
hashed,
|
||||
)
|
||||
.fetch_optional(&state.db)
|
||||
.await;
|
||||
match id {
|
||||
Ok(Some(i)) => Ok(i.id),
|
||||
Ok(Some(i)) => Ok((i.id, i.extra)),
|
||||
Ok(None) => Err(warp::reject::custom(WebError::InvalidAuthToken)),
|
||||
Err(e) => Err(warp::reject::custom(AnyhowRejection(e.into()))),
|
||||
}
|
||||
|
|
|
@ -14,7 +14,7 @@ pub fn erase(state: Arc<State>) -> BoxedFilter<(impl Reply, )> {
|
|||
.and(warp::path::param())
|
||||
.and(warp::path::end())
|
||||
.and(super::get_id(Arc::clone(&state)))
|
||||
.and_then(move |post_id: Uuid, id: i64| logic(Arc::clone(&state), id, post_id))
|
||||
.and_then(move |post_id: Uuid, (id, _)| logic(Arc::clone(&state), id, post_id))
|
||||
.boxed()
|
||||
}
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@ use std::collections::HashMap;
|
|||
use std::sync::Arc;
|
||||
|
||||
use anyhow::Context;
|
||||
use chrono::{Duration, Utc};
|
||||
use rand::distributions::WeightedIndex;
|
||||
use rand::Rng;
|
||||
use warp::{Filter, Rejection, Reply};
|
||||
|
@ -18,7 +19,7 @@ pub fn get_location(state: Arc<State>) -> BoxedFilter<(impl Reply, )> {
|
|||
.and(warp::path::end())
|
||||
.and(warp::query::<HashMap<String, String>>())
|
||||
.and(super::get_id(Arc::clone(&state)))
|
||||
.and_then(move |location: u32, query: HashMap<String, String>, id: i64| logic(Arc::clone(&state), id, location, query))
|
||||
.and_then(move |location: u32, query: HashMap<String, String>, (id, _)| logic(Arc::clone(&state), id, location, query))
|
||||
.boxed()
|
||||
}
|
||||
|
||||
|
@ -38,7 +39,8 @@ async fn logic(state: Arc<State>, id: i64, location: u32, query: HashMap<String,
|
|||
m.message,
|
||||
coalesce(sum(v.vote between 0 and 1), 0) as positive_votes,
|
||||
coalesce(sum(v.vote between -1 and 0), 0) as negative_votes,
|
||||
v2.vote as user_vote
|
||||
v2.vote as user_vote,
|
||||
m.created
|
||||
from messages m
|
||||
left join votes v on m.id = v.message
|
||||
left join votes v2 on m.id = v2.message and v2.user = ?
|
||||
|
@ -60,8 +62,6 @@ async fn logic(state: Arc<State>, id: i64, location: u32, query: HashMap<String,
|
|||
|
||||
fn filter_messages(messages: &mut Vec<RetrievedMessage>) {
|
||||
// just count nearby messages. this is O(n^2) but alternatives are hard
|
||||
// let mut nearby = HashMap::with_capacity(messages.len());
|
||||
let mut weights = HashMap::with_capacity(messages.len());
|
||||
let mut ids = Vec::with_capacity(messages.len());
|
||||
for a in messages.iter() {
|
||||
let mut nearby = 0;
|
||||
|
@ -79,10 +79,11 @@ fn filter_messages(messages: &mut Vec<RetrievedMessage>) {
|
|||
continue;
|
||||
}
|
||||
|
||||
// *nearby.entry(&a.id).or_insert(0) += 1;
|
||||
nearby += 1;
|
||||
}
|
||||
|
||||
println!("{} ({} nearby)", a.id, nearby);
|
||||
|
||||
if nearby <= 2 {
|
||||
// always include groups of three or fewer
|
||||
ids.push(a.id.clone());
|
||||
|
@ -90,28 +91,36 @@ fn filter_messages(messages: &mut Vec<RetrievedMessage>) {
|
|||
}
|
||||
|
||||
let score = (a.positive_votes - a.negative_votes).max(0);
|
||||
let raw_weight = score as f32 * (1.0 / nearby as f32);
|
||||
let weight = raw_weight.trunc() as i64;
|
||||
println!("{}: weight {} ({} nearby)", a.id, weight.max(1), nearby);
|
||||
weights.insert(a.id.clone(), weight.max(1));
|
||||
}
|
||||
|
||||
if weights.is_empty() {
|
||||
return;
|
||||
}
|
||||
|
||||
let max_weight = weights.values().map(|weight| *weight).max().unwrap();
|
||||
messages.drain_filter(|msg| {
|
||||
if ids.contains(&msg.id) {
|
||||
return false;
|
||||
let time_since_creation = Utc::now().naive_utc().signed_duration_since(a.created) - Duration::weeks(score as i64);
|
||||
println!(" time_since_creation: {}", Utc::now().naive_utc().signed_duration_since(a.created));
|
||||
println!(" modified: {}", time_since_creation);
|
||||
if time_since_creation > Duration::weeks(1) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let weight = match weights.get(&msg.id) {
|
||||
Some(w) => *w,
|
||||
None => return true,
|
||||
};
|
||||
let brand_new = time_since_creation < Duration::hours(6);
|
||||
let new = time_since_creation < Duration::days(2);
|
||||
|
||||
// weight / max_weight chance of being included (returning true means NOT included)
|
||||
!rand::thread_rng().gen_ratio(weight as u32, max_weight as u32)
|
||||
let mut numerator = 1;
|
||||
if brand_new {
|
||||
numerator = nearby;
|
||||
} else if new {
|
||||
numerator += (nearby / 3).min(1);
|
||||
}
|
||||
|
||||
if score > 0 {
|
||||
let pad = score as f32 / nearby as f32;
|
||||
let rounded = pad.round() as u32;
|
||||
numerator += rounded.max(nearby / 2);
|
||||
}
|
||||
|
||||
println!(" chance: {}/{}", numerator, nearby);
|
||||
if rand::thread_rng().gen_ratio(numerator.min(nearby), nearby) {
|
||||
ids.push(a.id.clone());
|
||||
}
|
||||
}
|
||||
|
||||
messages.drain_filter(|msg| {
|
||||
return !ids.contains(&msg.id);
|
||||
});
|
||||
}
|
||||
|
|
|
@ -15,7 +15,7 @@ pub fn get_message(state: Arc<State>) -> BoxedFilter<(impl Reply, )> {
|
|||
.and(warp::path::param())
|
||||
.and(warp::path::end())
|
||||
.and(super::get_id(Arc::clone(&state)))
|
||||
.and_then(move |message_id: Uuid, id: i64| logic(Arc::clone(&state), id, message_id))
|
||||
.and_then(move |message_id: Uuid, (id, _)| logic(Arc::clone(&state), id, message_id))
|
||||
.boxed()
|
||||
}
|
||||
|
||||
|
|
|
@ -13,7 +13,7 @@ pub fn get_mine(state: Arc<State>) -> BoxedFilter<(impl Reply, )> {
|
|||
.and(warp::path("messages"))
|
||||
.and(warp::path::end())
|
||||
.and(super::get_id(Arc::clone(&state)))
|
||||
.and_then(move |id: i64| logic(Arc::clone(&state), id))
|
||||
.and_then(move |(id, _)| logic(Arc::clone(&state), id))
|
||||
.boxed()
|
||||
}
|
||||
|
||||
|
|
|
@ -12,7 +12,7 @@ pub fn unregister(state: Arc<State>) -> BoxedFilter<(impl Reply, )> {
|
|||
.and(warp::path("account"))
|
||||
.and(warp::path::end())
|
||||
.and(super::get_id(Arc::clone(&state)))
|
||||
.and_then(move |id: i64| logic(Arc::clone(&state), id))
|
||||
.and_then(move |(id, _)| logic(Arc::clone(&state), id))
|
||||
.boxed()
|
||||
}
|
||||
|
||||
|
|
|
@ -16,7 +16,7 @@ pub fn vote(state: Arc<State>) -> BoxedFilter<(impl Reply, )> {
|
|||
.and(warp::path::end())
|
||||
.and(super::get_id(Arc::clone(&state)))
|
||||
.and(warp::body::json())
|
||||
.and_then(move |message_id: Uuid, id: i64, vote: i8| logic(Arc::clone(&state), id, message_id, vote))
|
||||
.and_then(move |message_id: Uuid, (id, _), vote: i8| logic(Arc::clone(&state), id, message_id, vote))
|
||||
.boxed()
|
||||
}
|
||||
|
||||
|
|
|
@ -15,11 +15,11 @@ pub fn write(state: Arc<State>) -> BoxedFilter<(impl Reply, )> {
|
|||
.and(warp::path::end())
|
||||
.and(super::get_id(Arc::clone(&state)))
|
||||
.and(warp::body::json())
|
||||
.and_then(move |id: i64, message: Message| logic(Arc::clone(&state), id, message))
|
||||
.and_then(move |(id, extra), message: Message| logic(Arc::clone(&state), id, extra, message))
|
||||
.boxed()
|
||||
}
|
||||
|
||||
async fn logic(state: Arc<State>, id: i64, message: Message) -> Result<impl Reply, Rejection> {
|
||||
async fn logic(state: Arc<State>, id: i64, extra: i64, message: Message) -> Result<impl Reply, Rejection> {
|
||||
let text = {
|
||||
let packs = state.packs.read().await;
|
||||
let pack = packs.get(&message.pack_id)
|
||||
|
@ -47,7 +47,7 @@ async fn logic(state: Arc<State>, id: i64, message: Message) -> Result<impl Repl
|
|||
.map_err(AnyhowRejection)
|
||||
.map_err(warp::reject::custom)?;
|
||||
|
||||
if existing.count >= 10 {
|
||||
if existing.count >= 10 + extra as i32 {
|
||||
return Err(warp::reject::custom(WebError::TooManyMessages));
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue