Client Examples
Platform-specific implementations and examples for integrating the License Server API into various programming languages and frameworks.
JavaScript/Node.js
Complete Integration Example
javascript
const fetch = require('node-fetch');
const os = require('os');
const crypto = require('crypto');
class LicenseClient {
constructor(licenseKey, apiUrl, options = {}) {
this.licenseKey = licenseKey;
this.apiUrl = apiUrl;
this.instanceId = options.instanceId || this.generateInstanceId();
this.isActivated = false;
this.licenseInfo = null;
this.usageTracker = null;
}
generateInstanceId() {
const hostname = os.hostname();
const platform = os.platform();
return crypto
.createHash('sha256')
.update(`${hostname}-${platform}-${Date.now()}`)
.digest('hex')
.substring(0, 16);
}
async initialize() {
try {
// Verify license
const verification = await this.verifyLicense();
if (!verification.valid) {
throw new Error(`Invalid license: ${verification.error}`);
}
// Activate license
const activation = await this.activateLicense();
if (!activation.activated) {
throw new Error(`Activation failed: ${activation.error}`);
}
this.isActivated = true;
this.licenseInfo = verification;
// Start usage tracking
this.startUsageTracking();
console.log('License initialized successfully');
return true;
} catch (error) {
console.error('License initialization failed:', error.message);
return false;
}
}
async verifyLicense() {
const response = await fetch(`${this.apiUrl}/verify-license`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ key: this.licenseKey }),
timeout: 30000
});
return response.json();
}
async activateLicense() {
const response = await fetch(`${this.apiUrl}/activate-license`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
key: this.licenseKey,
instance_id: this.instanceId,
instance_info: {
hostname: os.hostname(),
platform: os.platform(),
node_version: process.version,
arch: os.arch()
}
}),
timeout: 30000
});
return response.json();
}
async validateLicense() {
const response = await fetch(`${this.apiUrl}/validate-license`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
key: this.licenseKey,
instance_id: this.instanceId
}),
timeout: 30000
});
return response.json();
}
async trackUsage(usage) {
const response = await fetch(`${this.apiUrl}/track-usage`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
key: this.licenseKey,
instance_id: this.instanceId,
usage
}),
timeout: 30000
});
return response.json();
}
startUsageTracking() {
this.usageTracker = {
apiCalls: 0,
activeUsers: new Set(),
storageUsed: 0
};
// Report usage every 5 minutes
setInterval(async () => {
try {
await this.trackUsage({
api_calls: this.usageTracker.apiCalls,
active_users: this.usageTracker.activeUsers.size,
storage_gb: this.usageTracker.storageUsed / (1024 * 1024 * 1024)
});
// Reset counters
this.usageTracker.apiCalls = 0;
this.usageTracker.activeUsers.clear();
} catch (error) {
console.warn('Usage tracking failed:', error.message);
}
}, 300000);
}
recordAPICall() {
if (this.usageTracker) {
this.usageTracker.apiCalls++;
}
}
recordUserActivity(userId) {
if (this.usageTracker) {
this.usageTracker.activeUsers.add(userId);
}
}
updateStorageUsage(bytes) {
if (this.usageTracker) {
this.usageTracker.storageUsed = bytes;
}
}
async shutdown() {
if (this.isActivated) {
try {
const response = await fetch(`${this.apiUrl}/revoke-license`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
key: this.licenseKey,
revoked: true
}),
timeout: 30000
});
const result = await response.json();
if (result.status === 'revoked') {
console.log('License revoked successfully');
}
} catch (error) {
console.error('License deactivation failed:', error.message);
}
}
}
}
// Usage
const licenseClient = new LicenseClient(
process.env.LICENSE_KEY,
'https://your-license-api.com/v1'
);
licenseClient.initialize().then(success => {
if (success) {
console.log('Application ready');
// Your application logic here
licenseClient.recordAPICall();
licenseClient.recordUserActivity('user123');
// Graceful shutdown
process.on('SIGTERM', () => {
licenseClient.shutdown().then(() => process.exit(0));
});
} else {
process.exit(1);
}
});Express.js Middleware
javascript
const express = require('express');
class LicenseMiddleware {
constructor(licenseClient) {
this.licenseClient = licenseClient;
this.activeUsers = new Map();
}
// Middleware to track API calls
trackAPICalls() {
return (req, res, next) => {
this.licenseClient.recordAPICall();
next();
};
}
// Middleware to track user activity
trackUserActivity() {
return (req, res, next) => {
const userId = req.user?.id || req.headers['x-user-id'];
if (userId) {
this.licenseClient.recordUserActivity(userId);
// Track session duration
this.activeUsers.set(userId, Date.now());
}
next();
};
}
// Middleware to enforce license limits
enforceLimits() {
return async (req, res, next) => {
try {
const validation = await this.licenseClient.validateLicense();
if (!validation.valid) {
return res.status(403).json({
error: 'License validation failed',
message: 'Please check your license status'
});
}
// Check specific limits
if (validation.limits) {
const currentUsage = this.getCurrentUsage();
for (const [limit, value] of Object.entries(validation.limits)) {
if (currentUsage[limit] && currentUsage[limit] >= value) {
return res.status(429).json({
error: 'Usage limit exceeded',
limit: limit,
current: currentUsage[limit],
max: value
});
}
}
}
next();
} catch (error) {
console.error('License validation error:', error.message);
next(); // Continue on validation errors
}
};
}
getCurrentUsage() {
return {
api_calls: this.licenseClient.usageTracker?.apiCalls || 0,
active_users: this.licenseClient.usageTracker?.activeUsers?.size || 0
};
}
}
// Usage
const app = express();
const licenseMiddleware = new LicenseMiddleware(licenseClient);
// Apply middleware
app.use(licenseMiddleware.trackAPICalls());
app.use(licenseMiddleware.trackUserActivity());
app.use('/api', licenseMiddleware.enforceLimits());
app.get('/api/data', (req, res) => {
res.json({ data: 'Your protected data' });
});
app.listen(3000, () => {
console.log('Server running with license protection');
});Python
Complete Integration Example
python
import requests
import threading
import time
import hashlib
import platform
import psutil
import json
from typing import Dict, Any, Optional
from datetime import datetime, timedelta
class LicenseClient:
def __init__(self, license_key: str, api_url: str, instance_id: Optional[str] = None):
self.license_key = license_key
self.api_url = api_url.rstrip('/')
self.instance_id = instance_id or self.generate_instance_id()
self.is_activated = False
self.license_info = None
self.usage_tracker = None
self.validation_thread = None
self.tracking_thread = None
self.is_running = False
def generate_instance_id(self) -> str:
"""Generate a unique instance identifier."""
hostname = platform.node()
system = platform.system()
timestamp = str(int(time.time()))
unique_string = f"{hostname}-{system}-{timestamp}"
return hashlib.sha256(unique_string.encode()).hexdigest()[:16]
def initialize(self) -> bool:
"""Initialize license verification and activation."""
try:
# Verify license
verification = self.verify_license()
if not verification.get('valid'):
raise Exception(f"Invalid license: {verification.get('error', 'Unknown error')}")
# Activate license
activation = self.activate_license()
if not activation.get('activated'):
raise Exception(f"Activation failed: {activation.get('error', 'Unknown error')}")
self.is_activated = True
self.license_info = verification
# Start background tasks
self.start_background_tasks()
print("License initialized successfully")
return True
except Exception as e:
print(f"License initialization failed: {e}")
return False
def verify_license(self) -> Dict[str, Any]:
"""Verify license key validity."""
response = requests.post(
f'{self.api_url}/verify-license',
json={'key': self.license_key},
timeout=30
)
return response.json()
def activate_license(self) -> Dict[str, Any]:
"""Activate license for this instance."""
instance_info = self.get_instance_info()
response = requests.post(
f'{self.api_url}/activate-license',
json={
'key': self.license_key,
'instance_id': self.instance_id,
'instance_info': instance_info
},
timeout=30
)
return response.json()
def validate_license(self) -> Dict[str, Any]:
"""Validate current license status."""
response = requests.post(
f'{self.api_url}/validate-license',
json={
'key': self.license_key,
'instance_id': self.instance_id
},
timeout=30
)
return response.json()
def track_usage(self, usage: Dict[str, Any]) -> Dict[str, Any]:
"""Report usage metrics."""
response = requests.post(
f'{self.api_url}/track-usage',
json={
'key': self.license_key,
'instance_id': self.instance_id,
'usage': usage
},
timeout=30
)
return response.json()
def get_instance_info(self) -> Dict[str, Any]:
"""Gather instance information."""
return {
'hostname': platform.node(),
'platform': platform.system(),
'architecture': platform.machine(),
'python_version': platform.python_version(),
'processor': platform.processor(),
'cpu_count': psutil.cpu_count(),
'memory_gb': psutil.virtual_memory().total / (1024**3),
'boot_time': datetime.fromtimestamp(psutil.boot_time()).isoformat()
}
def start_background_tasks(self):
"""Start background validation and usage tracking."""
self.is_running = True
self.usage_tracker = {
'api_calls': 0,
'active_users': set(),
'storage_used': 0,
'start_time': time.time()
}
# Start validation thread
self.validation_thread = threading.Thread(target=self._validation_loop)
self.validation_thread.daemon = True
self.validation_thread.start()
# Start tracking thread
self.tracking_thread = threading.Thread(target=self._tracking_loop)
self.tracking_thread.daemon = True
self.tracking_thread.start()
def _validation_loop(self):
"""Background license validation."""
while self.is_running:
try:
validation = self.validate_license()
if not validation.get('valid'):
print(f"License validation failed: {validation.get('error')}")
self._handle_invalid_license()
break
time.sleep(3600) # Check every hour
except Exception as e:
print(f"Validation error: {e}")
time.sleep(300) # Retry in 5 minutes on error
def _tracking_loop(self):
"""Background usage tracking."""
while self.is_running:
try:
if self.usage_tracker:
usage = {
'api_calls': self.usage_tracker['api_calls'],
'active_users': len(self.usage_tracker['active_users']),
'storage_gb': self.usage_tracker['storage_used'] / (1024**3),
'uptime_hours': (time.time() - self.usage_tracker['start_time']) / 3600,
'cpu_percent': psutil.cpu_percent(),
'memory_percent': psutil.virtual_memory().percent
}
self.track_usage(usage)
# Reset counters
self.usage_tracker['api_calls'] = 0
self.usage_tracker['active_users'].clear()
time.sleep(300) # Report every 5 minutes
except Exception as e:
print(f"Usage tracking error: {e}")
time.sleep(300)
def _handle_invalid_license(self):
"""Handle invalid license scenario."""
print("License is invalid - shutting down application")
self.shutdown()
# In a real application, you might want to exit or disable features
def record_api_call(self):
"""Record an API call."""
if self.usage_tracker:
self.usage_tracker['api_calls'] += 1
def record_user_activity(self, user_id: str):
"""Record user activity."""
if self.usage_tracker:
self.usage_tracker['active_users'].add(user_id)
def update_storage_usage(self, bytes_used: int):
"""Update storage usage."""
if self.usage_tracker:
self.usage_tracker['storage_used'] = bytes_used
def shutdown(self):
"""Shutdown license client and deactivate."""
print("Shutting down license client...")
self.is_running = False
if self.is_activated:
try:
response = requests.post(
f'{self.api_url}/revoke-license',
json={
'key': self.license_key,
'revoked': True
},
timeout=30
)
result = response.json()
if result.get('status') == 'revoked':
print("License revoked successfully")
except Exception as e:
print(f"License deactivation failed: {e}")
# Usage example
def main():
import os
license_client = LicenseClient(
os.getenv('LICENSE_KEY'),
'https://your-license-api.com/v1'
)
if license_client.initialize():
print("Application starting with valid license")
try:
# Simulate application work
while True:
license_client.record_api_call()
license_client.record_user_activity('user123')
time.sleep(1)
except KeyboardInterrupt:
print("\nShutdown requested...")
license_client.shutdown()
else:
print("Failed to initialize license - exiting")
exit(1)
if __name__ == "__main__":
main()Flask Integration
python
from flask import Flask, request, jsonify, g
from functools import wraps
app = Flask(__name__)
license_client = None # Initialize with your license client
class LicenseFlaskIntegration:
def __init__(self, license_client):
self.license_client = license_client
def require_valid_license(self, f):
"""Decorator to require valid license for routes."""
@wraps(f)
def decorated_function(*args, **kwargs):
try:
validation = self.license_client.validate_license()
if not validation.get('valid'):
return jsonify({
'error': 'Invalid license',
'message': 'License validation failed'
}), 403
g.license_info = validation
return f(*args, **kwargs)
except Exception as e:
return jsonify({
'error': 'License validation error',
'message': str(e)
}), 500
return decorated_function
def track_request(self):
"""Track incoming requests."""
self.license_client.record_api_call()
user_id = request.headers.get('X-User-ID')
if user_id:
self.license_client.record_user_activity(user_id)
# Initialize integration
license_integration = LicenseFlaskIntegration(license_client)
@app.before_request
def before_request():
if license_client and license_client.is_activated:
license_integration.track_request()
@app.route('/api/protected-data')
@license_integration.require_valid_license
def get_protected_data():
return jsonify({
'data': 'This is protected data',
'license_tier': g.license_info.get('tier')
})
@app.route('/api/license-status')
def license_status():
if not license_client or not license_client.is_activated:
return jsonify({'status': 'not_activated'})
try:
validation = license_client.validate_license()
return jsonify({
'status': 'active' if validation.get('valid') else 'invalid',
'tier': license_client.license_info.get('tier'),
'expires_at': license_client.license_info.get('expires_at')
})
except Exception as e:
return jsonify({
'status': 'error',
'error': str(e)
}), 500
if __name__ == '__main__':
import os
# Initialize license client
license_client = LicenseClient(
os.getenv('LICENSE_KEY'),
'https://your-license-api.com/v1'
)
if license_client.initialize():
print("Starting Flask app with license protection")
app.run(debug=False, host='0.0.0.0', port=5000)
else:
print("Failed to initialize license - exiting")
exit(1)Java
Complete Integration Example
java
import java.io.IOException;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.time.Duration;
import java.time.Instant;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.JsonNode;
public class LicenseClient {
private final String licenseKey;
private final String apiUrl;
private final String instanceId;
private final HttpClient httpClient;
private final ObjectMapper objectMapper;
private final ScheduledExecutorService scheduler;
private boolean isActivated = false;
private JsonNode licenseInfo;
private UsageTracker usageTracker;
public LicenseClient(String licenseKey, String apiUrl) {
this.licenseKey = licenseKey;
this.apiUrl = apiUrl.replaceAll("/$", "");
this.instanceId = generateInstanceId();
this.httpClient = HttpClient.newBuilder()
.connectTimeout(Duration.ofSeconds(30))
.build();
this.objectMapper = new ObjectMapper();
this.scheduler = Executors.newScheduledThreadPool(2);
this.usageTracker = new UsageTracker();
}
private String generateInstanceId() {
try {
String hostname = java.net.InetAddress.getLocalHost().getHostName();
String os = System.getProperty("os.name");
String timestamp = String.valueOf(System.currentTimeMillis());
String combined = hostname + "-" + os + "-" + timestamp;
java.security.MessageDigest digest = java.security.MessageDigest.getInstance("SHA-256");
byte[] hash = digest.digest(combined.getBytes());
StringBuilder hexString = new StringBuilder();
for (int i = 0; i < Math.min(8, hash.length); i++) {
String hex = Integer.toHexString(0xff & hash[i]);
if (hex.length() == 1) {
hexString.append('0');
}
hexString.append(hex);
}
return hexString.toString();
} catch (Exception e) {
return "java-instance-" + System.currentTimeMillis();
}
}
public boolean initialize() {
try {
// Verify license
JsonNode verification = verifyLicense();
if (!verification.get("valid").asBoolean()) {
throw new RuntimeException("Invalid license: " +
verification.path("error").asText("Unknown error"));
}
// Activate license
JsonNode activation = activateLicense();
if (!activation.get("activated").asBoolean()) {
throw new RuntimeException("Activation failed: " +
activation.path("error").asText("Unknown error"));
}
this.isActivated = true;
this.licenseInfo = verification;
// Start background tasks
startBackgroundTasks();
System.out.println("License initialized successfully");
return true;
} catch (Exception e) {
System.err.println("License initialization failed: " + e.getMessage());
return false;
}
}
public JsonNode verifyLicense() throws IOException, InterruptedException {
String requestBody = objectMapper.writeValueAsString(
java.util.Map.of("key", licenseKey)
);
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(apiUrl + "/verify-license"))
.header("Content-Type", "application/json")
.timeout(Duration.ofSeconds(30))
.POST(HttpRequest.BodyPublishers.ofString(requestBody))
.build();
HttpResponse<String> response = httpClient.send(request,
HttpResponse.BodyHandlers.ofString());
return objectMapper.readTree(response.body());
}
public JsonNode activateLicense() throws IOException, InterruptedException {
java.util.Map<String, Object> instanceInfo = getInstanceInfo();
java.util.Map<String, Object> requestBody = java.util.Map.of(
"key", licenseKey,
"instance_id", instanceId,
"instance_info", instanceInfo
);
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(apiUrl + "/activate-license"))
.header("Content-Type", "application/json")
.timeout(Duration.ofSeconds(30))
.POST(HttpRequest.BodyPublishers.ofString(
objectMapper.writeValueAsString(requestBody)))
.build();
HttpResponse<String> response = httpClient.send(request,
HttpResponse.BodyHandlers.ofString());
return objectMapper.readTree(response.body());
}
public JsonNode validateLicense() throws IOException, InterruptedException {
String requestBody = objectMapper.writeValueAsString(java.util.Map.of(
"key", licenseKey,
"instance_id", instanceId
));
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(apiUrl + "/validate-license"))
.header("Content-Type", "application/json")
.timeout(Duration.ofSeconds(30))
.POST(HttpRequest.BodyPublishers.ofString(requestBody))
.build();
HttpResponse<String> response = httpClient.send(request,
HttpResponse.BodyHandlers.ofString());
return objectMapper.readTree(response.body());
}
public JsonNode trackUsage(java.util.Map<String, Object> usage)
throws IOException, InterruptedException {
java.util.Map<String, Object> requestBody = java.util.Map.of(
"key", licenseKey,
"instance_id", instanceId,
"usage", usage
);
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(apiUrl + "/track-usage"))
.header("Content-Type", "application/json")
.timeout(Duration.ofSeconds(30))
.POST(HttpRequest.BodyPublishers.ofString(
objectMapper.writeValueAsString(requestBody)))
.build();
HttpResponse<String> response = httpClient.send(request,
HttpResponse.BodyHandlers.ofString());
return objectMapper.readTree(response.body());
}
private java.util.Map<String, Object> getInstanceInfo() {
Runtime runtime = Runtime.getRuntime();
return java.util.Map.of(
"hostname", getHostname(),
"os_name", System.getProperty("os.name"),
"os_version", System.getProperty("os.version"),
"java_version", System.getProperty("java.version"),
"processors", runtime.availableProcessors(),
"max_memory_mb", runtime.maxMemory() / (1024 * 1024),
"start_time", Instant.now().toString()
);
}
private String getHostname() {
try {
return java.net.InetAddress.getLocalHost().getHostName();
} catch (Exception e) {
return "unknown";
}
}
private void startBackgroundTasks() {
// Start validation task (every hour)
scheduler.scheduleAtFixedRate(this::validateLicenseBackground,
1, 1, TimeUnit.HOURS);
// Start usage tracking task (every 5 minutes)
scheduler.scheduleAtFixedRate(this::reportUsage,
5, 5, TimeUnit.MINUTES);
}
private void validateLicenseBackground() {
try {
JsonNode validation = validateLicense();
if (!validation.get("valid").asBoolean()) {
System.err.println("License validation failed: " +
validation.path("error").asText());
handleInvalidLicense();
}
} catch (Exception e) {
System.err.println("License validation error: " + e.getMessage());
}
}
private void reportUsage() {
try {
java.util.Map<String, Object> usage = usageTracker.getCurrentUsage();
if (!usage.isEmpty()) {
trackUsage(usage);
usageTracker.reset();
}
} catch (Exception e) {
System.err.println("Usage reporting error: " + e.getMessage());
}
}
private void handleInvalidLicense() {
System.err.println("License is invalid - application should shut down");
shutdown();
}
public void recordApiCall() {
usageTracker.recordApiCall();
}
public void recordUserActivity(String userId) {
usageTracker.recordUserActivity(userId);
}
public void updateStorageUsage(long bytes) {
usageTracker.updateStorageUsage(bytes);
}
public void shutdown() {
System.out.println("Shutting down license client...");
if (isActivated) {
try {
deactivateLicense();
} catch (Exception e) {
System.err.println("License deactivation failed: " + e.getMessage());
}
}
scheduler.shutdown();
try {
if (!scheduler.awaitTermination(10, TimeUnit.SECONDS)) {
scheduler.shutdownNow();
}
} catch (InterruptedException e) {
scheduler.shutdownNow();
}
}
private void deactivateLicense() throws IOException, InterruptedException {
String requestBody = objectMapper.writeValueAsString(java.util.Map.of(
"key", licenseKey,
"revoked", true
));
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(apiUrl + "/revoke-license"))
.header("Content-Type", "application/json")
.timeout(Duration.ofSeconds(30))
.POST(HttpRequest.BodyPublishers.ofString(requestBody))
.build();
HttpResponse<String> response = httpClient.send(request,
HttpResponse.BodyHandlers.ofString());
JsonNode result = objectMapper.readTree(response.body());
if ("revoked".equals(result.get("status").asText())) {
System.out.println("License revoked successfully");
}
}
// Inner class for usage tracking
private static class UsageTracker {
private final AtomicInteger apiCalls = new AtomicInteger(0);
private final Set<String> activeUsers = ConcurrentHashMap.newKeySet();
private final AtomicLong storageUsed = new AtomicLong(0);
private final long startTime = System.currentTimeMillis();
public void recordApiCall() {
apiCalls.incrementAndGet();
}
public void recordUserActivity(String userId) {
activeUsers.add(userId);
}
public void updateStorageUsage(long bytes) {
storageUsed.set(bytes);
}
public java.util.Map<String, Object> getCurrentUsage() {
java.util.Map<String, Object> usage = new java.util.HashMap<>();
usage.put("api_calls", apiCalls.get());
usage.put("active_users", activeUsers.size());
usage.put("storage_gb", storageUsed.get() / (1024.0 * 1024.0 * 1024.0));
usage.put("uptime_hours", (System.currentTimeMillis() - startTime) / (1000.0 * 60.0 * 60.0));
return usage;
}
public void reset() {
apiCalls.set(0);
activeUsers.clear();
// Note: don't reset storageUsed as it's a current value, not a counter
}
}
// Getters
public boolean isActivated() { return isActivated; }
public JsonNode getLicenseInfo() { return licenseInfo; }
public String getInstanceId() { return instanceId; }
}
// Usage example
public class Main {
public static void main(String[] args) {
String licenseKey = System.getenv("LICENSE_KEY");
if (licenseKey == null) {
System.err.println("LICENSE_KEY environment variable not set");
System.exit(1);
}
LicenseClient licenseClient = new LicenseClient(
licenseKey,
"https://your-license-api.com/v1"
);
if (licenseClient.initialize()) {
System.out.println("Application starting with valid license");
// Add shutdown hook
Runtime.getRuntime().addShutdownHook(new Thread(licenseClient::shutdown));
// Simulate application work
try {
while (true) {
licenseClient.recordApiCall();
licenseClient.recordUserActivity("user123");
Thread.sleep(1000);
}
} catch (InterruptedException e) {
System.out.println("Application interrupted");
}
} else {
System.err.println("Failed to initialize license - exiting");
System.exit(1);
}
}
}Go
Complete Integration Example
go
package main
import (
"bytes"
"crypto/sha256"
"encoding/json"
"fmt"
"io"
"net/http"
"os"
"runtime"
"sync"
"sync/atomic"
"time"
)
type LicenseClient struct {
licenseKey string
apiURL string
instanceID string
httpClient *http.Client
isActivated bool
licenseInfo map[string]interface{}
usageTracker *UsageTracker
stopChan chan struct{}
wg sync.WaitGroup
mu sync.RWMutex
}
type UsageTracker struct {
apiCalls int64
activeUsers sync.Map
storageUsed int64
startTime time.Time
mu sync.Mutex
}
func NewLicenseClient(licenseKey, apiURL string) *LicenseClient {
return &LicenseClient{
licenseKey: licenseKey,
apiURL: apiURL,
instanceID: generateInstanceID(),
httpClient: &http.Client{Timeout: 30 * time.Second},
usageTracker: &UsageTracker{startTime: time.Now()},
stopChan: make(chan struct{}),
}
}
func generateInstanceID() string {
hostname, _ := os.Hostname()
goos := runtime.GOOS
timestamp := fmt.Sprintf("%d", time.Now().UnixNano())
combined := fmt.Sprintf("%s-%s-%s", hostname, goos, timestamp)
hash := sha256.Sum256([]byte(combined))
return fmt.Sprintf("%x", hash[:8])
}
func (lc *LicenseClient) Initialize() error {
// Verify license
verification, err := lc.verifyLicense()
if err != nil {
return fmt.Errorf("license verification failed: %w", err)
}
valid, ok := verification["valid"].(bool)
if !ok || !valid {
errorMsg := "unknown error"
if errStr, ok := verification["error"].(string); ok {
errorMsg = errStr
}
return fmt.Errorf("invalid license: %s", errorMsg)
}
// Activate license
activation, err := lc.activateLicense()
if err != nil {
return fmt.Errorf("license activation failed: %w", err)
}
activated, ok := activation["activated"].(bool)
if !ok || !activated {
errorMsg := "unknown error"
if errStr, ok := activation["error"].(string); ok {
errorMsg = errStr
}
return fmt.Errorf("activation failed: %s", errorMsg)
}
lc.mu.Lock()
lc.isActivated = true
lc.licenseInfo = verification
lc.mu.Unlock()
// Start background tasks
lc.startBackgroundTasks()
fmt.Println("License initialized successfully")
return nil
}
func (lc *LicenseClient) verifyLicense() (map[string]interface{}, error) {
payload := map[string]interface{}{
"key": lc.licenseKey,
}
return lc.makeRequest("POST", "/verify-license", payload)
}
func (lc *LicenseClient) activateLicense() (map[string]interface{}, error) {
instanceInfo := lc.getInstanceInfo()
payload := map[string]interface{}{
"key": lc.licenseKey,
"instance_id": lc.instanceID,
"instance_info": instanceInfo,
}
return lc.makeRequest("POST", "/activate-license", payload)
}
func (lc *LicenseClient) validateLicense() (map[string]interface{}, error) {
payload := map[string]interface{}{
"key": lc.licenseKey,
"instance_id": lc.instanceID,
}
return lc.makeRequest("POST", "/validate-license", payload)
}
func (lc *LicenseClient) trackUsage(usage map[string]interface{}) (map[string]interface{}, error) {
payload := map[string]interface{}{
"key": lc.licenseKey,
"instance_id": lc.instanceID,
"usage": usage,
}
return lc.makeRequest("POST", "/track-usage", payload)
}
func (lc *LicenseClient) makeRequest(method, endpoint string, payload map[string]interface{}) (map[string]interface{}, error) {
jsonData, err := json.Marshal(payload)
if err != nil {
return nil, err
}
url := lc.apiURL + endpoint
req, err := http.NewRequest(method, url, bytes.NewBuffer(jsonData))
if err != nil {
return nil, err
}
req.Header.Set("Content-Type", "application/json")
resp, err := lc.httpClient.Do(req)
if err != nil {
return nil, err
}
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
if err != nil {
return nil, err
}
var result map[string]interface{}
if err := json.Unmarshal(body, &result); err != nil {
return nil, err
}
return result, nil
}
func (lc *LicenseClient) getInstanceInfo() map[string]interface{} {
hostname, _ := os.Hostname()
var memStats runtime.MemStats
runtime.ReadMemStats(&memStats)
return map[string]interface{}{
"hostname": hostname,
"os": runtime.GOOS,
"arch": runtime.GOARCH,
"go_version": runtime.Version(),
"num_cpu": runtime.NumCPU(),
"memory_mb": memStats.Sys / 1024 / 1024,
"num_goroutine": runtime.NumGoroutine(),
"start_time": time.Now().Format(time.RFC3339),
}
}
func (lc *LicenseClient) startBackgroundTasks() {
// Start validation goroutine
lc.wg.Add(1)
go lc.validationLoop()
// Start usage tracking goroutine
lc.wg.Add(1)
go lc.usageTrackingLoop()
}
func (lc *LicenseClient) validationLoop() {
defer lc.wg.Done()
ticker := time.NewTicker(1 * time.Hour)
defer ticker.Stop()
for {
select {
case <-ticker.C:
validation, err := lc.validateLicense()
if err != nil {
fmt.Printf("License validation error: %v\n", err)
continue
}
valid, ok := validation["valid"].(bool)
if !ok || !valid {
errorMsg := "unknown error"
if errStr, ok := validation["error"].(string); ok {
errorMsg = errStr
}
fmt.Printf("License validation failed: %s\n", errorMsg)
lc.handleInvalidLicense()
return
}
case <-lc.stopChan:
return
}
}
}
func (lc *LicenseClient) usageTrackingLoop() {
defer lc.wg.Done()
ticker := time.NewTicker(5 * time.Minute)
defer ticker.Stop()
for {
select {
case <-ticker.C:
usage := lc.usageTracker.getCurrentUsage()
if len(usage) > 0 {
_, err := lc.trackUsage(usage)
if err != nil {
fmt.Printf("Usage tracking error: %v\n", err)
} else {
lc.usageTracker.reset()
}
}
case <-lc.stopChan:
return
}
}
}
func (lc *LicenseClient) handleInvalidLicense() {
fmt.Println("License is invalid - application should shut down")
lc.Shutdown()
}
func (lc *LicenseClient) RecordAPICall() {
atomic.AddInt64(&lc.usageTracker.apiCalls, 1)
}
func (lc *LicenseClient) RecordUserActivity(userID string) {
lc.usageTracker.activeUsers.Store(userID, time.Now())
}
func (lc *LicenseClient) UpdateStorageUsage(bytes int64) {
atomic.StoreInt64(&lc.usageTracker.storageUsed, bytes)
}
func (lc *LicenseClient) Shutdown() {
fmt.Println("Shutting down license client...")
lc.mu.RLock()
isActivated := lc.isActivated
lc.mu.RUnlock()
if isActivated {
if err := lc.deactivateLicense(); err != nil {
fmt.Printf("License deactivation failed: %v\n", err)
}
}
close(lc.stopChan)
lc.wg.Wait()
}
func (lc *LicenseClient) deactivateLicense() error {
payload := map[string]interface{}{
"key": lc.licenseKey,
"revoked": true,
}
result, err := lc.makeRequest("POST", "/revoke-license", payload)
if err != nil {
return err
}
status, ok := result["status"].(string)
if ok && status == "revoked" {
fmt.Println("License revoked successfully")
}
return nil
}
// UsageTracker methods
func (ut *UsageTracker) getCurrentUsage() map[string]interface{} {
ut.mu.Lock()
defer ut.mu.Unlock()
// Count active users
activeUserCount := 0
ut.activeUsers.Range(func(key, value interface{}) bool {
activeUserCount++
return true
})
usage := map[string]interface{}{
"api_calls": atomic.LoadInt64(&ut.apiCalls),
"active_users": activeUserCount,
"storage_gb": float64(atomic.LoadInt64(&ut.storageUsed)) / (1024 * 1024 * 1024),
"uptime_hours": time.Since(ut.startTime).Hours(),
}
return usage
}
func (ut *UsageTracker) reset() {
atomic.StoreInt64(&ut.apiCalls, 0)
ut.activeUsers = sync.Map{} // Create new map to clear old users
}
// Getters
func (lc *LicenseClient) IsActivated() bool {
lc.mu.RLock()
defer lc.mu.RUnlock()
return lc.isActivated
}
func (lc *LicenseClient) GetLicenseInfo() map[string]interface{} {
lc.mu.RLock()
defer lc.mu.RUnlock()
return lc.licenseInfo
}
func (lc *LicenseClient) GetInstanceID() string {
return lc.instanceID
}
// Main usage example
func main() {
licenseKey := os.Getenv("LICENSE_KEY")
if licenseKey == "" {
fmt.Println("LICENSE_KEY environment variable not set")
os.Exit(1)
}
licenseClient := NewLicenseClient(licenseKey, "https://your-license-api.com/v1")
if err := licenseClient.Initialize(); err != nil {
fmt.Printf("Failed to initialize license: %v\n", err)
os.Exit(1)
}
fmt.Println("Application starting with valid license")
// Simulate application work
go func() {
for {
licenseClient.RecordAPICall()
licenseClient.RecordUserActivity("user123")
time.Sleep(1 * time.Second)
}
}()
// Wait for interrupt signal
c := make(chan os.Signal, 1)
signal.Notify(c, os.Interrupt)
<-c
fmt.Println("\nShutdown requested...")
licenseClient.Shutdown()
}Best Practices
1. Error Handling
- Implement comprehensive error handling for network failures
- Use exponential backoff for retries
- Distinguish between retriable and non-retriable errors
- Log errors appropriately without exposing sensitive information
2. Performance
- Use connection pooling for HTTP clients
- Implement request timeouts
- Cache license verification results
- Use background threads/goroutines for non-blocking operations
3. Security
- Never log full license keys
- Use secure HTTP (TLS) for all requests
- Validate certificates and hostnames
- Store credentials securely
4. Monitoring
- Track license verification success/failure rates
- Monitor usage reporting health
- Set up alerts for license-related issues
- Implement health checks
5. Configuration
- Make API endpoints configurable
- Allow timeout configuration
- Support different environments (dev/staging/prod)
- Implement feature flags for license enforcement
Next Steps
- Error Handling - Comprehensive error management strategies
- API Reference - Complete endpoint documentation
- Getting Started - Set up your License Server