Skip to content

Go Client

Go client library for license validation, device activation, usage tracking, and offline operation against the License Server.

Terminal window
go get git.prd.embidio.de/hive/license-server/client@latest
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)
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)
}
}
// Register event callbacks
c.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()
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 fallback
resp, err := omc.ValidateWithOfflineSupport(ctx)
FieldTypeDefaultDescription
ServerAddrstringgRPC server address (required)
LicenseKeystringLicense key (required)
HardwareIDstringautoAutomatically generated from hardware characteristics
VersionstringClient version
RequestTimeoutDuration30sTimeout for individual requests
TLS*TLSConfignilTLS/mTLS configuration
Heartbeat*HeartbeatConfignilHeartbeat configuration
LicenseFilestringPath to a .lic file
PublicKey[]byteEd25519 public key for .lic verification
FieldTypeDescription
EnabledboolEnable TLS
CertFilestringClient certificate (mTLS)
KeyFilestringClient key (mTLS)
CAFilestringCA certificate for server verification
InsecureSkipVerifyboolSkip server certificate verification (dev only)
ServerNamestringOverride server name for certificate verification
FieldTypeDefaultDescription
IntervalDuration1hInterval between heartbeats
MaxRetriesint0 (unlimited)Max consecutive failures
RetryBackoffboolfalseEnable exponential backoff
RetryBackoffMultiplierfloat642.0Backoff multiplier
MinRetryIntervalDuration30sMinimum retry interval
MaxRetryIntervalDuration5mMaximum retry interval
SendImmediatelyboolfalseSend immediately on start
StopOnMaxRetriesbooltrueStop after MaxRetries reached
  • Validate(ctx) — Validate license online
  • ValidateWithMetadata(ctx, metadata) — Validate with additional metadata
  • Activate(ctx) — Activate device
  • ActivateWithMetadata(ctx, name, metadata) — Activate with device name and metadata
  • Deactivate(ctx) — Deactivate device
  • GetEntitlements() — Retrieve all active entitlements
  • HasEntitlement(code) — Check whether a feature is active
  • RemainingUsage(code) — Remaining usage quota for a feature
  • ReportUsage(ctx, amount) — Report usage at the license level
  • ReportUsageForFeature(ctx, amount, code) — Report usage per feature
  • GetUsageStatus(ctx) — Query current usage counters
  • StartHeartbeat(ctx) / StartHeartbeatWithConfig(ctx, cfg) — Start background heartbeat
  • StopHeartbeat() — Stop heartbeat
  • SendHeartbeatNow(ctx) — Send a heartbeat immediately
  • GetHeartbeatStatus() — Query status and metrics
  • IsHeartbeatRunning() — Check whether heartbeat is active
  • GetDecryptionKey() — Retrieve content decryption key
  • GetExpiresAt() — License expiration date
  • IsOffline() — Check offline status
  • Close() — Disconnect and clean up

The OfflineModeClient extends the base client with full offline capability:

  • Grace-Period-Cache — AES-256-encrypted local cache for grace tokens
  • .lic file 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
FieldTypeDefaultDescription
EnabledboolfalseEnable offline mode
CacheDirstring~/.config/license-client/Directory for encrypted cache
RetryIntervalDuration30sInitial reconnect interval
MaxRetryIntervalDuration5mMaximum reconnect interval
MaxRetryAttemptsint0 (unlimited)Max reconnect attempts
AllowOfflineUsageReportingboolfalseEnable offline usage queue
MaxQueuedUsageReportsintMax entries in the offline queue
RestrictedEntitlements[]stringFeature codes that are disabled offline

The event system is based on a pub/sub emitter with typed callbacks.

EventDescription
EventValidationSuccessLicense validated successfully
EventValidationFailureValidation failed
EventHeartbeatStartedHeartbeat started
EventHeartbeatSuccessHeartbeat successful
EventHeartbeatFailureHeartbeat failed
EventHeartbeatStoppedHeartbeat stopped
EventOfflineModeEnterEntered offline mode
EventOfflineModeExitBack online
EventReconnectingReconnection attempt
EventGracePeriodStartGrace period started
EventGracePeriodWarningGrace period expiring soon
EventGracePeriodExpiredGrace period expired
EventUsageWarningUsage limit approaching
EventUsageTrackedUsage tracked locally
EventUsageBatchSentUsage batch sent
EventUsageBatchFailedUsage batch failed
EventLicenseExpiryLicense expired
// Typed callbacks
unsub := c.Events().OnValidationSuccess(func(data events.ValidationSuccessData) {
log.Println("Valid until:", data.ExpiresAt)
})
defer unsub() // Unsubscribe
// Generic listener
c.Events().OnAny(func(eventType events.EventType, data interface{}) {
log.Printf("Event: %s", eventType)
})

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.

CodeConstantMeaning
0UnspecifiedNo specific error
1InvalidLicenseKeyLicense key is invalid
2LicenseExpiredLicense has expired
3LicenseInactiveLicense is deactivated
4CustomerInactiveCustomer is deactivated
5HardwareMismatchHardware ID does not match
6ActivationLimitExceededActivation limit reached
7UsageLimitExceededUsage limit exceeded
8ServerLicenseInvalidServer license invalid
99InternalErrorInternal server error

A complete example application demonstrating all features is located in examples/basic/.

Terminal window
# 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.