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.
このコミットが含まれているのは:
コミット
3076a5410a
105
as/registry.go
ノーマルファイル
105
as/registry.go
ノーマルファイル
@ -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
ノーマルファイル
83
as/vocabulary.go
ノーマルファイル
@ -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
|
||||
*/
|
読み込み中…
新しいイシューから参照
ユーザーをブロックする