Skip to content

Commit 99af021

Browse files
authored
Merge pull request #40 from spacestation13/cancelshit
adds job cancelling for commit spam, updates spacemandmm, updates
2 parents 45f35ef + 250a7ce commit 99af021

File tree

18 files changed

+872
-1316
lines changed

18 files changed

+872
-1316
lines changed

Cargo.lock

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

crates/diffbot_lib/Cargo.toml

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,22 @@
11
[package]
22
name = "diffbot_lib"
33
version = "0.1.0"
4-
edition = "2021"
4+
edition = "2024"
55
license = "MIT"
66

77
[dependencies]
88
serde = { version = "1.0.219", features = ["derive"] }
9-
octocrab = "0.44.0"
9+
octocrab = "0.44.1"
1010
eyre = "0.6.12"
1111
derive_builder = "0.20.2"
12-
chrono = "0.4.40"
13-
sha2 = "0.10.8"
12+
chrono = "0.4.41"
13+
sha2 = "0.10.9"
1414
hmac = "0.12.1"
1515
hex = "0.4.3"
1616
tracing = "0.1"
1717
tracing-subscriber = { version = "0.3", features = ["fmt", "time"] }
1818
tracing-panic = "0.1.2"
1919
tracing-loki = "0.2.6"
2020
flume = "0.11.1"
21-
async-fs = "2.1.2"
2221

23-
actix-web = "4.10.2"
22+
actix-web = "4.11.0"

crates/diffbot_lib/src/job/types.rs

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,6 @@ pub type JobRunner = fn(Job) -> Result<CheckOutputs>;
1111

1212
pub type JobSender<T> = Sender<T>;
1313

