Go Client
Go client library for license validation, device activation, usage tracking, and offline operation against the License Server.
Installation
Section titled “Installation”go get git.prd.embidio.de/hive/license-server/client@latestProject Structure
Section titled “Project Structure”client/├── client.go # Core: Client struct, New, Connect, Close├── types.go # All types, configs, error codes, constants├── validate.go # Validate, ValidateWithMetadata├── activate.go # Activate, ActivateWithMetadata, Deactivate├── heartbeat.go # Heartbeat lifecycle├── usage.go # ReportUsage, GetUsageStatus├── entitlements.go # HasEntitlement, GetEntitlements, state getters├── callbacks.go # Legacy callbacks (deprecated)├── offline_mode.go # OfflineModeClient with fallback chain├── usage_tracker.go # Local usage buffering with batch dispatch│├── admin/ # Admin HTTP client (management API)│ └── client.go # CRUD for customers, licenses, features│├── events/ # Event system│ ├── events.go # Emitter, event types, history│ └── callbacks.go # Typed callback wrappers│├── offline/ # Offline subsystem│ ├── cache.go # AES-encrypted persistent cache│ ├── license_file.go # .lic file validation (Ed25519)│ └── reconnect.go # Automatic reconnection with backoff│├── internal/│ ├── hardware/ # Platform-specific hardware ID│ │ ├── hardware.go│ │ ├── hardware_linux.go│ │ ├── hardware_darwin.go│ │ └── hardware_windows.go│ └── offlinecrypto/ # Cryptography internals│ ├── types.go│ ├── verify.go│ └── encrypt.go│├── examples/ # Example applications│ └── basic/ # Complete example│ ├── main.go│ └── README.md│└── go.mod # Go module (1.25.5)Quick Start
Section titled “Quick Start”Minimal Example
Section titled “Minimal Example”package main
import ( "context" "log"
client "git.prd.embidio.de/hive/license-server/client")
func main() { ctx := context.Background()
// 1. Create client c, err := client.New(client.Config{ ServerAddr: "localhost:9090", LicenseKey: "XXXX-XXXX-XXXX-XXXX", Version: "1.0.0", }) if err != nil { log.Fatal(err) } defer c.Close()
// 2. Establish connection (gRPC) if err := c.Connect(ctx, nil); err != nil { log.Fatal(err) }
// 3. Validate license resp, err := c.Validate(ctx) if err != nil { log.Fatal(err) }
if resp.Valid { log.Println("License valid until:", resp.ExpiresAt)
// Check entitlements if c.HasEntitlement("premium-export") { log.Println("Premium export enabled") } } else { log.Printf("Validation failed: %s (Code %d)", resp.ErrorMessage, resp.ErrorCode) }}With Heartbeat and Events
Section titled “With Heartbeat and Events”// Register event callbacksc.Events().OnValidationSuccess(func(data events.ValidationSuccessData) { log.Println("Valid until:", data.ExpiresAt)})c.Events().OnHeartbeatFailure(func(data events.HeartbeatFailureData) { log.Println("Heartbeat failed:", data.Error)})
// Start heartbeat (periodic background validation)c.StartHeartbeatWithConfig(ctx, &client.HeartbeatConfig{ Interval: 1 * time.Hour, MaxRetries: 5, RetryBackoff: true, SendImmediately: true,})defer c.StopHeartbeat()With Offline Mode
Section titled “With Offline Mode”omc, err := client.NewOfflineModeClient( client.Config{ ServerAddr: "localhost:9090", LicenseKey: "XXXX-XXXX-XXXX-XXXX", }, client.OfflineConfig{ Enabled: true, CacheDir: "/var/lib/myapp/cache", RetryInterval: 30 * time.Second, AllowOfflineUsageReporting: true, LicenseFile: "/path/to/license.lic", PublicKey: publicKeyBytes, },)defer omc.Close()
// Validation with automatic fallbackresp, err := omc.ValidateWithOfflineSupport(ctx)Configuration
Section titled “Configuration”Client Config
Section titled “Client Config”| Field | Type | Default | Description |
|---|---|---|---|
ServerAddr | string | — | gRPC server address (required) |
LicenseKey | string | — | License key (required) |
HardwareID | string | auto | Automatically generated from hardware characteristics |
Version | string | — | Client version |
RequestTimeout | Duration | 30s | Timeout for individual requests |
TLS | *TLSConfig | nil | TLS/mTLS configuration |
Heartbeat | *HeartbeatConfig | nil | Heartbeat configuration |
LicenseFile | string | — | Path to a .lic file |
PublicKey | []byte | — | Ed25519 public key for .lic verification |
TLS Config
Section titled “TLS Config”| Field | Type | Description |
|---|---|---|
Enabled | bool | Enable TLS |
CertFile | string | Client certificate (mTLS) |
KeyFile | string | Client key (mTLS) |
CAFile | string | CA certificate for server verification |
InsecureSkipVerify | bool | Skip server certificate verification (dev only) |
ServerName | string | Override server name for certificate verification |
Heartbeat Config
Section titled “Heartbeat Config”| Field | Type | Default | Description |
|---|---|---|---|
Interval | Duration | 1h | Interval between heartbeats |
MaxRetries | int | 0 (unlimited) | Max consecutive failures |
RetryBackoff | bool | false | Enable exponential backoff |
RetryBackoffMultiplier | float64 | 2.0 | Backoff multiplier |
MinRetryInterval | Duration | 30s | Minimum retry interval |
MaxRetryInterval | Duration | 5m | Maximum retry interval |
SendImmediately | bool | false | Send immediately on start |
StopOnMaxRetries | bool | true | Stop after MaxRetries reached |
Function Overview
Section titled “Function Overview”Validation
Section titled “Validation”Validate(ctx)— Validate license onlineValidateWithMetadata(ctx, metadata)— Validate with additional metadata
Activation
Section titled “Activation”Activate(ctx)— Activate deviceActivateWithMetadata(ctx, name, metadata)— Activate with device name and metadataDeactivate(ctx)— Deactivate device
Entitlements (Feature Gating)
Section titled “Entitlements (Feature Gating)”GetEntitlements()— Retrieve all active entitlementsHasEntitlement(code)— Check whether a feature is activeRemainingUsage(code)— Remaining usage quota for a feature
Usage Reporting
Section titled “Usage Reporting”ReportUsage(ctx, amount)— Report usage at the license levelReportUsageForFeature(ctx, amount, code)— Report usage per featureGetUsageStatus(ctx)— Query current usage counters
Heartbeat
Section titled “Heartbeat”StartHeartbeat(ctx)/StartHeartbeatWithConfig(ctx, cfg)— Start background heartbeatStopHeartbeat()— Stop heartbeatSendHeartbeatNow(ctx)— Send a heartbeat immediatelyGetHeartbeatStatus()— Query status and metricsIsHeartbeatRunning()— Check whether heartbeat is active
GetDecryptionKey()— Retrieve content decryption keyGetExpiresAt()— License expiration dateIsOffline()— Check offline statusClose()— Disconnect and clean up
Offline Mode
Section titled “Offline Mode”The OfflineModeClient extends the base client with full offline capability:
- Grace-Period-Cache — AES-256-encrypted local cache for grace tokens
.licfile validation — Ed25519-signed license files for air-gap environments- Automatic reconnection — Exponential backoff with configurable intervals
- Usage queue — Usage reports are buffered offline and synchronized on reconnect
- Restricted entitlements — Certain features can be disabled while offline
- Local usage tracking — In-memory buffer with periodic batch dispatch
Offline Config
Section titled “Offline Config”| Field | Type | Default | Description |
|---|---|---|---|
Enabled | bool | false | Enable offline mode |
CacheDir | string | ~/.config/license-client/ | Directory for encrypted cache |
RetryInterval | Duration | 30s | Initial reconnect interval |
MaxRetryInterval | Duration | 5m | Maximum reconnect interval |
MaxRetryAttempts | int | 0 (unlimited) | Max reconnect attempts |
AllowOfflineUsageReporting | bool | false | Enable offline usage queue |
MaxQueuedUsageReports | int | — | Max entries in the offline queue |
RestrictedEntitlements | []string | — | Feature codes that are disabled offline |
Events & Callbacks
Section titled “Events & Callbacks”The event system is based on a pub/sub emitter with typed callbacks.
Event Types
Section titled “Event Types”| Event | Description |
|---|---|
EventValidationSuccess | License validated successfully |
EventValidationFailure | Validation failed |
EventHeartbeatStarted | Heartbeat started |
EventHeartbeatSuccess | Heartbeat successful |
EventHeartbeatFailure | Heartbeat failed |
EventHeartbeatStopped | Heartbeat stopped |
EventOfflineModeEnter | Entered offline mode |
EventOfflineModeExit | Back online |
EventReconnecting | Reconnection attempt |
EventGracePeriodStart | Grace period started |
EventGracePeriodWarning | Grace period expiring soon |
EventGracePeriodExpired | Grace period expired |
EventUsageWarning | Usage limit approaching |
EventUsageTracked | Usage tracked locally |
EventUsageBatchSent | Usage batch sent |
EventUsageBatchFailed | Usage batch failed |
EventLicenseExpiry | License expired |
// Typed callbacksunsub := c.Events().OnValidationSuccess(func(data events.ValidationSuccessData) { log.Println("Valid until:", data.ExpiresAt)})defer unsub() // Unsubscribe
// Generic listenerc.Events().OnAny(func(eventType events.EventType, data interface{}) { log.Printf("Event: %s", eventType)})Admin Client
Section titled “Admin Client”The admin client provides an HTTP client for the management API:
import "git.prd.embidio.de/hive/license-server/client/admin"
ac := admin.NewClient("http://localhost:8080")err := ac.Login(ctx, "admin", "password")
customers, err := ac.ListCustomers(ctx)license, err := ac.CreateLicense(ctx, createReq)Supported entities: Customers, Licenses, Features/Entitlements, Activations.
Process Diagrams
Section titled “Process Diagrams”Validation Process (Online)
Section titled “Validation Process (Online)”Offline Fallback Chain
Section titled “Offline Fallback Chain”Heartbeat Lifecycle
Section titled “Heartbeat Lifecycle”Usage Tracking Process
Section titled “Usage Tracking Process”Error Codes
Section titled “Error Codes”| Code | Constant | Meaning |
|---|---|---|
| 0 | Unspecified | No specific error |
| 1 | InvalidLicenseKey | License key is invalid |
| 2 | LicenseExpired | License has expired |
| 3 | LicenseInactive | License is deactivated |
| 4 | CustomerInactive | Customer is deactivated |
| 5 | HardwareMismatch | Hardware ID does not match |
| 6 | ActivationLimitExceeded | Activation limit reached |
| 7 | UsageLimitExceeded | Usage limit exceeded |
| 8 | ServerLicenseInvalid | Server license invalid |
| 99 | InternalError | Internal server error |
Example Application
Section titled “Example Application”A complete example application demonstrating all features is located in examples/basic/.
# From the repository root:export LICENSE_KEY="your-license-key"go run ./client/examples/basic/
# With TLS:export TLS_CA="certs/ca.pem"export LICENSE_SERVER_ADDR="license.example.com:9090"go run ./client/examples/basic/
# With offline license:export LICENSE_FILE="/path/to/license.lic"export PUBLIC_KEY_FILE="/path/to/license.pub"go run ./client/examples/basic/See the examples/basic/README.md in the repository for a detailed description of all sections and environment variables.