feat: init
This commit is contained in:
commit
194e5112e5
9 changed files with 817 additions and 0 deletions
1
.envrc
Normal file
1
.envrc
Normal file
|
@ -0,0 +1 @@
|
||||||
|
use flake
|
24
.gitignore
vendored
Normal file
24
.gitignore
vendored
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
# Created by https://www.toptal.com/developers/gitignore/api/direnv,rust
|
||||||
|
# Edit at https://www.toptal.com/developers/gitignore?templates=direnv,rust
|
||||||
|
|
||||||
|
### direnv ###
|
||||||
|
.direnv
|
||||||
|
.envrc
|
||||||
|
|
||||||
|
### Rust ###
|
||||||
|
# Generated by Cargo
|
||||||
|
# will have compiled files and executables
|
||||||
|
debug/
|
||||||
|
target/
|
||||||
|
|
||||||
|
# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries
|
||||||
|
# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html
|
||||||
|
Cargo.lock
|
||||||
|
|
||||||
|
# These are backup files generated by rustfmt
|
||||||
|
**/*.rs.bk
|
||||||
|
|
||||||
|
# MSVC Windows builds of rustc generate these, which store debugging information
|
||||||
|
*.pdb
|
||||||
|
|
||||||
|
# End of https://www.toptal.com/developers/gitignore/api/direnv,rust
|
365
Cargo.lock
generated
Normal file
365
Cargo.lock
generated
Normal file
|
@ -0,0 +1,365 @@
|
||||||
|
# This file is automatically @generated by Cargo.
|
||||||
|
# It is not intended for manual editing.
|
||||||
|
version = 3
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "anstream"
|
||||||
|
version = "0.3.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0ca84f3628370c59db74ee214b3263d58f9aadd9b4fe7e711fd87dc452b7f163"
|
||||||
|
dependencies = [
|
||||||
|
"anstyle",
|
||||||
|
"anstyle-parse",
|
||||||
|
"anstyle-query",
|
||||||
|
"anstyle-wincon",
|
||||||
|
"colorchoice",
|
||||||
|
"is-terminal",
|
||||||
|
"utf8parse",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "anstyle"
|
||||||
|
version = "1.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "41ed9a86bf92ae6580e0a31281f65a1b1d867c0cc68d5346e2ae128dddfa6a7d"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "anstyle-parse"
|
||||||
|
version = "0.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e765fd216e48e067936442276d1d57399e37bce53c264d6fefbe298080cb57ee"
|
||||||
|
dependencies = [
|
||||||
|
"utf8parse",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "anstyle-query"
|
||||||
|
version = "1.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5ca11d4be1bab0c8bc8734a9aa7bf4ee8316d462a08c6ac5052f888fef5b494b"
|
||||||
|
dependencies = [
|
||||||
|
"windows-sys",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "anstyle-wincon"
|
||||||
|
version = "1.0.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "180abfa45703aebe0093f79badacc01b8fd4ea2e35118747e5811127f926e188"
|
||||||
|
dependencies = [
|
||||||
|
"anstyle",
|
||||||
|
"windows-sys",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "anyhow"
|
||||||
|
version = "1.0.71"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9c7d0618f0e0b7e8ff11427422b64564d5fb0be1940354bfe2e0529b18a9d9b8"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bitflags"
|
||||||
|
version = "1.3.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cc"
|
||||||
|
version = "1.0.79"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "clap"
|
||||||
|
version = "4.3.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "80672091db20273a15cf9fdd4e47ed43b5091ec9841bf4c6145c9dfbbcae09ed"
|
||||||
|
dependencies = [
|
||||||
|
"clap_builder",
|
||||||
|
"clap_derive",
|
||||||
|
"once_cell",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "clap_builder"
|
||||||
|
version = "4.3.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c1458a1df40e1e2afebb7ab60ce55c1fa8f431146205aa5f4887e0b111c27636"
|
||||||
|
dependencies = [
|
||||||
|
"anstream",
|
||||||
|
"anstyle",
|
||||||
|
"bitflags",
|
||||||
|
"clap_lex",
|
||||||
|
"strsim",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "clap_derive"
|
||||||
|
version = "4.3.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b8cd2b2a819ad6eec39e8f1d6b53001af1e5469f8c177579cdaeb313115b825f"
|
||||||
|
dependencies = [
|
||||||
|
"heck",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "clap_lex"
|
||||||
|
version = "0.5.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2da6da31387c7e4ef160ffab6d5e7f00c42626fe39aea70a7b0f1773f7dd6c1b"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "colorchoice"
|
||||||
|
version = "1.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "errno"
|
||||||
|
version = "0.3.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4bcfec3a70f97c962c307b2d2c56e358cf1d00b558d74262b5f929ee8cc7e73a"
|
||||||
|
dependencies = [
|
||||||
|
"errno-dragonfly",
|
||||||
|
"libc",
|
||||||
|
"windows-sys",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "errno-dragonfly"
|
||||||
|
version = "0.1.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf"
|
||||||
|
dependencies = [
|
||||||
|
"cc",
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "half"
|
||||||
|
version = "1.8.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "heck"
|
||||||
|
version = "0.4.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hermit-abi"
|
||||||
|
version = "0.3.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "fed44880c466736ef9a5c5b5facefb5ed0785676d0c02d612db14e54f0d84286"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "io-lifetimes"
|
||||||
|
version = "1.0.11"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2"
|
||||||
|
dependencies = [
|
||||||
|
"hermit-abi",
|
||||||
|
"libc",
|
||||||
|
"windows-sys",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "is-terminal"
|
||||||
|
version = "0.4.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "adcf93614601c8129ddf72e2d5633df827ba6551541c6d8c59520a371475be1f"
|
||||||
|
dependencies = [
|
||||||
|
"hermit-abi",
|
||||||
|
"io-lifetimes",
|
||||||
|
"rustix",
|
||||||
|
"windows-sys",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "libc"
|
||||||
|
version = "0.2.146"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f92be4933c13fd498862a9e02a3055f8a8d9c039ce33db97306fd5a6caa7f29b"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "linux-raw-sys"
|
||||||
|
version = "0.3.8"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "once_cell"
|
||||||
|
version = "1.18.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "proc-macro2"
|
||||||
|
version = "1.0.60"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "dec2b086b7a862cf4de201096214fa870344cf922b2b30c167badb3af3195406"
|
||||||
|
dependencies = [
|
||||||
|
"unicode-ident",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "quote"
|
||||||
|
version = "1.0.28"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1b9ab9c7eadfd8df19006f1cf1a4aed13540ed5cbc047010ece5826e10825488"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rustix"
|
||||||
|
version = "0.37.20"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b96e891d04aa506a6d1f318d2771bcb1c7dfda84e126660ace067c9b474bb2c0"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags",
|
||||||
|
"errno",
|
||||||
|
"io-lifetimes",
|
||||||
|
"libc",
|
||||||
|
"linux-raw-sys",
|
||||||
|
"windows-sys",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serde"
|
||||||
|
version = "1.0.164"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9e8c8cf938e98f769bc164923b06dce91cea1751522f46f8466461af04c9027d"
|
||||||
|
dependencies = [
|
||||||
|
"serde_derive",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serde_cbor"
|
||||||
|
version = "0.11.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2bef2ebfde456fb76bbcf9f59315333decc4fda0b2b44b420243c11e0f5ec1f5"
|
||||||
|
dependencies = [
|
||||||
|
"half",
|
||||||
|
"serde",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serde_derive"
|
||||||
|
version = "1.0.164"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d9735b638ccc51c28bf6914d90a2e9725b377144fc612c49a611fddd1b631d68"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "strsim"
|
||||||
|
version = "0.10.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "syn"
|
||||||
|
version = "2.0.18"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "32d41677bcbe24c20c52e7c70b0d8db04134c5d1066bf98662e2871ad200ea3e"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"unicode-ident",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "timers"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"anyhow",
|
||||||
|
"clap",
|
||||||
|
"serde",
|
||||||
|
"serde_cbor",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "unicode-ident"
|
||||||
|
version = "1.0.9"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b15811caf2415fb889178633e7724bad2509101cde276048e013b9def5e51fa0"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "utf8parse"
|
||||||
|
version = "0.2.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows-sys"
|
||||||
|
version = "0.48.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
|
||||||
|
dependencies = [
|
||||||
|
"windows-targets",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows-targets"
|
||||||
|
version = "0.48.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7b1eb6f0cd7c80c79759c929114ef071b87354ce476d9d94271031c0497adfd5"
|
||||||
|
dependencies = [
|
||||||
|
"windows_aarch64_gnullvm",
|
||||||
|
"windows_aarch64_msvc",
|
||||||
|
"windows_i686_gnu",
|
||||||
|
"windows_i686_msvc",
|
||||||
|
"windows_x86_64_gnu",
|
||||||
|
"windows_x86_64_gnullvm",
|
||||||
|
"windows_x86_64_msvc",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_aarch64_gnullvm"
|
||||||
|
version = "0.48.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_aarch64_msvc"
|
||||||
|
version = "0.48.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_i686_gnu"
|
||||||
|
version = "0.48.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_i686_msvc"
|
||||||
|
version = "0.48.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_x86_64_gnu"
|
||||||
|
version = "0.48.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_x86_64_gnullvm"
|
||||||
|
version = "0.48.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_x86_64_msvc"
|
||||||
|
version = "0.48.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a"
|
12
Cargo.toml
Normal file
12
Cargo.toml
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
[package]
|
||||||
|
name = "timers"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
anyhow = "1.0.71"
|
||||||
|
clap = { version = "4.3.4", features = ["derive"] }
|
||||||
|
serde = { version = "1.0.164", features = ["derive"] }
|
||||||
|
serde_cbor = "0.11.2"
|
7
default.nix
Normal file
7
default.nix
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
(import (
|
||||||
|
fetchTarball {
|
||||||
|
url = "https://github.com/edolstra/flake-compat/archive/99f1c2157fba4bfe6211a321fd0ee43199025dbf.tar.gz";
|
||||||
|
sha256 = "0x2jn3vrawwv9xp15674wjz9pixwjyj3j771izayl962zziivbx2"; }
|
||||||
|
) {
|
||||||
|
src = ./.;
|
||||||
|
}).defaultNix
|
94
flake.lock
Normal file
94
flake.lock
Normal file
|
@ -0,0 +1,94 @@
|
||||||
|
{
|
||||||
|
"nodes": {
|
||||||
|
"naersk": {
|
||||||
|
"inputs": {
|
||||||
|
"nixpkgs": "nixpkgs"
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1686572087,
|
||||||
|
"narHash": "sha256-jXTut7ZSYqLEgm/nTk7TuVL2ExahTip605bLINklAnQ=",
|
||||||
|
"owner": "nix-community",
|
||||||
|
"repo": "naersk",
|
||||||
|
"rev": "8507af04eb40c5520bd35d9ce6f9d2342cea5ad1",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "nix-community",
|
||||||
|
"ref": "master",
|
||||||
|
"repo": "naersk",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nixpkgs": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1685677062,
|
||||||
|
"narHash": "sha256-zoHF7+HNwNwne2XEomphbdc4Y8tdWT16EUxUTXpOKpQ=",
|
||||||
|
"path": "/nix/store/dnqwkazyg92hzya7400klxlk072g3zsk-source",
|
||||||
|
"rev": "95be94370d09f97f6af6a1df1eb9649b5260724e",
|
||||||
|
"type": "path"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"id": "nixpkgs",
|
||||||
|
"type": "indirect"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nixpkgs_2": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1687103638,
|
||||||
|
"narHash": "sha256-dwy/TK6Db5W7ivcgmcxUykhFwodIg0jrRzOFt7H5NUc=",
|
||||||
|
"owner": "NixOS",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"rev": "91430887645a0953568da2f3e9a3a3bb0a0378ac",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "NixOS",
|
||||||
|
"ref": "nixpkgs-unstable",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"root": {
|
||||||
|
"inputs": {
|
||||||
|
"naersk": "naersk",
|
||||||
|
"nixpkgs": "nixpkgs_2",
|
||||||
|
"utils": "utils"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"systems": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1681028828,
|
||||||
|
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
|
||||||
|
"owner": "nix-systems",
|
||||||
|
"repo": "default",
|
||||||
|
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "nix-systems",
|
||||||
|
"repo": "default",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"utils": {
|
||||||
|
"inputs": {
|
||||||
|
"systems": "systems"
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1687171271,
|
||||||
|
"narHash": "sha256-BJlq+ozK2B1sJDQXS3tzJM5a+oVZmi1q0FlBK/Xqv7M=",
|
||||||
|
"owner": "numtide",
|
||||||
|
"repo": "flake-utils",
|
||||||
|
"rev": "abfb11bd1aec8ced1c9bb9adfe68018230f4fb3c",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "numtide",
|
||||||
|
"repo": "flake-utils",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"root": "root",
|
||||||
|
"version": 7
|
||||||
|
}
|
21
flake.nix
Normal file
21
flake.nix
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
{
|
||||||
|
inputs = {
|
||||||
|
naersk.url = "github:nix-community/naersk/master";
|
||||||
|
nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable";
|
||||||
|
utils.url = "github:numtide/flake-utils";
|
||||||
|
};
|
||||||
|
|
||||||
|
outputs = { self, nixpkgs, utils, naersk }:
|
||||||
|
utils.lib.eachDefaultSystem (system:
|
||||||
|
let
|
||||||
|
pkgs = import nixpkgs { inherit system; };
|
||||||
|
naersk-lib = pkgs.callPackage naersk { };
|
||||||
|
in
|
||||||
|
{
|
||||||
|
defaultPackage = naersk-lib.buildPackage ./.;
|
||||||
|
devShell = with pkgs; mkShell {
|
||||||
|
buildInputs = [ cargo rustc rustfmt pre-commit rustPackages.clippy rust-analyzer ];
|
||||||
|
RUST_SRC_PATH = rustPlatform.rustLibSrc;
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
7
shell.nix
Normal file
7
shell.nix
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
(import (
|
||||||
|
fetchTarball {
|
||||||
|
url = "https://github.com/edolstra/flake-compat/archive/99f1c2157fba4bfe6211a321fd0ee43199025dbf.tar.gz";
|
||||||
|
sha256 = "0x2jn3vrawwv9xp15674wjz9pixwjyj3j771izayl962zziivbx2"; }
|
||||||
|
) {
|
||||||
|
src = ./.;
|
||||||
|
}).shellNix
|
286
src/main.rs
Normal file
286
src/main.rs
Normal file
|
@ -0,0 +1,286 @@
|
||||||
|
use crate::cli::{convert_command, send_command, Cli, Commands};
|
||||||
|
use crate::daemon::Daemon;
|
||||||
|
use anyhow::Result;
|
||||||
|
use clap::Parser;
|
||||||
|
|
||||||
|
mod timer {
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
use std::{
|
||||||
|
fmt::{Display, Formatter},
|
||||||
|
time::{Duration, Instant},
|
||||||
|
};
|
||||||
|
mod approx_instant {
|
||||||
|
use std::time::{Duration, Instant};
|
||||||
|
|
||||||
|
use serde::de::Error;
|
||||||
|
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
||||||
|
|
||||||
|
pub fn serialize<S>(instant: &Instant, serializer: S) -> Result<S::Ok, S::Error>
|
||||||
|
where
|
||||||
|
S: Serializer,
|
||||||
|
{
|
||||||
|
let duration = instant.elapsed();
|
||||||
|
duration.serialize(serializer)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn deserialize<'de, D>(deserializer: D) -> Result<Instant, D::Error>
|
||||||
|
where
|
||||||
|
D: Deserializer<'de>,
|
||||||
|
{
|
||||||
|
let duration = Duration::deserialize(deserializer)?;
|
||||||
|
let now = Instant::now();
|
||||||
|
let instant = now
|
||||||
|
.checked_sub(duration)
|
||||||
|
.ok_or_else(|| Error::custom("Error deserializing instant!"))?;
|
||||||
|
Ok(instant)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize, Deserialize, PartialEq, Eq, Clone)]
|
||||||
|
pub struct Timer {
|
||||||
|
pub name: String,
|
||||||
|
#[serde(with = "approx_instant")]
|
||||||
|
start: Instant,
|
||||||
|
duration: Duration,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for Timer {
|
||||||
|
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
|
||||||
|
write!(
|
||||||
|
f,
|
||||||
|
"{} has {}s remaining.",
|
||||||
|
self.name,
|
||||||
|
self.remaining().as_secs()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Timer {
|
||||||
|
pub fn new(name: String, duration: Duration) -> Timer {
|
||||||
|
Timer {
|
||||||
|
name,
|
||||||
|
start: Instant::now(),
|
||||||
|
duration,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_expired(&self) -> bool {
|
||||||
|
return Instant::now() - self.start > self.duration;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn remaining(&self) -> Duration {
|
||||||
|
self.duration - (Instant::now() - self.start)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mod daemon {
|
||||||
|
use crate::timer::Timer;
|
||||||
|
use anyhow::{Context, Ok, Result};
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
use std::fmt::{Display, Formatter};
|
||||||
|
use std::result::Result::Ok as ResultOk;
|
||||||
|
use std::{
|
||||||
|
io::Write,
|
||||||
|
os::unix::net::{UnixListener, UnixStream},
|
||||||
|
thread::sleep,
|
||||||
|
time::Duration,
|
||||||
|
};
|
||||||
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
|
pub enum Command {
|
||||||
|
Add(String, Duration),
|
||||||
|
Remove(String),
|
||||||
|
List,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
|
pub enum Answer {
|
||||||
|
Ok,
|
||||||
|
Timers(Vec<Timer>),
|
||||||
|
Err(String),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for Answer {
|
||||||
|
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
|
||||||
|
match self {
|
||||||
|
Answer::Ok => write!(f, "Ok"),
|
||||||
|
Answer::Timers(timers) => {
|
||||||
|
if timers.is_empty() {
|
||||||
|
write!(f, "No timers running.")
|
||||||
|
} else {
|
||||||
|
let strings: Vec<String> =
|
||||||
|
timers.iter().map(|timer| timer.to_string()).collect();
|
||||||
|
write!(f, "{}", strings.join("\n"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Answer::Err(msg) => write!(f, "Error: {}", msg),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Daemon {
|
||||||
|
listener: UnixListener,
|
||||||
|
timers: Vec<Timer>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Daemon {
|
||||||
|
pub fn new(socket_path: String) -> Result<Self> {
|
||||||
|
let path = std::path::Path::new(&socket_path);
|
||||||
|
if path.exists() {
|
||||||
|
std::fs::remove_file(path).with_context(|| {
|
||||||
|
format!("Could not remove previous socket {}!", socket_path)
|
||||||
|
})?;
|
||||||
|
}
|
||||||
|
let listener = UnixListener::bind(&socket_path)
|
||||||
|
.with_context(|| format!("Cannot bind to socket {}!", socket_path))?;
|
||||||
|
Ok(Self {
|
||||||
|
listener,
|
||||||
|
timers: Vec::new(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn has_timer(&mut self, name: &String) -> bool {
|
||||||
|
self.timers
|
||||||
|
.iter()
|
||||||
|
.find(|other| &other.name == name)
|
||||||
|
.is_some()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_command(&mut self, command: Command) -> Answer {
|
||||||
|
println!("Received command {:?}", command);
|
||||||
|
match command {
|
||||||
|
Command::List => Answer::Timers(self.timers.to_vec()),
|
||||||
|
Command::Add(name, duration) => {
|
||||||
|
if self.has_timer(&name) {
|
||||||
|
return Answer::Err(format!("Timer with name {} already exists!", name));
|
||||||
|
}
|
||||||
|
let timer = Timer::new(name, duration);
|
||||||
|
self.timers.push(timer);
|
||||||
|
Answer::Ok
|
||||||
|
}
|
||||||
|
Command::Remove(name) => {
|
||||||
|
if !self.has_timer(&name) {
|
||||||
|
return Answer::Err(format!("Timer with name {} does not exist!", name));
|
||||||
|
}
|
||||||
|
self.timers = self
|
||||||
|
.timers
|
||||||
|
.to_vec()
|
||||||
|
.into_iter()
|
||||||
|
.filter(|other| other.name != name)
|
||||||
|
.collect();
|
||||||
|
Answer::Ok
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_stream(&mut self, mut stream: &UnixStream) -> Result<()> {
|
||||||
|
let command = serde_cbor::from_reader(stream).context("Could not read command!")?;
|
||||||
|
let answer = self.handle_command(command);
|
||||||
|
serde_cbor::to_writer(stream, &answer).context("Could not write answer!")?;
|
||||||
|
stream.flush().context("Could not flush stream!")?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn check_timers(&mut self) {
|
||||||
|
self.timers = self
|
||||||
|
.timers
|
||||||
|
.to_vec()
|
||||||
|
.into_iter()
|
||||||
|
.filter(|timer| {
|
||||||
|
let expired = timer.is_expired();
|
||||||
|
if expired {
|
||||||
|
println!("Timer {} is expired!", timer.name);
|
||||||
|
}
|
||||||
|
!expired
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn run(&mut self) -> Result<()> {
|
||||||
|
self.listener
|
||||||
|
.set_nonblocking(true)
|
||||||
|
.context("Could not set listener to non blocking!")?;
|
||||||
|
loop {
|
||||||
|
while let ResultOk((stream, _)) = self.listener.accept() {
|
||||||
|
if let Err(e) = self.handle_stream(&stream) {
|
||||||
|
println!("Error while handling stream: {}", e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.check_timers();
|
||||||
|
sleep(Duration::from_millis(100));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mod cli {
|
||||||
|
use std::net::Shutdown;
|
||||||
|
use std::os::unix::net::UnixStream;
|
||||||
|
|
||||||
|
use std::time::Duration;
|
||||||
|
|
||||||
|
use clap::{Parser, Subcommand};
|
||||||
|
|
||||||
|
use anyhow::{Context, Result};
|
||||||
|
|
||||||
|
use crate::daemon::{Answer, Command};
|
||||||
|
|
||||||
|
#[derive(Debug, Parser)]
|
||||||
|
#[command(name = "timers")]
|
||||||
|
#[command(about = "A advanced timer daemon/cli.", long_about = None)]
|
||||||
|
pub struct Cli {
|
||||||
|
#[command(subcommand)]
|
||||||
|
pub command: Commands,
|
||||||
|
#[arg(short, long)]
|
||||||
|
#[clap(default_value = "/tmp/timers.socket")]
|
||||||
|
pub socket: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Subcommand)]
|
||||||
|
pub enum Commands {
|
||||||
|
Daemon,
|
||||||
|
Add { name: String, duration_seconds: u64 },
|
||||||
|
List,
|
||||||
|
Remove { name: String },
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_stream(socket_path: &String) -> Result<UnixStream> {
|
||||||
|
UnixStream::connect(socket_path)
|
||||||
|
.with_context(|| format!("Could not connect to socket {}!", socket_path))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn convert_command(command: &Commands) -> Command {
|
||||||
|
match command {
|
||||||
|
Commands::Add {
|
||||||
|
name,
|
||||||
|
duration_seconds,
|
||||||
|
} => Command::Add(name.to_string(), Duration::from_secs(*duration_seconds)),
|
||||||
|
Commands::List => Command::List,
|
||||||
|
Commands::Remove { name } => Command::Remove(name.to_string()),
|
||||||
|
_ => panic!("Invalid command!"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn send_command(socket_path: &String, command: Command) -> Result<()> {
|
||||||
|
let stream = get_stream(socket_path)?;
|
||||||
|
serde_cbor::to_writer(&stream, &command).with_context(|| "Could not write command!")?;
|
||||||
|
stream
|
||||||
|
.shutdown(Shutdown::Write)
|
||||||
|
.context("Could not shutdown write!")?;
|
||||||
|
let answer: Answer =
|
||||||
|
serde_cbor::from_reader(&stream).with_context(|| "Could not read answer!")?;
|
||||||
|
println!("{}", answer);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() -> Result<()> {
|
||||||
|
let args = Cli::parse();
|
||||||
|
match args.command {
|
||||||
|
Commands::Daemon => {
|
||||||
|
Daemon::new(args.socket)?.run()?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
_ => send_command(&args.socket, convert_command(&args.command)),
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue