rtj/lib.rs
1// rtj provides a generic job execution framework in Rust
2// Copyright 2021-2024 Anthony Martinez
3//
4// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
5// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
6// http://opensource.org/licenses/MIT>, at your option. This file may not be
7// copied, modified, or distributed except according to those terms.
8
9//! **rtj** aims to provide a generic, robust, and secure framework for users to develop
10//! their own job execution applications. Encryption uses [`crypto_box`] and is compatible with
11//! other implementations of the [standard](https://doc.libsodium.org/public-key_cryptography/authenticated_encryption).
12//!
13//! ### Example:
14//! ```
15//! // Full example avaialble in the source repo under /examples/hello.rs
16//! use rtj::{Job, Message};
17//!# use crypto_box::SecretKey;
18//!# use rmp_serde as rmps;
19//!# use serde::{Deserialize, Serialize};
20//!# type Result<T> = std::result::Result<T, Box<dyn std::error::Error>>;
21//!# enum MsgType {
22//!# Hello,
23//!# Unknown,
24//!# }
25//!# impl From<u8> for MsgType {
26//!# fn from(t: u8) -> MsgType {
27//!# match t {
28//!# 0 => MsgType::Hello,
29//!# _ => MsgType::Unknown,
30//!# }
31//!# }
32//!# }
33//!# impl From<MsgType> for u8 {
34//!# fn from(t: MsgType) -> u8 {
35//!# match t {
36//!# MsgType::Hello => 0,
37//!# MsgType::Unknown => 255,
38//!# }
39//!# }
40//!# }
41//!# #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
42//!# struct Hello {
43//!# name: String,
44//!# age: u8,
45//!# }
46//!# impl Job for Hello {
47//!# fn encode(&self) -> Vec<u8> {
48//!# rmps::to_vec(&self).unwrap()
49//!# }
50//!# fn decode(input: &[u8]) -> Hello {
51//!# let hello: Hello = rmps::from_read(input).unwrap();
52//!# hello
53//!# }
54//!# fn ack(&self) -> Vec<u8> {
55//!# let name = &self.name;
56//!# let age = &self.age;
57//!# let ack_string = format!("Hello from {name}, age {age}");
58//!# Vec::from(ack_string)
59//!# }
60//!# fn run(&self) -> Result<()> {
61//!# let ack_string = String::from_utf8(self.ack())?;
62//!# println!("{ack_string}");
63//!# Ok(())
64//!# }
65//!# }
66//!# fn main() -> Result<()> {
67//!# let mut rng = rand::thread_rng();
68//!# // Create the sender's keys
69//!# // This would normally be loaded from a secure location
70//!# let send_secret = SecretKey::generate(&mut rng);
71//!# let send_pub = send_secret.public_key().as_bytes().to_owned();
72//!# // Create the recipient's keys
73//!# // This would normally exist on a remote node, and be loaded
74//!# // from a secure location. The sender should have a copy of
75//!# // the remote node's public key to encrypt towards.
76//!# let recv_secret = SecretKey::generate(&mut rng);
77//!#
78//!# let name = "Anthony J. Martinez".to_owned();
79//!# let age = 38;
80//! // Create a struct that implements Job
81//! let hello = Hello { name, age };
82//!
83//! // Build a Message from that struct
84//! let msg = Message::new()
85//! .set_payload(&hello)
86//! .set_header(MsgType::Hello, send_pub, &mut rng)?;
87//!
88//! // Encrypt the message payload for the recipient.
89//! let encrypted_to_recv = msg.encrypt(recv_secret.public_key(), send_secret)?;
90//!
91//! // Decrypt the message payload as the recipient.
92//! let hello_again = encrypted_to_recv.decrypt(recv_secret)?;
93//!
94//! // Verify the message type.
95//! if let MsgType::Hello = hello_again.header.msgtype.into() {
96//! // Deserialize the message payload as the correct type
97//! let hello = Hello::decode(&hello_again.payload);
98//!
99//! // Execute the runner method on the deserialized type
100//! hello.run()?;
101//! }
102//!
103//!# Ok(())
104//!# }
105//! ```
106
107use crypto_box::{
108 aead::{consts::U24, generic_array::GenericArray, AeadMut},
109 PublicKey, SecretKey,
110};
111use rand::{CryptoRng, RngCore};
112use serde::{Deserialize, Serialize};
113
114mod error;
115mod header;
116mod job;
117mod message;
118
119pub use error::RtjError;
120pub use header::Header;
121pub use job::Job;
122pub use message::Message;
123
124type Result<T> = std::result::Result<T, RtjError>;