registry.go raw

   1  //go:build !(js && wasm)
   2  
   3  package acl
   4  
   5  import (
   6  	"context"
   7  	"sort"
   8  	"sync"
   9  
  10  	"next.orly.dev/pkg/lol/errorf"
  11  	"next.orly.dev/pkg/database"
  12  )
  13  
  14  // DriverFactory is the signature for ACL driver factory functions.
  15  type DriverFactory func(ctx context.Context, db database.Database, cfg *DriverConfig) (I, error)
  16  
  17  // DriverConfig holds configuration for ACL drivers.
  18  type DriverConfig struct {
  19  	// Common settings
  20  	LogLevel       string
  21  	Owners         []string
  22  	Admins         []string
  23  	BootstrapRelays []string
  24  	RelayAddresses []string
  25  
  26  	// Follows-specific settings
  27  	FollowListFrequency     string
  28  	FollowsThrottleEnabled  bool
  29  	FollowsThrottlePerEvent string
  30  	FollowsThrottleMaxDelay string
  31  }
  32  
  33  // DriverInfo contains metadata about a registered ACL driver.
  34  type DriverInfo struct {
  35  	Name        string
  36  	Description string
  37  	Factory     DriverFactory
  38  }
  39  
  40  // I is the ACL interface that drivers must implement.
  41  // This is re-exported from the interfaces package for convenience.
  42  type I interface {
  43  	Configure(cfg ...any) (err error)
  44  	GetAccessLevel(pub []byte, address string) (level string)
  45  	GetACLInfo() (name, description, documentation string)
  46  	Syncer()
  47  	Type() string
  48  }
  49  
  50  var (
  51  	driversMu sync.RWMutex
  52  	drivers   = make(map[string]*DriverInfo)
  53  )
  54  
  55  // RegisterDriver registers an ACL driver with the given name and factory.
  56  // This is typically called from init() in the driver package.
  57  func RegisterDriver(name, description string, factory DriverFactory) {
  58  	driversMu.Lock()
  59  	defer driversMu.Unlock()
  60  	drivers[name] = &DriverInfo{
  61  		Name:        name,
  62  		Description: description,
  63  		Factory:     factory,
  64  	}
  65  }
  66  
  67  // GetDriver returns the factory for the named driver, or nil if not found.
  68  func GetDriver(name string) DriverFactory {
  69  	driversMu.RLock()
  70  	defer driversMu.RUnlock()
  71  	if info, ok := drivers[name]; ok {
  72  		return info.Factory
  73  	}
  74  	return nil
  75  }
  76  
  77  // HasDriver returns true if the named driver is registered.
  78  func HasDriver(name string) bool {
  79  	driversMu.RLock()
  80  	defer driversMu.RUnlock()
  81  	_, ok := drivers[name]
  82  	return ok
  83  }
  84  
  85  // ListDrivers returns a sorted list of registered driver names.
  86  func ListDrivers() []string {
  87  	driversMu.RLock()
  88  	defer driversMu.RUnlock()
  89  	names := make([]string, 0, len(drivers))
  90  	for name := range drivers {
  91  		names = append(names, name)
  92  	}
  93  	sort.Strings(names)
  94  	return names
  95  }
  96  
  97  // ListDriversWithInfo returns information about all registered drivers.
  98  func ListDriversWithInfo() []*DriverInfo {
  99  	driversMu.RLock()
 100  	defer driversMu.RUnlock()
 101  	infos := make([]*DriverInfo, 0, len(drivers))
 102  	for _, info := range drivers {
 103  		infos = append(infos, info)
 104  	}
 105  	// Sort by name for consistent output
 106  	sort.Slice(infos, func(i, j int) bool {
 107  		return infos[i].Name < infos[j].Name
 108  	})
 109  	return infos
 110  }
 111  
 112  // NewFromDriver creates an ACL using the named driver.
 113  // Returns an error if the driver is not registered.
 114  func NewFromDriver(ctx context.Context, driverName string, db database.Database, cfg *DriverConfig) (I, error) {
 115  	factory := GetDriver(driverName)
 116  	if factory == nil {
 117  		return nil, errorf.E("ACL driver %q not available; registered: %v", driverName, ListDrivers())
 118  	}
 119  	return factory(ctx, db, cfg)
 120  }
 121