Turned the repo into a Cargo workspace, with r701 as a member
Check, format and test / build (push) Successful in 44s
Check, format and test / build (push) Successful in 44s
Moving the library into its own r701/ directory makes room for the Tauri GUI client (Oxibadge) to be added as a sibling workspace member in a following commit. edition/license/repository are now inherited from the new workspace root instead of being duplicated per member. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
+5
-25
@@ -1,28 +1,8 @@
|
|||||||
[package]
|
[workspace]
|
||||||
name = "r701"
|
resolver = "3"
|
||||||
version = "0.2.0"
|
members = ["r701"]
|
||||||
|
|
||||||
|
[workspace.package]
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
license = "AGPL-3.0-or-later"
|
license = "AGPL-3.0-or-later"
|
||||||
repository = "https://git.nicolabelluti.me/nicolabelluti/r701"
|
repository = "https://git.nicolabelluti.me/nicolabelluti/r701"
|
||||||
|
|
||||||
[dependencies]
|
|
||||||
async-stream = "0.3.6"
|
|
||||||
chrono = { version = "0.4.38", default-features = false, features = ["clock"] }
|
|
||||||
serde = { version = "1.0.203", default-features = false, features = ["derive"], optional = true }
|
|
||||||
tokio = { version = "1.53.1", default-features = false, features = ["net", "io-util", "sync"] }
|
|
||||||
tokio-stream = { version = "0.1.19", default-features = false }
|
|
||||||
|
|
||||||
[features]
|
|
||||||
serde = ["chrono/serde", "dep:serde"]
|
|
||||||
|
|
||||||
[lints.rust]
|
|
||||||
unsafe_code = "forbid"
|
|
||||||
|
|
||||||
[lints.clippy]
|
|
||||||
unwrap_used = "deny"
|
|
||||||
enum_glob_use = { level = "deny", priority = 1 }
|
|
||||||
pedantic = { level = "deny", priority = -1 }
|
|
||||||
nursery = { level = "deny", priority = -1 }
|
|
||||||
|
|
||||||
[dev-dependencies]
|
|
||||||
tokio = { version = "1.53.1", features = ["rt", "macros", "net"] }
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<div align="center">
|
<div align="center">
|
||||||
|
|
||||||
# R701 🕰️
|
# R701 | Oxibadge
|
||||||
|
|
||||||
[](https://www.rust-lang.org)
|
[](https://www.rust-lang.org)
|
||||||
[](https://claude.com/product/claude-code)
|
[](https://claude.com/product/claude-code)
|
||||||
@@ -11,58 +11,16 @@
|
|||||||
|
|
||||||
</div><br>
|
</div><br>
|
||||||
|
|
||||||
> A reverse-engineered library to communicate with the
|
> A reverse-engineered client for the
|
||||||
> [R701](https://ipsattendant.it/rilevatore-presenze-r701/) by [I.P.S.
|
> [R701](https://ipsattendant.it/rilevatore-presenze-r701/) attendance reader by
|
||||||
> Informatica](https://ipsinformatica.info/), written in Rust
|
> [I.P.S. Informatica](https://ipsinformatica.info/)
|
||||||
|
|
||||||
If you want to read about this reverse engineering attempt, check out
|
This repository is a Cargo workspace with two members:
|
||||||
<https://nicolabelluti.me/series/attendance-reader/>.
|
|
||||||
|
|
||||||
## Library Usage
|
- **[`r701/`](r701/README.md)** — the async Rust library that speaks the
|
||||||
|
device's TCP protocol.
|
||||||
|
- **`oxibadge/`** — Oxibadge, a minimal Tauri + Svelte desktop client built on
|
||||||
|
top of the library. *(Coming soon.)*
|
||||||
|
|
||||||
1. Add the library to you project:
|
If you want to read about the reverse engineering attempt behind the library,
|
||||||
|
check out <https://nicolabelluti.me/series/attendance-reader/>.
|
||||||
```shell
|
|
||||||
cargo add r701 --git https://git.nicolabelluti.me/nicolabelluti/r701.git
|
|
||||||
```
|
|
||||||
|
|
||||||
2. Use the library in you project:
|
|
||||||
|
|
||||||
This library is async and built on [tokio](https://tokio.rs); add it to your
|
|
||||||
own `[dependencies]` (e.g. `tokio = { version = "1", features =
|
|
||||||
["rt-multi-thread", "macros"] }`) to run the example below.
|
|
||||||
|
|
||||||
```rust
|
|
||||||
use r701::R701;
|
|
||||||
use tokio_stream::StreamExt;
|
|
||||||
|
|
||||||
#[tokio::main]
|
|
||||||
async fn main() {
|
|
||||||
let r701 = R701::connect("127.0.0.1:5005").await.unwrap();
|
|
||||||
let mut record_stream = r701.into_record_iter().await.unwrap();
|
|
||||||
let mut id = 0;
|
|
||||||
|
|
||||||
println!("No\tMchn\tEnNo\t\tName\t\tMode\tIOMd\tDateTime\t");
|
|
||||||
while let Some(record) = record_stream.next().await {
|
|
||||||
let record = record.unwrap();
|
|
||||||
let name = match r701.get_name(record.employee_id).await.unwrap() {
|
|
||||||
Some(Ok(name)) => name,
|
|
||||||
Some(Err(error)) => String::from_utf8_lossy(error.as_bytes()).into_owned(),
|
|
||||||
None => format!("user #{}", record.employee_id),
|
|
||||||
};
|
|
||||||
|
|
||||||
println!(
|
|
||||||
"{:0>6}\t{}\t{:0>9}\t{: <10}\t{}\t{}\t{}",
|
|
||||||
id + 1,
|
|
||||||
1,
|
|
||||||
record.employee_id,
|
|
||||||
name,
|
|
||||||
35,
|
|
||||||
record.clock as u8,
|
|
||||||
record.datetime.format("%Y/%m/%d %H:%M:%S"),
|
|
||||||
);
|
|
||||||
|
|
||||||
id += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|||||||
@@ -0,0 +1,28 @@
|
|||||||
|
[package]
|
||||||
|
name = "r701"
|
||||||
|
version = "0.2.0"
|
||||||
|
edition.workspace = true
|
||||||
|
license.workspace = true
|
||||||
|
repository.workspace = true
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
async-stream = "0.3.6"
|
||||||
|
chrono = { version = "0.4.38", default-features = false, features = ["clock"] }
|
||||||
|
serde = { version = "1.0.203", default-features = false, features = ["derive"], optional = true }
|
||||||
|
tokio = { version = "1.53.1", default-features = false, features = ["net", "io-util", "sync"] }
|
||||||
|
tokio-stream = { version = "0.1.19", default-features = false }
|
||||||
|
|
||||||
|
[features]
|
||||||
|
serde = ["chrono/serde", "dep:serde"]
|
||||||
|
|
||||||
|
[lints.rust]
|
||||||
|
unsafe_code = "forbid"
|
||||||
|
|
||||||
|
[lints.clippy]
|
||||||
|
unwrap_used = "deny"
|
||||||
|
enum_glob_use = { level = "deny", priority = 1 }
|
||||||
|
pedantic = { level = "deny", priority = -1 }
|
||||||
|
nursery = { level = "deny", priority = -1 }
|
||||||
|
|
||||||
|
[dev-dependencies]
|
||||||
|
tokio = { version = "1.53.1", features = ["rt", "macros", "net"] }
|
||||||
@@ -0,0 +1,68 @@
|
|||||||
|
<div align="center">
|
||||||
|
|
||||||
|
# R701 🕰️
|
||||||
|
|
||||||
|
[](https://www.rust-lang.org)
|
||||||
|
[](https://claude.com/product/claude-code)
|
||||||
|
[](https://choosealicense.com/licenses/agpl-3.0)
|
||||||
|
[](https://buymeacoffee.com/nicolabelluti)
|
||||||
|
<br>
|
||||||
|
[](https://git.nicolabelluti.me/nicolabelluti/r701/actions/?workflow=check-format-and-test.yaml)
|
||||||
|
|
||||||
|
</div><br>
|
||||||
|
|
||||||
|
> A reverse-engineered library to communicate with the
|
||||||
|
> [R701](https://ipsattendant.it/rilevatore-presenze-r701/) by [I.P.S.
|
||||||
|
> Informatica](https://ipsinformatica.info/), written in Rust
|
||||||
|
|
||||||
|
If you want to read about this reverse engineering attempt, check out
|
||||||
|
<https://nicolabelluti.me/series/attendance-reader/>.
|
||||||
|
|
||||||
|
## Library Usage
|
||||||
|
|
||||||
|
1. Add the library to you project:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
cargo add r701 --git https://git.nicolabelluti.me/nicolabelluti/r701.git
|
||||||
|
```
|
||||||
|
|
||||||
|
2. Use the library in you project:
|
||||||
|
|
||||||
|
This library is async and built on [tokio](https://tokio.rs); add it to your
|
||||||
|
own `[dependencies]` (e.g. `tokio = { version = "1", features =
|
||||||
|
["rt-multi-thread", "macros"] }`) to run the example below.
|
||||||
|
|
||||||
|
```rust
|
||||||
|
use r701::R701;
|
||||||
|
use tokio_stream::StreamExt;
|
||||||
|
|
||||||
|
#[tokio::main]
|
||||||
|
async fn main() {
|
||||||
|
let r701 = R701::connect("127.0.0.1:5005").await.unwrap();
|
||||||
|
let mut record_stream = r701.into_record_iter().await.unwrap();
|
||||||
|
let mut id = 0;
|
||||||
|
|
||||||
|
println!("No\tMchn\tEnNo\t\tName\t\tMode\tIOMd\tDateTime\t");
|
||||||
|
while let Some(record) = record_stream.next().await {
|
||||||
|
let record = record.unwrap();
|
||||||
|
let name = match r701.get_name(record.employee_id).await.unwrap() {
|
||||||
|
Some(Ok(name)) => name,
|
||||||
|
Some(Err(error)) => String::from_utf8_lossy(error.as_bytes()).into_owned(),
|
||||||
|
None => format!("user #{}", record.employee_id),
|
||||||
|
};
|
||||||
|
|
||||||
|
println!(
|
||||||
|
"{:0>6}\t{}\t{:0>9}\t{: <10}\t{}\t{}\t{}",
|
||||||
|
id + 1,
|
||||||
|
1,
|
||||||
|
record.employee_id,
|
||||||
|
name,
|
||||||
|
35,
|
||||||
|
record.clock as u8,
|
||||||
|
record.datetime.format("%Y/%m/%d %H:%M:%S"),
|
||||||
|
);
|
||||||
|
|
||||||
|
id += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
Reference in New Issue
Block a user