mirror of
https://github.com/tobychui/zoraxy.git
synced 2025-11-14 21:04:10 +01:00
Fixed #573
- Added whitelist loopback quick toggle - Fixed plugin exit stuck bug
This commit is contained in:
@@ -151,6 +151,7 @@ func (m *Manager) handlePluginSTDOUT(pluginID string, line string) {
|
||||
m.Log("["+thisPlugin.Spec.Name+":"+strconv.Itoa(processID)+"] "+line, nil)
|
||||
}
|
||||
|
||||
// StopPlugin stops a plugin, it is garanteed that the plugin is stopped after this function
|
||||
func (m *Manager) StopPlugin(pluginID string) error {
|
||||
plugin, ok := m.LoadedPlugins.Load(pluginID)
|
||||
if !ok {
|
||||
@@ -224,15 +225,3 @@ func (m *Manager) PluginStillRunning(pluginID string) bool {
|
||||
}
|
||||
return plugin.(*Plugin).process.ProcessState == nil
|
||||
}
|
||||
|
||||
// BlockUntilAllProcessExited blocks until all the plugins processes have exited
|
||||
func (m *Manager) BlockUntilAllProcessExited() {
|
||||
m.LoadedPlugins.Range(func(key, value interface{}) bool {
|
||||
plugin := value.(*Plugin)
|
||||
if m.PluginStillRunning(value.(*Plugin).Spec.ID) {
|
||||
//Wait for the plugin to exit
|
||||
plugin.process.Wait()
|
||||
}
|
||||
return true
|
||||
})
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ package plugins
|
||||
*/
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
@@ -34,14 +35,24 @@ func NewPluginManager(options *ManagerOptions) *Manager {
|
||||
os.MkdirAll(options.PluginDir, 0755)
|
||||
}
|
||||
|
||||
//Create the plugin config file if not exists
|
||||
if !utils.FileExists(options.PluginGroupsConfig) {
|
||||
js, _ := json.Marshal(map[string][]string{})
|
||||
err := os.WriteFile(options.PluginGroupsConfig, js, 0644)
|
||||
if err != nil {
|
||||
options.Logger.PrintAndLog("plugin-manager", "Failed to create plugin group config file", err)
|
||||
}
|
||||
}
|
||||
|
||||
//Create database table
|
||||
options.Database.NewTable("plugins")
|
||||
|
||||
return &Manager{
|
||||
LoadedPlugins: sync.Map{},
|
||||
tagPluginMap: sync.Map{},
|
||||
tagPluginList: make(map[string][]*Plugin),
|
||||
Options: options,
|
||||
LoadedPlugins: sync.Map{},
|
||||
tagPluginMap: sync.Map{},
|
||||
tagPluginListMutex: sync.RWMutex{},
|
||||
tagPluginList: make(map[string][]*Plugin),
|
||||
Options: options,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -76,6 +87,14 @@ func (m *Manager) LoadPluginsFromDisk() error {
|
||||
}
|
||||
}
|
||||
|
||||
if m.Options.PluginGroupsConfig != "" {
|
||||
//Load the plugin groups from the config file
|
||||
err = m.LoadPluginGroupsFromConfig()
|
||||
if err != nil {
|
||||
m.Log("Failed to load plugin groups", err)
|
||||
}
|
||||
}
|
||||
|
||||
//Generate the static forwarder radix tree
|
||||
m.UpdateTagsToPluginMaps()
|
||||
|
||||
@@ -156,9 +175,6 @@ func (m *Manager) Close() {
|
||||
}
|
||||
return true
|
||||
})
|
||||
|
||||
//Wait until all loaded plugin process are terminated
|
||||
m.BlockUntilAllProcessExited()
|
||||
}
|
||||
|
||||
/* Plugin Functions */
|
||||
|
||||
@@ -24,6 +24,7 @@ func (m *Manager) UpdateTagsToPluginMaps() {
|
||||
}
|
||||
|
||||
//build the plugin list for each tag
|
||||
m.tagPluginListMutex.Lock()
|
||||
m.tagPluginList = make(map[string][]*Plugin)
|
||||
for tag, pluginIds := range m.Options.PluginGroups {
|
||||
for _, pluginId := range pluginIds {
|
||||
@@ -35,6 +36,7 @@ func (m *Manager) UpdateTagsToPluginMaps() {
|
||||
m.tagPluginList[tag] = append(m.tagPluginList[tag], plugin)
|
||||
}
|
||||
}
|
||||
m.tagPluginListMutex.Unlock()
|
||||
}
|
||||
|
||||
// GenerateForwarderRadixTree generates the radix tree for static forwarders
|
||||
|
||||
99
src/mod/plugins/tags.go
Normal file
99
src/mod/plugins/tags.go
Normal file
@@ -0,0 +1,99 @@
|
||||
package plugins
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"os"
|
||||
)
|
||||
|
||||
/*
|
||||
Plugin Tags
|
||||
|
||||
This file contains the tags that are used to match the plugin tag
|
||||
to the one on HTTP proxy rule. Once the tag is matched, the plugin
|
||||
will be enabled on that given rule.
|
||||
*/
|
||||
|
||||
// LoadTagPluginMap loads the plugin map into the manager
|
||||
// This will only load the plugin tags to option.PluginGroups map
|
||||
// to push the changes to runtime, call UpdateTagsToPluginMaps()
|
||||
func (m *Manager) LoadPluginGroupsFromConfig() error {
|
||||
m.Options.pluginGroupsMutex.RLock()
|
||||
defer m.Options.pluginGroupsMutex.RUnlock()
|
||||
|
||||
//Read the config file
|
||||
rawConfig, err := os.ReadFile(m.Options.PluginGroupsConfig)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var config map[string][]string
|
||||
err = json.Unmarshal(rawConfig, &config)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
//Reset m.tagPluginList
|
||||
m.Options.PluginGroups = config
|
||||
return nil
|
||||
}
|
||||
|
||||
// AddPluginToTag adds a plugin to a tag
|
||||
func (m *Manager) AddPluginToTag(tag string, pluginID string) error {
|
||||
m.Options.pluginGroupsMutex.RLock()
|
||||
defer m.Options.pluginGroupsMutex.RUnlock()
|
||||
|
||||
//Check if the plugin exists
|
||||
_, err := m.GetPluginByID(pluginID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
//Add to m.Options.PluginGroups
|
||||
pluginList, ok := m.Options.PluginGroups[tag]
|
||||
if !ok {
|
||||
pluginList = []string{}
|
||||
}
|
||||
pluginList = append(pluginList, pluginID)
|
||||
m.Options.PluginGroups[tag] = pluginList
|
||||
|
||||
//Update to runtime
|
||||
m.UpdateTagsToPluginMaps()
|
||||
|
||||
//Save to file
|
||||
return m.savePluginTagMap()
|
||||
}
|
||||
|
||||
// RemovePluginFromTag removes a plugin from a tag
|
||||
func (m *Manager) RemovePluginFromTag(tag string, pluginID string) error {
|
||||
// Check if the plugin exists in Options.PluginGroups
|
||||
m.Options.pluginGroupsMutex.RLock()
|
||||
defer m.Options.pluginGroupsMutex.RUnlock()
|
||||
pluginList, ok := m.Options.PluginGroups[tag]
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Remove the plugin from the list
|
||||
for i, id := range pluginList {
|
||||
if id == pluginID {
|
||||
pluginList = append(pluginList[:i], pluginList[i+1:]...)
|
||||
break
|
||||
}
|
||||
}
|
||||
m.Options.PluginGroups[tag] = pluginList
|
||||
|
||||
// Update to runtime
|
||||
m.UpdateTagsToPluginMaps()
|
||||
|
||||
// Save to file
|
||||
return m.savePluginTagMap()
|
||||
}
|
||||
|
||||
// savePluginTagMap saves the plugin tag map to the config file
|
||||
func (m *Manager) savePluginTagMap() error {
|
||||
m.Options.pluginGroupsMutex.RLock()
|
||||
defer m.Options.pluginGroupsMutex.RUnlock()
|
||||
|
||||
js, _ := json.Marshal(m.Options.PluginGroups)
|
||||
return os.WriteFile(m.Options.PluginGroupsConfig, js, 0644)
|
||||
}
|
||||
@@ -45,6 +45,7 @@ func (m *Manager) HandleRoute(w http.ResponseWriter, r *http.Request, tags []str
|
||||
wg.Add(1)
|
||||
go func(thisTag string) {
|
||||
defer wg.Done()
|
||||
m.tagPluginListMutex.RLock()
|
||||
for _, plugin := range m.tagPluginList[thisTag] {
|
||||
if plugin.Enabled && plugin.Spec.DynamicCaptureSniff != "" && plugin.Spec.DynamicCaptureIngress != "" {
|
||||
mutex.Lock()
|
||||
@@ -52,6 +53,7 @@ func (m *Manager) HandleRoute(w http.ResponseWriter, r *http.Request, tags []str
|
||||
mutex.Unlock()
|
||||
}
|
||||
}
|
||||
m.tagPluginListMutex.RUnlock()
|
||||
}(tag)
|
||||
}
|
||||
wg.Wait()
|
||||
|
||||
@@ -29,19 +29,24 @@ type Plugin struct {
|
||||
}
|
||||
|
||||
type ManagerOptions struct {
|
||||
PluginDir string //The directory where the plugins are stored
|
||||
PluginGroups map[string][]string //The plugin groups,key is the tag name and the value is an array of plugin IDs
|
||||
PluginDir string //The directory where the plugins are stored
|
||||
PluginGroups map[string][]string //The plugin groups,key is the tag name and the value is an array of plugin IDs
|
||||
PluginGroupsConfig string //The group / tag configuration file, if set the plugin groups will be loaded from this file
|
||||
|
||||
/* Runtime */
|
||||
SystemConst *zoraxyPlugin.RuntimeConstantValue
|
||||
CSRFTokenGen func(*http.Request) string `json:"-"` //The CSRF token generator function
|
||||
Database *database.Database `json:"-"`
|
||||
Logger *logger.Logger `json:"-"`
|
||||
|
||||
/* Internal */
|
||||
pluginGroupsMutex sync.RWMutex //Mutex for the pluginGroups
|
||||
}
|
||||
|
||||
type Manager struct {
|
||||
LoadedPlugins sync.Map //Storing *Plugin
|
||||
tagPluginMap sync.Map //Storing *radix.Tree for each plugin tag
|
||||
tagPluginList map[string][]*Plugin //Storing the plugin list for each tag, only concurrent READ is allowed
|
||||
Options *ManagerOptions
|
||||
LoadedPlugins sync.Map //Storing *Plugin
|
||||
tagPluginMap sync.Map //Storing *radix.Tree for each plugin tag
|
||||
tagPluginListMutex sync.RWMutex //Mutex for the tagPluginList
|
||||
tagPluginList map[string][]*Plugin //Storing the plugin list for each tag, only concurrent READ is allowed
|
||||
Options *ManagerOptions
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user