Search Apps Documentation Source Content File Folder Download Copy Actions Download

extensions.gno

4.03 Kb · 137 lines
  1package daokit
  2
  3// Extensions system enables DAOs to expose additional functionality that can be
  4// accessed by other packages or realms. It provides a secure way to make
  5// specific DAO capabilities available without exposing internal implementation details.
  6
  7import "gno.land/p/nt/avl/v0"
  8
  9// Interface must be implemented by any object that wants to be
 10// registered as a DAO extension. Extensions expose functionality through
 11// well-defined interfaces while maintaining encapsulation.
 12type Extension interface {
 13	// Returns metadata about this extension including its path, version,
 14	// query path for external access, and privacy settings.
 15	Info() ExtensionInfo
 16}
 17
 18type ExtensionInfo struct {
 19	Path      string // Unique extension identifier (e.g., "gno.land/p/demo/basedao.MembersView")
 20	Version   string // Extension version (e.g., "1", "2.0", etc.)
 21	QueryPath string // Path for external queries to access this extension's data
 22	Private   bool   // If true, extension is only accessible from the same realm that registered it
 23}
 24
 25type ExtensionsList interface {
 26	// Returns the total number of registered extensions.
 27	Len() int
 28	// Returns extension info at the specified index, or nil if index is out of bounds.
 29	Get(index int) *ExtensionInfo
 30	// Returns a slice of ExtensionInfo from startIndex to endIndex.
 31	Slice(startIndex, endIndex int) []ExtensionInfo
 32	// Iterates over all extensions, calling fn for each one.
 33	// Iteration stops if fn returns true.
 34	ForEach(fn func(index int, value ExtensionInfo) bool)
 35}
 36
 37type ExtensionsStore struct {
 38	Tree avl.Tree
 39}
 40
 41// Registers a new extension using its path as the key.
 42// Returns true if the extension was successfully registered.
 43// If an extension with the same path already exists, it will be replaced.
 44func (es *ExtensionsStore) Set(ext Extension) bool {
 45	info := ext.Info()
 46	return es.Tree.Set(info.Path, ext)
 47}
 48
 49func (es *ExtensionsStore) Get(path string) (Extension, bool) {
 50	iface, ok := es.Tree.Get(path)
 51	if !ok {
 52		return nil, false
 53	}
 54	return iface.(Extension), true
 55}
 56
 57// Remove unregisters an extension by its path.
 58// Returns the removed extension and true if found, nil and false otherwise.
 59func (es *ExtensionsStore) Remove(path string) (Extension, bool) {
 60	iface, ok := es.Tree.Remove(path)
 61	if !ok {
 62		return nil, false
 63	}
 64	return iface.(Extension), true
 65}
 66
 67// Returns an ExtensionsList interface for iterating over all registered extensions.
 68// This provides read-only access to the extensions registry.
 69func (es *ExtensionsStore) List() ExtensionsList {
 70	return &extensionsList{es: es}
 71}
 72
 73type extensionsList struct {
 74	es *ExtensionsStore
 75}
 76
 77// Iterates over all extensions, calling fn for each extension with its index and info.
 78// Iteration stops early if fn returns true.
 79func (e *extensionsList) ForEach(fn func(index int, value ExtensionInfo) bool) {
 80	if e.es.Tree.Size() == 0 {
 81		return
 82	}
 83
 84	index := 0
 85	e.es.Tree.IterateByOffset(0, e.es.Tree.Size(), func(_ string, value any) bool {
 86		result := fn(index, value.(Extension).Info())
 87		index++
 88		return result
 89	})
 90}
 91
 92// Returns the ExtensionInfo at the specified index.
 93func (e *extensionsList) Get(index int) *ExtensionInfo {
 94	if index < 0 || index >= e.es.Tree.Size() {
 95		return nil
 96	}
 97
 98	_, value := e.es.Tree.GetByIndex(index)
 99	info := value.(Extension).Info()
100	return &info
101}
102
103// Returns the total number of registered extensions.
104func (e *extensionsList) Len() int {
105	return e.es.Tree.Size()
106}
107
108// Returns a slice of ExtensionInfo from startIndex (inclusive) to endIndex (exclusive).
109// Bounds are automatically normalized: negative startIndex becomes 0, endIndex beyond size becomes size.
110func (e *extensionsList) Slice(startIndex int, endIndex int) []ExtensionInfo {
111	size := e.es.Tree.Size()
112
113	// Normalize bounds
114	if startIndex < 0 {
115		startIndex = 0
116	}
117
118	if endIndex > size {
119		endIndex = size
120	}
121
122	if startIndex >= endIndex {
123		return nil
124	}
125
126	count := endIndex - startIndex
127	result := make([]ExtensionInfo, count)
128
129	i := 0
130	e.es.Tree.IterateByOffset(startIndex, count, func(_ string, value any) bool {
131		result[i] = value.(Extension).Info()
132		i++
133		return false
134	})
135
136	return result
137}