352 lines
9.0 KiB
Markdown
352 lines
9.0 KiB
Markdown
<p align="center">
|
|
<a href="https://ironlicensing.com">
|
|
<img src="https://ironlicensing.com/logo.png" alt="IronLicensing" width="120" />
|
|
</a>
|
|
</p>
|
|
|
|
<h1 align="center">IronLicensing SDK for Rust</h1>
|
|
|
|
<p align="center">
|
|
<strong>Software licensing and activation for Rust applications</strong>
|
|
</p>
|
|
|
|
<p align="center">
|
|
<a href="https://crates.io/crates/ironlicensing"><img src="https://img.shields.io/crates/v/ironlicensing.svg" alt="Crates.io"></a>
|
|
<a href="https://docs.rs/ironlicensing"><img src="https://docs.rs/ironlicensing/badge.svg" alt="Documentation"></a>
|
|
<a href="https://opensource.org/licenses/MIT"><img src="https://img.shields.io/badge/License-MIT-yellow.svg" alt="License: MIT"></a>
|
|
</p>
|
|
|
|
<p align="center">
|
|
<a href="https://ironlicensing.com">Website</a> •
|
|
<a href="https://ironlicensing.com/docs">Documentation</a> •
|
|
<a href="https://ironlicensing.com/docs/rust">Rust Guide</a> •
|
|
<a href="https://git.marketally.com/ironservices">Git</a>
|
|
</p>
|
|
|
|
---
|
|
|
|
**IronLicensing** helps you protect your software with flexible licensing, activations, and feature management. Built for developers who want simple, powerful licensing without the complexity.
|
|
|
|
## Installation
|
|
|
|
Add to your `Cargo.toml`:
|
|
|
|
```toml
|
|
[dependencies]
|
|
ironlicensing = "1.0"
|
|
```
|
|
|
|
## Quick Start
|
|
|
|
### Using Client Instance
|
|
|
|
```rust
|
|
use ironlicensing::{LicenseClient, LicenseOptions};
|
|
|
|
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|
// Create a client
|
|
let client = LicenseClient::with_credentials(
|
|
"pk_live_your_public_key",
|
|
"your-product-slug"
|
|
)?;
|
|
|
|
// Validate a license
|
|
let result = client.validate("IRON-XXXX-XXXX-XXXX-XXXX");
|
|
if result.valid {
|
|
println!("License is valid!");
|
|
if let Some(license) = &result.license {
|
|
println!("Status: {:?}", license.status);
|
|
}
|
|
} else {
|
|
println!("Validation failed: {:?}", result.error);
|
|
}
|
|
|
|
// Check for features
|
|
if client.has_feature("premium") {
|
|
println!("Premium features enabled!");
|
|
}
|
|
|
|
Ok(())
|
|
}
|
|
```
|
|
|
|
### Using Global Client
|
|
|
|
```rust
|
|
use ironlicensing::{init, validate, has_feature};
|
|
|
|
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|
// Initialize the global client
|
|
init("pk_live_your_public_key", "your-product-slug")?;
|
|
|
|
// Use global functions
|
|
let result = validate("IRON-XXXX-XXXX-XXXX-XXXX")?;
|
|
if result.valid {
|
|
println!("License is valid!");
|
|
}
|
|
|
|
if has_feature("premium")? {
|
|
println!("Premium features enabled!");
|
|
}
|
|
|
|
Ok(())
|
|
}
|
|
```
|
|
|
|
## Configuration
|
|
|
|
```rust
|
|
use ironlicensing::{LicenseClient, LicenseOptions};
|
|
use std::time::Duration;
|
|
|
|
let options = LicenseOptions::new("pk_live_xxx", "your-product")
|
|
.api_base_url("https://api.ironlicensing.com")
|
|
.debug(true)
|
|
.enable_offline_cache(true)
|
|
.cache_validation_minutes(60)
|
|
.offline_grace_days(7)
|
|
.http_timeout(Duration::from_secs(30));
|
|
|
|
let client = LicenseClient::new(options)?;
|
|
```
|
|
|
|
## License Validation
|
|
|
|
```rust
|
|
let result = client.validate("IRON-XXXX-XXXX-XXXX-XXXX");
|
|
|
|
if result.valid {
|
|
if let Some(license) = &result.license {
|
|
println!("License: {}", license.key);
|
|
println!("Status: {:?}", license.status);
|
|
println!("Type: {:?}", license.license_type);
|
|
println!("Activations: {}/{}",
|
|
license.current_activations,
|
|
license.max_activations);
|
|
}
|
|
}
|
|
```
|
|
|
|
## License Activation
|
|
|
|
```rust
|
|
// Simple activation (uses hostname as machine name)
|
|
let result = client.activate("IRON-XXXX-XXXX-XXXX-XXXX");
|
|
|
|
// With custom machine name
|
|
let result = client.activate_with_name(
|
|
"IRON-XXXX-XXXX-XXXX-XXXX",
|
|
Some("Production Server")
|
|
);
|
|
|
|
if result.valid {
|
|
println!("License activated successfully!");
|
|
|
|
// View activations
|
|
if let Some(activations) = &result.activations {
|
|
for activation in activations {
|
|
println!("- {} ({:?})",
|
|
activation.machine_name.as_deref().unwrap_or("Unknown"),
|
|
activation.platform);
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
## License Deactivation
|
|
|
|
```rust
|
|
if client.deactivate() {
|
|
println!("License deactivated from this machine");
|
|
}
|
|
```
|
|
|
|
## Feature Checking
|
|
|
|
```rust
|
|
// Check if feature is available
|
|
if client.has_feature("advanced-analytics") {
|
|
// Enable advanced analytics
|
|
}
|
|
|
|
// Require feature (returns error if not available)
|
|
client.require_feature("export-pdf")?;
|
|
// Feature is available, continue with export
|
|
|
|
// Get feature details
|
|
if let Some(feature) = client.get_feature("max-users") {
|
|
println!("Feature: {} - {:?}", feature.name, feature.description);
|
|
}
|
|
```
|
|
|
|
## Trial Management
|
|
|
|
```rust
|
|
let result = client.start_trial("user@example.com");
|
|
|
|
if result.valid {
|
|
println!("Trial started!");
|
|
if let Some(license) = &result.license {
|
|
println!("Trial key: {}", license.key);
|
|
if let Some(expires) = &license.expires_at {
|
|
println!("Expires: {}", expires);
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
## In-App Purchase
|
|
|
|
```rust
|
|
// Get available tiers
|
|
let tiers = client.get_tiers();
|
|
for tier in &tiers {
|
|
println!("{} - ${:.2} {}", tier.name, tier.price, tier.currency);
|
|
}
|
|
|
|
// Start checkout
|
|
let checkout = client.start_purchase("tier-id", "user@example.com");
|
|
if checkout.success {
|
|
if let Some(url) = &checkout.checkout_url {
|
|
println!("Checkout URL: {}", url);
|
|
// Open URL in browser for user to complete purchase
|
|
}
|
|
}
|
|
```
|
|
|
|
## License Status
|
|
|
|
```rust
|
|
use ironlicensing::LicenseStatus;
|
|
|
|
// Get current license
|
|
if let Some(license) = client.license() {
|
|
println!("Licensed to: {:?}", license.email);
|
|
}
|
|
|
|
// Check status
|
|
match client.status() {
|
|
LicenseStatus::Valid => println!("License is valid"),
|
|
LicenseStatus::Expired => println!("License has expired"),
|
|
LicenseStatus::Trial => println!("Running in trial mode"),
|
|
LicenseStatus::NotActivated => println!("No license activated"),
|
|
status => println!("Status: {:?}", status),
|
|
}
|
|
|
|
// Quick checks
|
|
if client.is_licensed() {
|
|
println!("Application is licensed");
|
|
}
|
|
|
|
if client.is_trial() {
|
|
println!("Running in trial mode");
|
|
}
|
|
```
|
|
|
|
## License Types
|
|
|
|
| Type | Description |
|
|
|------|-------------|
|
|
| `Perpetual` | One-time purchase, never expires |
|
|
| `Subscription` | Recurring payment, expires if not renewed |
|
|
| `Trial` | Time-limited trial license |
|
|
|
|
## License Statuses
|
|
|
|
| Status | Description |
|
|
|--------|-------------|
|
|
| `Valid` | License is valid and active |
|
|
| `Expired` | License has expired |
|
|
| `Suspended` | License temporarily suspended |
|
|
| `Revoked` | License permanently revoked |
|
|
| `Trial` | Active trial license |
|
|
| `TrialExpired` | Trial period ended |
|
|
| `NotActivated` | No license activated |
|
|
|
|
## Thread Safety
|
|
|
|
The client uses `parking_lot::RwLock` and is safe to share across threads:
|
|
|
|
```rust
|
|
use std::sync::Arc;
|
|
use std::thread;
|
|
|
|
let client = Arc::new(LicenseClient::with_credentials("pk_live_xxx", "product")?);
|
|
|
|
let handles: Vec<_> = (0..10).map(|_| {
|
|
let client = Arc::clone(&client);
|
|
thread::spawn(move || {
|
|
if client.has_feature("concurrent-feature") {
|
|
// Safe to call from multiple threads
|
|
}
|
|
})
|
|
}).collect();
|
|
|
|
for handle in handles {
|
|
handle.join().unwrap();
|
|
}
|
|
```
|
|
|
|
## Error Handling
|
|
|
|
```rust
|
|
use ironlicensing::{LicenseError, LicenseResult};
|
|
|
|
// Validation errors
|
|
let result = client.validate(license_key);
|
|
if !result.valid {
|
|
if let Some(error) = &result.error {
|
|
match error.as_str() {
|
|
"license_not_found" => println!("Invalid license key"),
|
|
"license_expired" => println!("Your license has expired"),
|
|
"max_activations_reached" => println!("No more activations available"),
|
|
_ => println!("Error: {}", error),
|
|
}
|
|
}
|
|
}
|
|
|
|
// Feature requirement errors
|
|
match client.require_feature("premium") {
|
|
Ok(()) => println!("Feature available"),
|
|
Err(LicenseError::FeatureRequired(feature)) => {
|
|
println!("Feature '{}' requires a valid license", feature);
|
|
}
|
|
Err(e) => println!("Error: {}", e),
|
|
}
|
|
```
|
|
|
|
## Machine ID
|
|
|
|
The SDK automatically generates and persists a unique machine ID at `~/.ironlicensing/machine_id`. This ID is used for:
|
|
- Tracking activations per machine
|
|
- Preventing license sharing
|
|
- Offline validation
|
|
|
|
```rust
|
|
let machine_id = client.machine_id();
|
|
```
|
|
|
|
## Documentation
|
|
|
|
For complete documentation, visit [ironlicensing.com/docs](https://ironlicensing.com/docs).
|
|
|
|
## Other SDKs
|
|
|
|
| Platform | Package |
|
|
|----------|---------|
|
|
| JavaScript/TypeScript | [@ironservices/licensing](https://git.marketally.com/ironservices/ironlicensing-js) |
|
|
| .NET | [IronLicensing.Client](https://git.marketally.com/ironservices/ironlicensing-dotnet) |
|
|
| Python | [ironlicensing](https://git.marketally.com/ironservices/ironlicensing-python) |
|
|
| Go | [ironlicensing-go](https://git.marketally.com/ironservices/ironlicensing-go) |
|
|
| Java | [ironlicensing-java](https://git.marketally.com/ironservices/ironlicensing-java) |
|
|
|
|
## Support
|
|
|
|
- **Documentation**: [ironlicensing.com/docs](https://ironlicensing.com/docs)
|
|
- **Email**: dev@ironservices.io
|
|
- **Issues**: [git.marketally.com/ironservices/ironlicensing-rust/issues](https://git.marketally.com/ironservices/ironlicensing-rust/issues)
|
|
|
|
## License
|
|
|
|
MIT License - see [LICENSE](LICENSE) for details.
|