mirror of
https://github.com/Kong/go-pluginserver.git
synced 2025-10-05 08:06:58 +08:00
142 lines
3.8 KiB
Go
142 lines
3.8 KiB
Go
package main
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"github.com/kong/go-pdk"
|
|
)
|
|
|
|
// --- instanceData --- //
|
|
type instanceData struct {
|
|
id int
|
|
plugin *pluginData
|
|
initialized bool
|
|
config interface{}
|
|
handlers map[string]func(kong *pdk.PDK)
|
|
}
|
|
|
|
type (
|
|
certificater interface{ Certificate(*pdk.PDK) }
|
|
rewriter interface{ Rewrite(*pdk.PDK) }
|
|
accesser interface{ Access(*pdk.PDK) }
|
|
headerFilter interface{ HeaderFilter(*pdk.PDK) }
|
|
bodyFilter interface{ BodyFilter(*pdk.PDK) }
|
|
prereader interface{ Preread(*pdk.PDK) }
|
|
logger interface{ Log(*pdk.PDK) }
|
|
)
|
|
|
|
func getHandlers(config interface{}) map[string]func(kong *pdk.PDK) {
|
|
handlers := map[string]func(kong *pdk.PDK){}
|
|
|
|
if h, ok := config.(certificater); ok { handlers["certificate"] = h.Certificate }
|
|
if h, ok := config.(rewriter) ; ok { handlers["rewrite"] = h.Rewrite }
|
|
if h, ok := config.(accesser) ; ok { handlers["access"] = h.Access }
|
|
if h, ok := config.(headerFilter); ok { handlers["header_filter"] = h.HeaderFilter }
|
|
if h, ok := config.(bodyFilter) ; ok { handlers["body_filter"] = h.BodyFilter }
|
|
if h, ok := config.(prereader) ; ok { handlers["preread"] = h.Preread }
|
|
if h, ok := config.(logger) ; ok { handlers["log"] = h.Log }
|
|
|
|
return handlers
|
|
}
|
|
|
|
// Configuration data for a new plugin instance.
|
|
type PluginConfig struct {
|
|
Name string // plugin name
|
|
Config []byte // configuration data, as a JSON string
|
|
}
|
|
|
|
// Current state of a plugin instance. TODO: add some statistics
|
|
type InstanceStatus struct {
|
|
Name string // plugin name
|
|
Id int // instance id
|
|
Config interface{} // configuration data, decoded
|
|
}
|
|
|
|
// StartInstance starts a plugin instance, as requred by configuration data. More than
|
|
// one instance can be started for a single plugin. If the configuration changes,
|
|
// a new instance should be started and the old one closed.
|
|
//
|
|
// RPC exported method
|
|
func (s *PluginServer) StartInstance(config PluginConfig, status *InstanceStatus) error {
|
|
plug, err := s.loadPlugin(config.Name)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
instanceConfig := plug.constructor()
|
|
|
|
if err := json.Unmarshal(config.Config, instanceConfig); err != nil {
|
|
return fmt.Errorf("Decoding config: %w", err)
|
|
}
|
|
|
|
instance := instanceData{
|
|
plugin: plug,
|
|
config: instanceConfig,
|
|
handlers: getHandlers(instanceConfig),
|
|
}
|
|
|
|
s.lock.Lock()
|
|
instance.id = s.nextInstanceId
|
|
s.nextInstanceId++
|
|
s.instances[instance.id] = &instance
|
|
s.lock.Unlock()
|
|
|
|
*status = InstanceStatus{
|
|
Name: config.Name,
|
|
Id: instance.id,
|
|
Config: instance.config,
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// InstanceStatus returns a given resource's status (the same given when started)
|
|
//
|
|
// RPC exported method
|
|
func (s *PluginServer) InstanceStatus(id int, status *InstanceStatus) error {
|
|
s.lock.RLock()
|
|
instance, ok := s.instances[id]
|
|
s.lock.RUnlock()
|
|
if !ok {
|
|
return fmt.Errorf("No plugin instance %d", id)
|
|
}
|
|
|
|
*status = InstanceStatus{
|
|
Name: instance.plugin.name,
|
|
Id: instance.id,
|
|
Config: instance.config,
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// CloseInstance is used when an instance shouldn't be used anymore.
|
|
// Doesn't kill any running event but the instance is no longer accesible,
|
|
// so it's not possible to start a new event with it and will be garbage
|
|
// collected after the last reference event finishes.
|
|
// Returns the status just before closing.
|
|
//
|
|
// RPC exported method
|
|
func (s *PluginServer) CloseInstance(id int, status *InstanceStatus) error {
|
|
s.lock.RLock()
|
|
instance, ok := s.instances[id]
|
|
s.lock.RUnlock()
|
|
if !ok {
|
|
return fmt.Errorf("No plugin instance %d", id)
|
|
}
|
|
|
|
*status = InstanceStatus{
|
|
Name: instance.plugin.name,
|
|
Id: instance.id,
|
|
Config: instance.config,
|
|
}
|
|
|
|
// kill?
|
|
|
|
s.lock.Lock()
|
|
delete(s.instances, id)
|
|
s.lock.Unlock()
|
|
|
|
return nil
|
|
}
|