Add nascent idea to static + dynamic plugin system

This is on the road for v1: enabling plugins for vocabulary extensions
and either supporting them in static or dynamic scenarios.

This new as/ folder is temporary to play around with, it is expected to
fold back into the pub area once I am making more sweeping changes for v1.
This commit is contained in:
Cory Slep 2018-09-01 20:03:51 +02:00
parent 806c037e3b
commit 3076a5410a
2 changed files with 188 additions and 0 deletions

105
as/registry.go Normal file
View File

@ -0,0 +1,105 @@
package extension
import (
"fmt"
"sync"
)
// The global mapping of names to specific vocabularies and the plugins
// providing their implementations.
var (
pluginRegistry = make(map[string]Plugin)
pluginRegistryMu sync.RWMutex
)
func RegisteredPlugins() []string {
pluginRegistryMu.RLock()
defer pluginRegistryMu.RUnlock()
s := make([]string, 0, len(pluginRegistry))
for name, _ := range pluginRegistry {
s = append(s, name)
}
return s
}
/* BEGIN TEST SPECIFIC STUFF */
func unregisterAllExtensions() {
pluginRegistryMu.Lock()
defer pluginRegistryMu.Unlock()
pluginRegistry = make(map[string]Plugin)
}
/* BEGIN STATIC SPECIFIC STUFF */
func RegisterExtension(name string, plugin Plugin) {
pluginRegistryMu.Lock()
defer pluginRegistryMu.Unlock()
if plugin == nil {
panic("nil plugin passed to RegisterExtension")
}
if _, ok := pluginRegistry[name]; ok {
panic("duplicate RegisterExtension name: " + name)
}
pluginRegistry[name] = plugin
}
/* BEGIN DYNAMIC SPECIFIC STUFF */
var (
pluginProvider PluginProvider = nil
pluginProviderMu sync.RWMutex
)
type NamedPlugin struct {
Name string
Plugin Plugin
}
type PluginProvider interface {
Add() <-chan NamedPlugin
Remove() <-chan string
// nil errors will be sent in response to successful calls to Add or Remove
Err() chan<- error
Done() <-chan struct{}
}
func RegisterPluginProvider(p PluginProvider) {
pluginProviderMu.Lock()
defer pluginProviderMu.Unlock()
if pluginProvider != nil {
panic("RegisterPluginProvider already called")
}
pluginProvider = p
go func() {
addCh := pluginProvider.Add()
remCh := pluginProvider.Remove()
errCh := pluginProvider.Err()
doneCh := pluginProvider.Done()
for {
select {
case namedPlugin := <-addCh:
pluginRegistryMu.Lock() // LOCK
if _, ok := pluginRegistry[namedPlugin.Name]; ok {
errCh <- fmt.Errorf("cannot add: plugin already registered: %s", namedPlugin.Name)
} else {
pluginRegistry[namedPlugin.Name] = namedPlugin.Plugin
errCh <- nil
}
pluginRegistryMu.Unlock() // UNLOCK
case removeName := <-remCh:
pluginRegistryMu.Lock() // LOCK
if _, ok := pluginRegistry[removeName]; !ok {
errCh <- fmt.Errorf("cannot remove: plugin not registered: %s", removeName)
} else {
delete(pluginRegistry, removeName)
errCh <- nil
}
pluginRegistryMu.Unlock() // UNLOCK
case <-doneCh:
close(errCh)
return
}
}
}()
}

83
as/vocabulary.go Normal file
View File

@ -0,0 +1,83 @@
// Package extension outlines the interfaces required for an ActivityStreams
// extension.
package extension
import ()
// TODO: Figure out the new "Resolver" and "Property-Resolver" algorithms for
// the plugin architecture. Two kinds: for deserialization, and for dispatching.
// Plugin
type Plugin interface {
NewTypeResolver()
}
// Resolver
type Resolver interface {
Deserialize(map[string]interface{}) error
}
type PropertyResolver interface {
}
/*
EXISTING USAGE:
vocab.IsActivityType()
vocab.HasTypeTombstone()
vocab.HasTypeCreate()
vocab.Serializer
vocab.Typer
vocab.ObjectType
vocab.LinkType
vocab.ActivityType
vocab.IntransitiveActivityType
vocab.CollectionType
vocab.CollectionPageType
vocab.OrderedCollectionType
vocab.OrderedCollectionPageType
vocab.FollowType
vocab.TombstoneType
vocab.Object
vocab.Create
vocab.Accept
vocab.Reject
vocab.OrderedCollection
vocab.OrderedCollectionPage
vocab.Collection
vocab.CollectionPage
vocab.Tombstone
streams.Resolver
streams.Create
streams.Update
streams.Delete
streams.Follow
streams.Accept
streams.Reject
streams.Add
streams.Remove
streams.Like
streams.Undo
streams.Block
streams.Announce
streams.Dislike
streams.Flag
streams.Ignore
streams.Invite
streams.Join
streams.Leave
streams.Listen
streams.Move
streams.Offer
streams.Question
streams.Read
streams.TentativeAccept
streams.TentativeReject
streams.Travel
streams.View
streams.Collection
streams.OrderedCollection
streams.CollectionPage
streams.OrderedCollectionPage
*/