267 lines
5.9 KiB
Go
267 lines
5.9 KiB
Go
package ironlicensing
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
"sync"
|
|
)
|
|
|
|
var (
|
|
ErrNotInitialized = errors.New("ironlicensing: client not initialized")
|
|
ErrPublicKeyRequired = errors.New("ironlicensing: public key is required")
|
|
ErrProductSlugRequired = errors.New("ironlicensing: product slug is required")
|
|
)
|
|
|
|
type LicenseRequiredError struct {
|
|
Feature string
|
|
}
|
|
|
|
func (e *LicenseRequiredError) Error() string {
|
|
return fmt.Sprintf("Feature '%s' requires a valid license", e.Feature)
|
|
}
|
|
|
|
type Client struct {
|
|
options Options
|
|
transport *Transport
|
|
currentLicense *License
|
|
licenseKey string
|
|
mu sync.RWMutex
|
|
}
|
|
|
|
var globalClient *Client
|
|
var globalMu sync.RWMutex
|
|
|
|
func NewClient(options Options) (*Client, error) {
|
|
if options.PublicKey == "" {
|
|
return nil, ErrPublicKeyRequired
|
|
}
|
|
if options.ProductSlug == "" {
|
|
return nil, ErrProductSlugRequired
|
|
}
|
|
opts := options.WithDefaults()
|
|
c := &Client{
|
|
options: opts,
|
|
transport: NewTransport(opts.APIBaseURL, opts.PublicKey, opts.ProductSlug, opts.HTTPTimeout, opts.Debug),
|
|
}
|
|
if opts.Debug {
|
|
fmt.Println("[IronLicensing] Client initialized")
|
|
}
|
|
return c, nil
|
|
}
|
|
|
|
func Init(publicKey, productSlug string, opts ...func(*Options)) error {
|
|
options := DefaultOptions()
|
|
options.PublicKey = publicKey
|
|
options.ProductSlug = productSlug
|
|
for _, opt := range opts {
|
|
opt(&options)
|
|
}
|
|
client, err := NewClient(options)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
globalMu.Lock()
|
|
globalClient = client
|
|
globalMu.Unlock()
|
|
return nil
|
|
}
|
|
|
|
func WithDebug(debug bool) func(*Options) {
|
|
return func(o *Options) { o.Debug = debug }
|
|
}
|
|
|
|
func getGlobalClient() (*Client, error) {
|
|
globalMu.RLock()
|
|
defer globalMu.RUnlock()
|
|
if globalClient == nil {
|
|
return nil, ErrNotInitialized
|
|
}
|
|
return globalClient, nil
|
|
}
|
|
|
|
func (c *Client) Validate(licenseKey string) LicenseResult {
|
|
return c.ValidateContext(context.Background(), licenseKey)
|
|
}
|
|
|
|
func (c *Client) ValidateContext(ctx context.Context, licenseKey string) LicenseResult {
|
|
result := c.transport.Validate(ctx, licenseKey)
|
|
if result.Valid && result.License != nil {
|
|
c.mu.Lock()
|
|
c.currentLicense = result.License
|
|
c.licenseKey = licenseKey
|
|
c.mu.Unlock()
|
|
}
|
|
return result
|
|
}
|
|
|
|
func (c *Client) Activate(licenseKey string) LicenseResult {
|
|
return c.ActivateContext(context.Background(), licenseKey, "")
|
|
}
|
|
|
|
func (c *Client) ActivateContext(ctx context.Context, licenseKey, machineName string) LicenseResult {
|
|
result := c.transport.Activate(ctx, licenseKey, machineName)
|
|
if result.Valid && result.License != nil {
|
|
c.mu.Lock()
|
|
c.currentLicense = result.License
|
|
c.licenseKey = licenseKey
|
|
c.mu.Unlock()
|
|
}
|
|
return result
|
|
}
|
|
|
|
func (c *Client) Deactivate() bool {
|
|
return c.DeactivateContext(context.Background())
|
|
}
|
|
|
|
func (c *Client) DeactivateContext(ctx context.Context) bool {
|
|
c.mu.RLock()
|
|
key := c.licenseKey
|
|
c.mu.RUnlock()
|
|
if key == "" {
|
|
return false
|
|
}
|
|
if c.transport.Deactivate(ctx, key) {
|
|
c.mu.Lock()
|
|
c.currentLicense = nil
|
|
c.licenseKey = ""
|
|
c.mu.Unlock()
|
|
return true
|
|
}
|
|
return false
|
|
}
|
|
|
|
func (c *Client) StartTrial(email string) LicenseResult {
|
|
return c.StartTrialContext(context.Background(), email)
|
|
}
|
|
|
|
func (c *Client) StartTrialContext(ctx context.Context, email string) LicenseResult {
|
|
result := c.transport.StartTrial(ctx, email)
|
|
if result.Valid && result.License != nil {
|
|
c.mu.Lock()
|
|
c.currentLicense = result.License
|
|
c.licenseKey = result.License.Key
|
|
c.mu.Unlock()
|
|
}
|
|
return result
|
|
}
|
|
|
|
func (c *Client) HasFeature(featureKey string) bool {
|
|
c.mu.RLock()
|
|
defer c.mu.RUnlock()
|
|
if c.currentLicense == nil {
|
|
return false
|
|
}
|
|
for _, f := range c.currentLicense.Features {
|
|
if f.Key == featureKey && f.Enabled {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
func (c *Client) RequireFeature(featureKey string) error {
|
|
if !c.HasFeature(featureKey) {
|
|
return &LicenseRequiredError{Feature: featureKey}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (c *Client) GetFeature(featureKey string) *Feature {
|
|
c.mu.RLock()
|
|
defer c.mu.RUnlock()
|
|
if c.currentLicense == nil {
|
|
return nil
|
|
}
|
|
for _, f := range c.currentLicense.Features {
|
|
if f.Key == featureKey {
|
|
return &f
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (c *Client) License() *License {
|
|
c.mu.RLock()
|
|
defer c.mu.RUnlock()
|
|
return c.currentLicense
|
|
}
|
|
|
|
func (c *Client) Status() LicenseStatus {
|
|
c.mu.RLock()
|
|
defer c.mu.RUnlock()
|
|
if c.currentLicense != nil {
|
|
return c.currentLicense.Status
|
|
}
|
|
return StatusNotActivated
|
|
}
|
|
|
|
func (c *Client) IsLicensed() bool {
|
|
c.mu.RLock()
|
|
defer c.mu.RUnlock()
|
|
return c.currentLicense != nil && (c.currentLicense.Status == StatusValid || c.currentLicense.Status == StatusTrial)
|
|
}
|
|
|
|
func (c *Client) IsTrial() bool {
|
|
c.mu.RLock()
|
|
defer c.mu.RUnlock()
|
|
return c.currentLicense != nil && (c.currentLicense.Status == StatusTrial || c.currentLicense.Type == TypeTrial)
|
|
}
|
|
|
|
func (c *Client) GetTiers() []ProductTier {
|
|
return c.transport.GetTiers(context.Background())
|
|
}
|
|
|
|
func (c *Client) StartPurchase(tierID, email string) CheckoutResult {
|
|
return c.transport.StartCheckout(context.Background(), tierID, email)
|
|
}
|
|
|
|
// Global functions
|
|
func Validate(licenseKey string) LicenseResult {
|
|
c, err := getGlobalClient()
|
|
if err != nil {
|
|
return LicenseResult{Valid: false, Error: err.Error()}
|
|
}
|
|
return c.Validate(licenseKey)
|
|
}
|
|
|
|
func Activate(licenseKey string) LicenseResult {
|
|
c, err := getGlobalClient()
|
|
if err != nil {
|
|
return LicenseResult{Valid: false, Error: err.Error()}
|
|
}
|
|
return c.Activate(licenseKey)
|
|
}
|
|
|
|
func Deactivate() bool {
|
|
c, err := getGlobalClient()
|
|
if err != nil {
|
|
return false
|
|
}
|
|
return c.Deactivate()
|
|
}
|
|
|
|
func StartTrial(email string) LicenseResult {
|
|
c, err := getGlobalClient()
|
|
if err != nil {
|
|
return LicenseResult{Valid: false, Error: err.Error()}
|
|
}
|
|
return c.StartTrial(email)
|
|
}
|
|
|
|
func HasFeature(featureKey string) bool {
|
|
c, err := getGlobalClient()
|
|
if err != nil {
|
|
return false
|
|
}
|
|
return c.HasFeature(featureKey)
|
|
}
|
|
|
|
func RequireFeature(featureKey string) error {
|
|
c, err := getGlobalClient()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return c.RequireFeature(featureKey)
|
|
}
|