1 release (0 unstable)
2.1.1-alpha | Oct 3, 2024 |
---|
#643 in Network programming
Used in 2 crates
(via acton-core)
56KB
806 lines
Acton ERN (Entity Resource Name)
Overview
The acton-ern
crate provides a robust, type-safe implementation for handling Entity Resource Names (ERNs). ERNs are structured identifiers used to uniquely identify and manage hierarchical resources across different services and partitions in distributed systems. While ERNs adhere to the Uniform Resource Name (URN) format as defined in RFC 8141, they extend beyond standard URNs by offering additional features:
-
K-Sortability: Unlike standard URNs, ERNs can be k-sortable when using
UnixTime
orTimestamp
ID types. This allows for efficient ordering and range queries on ERNs, which is particularly valuable in distributed systems and databases. -
Type-Safe Construction: The builder pattern ensures that ERNs are constructed correctly, with all required components in the right order.
-
Flexible ID Types: ERNs support various ID types for the root component, allowing for different use cases such as content-based hashing or time-based ordering.
These features make ERNs particularly suitable for use in distributed systems, providing a standardized, hierarchical, and sortable naming scheme that is both human-readable and machine-parseable.
Table of Contents
- Installation
- ERN Structure
- Basic Usage
- Advanced Usage
- ERN Components
- ID Types
- Error Handling
- Best Practices
- Contributing
- License
Installation
Add the following to your Cargo.toml
:
[dependencies]
acton-ern = "2.1.0-alpha"
ERN Structure
An ERN follows the URN format and has the following structure:
ern:domain:category:account:root/path/to/resource
This structure can be mapped to the URN format as follows:
ern
: NID (Namespace Identifier)domain:category:account:root
: NSS (Namespace Specific String)/path/to/resource
: Optional path components
The components of an ERN are:
ern
: Prefix indicating an Entity Resource Name (serves as the URN namespace)domain
: Classifies the resource (e.g., internal, external, custom domains)category
: Specifies the service or category within the systemaccount
: Identifies the owner or account responsible for the resourceroot
: A unique identifier for the root of the resource hierarchy. When usingUnixTime
orTimestamp
ID types, this component enables k-sortability.path
: Optional path-like structure showing the resource's position within the hierarchy
By extending the URN format with k-sortability and type-safe construction, ERNs provide a powerful naming scheme for distributed systems that goes beyond the capabilities of standard URNs.
Basic Usage
Here's a simple example of creating and using an ERN:
use acton_ern::prelude::*;
fn main() -> Result<(), ErnError> {
// Create an ERN
let ern: Ern<UnixTime> = ErnBuilder::new()
.with::<Domain>("custom-domain")?
.with::<Category>("service")?
.with::<Account>("user123")?
.with::<Root<UnixTime>>("resource")?
.with::<Part>("subresource")?
.build()?;
// Convert ERN to string
println!("ERN: {}", ern);
// Parse an ERN string
let ern_str = "ern:custom-domain:service:user123:resource/subresource";
let parsed_ern: Ern<UnixTime> = ErnParser::new(ern_str).parse()?;
assert_eq!(ern, parsed_ern);
Ok(())
}
Advanced Usage
Building ERNs
The ErnBuilder
provides a fluent interface for constructing ERNs, ensuring that required parts are added in the correct order:
use acton_ern::prelude::*;
fn create_ern() -> Result<Ern, ErnError> {
ErnBuilder::new()
.with::<Domain>("custom-domain")?
.with::<Category>("iot")?
.with::<Account>("device_manufacturer")?
.with::<Root<UnixTime>>("sensors")?
.with::<Part>("region1")?
.with::<Part>("device42")?
.build()
}
Parsing ERNs
Use ErnParser
to parse ERN strings:
use acton_ern::prelude::*;
fn parse_ern(ern_str: &str) -> Result<Ern, ErnError> {
ErnParser::new(ern_str).parse()
}
Manipulating ERNs
ERNs can be manipulated after creation:
use acton_ern::prelude::*;
fn manipulate_ern(ern: &Ern) -> Result<Ern, ErnError> {
// Add a new part
let new_ern = ern.add_part("new_subsystem")?;
// Change the root
let new_root_ern = ern.with_new_root("new_root")?;
// Combine ERNs
let combined_ern = ern.clone() + new_ern;
Ok(combined_ern)
}
ERN Components
The acton-ern
crate provides separate types for each ERN component:
Domain
: Represents the domain of the resourceCategory
: Specifies the service categoryAccount
: Identifies the account or ownerRoot
: Represents the root of the resource hierarchyPart
: Represents a single part in the resource pathParts
: A collection ofPart
s
Each component is created with validation, returning a Result
:
use acton_ern::prelude::*;
fn work_with_components() -> Result<(), ErnError> {
let domain = Domain::new("custom-domain")?;
let category = Category::new("finance");
let account = Account::new("acme_corp");
let root = Root::new("transactions")?;
let part = Part::new("2023")?;
let parts = Parts::new(vec![part]);
Ok(())
}
ID Types
The acton-ern
crate supports different ID types for the Root
component:
SHA1Name
: Uses UUID v5 (SHA1 hash)- Use case: When you need a deterministic, content-based identifier
Timestamp
: Uses UUID v6 (timestamp-based)- Use case: For time-ordered identifiers with microsecond precision
UnixTime
: Uses UUID v7 (Unix timestamp-based)- Use case: For time-ordered identifiers with millisecond precision, following the TypeId specification
Note: UnixTime
and Timestamp
implement Ord
and are K-sortable based on their root value, allowing ERNs of these types to be used as sortable keys.
When using UnixTime
, the root follows the TypeId specification found at: typeid/spec.
Example of creating ERNs with different ID types:
use acton_ern::prelude::*;
fn create_erns_with_different_id_types() -> Result<(), ErnError> {
let sha1_ern: Ern<SHA1Name> = Ern::with_root("sha1_root")?;
let timestamp_ern: Ern<Timestamp> = Ern::with_root("timestamp_root")?;
let unix_time_ern: Ern<UnixTime> = Ern::with_root("unix_time_root")?;
Ok(())
}
Error Handling
The crate uses a custom ErnError
type for error handling. Always check for and handle potential errors when working with ERNs:
use acton_ern::prelude::*;
fn handle_ern_errors() {
match ErnBuilder::new().with::<Domain>("").build() {
Ok(ern) => println!("Created ERN: {}", ern),
Err(ErnError::ParseFailure(component, msg)) => {
eprintln!("Failed to parse {}: {}", component, msg);
}
Err(e) => eprintln!("An error occurred: {}", e),
}
}
Best Practices
- Use the builder pattern (
ErnBuilder
) for creating new ERNs, ensuring required parts are added in the correct order. - Parse ERN strings using
ErnParser
to ensure validity. - Choose appropriate ID types based on your use case (e.g.,
UnixTime
for timestamp-based, sortable IDs). - Handle all potential errors using the
ErnError
type. - Use the provided component types (
Domain
,Category
, etc.) for type safety. - Leverage the
is_child_of
andparent
methods for working with hierarchical ERNs. - When using
UnixTime
orTimestamp
ID types, take advantage of theirOrd
implementation for sorting and ordering ERNs.
Contributing
Contributions to acton-ern
are welcome! Please refer to the project's GitHub repository for contribution guidelines.
License
This project is licensed under either of
- Apache License, Version 2.0, (LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0)
- MIT license (LICENSE-MIT or http://opensource.org/licenses/MIT)
at your option.
Dependencies
~0.9–1.4MB
~28K SLoC