Documentation
¶
Index ¶
- Constants
- Variables
- func GenerateLicenseID() (string, error)
- func GenerateLicenseKey(licenseType LicenseType, email string) (string, error)
- func InitGlobal(licenseKey, serverURL string)
- func ReportOnce(license *License, version string) error
- func SendLicenseEmail(config *EmailConfig, license *License) error
- func ValidateLicenseKey(key string) bool
- func VerifyFingerprint(expectedHash string) (bool, error)
- type Client
- type EmailConfig
- type Feature
- type FeatureNotAvailableError
- type HardwareFingerprint
- type License
- func (l *License) BindToFingerprint(fingerprint *HardwareFingerprint)
- func (l *License) GetFingerprint() (string, bool)
- func (l *License) IsActive() bool
- func (l *License) IsExpired() bool
- func (l *License) Validate() error
- func (l *License) ValidateWithOptions(opts ValidationOptions) error
- func (l *License) VerifyHardwareBinding() (bool, error)
- type LicenseInfo
- type LicenseStatus
- type LicenseStore
- type LicenseTier
- type LicenseType
- type Manager
- func (m *Manager) CheckFeature(feature Feature) error
- func (m *Manager) GetLicense() *LicenseInfo
- func (m *Manager) GetTier() LicenseTier
- func (m *Manager) HasFeature(feature Feature) bool
- func (m *Manager) IsEnterprise() bool
- func (m *Manager) IsPro() bool
- func (m *Manager) IsValid() bool
- func (m *Manager) RequireFeature(feature Feature)
- func (m *Manager) Stop()
- type PGStore
- func (s *PGStore) Close() error
- func (s *PGStore) CreateLicense(ctx context.Context, license *License) error
- func (s *PGStore) GetLicense(ctx context.Context, id string) (*License, error)
- func (s *PGStore) GetLicenseByCustomer(ctx context.Context, customerID string) (*License, error)
- func (s *PGStore) GetLicenseByKey(ctx context.Context, key string) (*License, error)
- func (s *PGStore) ListLicenses(ctx context.Context) ([]*License, error)
- func (s *PGStore) Ping(ctx context.Context) error
- func (s *PGStore) UpdateLicense(ctx context.Context, license *License) error
- type Store
- func (s *Store) Close() error
- func (s *Store) CreateLicense(_ context.Context, license *License) error
- func (s *Store) GetLicense(_ context.Context, id string) (*License, error)
- func (s *Store) GetLicenseByCustomer(_ context.Context, customerID string) (*License, error)
- func (s *Store) GetLicenseByKey(_ context.Context, key string) (*License, error)
- func (s *Store) ListLicenses(_ context.Context) ([]*License, error)
- func (s *Store) Ping(_ context.Context) error
- func (s *Store) UpdateLicense(_ context.Context, license *License) error
- type TelemetryData
- type TelemetryReporter
- type ValidateRequest
- type ValidateResponse
- type ValidationError
- type ValidationOptions
Examples ¶
Constants ¶
const ( // Cache TTL (24 hours) CacheTTL = 24 * time.Hour // Fallback cache TTL (7 days - used when license server is down) FallbackCacheTTL = 7 * 24 * time.Hour // Revalidation interval (check license server every 24 hours in background) RevalidationInterval = 24 * time.Hour // Default license server URL DefaultLicenseServerURL = "https://license.graphdb.com" // DefaultVersion is used when build info is not available DefaultVersion = "dev" )
Variables ¶
var ( // Community features (always available) FeatureBasicQueries = Feature{ Name: "basic_queries", Description: "Basic graph queries (nodes, edges, traversal)", RequiredTier: TierCommunity, } FeatureShortestPath = Feature{ Name: "shortest_path", Description: "Shortest path algorithm", RequiredTier: TierCommunity, } FeatureBFS = Feature{ Name: "bfs", Description: "Breadth-first search", RequiredTier: TierCommunity, } FeatureDFS = Feature{ Name: "dfs", Description: "Depth-first search", RequiredTier: TierCommunity, } // Pro features FeaturePageRank = Feature{ Name: "pagerank", Description: "PageRank algorithm", RequiredTier: TierPro, } FeatureCommunityDetection = Feature{ Name: "community_detection", Description: "Community detection algorithms", RequiredTier: TierPro, } FeatureTrustScoring = Feature{ Name: "trust_scoring", Description: "Trust and reputation scoring", RequiredTier: TierPro, } FeatureFraudDetection = Feature{ Name: "fraud_detection", Description: "Fraud ring detection", RequiredTier: TierPro, } FeatureTemporalGraphs = Feature{ Name: "temporal_graphs", Description: "Time-based graph queries", RequiredTier: TierPro, } FeatureAuditLogging = Feature{ Name: "audit_logging", Description: "Comprehensive audit logging", RequiredTier: TierPro, } // Enterprise features FeatureRBAC = Feature{ Name: "rbac", Description: "Role-based access control", RequiredTier: TierEnterprise, } FeatureSSO = Feature{ Name: "sso", Description: "Single sign-on (SAML/OAuth)", RequiredTier: TierEnterprise, } FeaturePrioritySupport = Feature{ Name: "priority_support", Description: "Priority email support with 24h SLA", RequiredTier: TierEnterprise, } FeatureMultiRegion = Feature{ Name: "multi_region", Description: "Multi-region replication", RequiredTier: TierEnterprise, } )
GraphDB feature definitions
var TelemetryEndpoint = "https://telemetry.graphdb.io/v1/report"
TelemetryEndpoint is the URL where telemetry data is sent Override this in production to point to your telemetry server
Functions ¶
func GenerateLicenseID ¶
GenerateLicenseID creates a unique license ID. Returns an error if random generation fails.
func GenerateLicenseKey ¶
func GenerateLicenseKey(licenseType LicenseType, email string) (string, error)
GenerateLicenseKey creates a unique license key with checksum Format: CGDB-XXXX-XXXX-XXXX-XXXX-CC (where CC is checksum)
func InitGlobal ¶
func InitGlobal(licenseKey, serverURL string)
InitGlobal initializes the global license manager
func ReportOnce ¶
ReportOnce sends a single telemetry report without starting the periodic reporter Useful for one-time events like startup or shutdown
func SendLicenseEmail ¶
func SendLicenseEmail(config *EmailConfig, license *License) error
SendLicenseEmail sends a license key to a customer
func ValidateLicenseKey ¶
ValidateLicenseKey checks if a license key has valid format and checksum Supports both old format (CGDB-XXXX-XXXX-XXXX-XXXX) and new format with checksum
func VerifyFingerprint ¶
VerifyFingerprint checks if the current hardware matches the provided fingerprint
Types ¶
type Client ¶
type Client struct {
// contains filtered or unexported fields
}
Client validates licenses against the license server
func (*Client) GetCurrent ¶
func (c *Client) GetCurrent() *LicenseInfo
GetCurrent returns the current cached license (if any)
func (*Client) StartBackgroundValidation ¶
StartBackgroundValidation starts background license re-validation
type EmailConfig ¶
type EmailConfig struct {
SMTPHost string
SMTPPort string
SMTPUsername string
SMTPPassword string
FromEmail string
FromName string
}
EmailConfig holds email configuration
func LoadEmailConfigFromEnv ¶
func LoadEmailConfigFromEnv() *EmailConfig
LoadEmailConfigFromEnv loads email configuration from environment variables
func (*EmailConfig) IsConfigured ¶
func (c *EmailConfig) IsConfigured() bool
IsConfigured checks if email is properly configured
type Feature ¶
type Feature struct {
Name string
Description string
RequiredTier LicenseTier
}
Feature represents a GraphDB feature with licensing requirements
func FeaturesByTier ¶
func FeaturesByTier(tier LicenseTier) []Feature
FeaturesByTier returns features available for a given tier
Example ¶
Example: Feature-based route registration
package main
import (
"fmt"
"github.com/dd0wney/graphdb/pkg/licensing"
)
func main() {
licensing.InitGlobal("", "")
// Get available features for current tier
currentTier := licensing.Global().GetTier()
features := licensing.FeaturesByTier(currentTier)
fmt.Printf("Available features for %s tier:\n", currentTier)
for _, feature := range features {
fmt.Printf(" - %s: %s\n", feature.Name, feature.Description)
}
// Example output for Community tier:
// Available features for community tier:
// - basic_queries: Basic graph queries
// - shortest_path: Shortest path algorithm
// - bfs: Breadth-first search
// - dfs: Depth-first search
}
Output:
type FeatureNotAvailableError ¶
type FeatureNotAvailableError struct {
Feature Feature
CurrentTier LicenseTier
RequiredTier LicenseTier
}
FeatureNotAvailableError is returned when a feature is not available in the current tier
func (*FeatureNotAvailableError) Error ¶
func (e *FeatureNotAvailableError) Error() string
type HardwareFingerprint ¶
type HardwareFingerprint struct {
Hash string `json:"hash"`
Components map[string]string `json:"components"`
Generated string `json:"generated_at"`
}
HardwareFingerprint represents a unique hardware identifier
func GenerateFingerprint ¶
func GenerateFingerprint() (*HardwareFingerprint, error)
GenerateFingerprint creates a unique hardware fingerprint based on: - CPU architecture and cores - Primary MAC address - Hostname This allows licenses to be tied to specific deployments
type License ¶
type License struct {
ID string `json:"id"`
Key string `json:"key"`
Type LicenseType `json:"type"`
Email string `json:"email"`
CustomerID string `json:"customer_id"` // Stripe customer ID
SubscriptionID string `json:"subscription_id"` // Stripe subscription ID
Status string `json:"status"` // active, cancelled, expired
CreatedAt time.Time `json:"created_at"`
ExpiresAt *time.Time `json:"expires_at,omitempty"`
Metadata map[string]string `json:"metadata,omitempty"`
}
License represents a GraphDB license
func (*License) BindToFingerprint ¶
func (l *License) BindToFingerprint(fingerprint *HardwareFingerprint)
BindLicenseToFingerprint stores the hardware fingerprint in license metadata
func (*License) GetFingerprint ¶
GetFingerprint returns the hardware fingerprint bound to this license, if any
func (*License) Validate ¶
Validate performs comprehensive license validation Returns nil if license is valid, error otherwise
func (*License) ValidateWithOptions ¶
func (l *License) ValidateWithOptions(opts ValidationOptions) error
ValidateWithOptions performs license validation with custom options
func (*License) VerifyHardwareBinding ¶
VerifyHardwareBinding checks if the license is bound to the current hardware Returns true if: - License has no hardware binding (not enforced) - Current hardware matches the bound fingerprint
type LicenseInfo ¶
type LicenseInfo struct {
Valid bool
Tier LicenseTier
Status LicenseStatus
ExpiresAt *time.Time
MaxNodes *int
ValidatedAt time.Time
CachedUntil time.Time
}
LicenseInfo represents a validated license with caching info
func (*LicenseInfo) HasFeature ¶
func (l *LicenseInfo) HasFeature(feature Feature) bool
HasFeature checks if a license tier supports a feature
func (*LicenseInfo) IsEnterprise ¶
func (l *LicenseInfo) IsEnterprise() bool
IsEnterprise returns whether the license is Enterprise
func (*LicenseInfo) IsPro ¶
func (l *LicenseInfo) IsPro() bool
IsPro returns whether the license is Pro or higher
func (*LicenseInfo) IsValid ¶
func (l *LicenseInfo) IsValid() bool
IsValid returns whether the license is valid
type LicenseStatus ¶
type LicenseStatus string
LicenseStatus represents the status of a license
const ( StatusActive LicenseStatus = "active" StatusSuspended LicenseStatus = "suspended" StatusCancelled LicenseStatus = "cancelled" StatusExpired LicenseStatus = "expired" )
type LicenseStore ¶
type LicenseStore interface {
CreateLicense(ctx context.Context, license *License) error
GetLicense(ctx context.Context, id string) (*License, error)
GetLicenseByKey(ctx context.Context, key string) (*License, error)
GetLicenseByCustomer(ctx context.Context, customerID string) (*License, error)
UpdateLicense(ctx context.Context, license *License) error
ListLicenses(ctx context.Context) ([]*License, error)
Ping(ctx context.Context) error
Close() error
}
LicenseStore defines the interface for license persistence
type LicenseTier ¶
type LicenseTier string
LicenseTier represents the GraphDB license tier
const ( TierCommunity LicenseTier = "community" TierPro LicenseTier = "pro" TierEnterprise LicenseTier = "enterprise" )
type LicenseType ¶
type LicenseType string
LicenseType represents the license tier
const ( LicenseTypeProfessional LicenseType = "professional" LicenseTypeEnterprise LicenseType = "enterprise" )
type Manager ¶
type Manager struct {
// contains filtered or unexported fields
}
Manager manages license validation and feature access
func (*Manager) CheckFeature ¶
CheckFeature returns an error if the current license doesn't support a feature Use this for graceful feature gating in API handlers
Example ¶
Example: Graceful feature gating with error messages
package main
import (
"encoding/json"
"net/http"
"github.com/dd0wney/graphdb/pkg/licensing"
)
func main() {
licensing.InitGlobal("", "") // Community tier
handler := func(w http.ResponseWriter, r *http.Request) {
// CheckFeature returns a helpful error with upgrade link
if err := licensing.Global().CheckFeature(licensing.FeatureFraudDetection); err != nil {
// Error message includes current tier, required tier, and upgrade URL
http.Error(w, err.Error(), http.StatusForbidden)
return
}
// Feature is available
w.WriteHeader(http.StatusOK)
json.NewEncoder(w).Encode(map[string]any{
"fraudRings": []string{"ring-1", "ring-2"},
})
}
_ = handler
}
Output:
func (*Manager) GetLicense ¶
func (m *Manager) GetLicense() *LicenseInfo
GetLicense returns the current license
Example ¶
Example: License info endpoint
package main
import (
"encoding/json"
"net/http"
"github.com/dd0wney/graphdb/pkg/licensing"
)
func main() {
licensing.InitGlobal("", "")
handler := func(w http.ResponseWriter, r *http.Request) {
license := licensing.Global().GetLicense()
response := map[string]any{
"valid": license.IsValid(),
"tier": license.Tier,
"status": license.Status,
}
if license.ExpiresAt != nil {
response["expiresAt"] = license.ExpiresAt
}
if license.MaxNodes != nil {
response["maxNodes"] = license.MaxNodes
}
json.NewEncoder(w).Encode(response)
}
_ = handler
}
Output:
func (*Manager) GetTier ¶
func (m *Manager) GetTier() LicenseTier
GetTier returns the current license tier
Example ¶
Example: Check license tier for conditional features
package main
import (
"encoding/json"
"net/http"
"github.com/dd0wney/graphdb/pkg/licensing"
)
func main() {
licensing.InitGlobal("", "")
handler := func(w http.ResponseWriter, r *http.Request) {
tier := licensing.Global().GetTier()
// Return tier-appropriate response
response := map[string]any{
"tier": tier,
}
switch tier {
case licensing.TierEnterprise:
response["features"] = []string{"all", "rbac", "sso", "multi-region"}
case licensing.TierPro:
response["features"] = []string{"pagerank", "fraud-detection", "audit-logging"}
case licensing.TierCommunity:
response["features"] = []string{"basic-queries", "shortest-path"}
}
json.NewEncoder(w).Encode(response)
}
_ = handler
}
Output:
func (*Manager) HasFeature ¶
HasFeature checks if the current license supports a feature
Example ¶
Example: Basic feature check in an API handler
package main
import (
"encoding/json"
"net/http"
"github.com/dd0wney/graphdb/pkg/licensing"
)
func main() {
// Initialize the global license manager (typically done in main.go)
licensing.InitGlobal("", "") // Community tier (no license key)
// In your API handler, check if a feature is available
handler := func(w http.ResponseWriter, r *http.Request) {
// Check if PageRank is available (Pro+ feature)
if !licensing.Global().HasFeature(licensing.FeaturePageRank) {
http.Error(w, "PageRank requires Pro or Enterprise tier", http.StatusForbidden)
return
}
// Feature is available, proceed with request
w.WriteHeader(http.StatusOK)
json.NewEncoder(w).Encode(map[string]any{
"status": "success",
"data": []float64{0.15, 0.23, 0.42}, // PageRank results
})
}
_ = handler // Use the handler in your HTTP router
}
Output:
Example (Fallback) ¶
Example: Multiple feature checks with fallback behavior
package main
import (
"encoding/json"
"net/http"
"github.com/dd0wney/graphdb/pkg/licensing"
)
func main() {
licensing.InitGlobal("", "")
handler := func(w http.ResponseWriter, r *http.Request) {
var results any
// Try enterprise algorithm first
if licensing.Global().HasFeature(licensing.FeatureCommunityDetection) {
results = runAdvancedCommunityDetection()
} else {
// Fall back to basic algorithm
results = runBasicClustering()
}
json.NewEncoder(w).Encode(map[string]any{
"results": results,
"tier": licensing.Global().GetTier(),
})
}
_ = handler
}
// Mock functions for examples
func runAdvancedCommunityDetection() any {
return map[string]any{"algorithm": "louvain", "communities": 5}
}
func runBasicClustering() any {
return map[string]any{"algorithm": "simple", "clusters": 3}
}
Output:
func (*Manager) IsEnterprise ¶
IsEnterprise returns whether the license is Enterprise
func (*Manager) RequireFeature ¶
RequireFeature panics if the current license doesn't support a feature Use this for critical features that should never be accessed without proper licensing
type PGStore ¶
type PGStore struct {
// contains filtered or unexported fields
}
PGStore handles license persistence using PostgreSQL
func NewPGStore ¶
NewPGStore creates a new PostgreSQL-backed license store
func (*PGStore) CreateLicense ¶
CreateLicense stores a new license
func (*PGStore) GetLicense ¶
GetLicense retrieves a license by ID
func (*PGStore) GetLicenseByCustomer ¶
GetLicenseByCustomer retrieves a license by Stripe customer ID
func (*PGStore) GetLicenseByKey ¶
GetLicenseByKey retrieves a license by its key
func (*PGStore) ListLicenses ¶
ListLicenses returns all licenses
type Store ¶
type Store struct {
// contains filtered or unexported fields
}
Store handles license persistence using a local file
func (*Store) CreateLicense ¶
CreateLicense stores a new license
func (*Store) GetLicense ¶
GetLicense retrieves a license by ID
func (*Store) GetLicenseByCustomer ¶
GetLicenseByCustomer retrieves a license by Stripe customer ID
func (*Store) GetLicenseByKey ¶
GetLicenseByKey retrieves a license by its key
func (*Store) ListLicenses ¶
ListLicenses returns all licenses
type TelemetryData ¶
type TelemetryData struct {
// Anonymous license hash (SHA-256 of license key)
LicenseHash string `json:"license_hash"`
// Version information
Version string `json:"version"`
GoVersion string `json:"go_version"`
OS string `json:"os"`
Arch string `json:"arch"`
// Usage metrics (anonymous)
NodeCount int64 `json:"node_count,omitempty"`
EdgeCount int64 `json:"edge_count,omitempty"`
Uptime int64 `json:"uptime_seconds,omitempty"`
// Deployment type
DeploymentType string `json:"deployment_type,omitempty"` // docker, binary, kubernetes
// Timestamp
Timestamp time.Time `json:"timestamp"`
// Installation ID (anonymous hash of hardware fingerprint)
InstallationID string `json:"installation_id,omitempty"`
}
TelemetryData represents anonymous usage metrics All data is anonymized - no personal or identifying information is sent
type TelemetryReporter ¶
type TelemetryReporter struct {
// contains filtered or unexported fields
}
TelemetryReporter handles periodic telemetry reporting
func NewTelemetryReporter ¶
func NewTelemetryReporter(enabled bool, interval time.Duration) *TelemetryReporter
NewTelemetryReporter creates a new telemetry reporter
func (*TelemetryReporter) Start ¶
func (t *TelemetryReporter) Start(license *License, getMetrics func() (nodeCount, edgeCount int64))
Start begins periodic telemetry reporting
type ValidateRequest ¶
type ValidateRequest struct {
LicenseKey string `json:"licenseKey"`
InstanceID string `json:"instanceId,omitempty"`
Version string `json:"version,omitempty"`
}
ValidateRequest is sent to the license server
type ValidateResponse ¶
type ValidateResponse struct {
Valid bool `json:"valid"`
Tier LicenseTier `json:"tier,omitempty"`
Status LicenseStatus `json:"status,omitempty"`
Error string `json:"error,omitempty"`
ExpiresAt *time.Time `json:"expiresAt,omitempty"`
MaxNodes *int `json:"maxNodes,omitempty"`
Timestamp time.Time `json:"timestamp"`
}
ValidateResponse is received from the license server
type ValidationError ¶
ValidationError represents a license validation failure
func (*ValidationError) Error ¶
func (e *ValidationError) Error() string
type ValidationOptions ¶
ValidationOptions controls which validations to perform
func DefaultValidationOptions ¶
func DefaultValidationOptions() ValidationOptions
DefaultValidationOptions returns the standard validation options