14-
#[derive(Serialize, Deserialize, Debug, Clone)]
15-
pub enum JobType {
16-
GithubJob(Box<Job>),
17-
CleanupJob,
18-
}
19-
2014
#[derive(Serialize, Deserialize, Debug, Clone)]
2115
pub struct Job {
2216
pub repo: github_types::Repository,

crates/diffbot_lib/src/lib.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,4 @@ pub mod github;
22
pub mod job;
33
pub mod logger;
44
pub mod verify;
5-
pub use async_fs;
65
pub use tracing;

crates/icondiffbot2/Cargo.toml

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,33 @@
11
[package]
22
name = "icondiffbot2"
33
version = "0.1.0"
4-
edition = "2021"
4+
edition = "2024"
55
license = "MIT"
66
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
77

88
[dependencies]
99
serde = { version = "1.0.219", features = ["derive"] }
10-
serde_json = "1.0.140"
11-
octocrab = "0.44.0"
10+
serde_json = "1.0.143"
11+
octocrab = "0.44.1"
1212
dmm-tools = { git = "https://github.com/jupyterkat/SpacemanDMM/" }
1313
jsonwebtoken = "9.3.1"
14-
reqwest = "0.12.15"
14+
reqwest = "0.12.23"
1515
diffbot_lib = { path = "../diffbot_lib" }
1616
eyre = "0.6.12"
1717
simple-eyre = "0.3.1"
18-
rayon = "1.10.0"
19-
toml = "0.8.20"
20-
ahash = "0.8.11"
21-
hashbrown = { version = "0.15.2", features = ["rayon"] }
18+
rayon = "1.11.0"
19+
toml = "0.9.5"
20+
ahash = "0.8.12"
21+
hashbrown = { version = "0.15.5", features = ["rayon"] }
2222
tracing-loki = "0.2.6"
2323
flume = "0.11.1"
24-
mysql_async = "0.35.1"
24+
mysql_async = "0.36.1"
2525
time = "0.3.41"
2626
secrecy = "0.10.3"
27-
percent-encoding = "2.3.1"
27+
percent-encoding = "2.3.2"
28+
dashmap = "6.1.0"
2829

29-
actix-web = "4.10.2"
30+
actix-web = "4.11.0"
3031
actix-files = "0.6.6"
3132

3233
[target.'cfg(not(target_env = "msvc"))'.dependencies]

crates/icondiffbot2/src/github_processor.rs

Lines changed: 39 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use actix_web::web::Data;
12
use diffbot_lib::{
23
github::{
34
github_api::CheckRun,
@@ -12,15 +13,14 @@ use octocrab::models::InstallationId;
1213

1314
use mysql_async::{params, prelude::Queryable};
1415

15-
use crate::DataJobSender;
16+
use crate::JobScheduler;
1617

1718
async fn handle_pull_request(
1819
payload: PullRequestEventPayload,
19-
job_sender: DataJobSender,
20-
pool: actix_web::web::Data<Option<mysql_async::Pool>>,
20+
scheduler: &JobScheduler,
21+
sender: &flume::Sender<(String, u64)>,
22+
pool: Option<&mysql_async::Pool>,
2123
) -> Result<()> {
22-
let pool = pool.get_ref();
23-
2424
match payload.action.as_str() {
2525
"opened" | "synchronize" => {
2626
let check_run = CheckRun::create(
@@ -37,9 +37,9 @@ async fn handle_pull_request(
3737
payload.pull_request.number,
3838
);
3939

40-
let num_icons = handle_pull(payload, job_sender, check_run).await?;
40+
let num_icons = handle_pull(payload, scheduler, sender, check_run).await?;
4141

42-
if let Some(ref pool) = pool {
42+
if let Some(pool) = pool {
4343
let mut conn = match pool.get_conn().await {
4444
Ok(conn) => conn,
4545
Err(e) => {
@@ -81,7 +81,9 @@ async fn handle_pull_request(
8181
Ok(())
8282
}
8383
"closed" => {
84-
if let Some(ref pool) = pool {
84+
scheduler.remove(&(payload.repository.full_name(), payload.pull_request.number));
85+
86+
if let Some(pool) = pool {
8587
let mut conn = match pool.get_conn().await {
8688
Ok(conn) => conn,
8789
Err(e) => {
@@ -106,7 +108,7 @@ async fn handle_pull_request(
106108
{
107109
tracing::error!("{:?}", e);
108110
};
109-
};
111+
}
110112
Ok(())
111113
}
112114
_ => Ok(()),
@@ -115,7 +117,8 @@ async fn handle_pull_request(
115117

116118
async fn handle_pull(
117119
payload: PullRequestEventPayload,
118-
job_sender: DataJobSender,
120+
scheduler: &JobScheduler,
121+
sender: &flume::Sender<(String, u64)>,
119122
check_run: CheckRun,
120123
) -> Result<usize> {
121124
if payload
@@ -188,6 +191,9 @@ async fn handle_pull(
188191

189192
check_run.mark_queued().await?;
190193

194+
let scheduler_entry = (payload.repository.full_name(), payload.pull_request.number);
195+
let scheduler_entry_clone = (payload.repository.full_name(), payload.pull_request.number);
196+
191197
let pull = payload.pull_request;
192198
let installation = payload.installation;
193199

@@ -201,7 +207,20 @@ async fn handle_pull(
201207
installation: InstallationId(installation.id),
202208
};
203209

204-
job_sender.send_async(job).await?;
210+
if let Some(old_job) = match scheduler.entry(scheduler_entry) {
211+
dashmap::Entry::Occupied(mut entry) => Some(entry.insert(job)),
212+
dashmap::Entry::Vacant(entry) => {
213+
entry.insert(job);
214+
None
215+
}
216+
} {
217+
_ = old_job
218+
.check_run
219+
.mark_failed("Check cancelled, a later commit has triggered the check")
220+
.await;
221+
}
222+
223+
sender.send_async(scheduler_entry_clone).await?;
205224

206225
Ok(num_icons_diffed)
207226
}
@@ -210,9 +229,15 @@ async fn handle_pull(
210229
pub async fn process_github_payload_actix(
211230
event: diffbot_lib::github::github_api::GithubEvent,
212231
payload: String,
213-
job_sender: DataJobSender,
214-
pool: actix_web::web::Data<Option<mysql_async::Pool>>,
232+
pool: Data<Option<mysql_async::Pool>>,
233+
scheduler: Data<JobScheduler>,
234+
sender: Data<flume::Sender<(String, u64)>>,
215235
) -> actix_web::Result<&'static str> {
236+
let (pool, scheduler, sender) = (
237+
pool.get_ref().as_ref(),
238+
scheduler.get_ref(),
239+
sender.get_ref(),
240+
);
216241
// TODO: Handle reruns
217242
if event.0 != "pull_request" {
218243
return Ok("Not a pull request event");
@@ -231,7 +256,7 @@ pub async fn process_github_payload_actix(
231256

232257
let payload: PullRequestEventPayload = serde_json::from_str(&payload)?;
233258

234-
handle_pull_request(payload, job_sender, pool)
259+
handle_pull_request(payload, scheduler, sender, pool)
235260
.await
236261
.map_err(actix_web::error::ErrorBadRequest)?;
237262

crates/icondiffbot2/src/job_processor.rs

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
use crate::{
2-
sha::{sha_to_iconfile, status_to_sha, IconFileWithName},
3-
table_builder::OutputTableBuilder,
42
CONFIG,
3+
sha::{IconFileWithName, sha_to_iconfile, status_to_sha},
4+
table_builder::OutputTableBuilder,
55
};
66
use diffbot_lib::{github::github_types::CheckOutputs, job::types::Job, tracing};
7-
use dmm_tools::dmi::render::{IconRenderer, RenderType};
87
use dmm_tools::dmi::State;
8+
use dmm_tools::dmi::render::{IconRenderer, RenderType};
99
use eyre::{Context, Result};
1010
use hashbrown::HashSet;
1111
use rayon::prelude::*;
@@ -344,14 +344,13 @@ fn full_render(job: &Job, target: &IconFileWithName) -> Result<Vec<((usize, Stri
344344
let vec: Vec<((usize, String), String)> = icon
345345
.metadata
346346
.states
347-
.par_values()
348-
.map(|vec| {
347+
.values()
348+
.flat_map(|vec| {
349349
vec.iter()
350350
.enumerate()
351351
.map(|(duplication_index, (_, state))| (duplication_index, state))
352352
.collect::<Vec<_>>()
353353
})
354-
.flatten()
355354
.map(|(idx, state)| {
356355
render_state(&prefix, target, (idx, state), &renderer)
357356
.with_context(|| format!("Failed to render state {}", state.name))

crates/icondiffbot2/src/main.rs

Lines changed: 15 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,11 @@ mod runner;
55
mod sha;
66
mod table_builder;
77

8-
use diffbot_lib::{
9-
async_fs,
10-
job::types::{Job, JobSender},
11-
};
8+
use diffbot_lib::job::types::Job;
129
use mysql_async::prelude::Queryable;
1310
use octocrab::OctocrabBuilder;
1411
use serde::Deserialize;
15-
use std::sync::OnceLock;
12+
use std::sync::{Arc, OnceLock};
1613
use std::{
1714
fs::File,
1815
io::Read,
@@ -23,7 +20,7 @@ use std::{
2320
#[global_allocator]
2421
static GLOBAL: tikv_jemallocator::Jemalloc = tikv_jemallocator::Jemalloc;
2522

26-
pub type DataJobSender = actix_web::web::Data<JobSender<Job>>;
23+
pub type JobScheduler = Arc<dashmap::DashMap<(String, u64), Job, ahash::RandomState>>;
2724

2825
#[actix_web::get("/")]
2926
async fn index() -> &'static str {
@@ -132,9 +129,8 @@ async fn main() -> eyre::Result<()> {
132129
simple_eyre::install().expect("Eyre handler installation failed!");
133130
// init_global_subscriber();
134131

135-
let config_path = Path::new(".").join("config.toml");
136-
let config =
137-
init_config(&config_path).unwrap_or_else(|_| panic!("Failed to read {config_path:?}"));
132+
let config_path = std::path::Path::new(".").join("config").join("config.toml");
133+
let config = init_config(&config_path).unwrap();
138134

139135
let (layer, tasks) = if let Some(ref loki_config) = config.grafana_loki {
140136
let (layer, tasks) = tracing_loki::builder()
@@ -164,9 +160,7 @@ async fn main() -> eyre::Result<()> {
164160
);
165161
let reqwest_client = reqwest::Client::new();
166162

167-
async_fs::create_dir_all("./images").await.unwrap();
168-
169-
let (job_sender, job_receiver) = flume::unbounded();
163+
std::fs::create_dir_all("./images").unwrap();
170164

171165
let pool = config
172166
.db_url
@@ -191,16 +185,18 @@ async fn main() -> eyre::Result<()> {
191185
.await?;
192186
}
193187

188+
let (sender, receiver) = flume::unbounded();
189+
190+
let scheduler: JobScheduler = Default::default();
191+
194192
actix_web::rt::spawn(runner::handle_jobs(
195193
"IconDiffBot2",
196-
job_receiver,
194+
scheduler.clone(),
195+
receiver,
197196
reqwest_client,
198197
));
199198

200-
let job_sender: DataJobSender = actix_web::web::Data::new(job_sender);
201-
202199
actix_web::HttpServer::new(move || {
203-
let pool = actix_web::web::Data::new(pool.clone());
204200
use actix_web::web::{FormConfig, PayloadConfig};
205201
//absolutely rancid
206202
let (form_config, string_config) = config.web.limits.as_ref().map_or(
@@ -215,8 +211,9 @@ async fn main() -> eyre::Result<()> {
215211
actix_web::App::new()
216212
.app_data(form_config)
217213
.app_data(string_config)
218-
.app_data(job_sender.clone())
219-
.app_data(pool)
214+
.app_data(actix_web::web::Data::new(pool.clone()))
215+
.app_data(actix_web::web::Data::new(scheduler.clone()))
216+
.app_data(actix_web::web::Data::new(sender.clone()))
220217
.service(index)
221218
.service(github_processor::process_github_payload_actix)
222219
.service(actix_files::Files::new("/images", "./images"))

crates/icondiffbot2/src/runner.rs

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

3+
use crate::JobScheduler;
4+
35
use super::job_processor::do_job;
46
use diffbot_lib::job::types::Job;
57

68
use diffbot_lib::tracing;
79

810
pub async fn handle_jobs<S: AsRef<str>>(
911
name: S,
10-
job_receiver: flume::Receiver<Job>,
12+
scheduler: JobScheduler,
13+
receiver: flume::Receiver<(String, u64)>,
1114
client: reqwest::Client,
1215
) {
1316
loop {
14-
match job_receiver.recv_async().await {
15-
Ok(job) => {
16-
tracing::info!("Job received from queue");
17-
job_handler(name.as_ref(), job, client.clone()).await;
17+
match receiver.recv_async().await {
18+
Ok(entry) => {
19+
if let Some((_, job)) = scheduler.remove(&entry) {
20+
tracing::info!("Job received from queue");
21+
job_handler(name.as_ref(), job, client.clone()).await;
22+
}
1823
}
19-
Err(err) => tracing::error!("{err}"),
24+
Err(e) => tracing::error!("{e}"),
2025
}
2126
}
2227
}

crates/icondiffbot2/src/sha.rs

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,7 @@ use actix_web::rt::Runtime;
22
use diffbot_lib::{github::github_types::ChangeType, job::types::Job};
33
use dmm_tools::dmi::IconFile;
44
use eyre::{Context, Result};
5-
use std::{
6-
collections::hash_map::DefaultHasher,
7-
hash::{Hash, Hasher},
8-
};
5+
use std::hash::{Hash, Hasher};
96

107
use crate::downloading::download_url;
118

@@ -53,7 +50,7 @@ fn get_if_exists(
5350
.wrap_err_with(|| format!("Failed to download file {filename:?}"))
5451
})?;
5552

56-
let mut hasher = DefaultHasher::new();
53+
let mut hasher = ahash::AHasher::default();
5754
raw.hash(&mut hasher);
5855
let hash = hasher.finish();
5956

0 commit comments

Comments
 (0)