initial commit
This commit is contained in:
commit
3222d5f8ba
8 changed files with 2719 additions and 0 deletions
1
.envrc
Normal file
1
.envrc
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
use flake
|
||||||
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
target/
|
||||||
2095
Cargo.lock
generated
Normal file
2095
Cargo.lock
generated
Normal file
File diff suppressed because it is too large
Load diff
3
Cargo.toml
Normal file
3
Cargo.toml
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
[workspace]
|
||||||
|
resolver = "2"
|
||||||
|
members = ["crates/ciderd"]
|
||||||
16
crates/ciderd/Cargo.toml
Normal file
16
crates/ciderd/Cargo.toml
Normal file
|
|
@ -0,0 +1,16 @@
|
||||||
|
[package]
|
||||||
|
name = "ciderd"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2024"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
ctrlc = "3.4.7"
|
||||||
|
crossbeam-channel = "0.5"
|
||||||
|
rust_socketio = { version = "0.6.0", features = ["async"] }
|
||||||
|
tracing = "0.1.41"
|
||||||
|
serde_json = "1"
|
||||||
|
reqwest = { version = "0.12", features = ["blocking", "json"] }
|
||||||
|
serde = {version = "1", features = ["derive"]}
|
||||||
|
tracing-subscriber = "0.3.19"
|
||||||
|
anyhow = "1"
|
||||||
|
color-eyre = "0.6"
|
||||||
349
crates/ciderd/src/main.rs
Normal file
349
crates/ciderd/src/main.rs
Normal file
|
|
@ -0,0 +1,349 @@
|
||||||
|
use std::{
|
||||||
|
sync::{LazyLock, RwLock},
|
||||||
|
time::Duration,
|
||||||
|
};
|
||||||
|
|
||||||
|
use crossbeam_channel::unbounded;
|
||||||
|
use rust_socketio::{ClientBuilder, Payload};
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
use tracing::{error, info};
|
||||||
|
|
||||||
|
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||||
|
pub struct PlaybackUpdate {
|
||||||
|
pub data: Data,
|
||||||
|
#[serde(rename = "type")]
|
||||||
|
pub type_field: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||||
|
pub struct Data {
|
||||||
|
#[serde(rename = "currentPlaybackDuration")]
|
||||||
|
pub current_playback_duration: Option<f64>,
|
||||||
|
#[serde(rename = "currentPlaybackTime")]
|
||||||
|
pub current_playback_time: Option<f64>,
|
||||||
|
#[serde(rename = "currentPlaybackTimeRemaining")]
|
||||||
|
pub current_playback_time_remaining: Option<f64>,
|
||||||
|
#[serde(rename = "isPlaying")]
|
||||||
|
pub is_playing: Option<bool>,
|
||||||
|
#[serde(rename = "albumName")]
|
||||||
|
pub album_name: Option<String>,
|
||||||
|
#[serde(rename = "artistName")]
|
||||||
|
pub artist_name: Option<String>,
|
||||||
|
pub artwork: Option<Artwork>,
|
||||||
|
#[serde(rename = "audioLocale")]
|
||||||
|
pub audio_locale: Option<String>,
|
||||||
|
#[serde(rename = "audioTraits")]
|
||||||
|
pub audio_traits: Option<Vec<String>>,
|
||||||
|
#[serde(rename = "composerName")]
|
||||||
|
pub composer_name: Option<String>,
|
||||||
|
#[serde(rename = "discNumber")]
|
||||||
|
pub disc_number: Option<i64>,
|
||||||
|
#[serde(rename = "durationInMillis")]
|
||||||
|
pub duration_in_millis: Option<i64>,
|
||||||
|
#[serde(rename = "genreNames")]
|
||||||
|
#[serde(default)]
|
||||||
|
pub genre_names: Vec<String>,
|
||||||
|
#[serde(rename = "hasLyrics")]
|
||||||
|
pub has_lyrics: Option<bool>,
|
||||||
|
#[serde(rename = "hasTimeSyncedLyrics")]
|
||||||
|
pub has_time_synced_lyrics: Option<bool>,
|
||||||
|
#[serde(rename = "isAppleDigitalMaster")]
|
||||||
|
pub is_apple_digital_master: Option<bool>,
|
||||||
|
#[serde(rename = "isMasteredForItunes")]
|
||||||
|
pub is_mastered_for_itunes: Option<bool>,
|
||||||
|
#[serde(rename = "isVocalAttenuationAllowed")]
|
||||||
|
pub is_vocal_attenuation_allowed: Option<bool>,
|
||||||
|
pub isrc: Option<String>,
|
||||||
|
pub name: Option<String>,
|
||||||
|
#[serde(rename = "playParams")]
|
||||||
|
pub play_params: Option<PlayParams>,
|
||||||
|
#[serde(default)]
|
||||||
|
pub previews: Vec<Preview>,
|
||||||
|
#[serde(rename = "releaseDate")]
|
||||||
|
pub release_date: Option<String>,
|
||||||
|
#[serde(rename = "remainingTime")]
|
||||||
|
pub remaining_time: Option<f64>,
|
||||||
|
#[serde(rename = "trackNumber")]
|
||||||
|
pub track_number: Option<i64>,
|
||||||
|
pub url: Option<String>,
|
||||||
|
pub attributes: Option<Attributes>,
|
||||||
|
pub state: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||||
|
pub struct Artwork {
|
||||||
|
pub height: i64,
|
||||||
|
pub url: String,
|
||||||
|
pub width: i64,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||||
|
pub struct PlayParams {
|
||||||
|
pub id: String,
|
||||||
|
pub kind: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||||
|
pub struct Preview {
|
||||||
|
pub url: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||||
|
pub struct Attributes {
|
||||||
|
#[serde(rename = "albumName")]
|
||||||
|
pub album_name: String,
|
||||||
|
#[serde(rename = "artistName")]
|
||||||
|
pub artist_name: String,
|
||||||
|
pub artwork: Artwork2,
|
||||||
|
#[serde(rename = "audioLocale")]
|
||||||
|
pub audio_locale: String,
|
||||||
|
#[serde(rename = "audioTraits")]
|
||||||
|
pub audio_traits: Vec<String>,
|
||||||
|
#[serde(rename = "composerName")]
|
||||||
|
pub composer_name: String,
|
||||||
|
#[serde(rename = "currentPlaybackTime")]
|
||||||
|
pub current_playback_time: f64,
|
||||||
|
#[serde(rename = "discNumber")]
|
||||||
|
pub disc_number: i64,
|
||||||
|
#[serde(rename = "durationInMillis")]
|
||||||
|
pub duration_in_millis: i64,
|
||||||
|
#[serde(rename = "genreNames")]
|
||||||
|
pub genre_names: Vec<String>,
|
||||||
|
#[serde(rename = "hasLyrics")]
|
||||||
|
pub has_lyrics: bool,
|
||||||
|
#[serde(rename = "hasTimeSyncedLyrics")]
|
||||||
|
pub has_time_synced_lyrics: bool,
|
||||||
|
#[serde(rename = "isAppleDigitalMaster")]
|
||||||
|
pub is_apple_digital_master: bool,
|
||||||
|
#[serde(rename = "isMasteredForItunes")]
|
||||||
|
pub is_mastered_for_itunes: bool,
|
||||||
|
#[serde(rename = "isVocalAttenuationAllowed")]
|
||||||
|
pub is_vocal_attenuation_allowed: bool,
|
||||||
|
pub isrc: String,
|
||||||
|
pub name: String,
|
||||||
|
#[serde(rename = "playParams")]
|
||||||
|
pub play_params: PlayParams2,
|
||||||
|
pub previews: Vec<Preview2>,
|
||||||
|
#[serde(rename = "releaseDate")]
|
||||||
|
pub release_date: String,
|
||||||
|
#[serde(rename = "remainingTime")]
|
||||||
|
pub remaining_time: f64,
|
||||||
|
#[serde(rename = "trackNumber")]
|
||||||
|
pub track_number: i64,
|
||||||
|
pub url: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||||
|
pub struct Artwork2 {
|
||||||
|
pub height: i64,
|
||||||
|
pub url: String,
|
||||||
|
pub width: i64,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||||
|
pub struct PlayParams2 {
|
||||||
|
pub id: String,
|
||||||
|
pub kind: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||||
|
pub struct Preview2 {
|
||||||
|
pub url: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize)]
|
||||||
|
struct NowPlayingResponse {
|
||||||
|
info: Data,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize)]
|
||||||
|
struct IsPlayingResponse {
|
||||||
|
is_playing: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Serialize, Deserialize)]
|
||||||
|
struct StatusUpdate {
|
||||||
|
text: String,
|
||||||
|
tooltip: String,
|
||||||
|
class: Vec<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for StatusUpdate {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
text: "Not playing".to_owned(),
|
||||||
|
tooltip: "Open cider to start playing".to_owned(),
|
||||||
|
class: vec!["paused".to_owned()],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static STATE: LazyLock<RwLock<StatusUpdate>> =
|
||||||
|
LazyLock::new(|| RwLock::new(StatusUpdate::default()));
|
||||||
|
|
||||||
|
fn parse_payload(payload: Payload) -> color_eyre::Result<bool> {
|
||||||
|
let values = match payload {
|
||||||
|
Payload::Text(values) => values,
|
||||||
|
_ => return Ok(false),
|
||||||
|
};
|
||||||
|
|
||||||
|
let Some(value) = values.first() else {
|
||||||
|
return Ok(false);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Note: No .clone() needed here, we deserialize from a reference.
|
||||||
|
let update_data: PlaybackUpdate = serde_json::from_value(value.clone())?;
|
||||||
|
|
||||||
|
let mut state_changed = false;
|
||||||
|
let mut state_guard = STATE.write().unwrap();
|
||||||
|
|
||||||
|
match update_data.type_field.as_str() {
|
||||||
|
"playbackStatus.nowPlayingItemDidChange" => {
|
||||||
|
let new_text = format!(
|
||||||
|
"{} - {}",
|
||||||
|
update_data.data.name.as_deref().unwrap_or_default(),
|
||||||
|
update_data.data.artist_name.as_deref().unwrap_or_default()
|
||||||
|
);
|
||||||
|
let new_tooltip = format!(
|
||||||
|
"On the album **{}**",
|
||||||
|
update_data.data.album_name.as_deref().unwrap_or_default()
|
||||||
|
);
|
||||||
|
|
||||||
|
if state_guard.text != new_text {
|
||||||
|
state_guard.text = new_text;
|
||||||
|
state_changed = true;
|
||||||
|
}
|
||||||
|
if state_guard.tooltip != new_tooltip {
|
||||||
|
state_guard.tooltip = new_tooltip;
|
||||||
|
state_changed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"playbackStatus.playbackStateDidChange" => {
|
||||||
|
if let Some(new_state) = update_data.data.state {
|
||||||
|
// Check if the class vec already contains this state
|
||||||
|
if state_guard.class.first() != Some(&new_state) {
|
||||||
|
state_guard.class = vec![new_state];
|
||||||
|
state_changed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(state_changed)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn setup_ctrlc_handler() -> crossbeam_channel::Receiver<()> {
|
||||||
|
let (sender, receiver) = unbounded();
|
||||||
|
|
||||||
|
// The `move` keyword transfers ownership of the sender to the closure.
|
||||||
|
ctrlc::set_handler(move || {
|
||||||
|
println!("\n🛑 Ctrl-C received, sending shutdown signal...");
|
||||||
|
// Sending a message on the channel to notify the main loop.
|
||||||
|
sender.send(()).expect("Could not send signal on channel.");
|
||||||
|
})
|
||||||
|
.expect("Error setting Ctrl-C handler");
|
||||||
|
|
||||||
|
receiver
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_now_playing() -> Result<NowPlayingResponse, reqwest::Error> {
|
||||||
|
const URL: &str = "http://localhost:10767/api/v1/playback/now-playing";
|
||||||
|
|
||||||
|
// This call blocks until the request is complete.
|
||||||
|
let response = reqwest::blocking::get(URL)?;
|
||||||
|
|
||||||
|
let data: NowPlayingResponse = response.json()?;
|
||||||
|
|
||||||
|
Ok(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_is_playing() -> Result<IsPlayingResponse, reqwest::Error> {
|
||||||
|
const URL: &str = "http://localhost:10767/api/v1/playback/is-playing";
|
||||||
|
|
||||||
|
// This call blocks until the request is complete.
|
||||||
|
let response = reqwest::blocking::get(URL)?;
|
||||||
|
|
||||||
|
let data: IsPlayingResponse = response.json()?;
|
||||||
|
|
||||||
|
Ok(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() -> color_eyre::Result<()> {
|
||||||
|
color_eyre::install()?;
|
||||||
|
tracing_subscriber::fmt().pretty().init();
|
||||||
|
|
||||||
|
let ctrlc_receiver = setup_ctrlc_handler();
|
||||||
|
|
||||||
|
let socket = ClientBuilder::new("http://localhost:10767")
|
||||||
|
.on("connect", |_, _| {
|
||||||
|
info!("connecting!");
|
||||||
|
})
|
||||||
|
.on("API:Playback", |payload, _| {
|
||||||
|
if let Ok(true) = parse_payload(payload) {
|
||||||
|
let update_str = serde_json::to_string(&*STATE.read().unwrap()).unwrap();
|
||||||
|
println!("{update_str}")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.connect();
|
||||||
|
|
||||||
|
'main_loop: loop {
|
||||||
|
if let Err(e) = socket.as_ref() {
|
||||||
|
error!("An error occurred: {e}, retrying...");
|
||||||
|
|
||||||
|
match ctrlc_receiver.recv_timeout(Duration::from_secs(1)) {
|
||||||
|
Ok(_) => {
|
||||||
|
info!("Shutting down");
|
||||||
|
break 'main_loop;
|
||||||
|
}
|
||||||
|
Err(_) => continue 'main_loop,
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if let Ok(d) = get_now_playing() {
|
||||||
|
let new_text = format!(
|
||||||
|
"{} - {}",
|
||||||
|
d.info.name.as_deref().unwrap_or_default(),
|
||||||
|
d.info.artist_name.as_deref().unwrap_or_default()
|
||||||
|
);
|
||||||
|
let new_tooltip = format!(
|
||||||
|
"On the album **{}**",
|
||||||
|
d.info.album_name.as_deref().unwrap_or_default()
|
||||||
|
);
|
||||||
|
|
||||||
|
let mut state_guard = STATE.write().unwrap();
|
||||||
|
|
||||||
|
if state_guard.text != new_text {
|
||||||
|
state_guard.text = new_text;
|
||||||
|
}
|
||||||
|
if state_guard.tooltip != new_tooltip {
|
||||||
|
state_guard.tooltip = new_tooltip;
|
||||||
|
}
|
||||||
|
drop(state_guard);
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Ok(d) = get_is_playing() {
|
||||||
|
let new_text = match d.is_playing {
|
||||||
|
true => "playing".to_owned(),
|
||||||
|
false => "paused".to_owned(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut state_guard = STATE.write().unwrap();
|
||||||
|
|
||||||
|
if state_guard.text != new_text {
|
||||||
|
state_guard.class = vec![new_text];
|
||||||
|
}
|
||||||
|
drop(state_guard);
|
||||||
|
}
|
||||||
|
|
||||||
|
let update_str = serde_json::to_string(&*STATE.read().unwrap()).unwrap();
|
||||||
|
println!("{update_str}");
|
||||||
|
|
||||||
|
ctrlc_receiver.recv().unwrap();
|
||||||
|
|
||||||
|
socket.as_ref().unwrap().disconnect()?;
|
||||||
|
break 'main_loop;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
147
flake.lock
generated
Normal file
147
flake.lock
generated
Normal file
|
|
@ -0,0 +1,147 @@
|
||||||
|
{
|
||||||
|
"nodes": {
|
||||||
|
"crane": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1753316655,
|
||||||
|
"narHash": "sha256-tzWa2kmTEN69OEMhxFy+J2oWSvZP5QhEgXp3TROOzl0=",
|
||||||
|
"owner": "ipetkov",
|
||||||
|
"repo": "crane",
|
||||||
|
"rev": "f35a3372d070c9e9ccb63ba7ce347f0634ddf3d2",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "ipetkov",
|
||||||
|
"repo": "crane",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"flake-parts": {
|
||||||
|
"inputs": {
|
||||||
|
"nixpkgs-lib": "nixpkgs-lib"
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1753121425,
|
||||||
|
"narHash": "sha256-TVcTNvOeWWk1DXljFxVRp+E0tzG1LhrVjOGGoMHuXio=",
|
||||||
|
"owner": "hercules-ci",
|
||||||
|
"repo": "flake-parts",
|
||||||
|
"rev": "644e0fc48951a860279da645ba77fe4a6e814c5e",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "hercules-ci",
|
||||||
|
"repo": "flake-parts",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nixpkgs": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1753432016,
|
||||||
|
"narHash": "sha256-cnL5WWn/xkZoyH/03NNUS7QgW5vI7D1i74g48qplCvg=",
|
||||||
|
"owner": "NixOS",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"rev": "6027c30c8e9810896b92429f0092f624f7b1aace",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "NixOS",
|
||||||
|
"ref": "nixpkgs-unstable",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nixpkgs-lib": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1751159883,
|
||||||
|
"narHash": "sha256-urW/Ylk9FIfvXfliA1ywh75yszAbiTEVgpPeinFyVZo=",
|
||||||
|
"owner": "nix-community",
|
||||||
|
"repo": "nixpkgs.lib",
|
||||||
|
"rev": "14a40a1d7fb9afa4739275ac642ed7301a9ba1ab",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "nix-community",
|
||||||
|
"repo": "nixpkgs.lib",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nixpkgs_2": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1744536153,
|
||||||
|
"narHash": "sha256-awS2zRgF4uTwrOKwwiJcByDzDOdo3Q1rPZbiHQg/N38=",
|
||||||
|
"owner": "NixOS",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"rev": "18dd725c29603f582cf1900e0d25f9f1063dbf11",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "NixOS",
|
||||||
|
"ref": "nixpkgs-unstable",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nixpkgs_3": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1747958103,
|
||||||
|
"narHash": "sha256-qmmFCrfBwSHoWw7cVK4Aj+fns+c54EBP8cGqp/yK410=",
|
||||||
|
"owner": "nixos",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"rev": "fe51d34885f7b5e3e7b59572796e1bcb427eccb1",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "nixos",
|
||||||
|
"ref": "nixpkgs-unstable",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"root": {
|
||||||
|
"inputs": {
|
||||||
|
"crane": "crane",
|
||||||
|
"flake-parts": "flake-parts",
|
||||||
|
"nixpkgs": "nixpkgs",
|
||||||
|
"rust-overlay": "rust-overlay",
|
||||||
|
"treefmt-nix": "treefmt-nix"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"rust-overlay": {
|
||||||
|
"inputs": {
|
||||||
|
"nixpkgs": "nixpkgs_2"
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1753584741,
|
||||||
|
"narHash": "sha256-i147iFSy4K4PJvID+zoszLbRi2o+YV8AyG4TUiDQ3+I=",
|
||||||
|
"owner": "oxalica",
|
||||||
|
"repo": "rust-overlay",
|
||||||
|
"rev": "69dfe029679e73b8d159011c9547f6148a85ca6b",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "oxalica",
|
||||||
|
"repo": "rust-overlay",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"treefmt-nix": {
|
||||||
|
"inputs": {
|
||||||
|
"nixpkgs": "nixpkgs_3"
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1753439394,
|
||||||
|
"narHash": "sha256-Bv9h1AJegLI8uAhiJ1sZ4XAndYxhgf38tMgCQwiEpmc=",
|
||||||
|
"owner": "numtide",
|
||||||
|
"repo": "treefmt-nix",
|
||||||
|
"rev": "2673921c03d6e75fdf4aa93e025772608d1482cf",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "numtide",
|
||||||
|
"repo": "treefmt-nix",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"root": "root",
|
||||||
|
"version": 7
|
||||||
|
}
|
||||||
107
flake.nix
Normal file
107
flake.nix
Normal file
|
|
@ -0,0 +1,107 @@
|
||||||
|
# SPDX-License-Identifier: Unlicense
|
||||||
|
{
|
||||||
|
inputs = {
|
||||||
|
flake-parts.url = "github:hercules-ci/flake-parts";
|
||||||
|
nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable";
|
||||||
|
# systems.url = "github:nix-systems/default";
|
||||||
|
|
||||||
|
treefmt-nix.url = "github:numtide/treefmt-nix";
|
||||||
|
|
||||||
|
rust-overlay.url = "github:oxalica/rust-overlay";
|
||||||
|
crane.url = "github:ipetkov/crane";
|
||||||
|
};
|
||||||
|
|
||||||
|
# Add settings for your binary cache.
|
||||||
|
# nixConfig = {
|
||||||
|
# extra-substituters = [
|
||||||
|
# ];
|
||||||
|
# extra-trusted-public-keys = [
|
||||||
|
# ];
|
||||||
|
# };
|
||||||
|
|
||||||
|
outputs = inputs @ {
|
||||||
|
nixpkgs,
|
||||||
|
flake-parts,
|
||||||
|
...
|
||||||
|
}: let
|
||||||
|
# For details on these options, See
|
||||||
|
# https://github.com/oxalica/rust-overlay?tab=readme-ov-file#cheat-sheet-common-usage-of-rust-bin
|
||||||
|
#
|
||||||
|
# Channel of the Rust toolchain (stable or beta).
|
||||||
|
rustChannel = "stable";
|
||||||
|
# Version (latest or specific date/semantic version)
|
||||||
|
rustVersion = "latest";
|
||||||
|
# Profile (default or minimal)
|
||||||
|
rustProfile = "default";
|
||||||
|
in
|
||||||
|
flake-parts.lib.mkFlake {inherit inputs;} {
|
||||||
|
systems = nixpkgs.lib.systems.flakeExposed;
|
||||||
|
|
||||||
|
imports = [
|
||||||
|
inputs.treefmt-nix.flakeModule
|
||||||
|
];
|
||||||
|
|
||||||
|
perSystem = {
|
||||||
|
config,
|
||||||
|
system,
|
||||||
|
pkgs,
|
||||||
|
lib,
|
||||||
|
craneLib,
|
||||||
|
commonArgs,
|
||||||
|
...
|
||||||
|
}: {
|
||||||
|
_module.args = {
|
||||||
|
pkgs = import nixpkgs {
|
||||||
|
inherit system;
|
||||||
|
overlays = [inputs.rust-overlay.overlays.default];
|
||||||
|
};
|
||||||
|
craneLib = (inputs.crane.mkLib pkgs).overrideToolchain (
|
||||||
|
pkgs: pkgs.rust-bin.${rustChannel}.${rustVersion}.${rustProfile}
|
||||||
|
);
|
||||||
|
commonArgs = {
|
||||||
|
# Depending on your code base, you may have to customize the
|
||||||
|
# source filtering to include non-standard files during the build.
|
||||||
|
# See
|
||||||
|
# https://crane.dev/source-filtering.html?highlight=source#source-filtering
|
||||||
|
src = craneLib.cleanCargoSource (craneLib.path ./.);
|
||||||
|
|
||||||
|
nativeBuildInputs = with pkgs; [
|
||||||
|
pkg-config
|
||||||
|
];
|
||||||
|
|
||||||
|
buildInputs = with pkgs; [
|
||||||
|
openssl
|
||||||
|
];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
# Build the executable package.
|
||||||
|
packages.default = craneLib.buildPackage (
|
||||||
|
commonArgs
|
||||||
|
// {
|
||||||
|
cargoArtifacts = craneLib.buildDepsOnly commonArgs;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
devShells.default = craneLib.devShell {
|
||||||
|
packages =
|
||||||
|
(commonArgs.nativeBuildInputs or [])
|
||||||
|
++ (commonArgs.buildInputs or [])
|
||||||
|
++ [pkgs.rust-analyzer-unwrapped];
|
||||||
|
|
||||||
|
RUST_SRC_PATH = "${
|
||||||
|
pkgs.rust-bin.${rustChannel}.${rustVersion}.rust-src
|
||||||
|
}/lib/rustlib/src/rust/library";
|
||||||
|
};
|
||||||
|
|
||||||
|
treefmt = {
|
||||||
|
projectRootFile = "Cargo.toml";
|
||||||
|
programs = {
|
||||||
|
actionlint.enable = true;
|
||||||
|
nixfmt.enable = true;
|
||||||
|
rustfmt.enable = true;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue