mirror of
https://github.com/cadmium-im/zirconium-go.git
synced 2024-11-23 10:52:24 +00:00
Implement dynamic plugins support (by RPC)
This commit is contained in:
parent
7e534680c7
commit
1584f9e58a
@ -1,16 +1,22 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
|
"flag"
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
"log"
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"os"
|
||||||
|
|
||||||
"github.com/ChronosX88/zirconium/internal"
|
core "github.com/ChronosX88/zirconium/core"
|
||||||
"github.com/google/logger"
|
"github.com/google/logger"
|
||||||
"github.com/gorilla/mux"
|
"github.com/gorilla/mux"
|
||||||
"github.com/gorilla/websocket"
|
"github.com/gorilla/websocket"
|
||||||
|
"github.com/pelletier/go-toml"
|
||||||
)
|
)
|
||||||
|
|
||||||
var connectionHandler = internal.NewConnectionHandler()
|
var connectionHandler = core.NewConnectionHandler()
|
||||||
var upgrader = websocket.Upgrader{
|
var upgrader = websocket.Upgrader{
|
||||||
CheckOrigin: func(r *http.Request) bool {
|
CheckOrigin: func(r *http.Request) bool {
|
||||||
return true
|
return true
|
||||||
@ -18,7 +24,44 @@ var upgrader = websocket.Upgrader{
|
|||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
internal.InitializeContext("localhost")
|
|
||||||
|
var cfg core.ServerConfig
|
||||||
|
var configPath string
|
||||||
|
var generateConfig bool
|
||||||
|
flag.StringVar(&configPath, "config", "", "Path to config")
|
||||||
|
flag.BoolVar(&generateConfig, "gen_config", false, "Generate the config")
|
||||||
|
flag.Parse()
|
||||||
|
if generateConfig == true {
|
||||||
|
sampleConfig := &core.ServerConfig{}
|
||||||
|
val, err := toml.Marshal(sampleConfig)
|
||||||
|
if err != nil {
|
||||||
|
logger.Errorf("Failed to generate config: %s", err.Error())
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
fmt.Println(string(val))
|
||||||
|
os.Exit(0)
|
||||||
|
}
|
||||||
|
if configPath == "" {
|
||||||
|
logger.Error("Path to config isn't specified!")
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
cfgData, err := ioutil.ReadFile(configPath)
|
||||||
|
if err != nil {
|
||||||
|
logger.Error("Failed to read config!")
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
err = toml.Unmarshal(cfgData, &cfg)
|
||||||
|
if err != nil {
|
||||||
|
logger.Errorf("Failed to read config! (yaml error: %s)", err.Error())
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
err = validateConfig(&cfg)
|
||||||
|
if err != nil {
|
||||||
|
logger.Errorf("Config validation failed: %s", err.Error())
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
core.InitializeContext(cfg.ServerDomain, cfg.PluginsDirPath, cfg.EnabledPlugins)
|
||||||
router := mux.NewRouter()
|
router := mux.NewRouter()
|
||||||
router.HandleFunc("/", func(response http.ResponseWriter, request *http.Request) {
|
router.HandleFunc("/", func(response http.ResponseWriter, request *http.Request) {
|
||||||
response.Write([]byte("Zirconium server is up and running!"))
|
response.Write([]byte("Zirconium server is up and running!"))
|
||||||
@ -36,3 +79,12 @@ func wsHandler(w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
connectionHandler.HandleNewConnection(ws)
|
connectionHandler.HandleNewConnection(ws)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func validateConfig(config *core.ServerConfig) error {
|
||||||
|
if config.ServerDomain == "" {
|
||||||
|
return errors.New("server domain isn't specified")
|
||||||
|
} else if config.PluginsDirPath == "" {
|
||||||
|
return errors.New("plugin directory path isn't specified")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
package internal
|
package core
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/base64"
|
"encoding/base64"
|
4
core/builtin_plugins.go
Normal file
4
core/builtin_plugins.go
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
package core
|
||||||
|
|
||||||
|
// BuiltinPlugins is a list of builtin plugins
|
||||||
|
var BuiltinPlugins = map[string]Module{}
|
12
core/config.go
Normal file
12
core/config.go
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
package core
|
||||||
|
|
||||||
|
type ServerConfig struct {
|
||||||
|
// A list of enabled plugins (or extensions) in server
|
||||||
|
EnabledPlugins []string `toml:"enabledPlugins" comment:"A list of enabled plugins (or extensions) in server"`
|
||||||
|
|
||||||
|
// Server domain name (e.g. example.com)
|
||||||
|
ServerDomain string `toml:"serverDomain" comment:"Server domain name (e.g. example.com)"`
|
||||||
|
|
||||||
|
// Path to directory with plugin executables
|
||||||
|
PluginsDirPath string `toml:"pluginsDirPath" comment:"Path to directory with plugin executables"`
|
||||||
|
}
|
@ -1,7 +1,7 @@
|
|||||||
package internal
|
package core
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/ChronosX88/zirconium/internal/models"
|
"github.com/ChronosX88/zirconium/core/models"
|
||||||
"github.com/google/logger"
|
"github.com/google/logger"
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
"github.com/gorilla/websocket"
|
"github.com/gorilla/websocket"
|
41
core/globals.go
Normal file
41
core/globals.go
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
package core
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/google/logger"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
moduleMgr *ModuleManager
|
||||||
|
router *Router
|
||||||
|
authManager *AuthManager
|
||||||
|
serverDomain string
|
||||||
|
pluginManager *PluginManager
|
||||||
|
)
|
||||||
|
|
||||||
|
func InitializeContext(sDomain string, pluginsDirPath string, enabledPlugins []string) {
|
||||||
|
var err error
|
||||||
|
moduleMgr, err = NewModuleManager()
|
||||||
|
if err != nil {
|
||||||
|
logger.Fatalf("Unable to initialize module manager: %s", err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
router, err = NewRouter()
|
||||||
|
if err != nil {
|
||||||
|
logger.Fatalf("Unable to initialize router: %s", err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
authManager, err = NewAuthManager()
|
||||||
|
if err != nil {
|
||||||
|
logger.Fatalf("Unable to initialize authentication manager: %s", err.Error())
|
||||||
|
}
|
||||||
|
serverDomain = sDomain
|
||||||
|
|
||||||
|
for _, v := range BuiltinPlugins {
|
||||||
|
go v.Initialize(moduleMgr) // Initialize builtin plugins
|
||||||
|
}
|
||||||
|
|
||||||
|
pluginManager = NewPluginManager()
|
||||||
|
for _, v := range enabledPlugins {
|
||||||
|
pluginManager.StartPlugin(pluginsDirPath, v, moduleMgr)
|
||||||
|
}
|
||||||
|
}
|
17
core/module.go
Normal file
17
core/module.go
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
package core
|
||||||
|
|
||||||
|
const (
|
||||||
|
ModuleInterfaceName = "Module"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Module interface {
|
||||||
|
Initialize(moduleAPI *ModuleManager)
|
||||||
|
Name() string
|
||||||
|
Version() string
|
||||||
|
}
|
||||||
|
|
||||||
|
type ModuleRef struct {
|
||||||
|
F func() Module
|
||||||
|
}
|
||||||
|
|
||||||
|
type ModuleFunc func() Module
|
@ -1,11 +1,11 @@
|
|||||||
package internal
|
package core
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"reflect"
|
"reflect"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/ChronosX88/zirconium/internal/models"
|
"github.com/ChronosX88/zirconium/core/models"
|
||||||
)
|
)
|
||||||
|
|
||||||
type C2SMessageHandler struct {
|
type C2SMessageHandler struct {
|
||||||
@ -14,15 +14,15 @@ type C2SMessageHandler struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type ModuleManager struct {
|
type ModuleManager struct {
|
||||||
moduleMutex sync.Mutex
|
moduleMutex sync.Mutex
|
||||||
c2sMessageHandlers map[string][]*C2SMessageHandler
|
c2sMessageHandlers map[string][]*C2SMessageHandler
|
||||||
internalEventHandlers map[string][]func(sourceModuleName string, event map[string]interface{})
|
coreEventHandlers map[string][]func(sourceModuleName string, event map[string]interface{})
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewModuleManager() (*ModuleManager, error) {
|
func NewModuleManager() (*ModuleManager, error) {
|
||||||
var mm = &ModuleManager{
|
var mm = &ModuleManager{
|
||||||
c2sMessageHandlers: make(map[string][]*C2SMessageHandler),
|
c2sMessageHandlers: make(map[string][]*C2SMessageHandler),
|
||||||
internalEventHandlers: make(map[string][]func(sourceModuleName string, event map[string]interface{})),
|
coreEventHandlers: make(map[string][]func(sourceModuleName string, event map[string]interface{})),
|
||||||
}
|
}
|
||||||
return mm, nil
|
return mm, nil
|
||||||
}
|
}
|
||||||
@ -36,9 +36,9 @@ func (mm *ModuleManager) Hook(messageType string, anonymousAllowed bool, handler
|
|||||||
mm.moduleMutex.Unlock()
|
mm.moduleMutex.Unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (mm *ModuleManager) HookInternalEvent(eventName string, handlerFunc func(sourceModuleName string, event map[string]interface{})) {
|
func (mm *ModuleManager) HookcoreEvent(eventName string, handlerFunc func(sourceModuleName string, event map[string]interface{})) {
|
||||||
mm.moduleMutex.Lock()
|
mm.moduleMutex.Lock()
|
||||||
mm.internalEventHandlers[eventName] = append(mm.internalEventHandlers[eventName], handlerFunc)
|
mm.coreEventHandlers[eventName] = append(mm.coreEventHandlers[eventName], handlerFunc)
|
||||||
mm.moduleMutex.Unlock()
|
mm.moduleMutex.Unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -59,17 +59,17 @@ func (mm *ModuleManager) Unhook(messageType string, handlerFunc func(origin *Ori
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (mm *ModuleManager) UnhookInternalEvent(eventName string, handlerFunc func(sourceModuleName string, event map[string]interface{})) {
|
func (mm *ModuleManager) UnhookcoreEvent(eventName string, handlerFunc func(sourceModuleName string, event map[string]interface{})) {
|
||||||
mm.moduleMutex.Lock()
|
mm.moduleMutex.Lock()
|
||||||
defer mm.moduleMutex.Unlock()
|
defer mm.moduleMutex.Unlock()
|
||||||
var handlers = mm.internalEventHandlers[eventName]
|
var handlers = mm.coreEventHandlers[eventName]
|
||||||
if handlers != nil {
|
if handlers != nil {
|
||||||
for i, v := range handlers {
|
for i, v := range handlers {
|
||||||
if reflect.ValueOf(v).Pointer() == reflect.ValueOf(handlerFunc).Pointer() {
|
if reflect.ValueOf(v).Pointer() == reflect.ValueOf(handlerFunc).Pointer() {
|
||||||
handlers[i] = handlers[len(handlers)-1]
|
handlers[i] = handlers[len(handlers)-1]
|
||||||
handlers[len(handlers)-1] = nil
|
handlers[len(handlers)-1] = nil
|
||||||
handlers = handlers[:len(handlers)-1]
|
handlers = handlers[:len(handlers)-1]
|
||||||
mm.internalEventHandlers[eventName] = handlers
|
mm.coreEventHandlers[eventName] = handlers
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -77,7 +77,7 @@ func (mm *ModuleManager) UnhookInternalEvent(eventName string, handlerFunc func(
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (mm *ModuleManager) FireEvent(sourceModuleName string, eventName string, eventPayload map[string]interface{}) {
|
func (mm *ModuleManager) FireEvent(sourceModuleName string, eventName string, eventPayload map[string]interface{}) {
|
||||||
router.RouteInternalEvent(sourceModuleName, eventName, eventPayload)
|
router.RoutecoreEvent(sourceModuleName, eventName, eventPayload)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (mm *ModuleManager) GenerateToken(entityID, deviceID string, tokenExpireTimeDuration time.Duration) (string, error) {
|
func (mm *ModuleManager) GenerateToken(entityID, deviceID string, tokenExpireTimeDuration time.Duration) (string, error) {
|
38
core/module_rpc_receiver.go
Normal file
38
core/module_rpc_receiver.go
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
package core
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
|
||||||
|
"github.com/hashicorp/go-plugin"
|
||||||
|
)
|
||||||
|
|
||||||
|
type greeterServer struct {
|
||||||
|
Broker *plugin.MuxBroker
|
||||||
|
Module Module
|
||||||
|
}
|
||||||
|
|
||||||
|
// Server implmentation of go-plugin.plugin.Plugin.Server
|
||||||
|
func (p *ModuleRef) Server(b *plugin.MuxBroker) (interface{}, error) {
|
||||||
|
if p.F == nil {
|
||||||
|
return nil, errors.New("Greeter interface not implemeted")
|
||||||
|
}
|
||||||
|
return &greeterServer{Broker: b, Module: p.F()}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Name calls the plugin implementation to get the name of the plugin
|
||||||
|
func (p *greeterServer) Name(nothing interface{}, result *string) error {
|
||||||
|
*result = p.Module.Name()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Version calls the plugin implementation to get the version of the plugin
|
||||||
|
func (p *greeterServer) Version(nothing interface{}, result *string) error {
|
||||||
|
*result = p.Module.Version()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// StartTime calls the plugin implementation to initialize plugin
|
||||||
|
func (p *greeterServer) Initialize(moduleAPI *ModuleManager, emptyResult interface{}) error {
|
||||||
|
p.Module.Initialize(moduleAPI)
|
||||||
|
return nil
|
||||||
|
}
|
48
core/module_rpc_sender.go
Normal file
48
core/module_rpc_sender.go
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
package core
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log"
|
||||||
|
"net/rpc"
|
||||||
|
|
||||||
|
"github.com/hashicorp/go-plugin"
|
||||||
|
)
|
||||||
|
|
||||||
|
type moduleClient struct {
|
||||||
|
Broker *plugin.MuxBroker
|
||||||
|
Client *rpc.Client
|
||||||
|
}
|
||||||
|
|
||||||
|
// Client implmentation of go-plugin.plugin.Plugin.Client
|
||||||
|
func (p *ModuleRef) Client(b *plugin.MuxBroker, c *rpc.Client) (interface{}, error) {
|
||||||
|
return &moduleClient{Broker: b, Client: c}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Name initiates an RPC call to the plugin name
|
||||||
|
func (p *moduleClient) Name() string {
|
||||||
|
var resp string
|
||||||
|
err := p.Client.Call("Plugin.Name", new(interface{}), &resp)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err) // FIXME
|
||||||
|
}
|
||||||
|
return resp
|
||||||
|
}
|
||||||
|
|
||||||
|
// Version initiates an RPC call to the plugin version
|
||||||
|
func (p *moduleClient) Version() string {
|
||||||
|
var resp string
|
||||||
|
err := p.Client.Call("Plugin.Version", new(interface{}), &resp)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err) // FIXME
|
||||||
|
}
|
||||||
|
return resp
|
||||||
|
}
|
||||||
|
|
||||||
|
// StartTime initiates an RPC call to the plugin for initializing
|
||||||
|
func (p *moduleClient) Initialize(moduleAPI *ModuleManager) {
|
||||||
|
err := p.Client.Call("Plugin.Initialize", map[string]interface{}{
|
||||||
|
"moduleAPI": moduleAPI,
|
||||||
|
}, nil)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err) // FIXME
|
||||||
|
}
|
||||||
|
}
|
@ -1,7 +1,7 @@
|
|||||||
package internal
|
package core
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/ChronosX88/zirconium/internal/models"
|
"github.com/ChronosX88/zirconium/core/models"
|
||||||
"github.com/gorilla/websocket"
|
"github.com/gorilla/websocket"
|
||||||
)
|
)
|
||||||
|
|
56
core/plugin_manager.go
Normal file
56
core/plugin_manager.go
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
package core
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
"path/filepath"
|
||||||
|
|
||||||
|
"github.com/google/logger"
|
||||||
|
"github.com/hashicorp/go-plugin"
|
||||||
|
)
|
||||||
|
|
||||||
|
type PluginManager struct{}
|
||||||
|
|
||||||
|
func NewPluginManager() *PluginManager {
|
||||||
|
return &PluginManager{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *PluginManager) StartPlugin(pluginsDirPath, pluginFile string, moduleManager *ModuleManager) error {
|
||||||
|
pluginsDirectory, _ := filepath.Abs(filepath.Dir(pluginsDirPath))
|
||||||
|
pluginFile = filepath.Join(pluginsDirectory, pluginFile)
|
||||||
|
|
||||||
|
logger.Info("Starting plugin: %s", pluginFile)
|
||||||
|
|
||||||
|
client := plugin.NewClient(&plugin.ClientConfig{
|
||||||
|
Cmd: exec.Command(pluginFile),
|
||||||
|
Managed: true,
|
||||||
|
SyncStdout: os.Stdout,
|
||||||
|
SyncStderr: os.Stderr,
|
||||||
|
|
||||||
|
HandshakeConfig: HandshakeConfig,
|
||||||
|
Plugins: GetPluginMap(nil),
|
||||||
|
})
|
||||||
|
|
||||||
|
rpcclient, err := client.Client()
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
logger.Errorf("Failed to get RPC Client: %s", err)
|
||||||
|
client.Kill()
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// get the interface
|
||||||
|
raw, err := rpcclient.Dispense(ModuleInterfaceName)
|
||||||
|
if err != nil {
|
||||||
|
logger.Errorf("Failed to get interface: %s error: %s", ModuleInterfaceName, err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
moduleObj := raw.(Module)
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
moduleObj.Initialize(moduleManager)
|
||||||
|
}()
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
@ -1,7 +1,7 @@
|
|||||||
package internal
|
package core
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/ChronosX88/zirconium/internal/models"
|
"github.com/ChronosX88/zirconium/core/models"
|
||||||
"github.com/google/logger"
|
"github.com/google/logger"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -64,8 +64,8 @@ func (r *Router) RouteMessage(origin *OriginC2S, message models.BaseMessage) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Router) RouteInternalEvent(sourceModuleName string, eventName string, eventPayload map[string]interface{}) {
|
func (r *Router) RoutecoreEvent(sourceModuleName string, eventName string, eventPayload map[string]interface{}) {
|
||||||
handlers := r.moduleManager.internalEventHandlers[eventName]
|
handlers := r.moduleManager.coreEventHandlers[eventName]
|
||||||
if handlers != nil {
|
if handlers != nil {
|
||||||
for _, v := range handlers {
|
for _, v := range handlers {
|
||||||
go v(sourceModuleName, eventPayload)
|
go v(sourceModuleName, eventPayload)
|
99
core/utils.go
Normal file
99
core/utils.go
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
package core
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/rand"
|
||||||
|
"log"
|
||||||
|
"reflect"
|
||||||
|
|
||||||
|
"github.com/ChronosX88/zirconium/core/models"
|
||||||
|
"github.com/google/logger"
|
||||||
|
"github.com/hashicorp/go-plugin"
|
||||||
|
)
|
||||||
|
|
||||||
|
func GenRandomBytes(size int) (blk []byte, err error) {
|
||||||
|
blk = make([]byte, size)
|
||||||
|
_, err = rand.Read(blk)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func StructToMap(item interface{}) map[string]interface{} {
|
||||||
|
res := map[string]interface{}{}
|
||||||
|
if item == nil {
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
v := reflect.TypeOf(item)
|
||||||
|
reflectValue := reflect.ValueOf(item)
|
||||||
|
reflectValue = reflect.Indirect(reflectValue)
|
||||||
|
|
||||||
|
if v.Kind() == reflect.Ptr {
|
||||||
|
v = v.Elem()
|
||||||
|
}
|
||||||
|
for i := 0; i < v.NumField(); i++ {
|
||||||
|
tag := v.Field(i).Tag.Get("json")
|
||||||
|
field := reflectValue.Field(i).Interface()
|
||||||
|
if tag != "" && tag != "-" {
|
||||||
|
if v.Field(i).Type.Kind() == reflect.Struct {
|
||||||
|
res[tag] = StructToMap(field)
|
||||||
|
} else {
|
||||||
|
res[tag] = field
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
func PrepareMessageUnauthorized(msg models.BaseMessage) models.BaseMessage {
|
||||||
|
protocolError := models.ProtocolError{
|
||||||
|
ErrCode: "unauthorized",
|
||||||
|
ErrText: "Unauthorized access",
|
||||||
|
ErrPayload: make(map[string]interface{}),
|
||||||
|
}
|
||||||
|
errMsg := models.NewBaseMessage(msg.ID, msg.MessageType, serverDomain, msg.From, false, StructToMap(protocolError))
|
||||||
|
return errMsg
|
||||||
|
}
|
||||||
|
|
||||||
|
var HandshakeConfig = plugin.HandshakeConfig{
|
||||||
|
ProtocolVersion: 1,
|
||||||
|
MagicCookieKey: "TEST_TEST",
|
||||||
|
MagicCookieValue: "qwerty",
|
||||||
|
}
|
||||||
|
|
||||||
|
type PluginOpts struct {
|
||||||
|
Module ModuleFunc
|
||||||
|
RunAsPlugin bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetPluginMap returns the plugin map defined Hashicorp go-plugin.
|
||||||
|
// The reserved parameter should only be used by the RPC receiver (the plugin).
|
||||||
|
// Otherwise, reserved should be nil for the RPC sender (the mainapp).
|
||||||
|
func GetPluginMap(reserved *PluginOpts) map[string]plugin.Plugin {
|
||||||
|
var moduleObj ModuleRef
|
||||||
|
|
||||||
|
if reserved != nil {
|
||||||
|
moduleObj.F = reserved.Module
|
||||||
|
}
|
||||||
|
|
||||||
|
return map[string]plugin.Plugin{
|
||||||
|
ModuleInterfaceName: &moduleObj,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func StartPlugin(opts *PluginOpts, quit chan bool) {
|
||||||
|
if opts.RunAsPlugin {
|
||||||
|
go func() {
|
||||||
|
logger.Info("Starting plugin communication...")
|
||||||
|
|
||||||
|
plugin.Serve(&plugin.ServeConfig{
|
||||||
|
HandshakeConfig: HandshakeConfig,
|
||||||
|
Plugins: GetPluginMap(opts),
|
||||||
|
})
|
||||||
|
|
||||||
|
logger.Info("Exiting plugin communication...")
|
||||||
|
|
||||||
|
quit <- true
|
||||||
|
logger.Info("Exiting plugin...")
|
||||||
|
}()
|
||||||
|
} else {
|
||||||
|
log.Println("Starting in standalone mode...")
|
||||||
|
}
|
||||||
|
}
|
2
go.mod
2
go.mod
@ -8,4 +8,6 @@ require (
|
|||||||
github.com/google/uuid v1.1.1
|
github.com/google/uuid v1.1.1
|
||||||
github.com/gorilla/mux v1.7.3
|
github.com/gorilla/mux v1.7.3
|
||||||
github.com/gorilla/websocket v1.4.1
|
github.com/gorilla/websocket v1.4.1
|
||||||
|
github.com/hashicorp/go-plugin v1.0.1
|
||||||
|
github.com/pelletier/go-toml v1.6.0
|
||||||
)
|
)
|
||||||
|
41
go.sum
41
go.sum
@ -1,5 +1,14 @@
|
|||||||
|
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
|
||||||
|
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||||
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM=
|
github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM=
|
||||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
|
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
|
||||||
|
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58=
|
||||||
|
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||||
|
github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM=
|
||||||
|
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
github.com/google/logger v1.0.1 h1:Jtq7/44yDwUXMaLTYgXFC31zpm6Oku7OI/k4//yVANQ=
|
github.com/google/logger v1.0.1 h1:Jtq7/44yDwUXMaLTYgXFC31zpm6Oku7OI/k4//yVANQ=
|
||||||
github.com/google/logger v1.0.1/go.mod h1:w7O8nrRr0xufejBlQMI83MXqRusvREoJdaAxV+CoAB4=
|
github.com/google/logger v1.0.1/go.mod h1:w7O8nrRr0xufejBlQMI83MXqRusvREoJdaAxV+CoAB4=
|
||||||
github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY=
|
github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY=
|
||||||
@ -8,5 +17,37 @@ github.com/gorilla/mux v1.7.3 h1:gnP5JzjVOuiZD07fKKToCAOjS0yOpj/qPETTXCCS6hw=
|
|||||||
github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
|
github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
|
||||||
github.com/gorilla/websocket v1.4.1 h1:q7AeDBpnBk8AogcD4DSag/Ukw/KV+YhzLj2bP5HvKCM=
|
github.com/gorilla/websocket v1.4.1 h1:q7AeDBpnBk8AogcD4DSag/Ukw/KV+YhzLj2bP5HvKCM=
|
||||||
github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||||
|
github.com/hashicorp/go-hclog v0.0.0-20180709165350-ff2cf002a8dd h1:rNuUHR+CvK1IS89MMtcF0EpcVMZtjKfPRp4MEmt/aTs=
|
||||||
|
github.com/hashicorp/go-hclog v0.0.0-20180709165350-ff2cf002a8dd/go.mod h1:9bjs9uLqI8l75knNv3lV1kA55veR+WUPSiKIWcQHudI=
|
||||||
|
github.com/hashicorp/go-plugin v1.0.1 h1:4OtAfUGbnKC6yS48p0CtMX2oFYtzFZVv6rok3cRWgnE=
|
||||||
|
github.com/hashicorp/go-plugin v1.0.1/go.mod h1:++UyYGoz3o5w9ZzAdZxtQKrWWP+iqPBn3cQptSMzBuY=
|
||||||
|
github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb h1:b5rjCoWHc7eqmAS4/qyk21ZsHyb6Mxv/jykxvNTkU4M=
|
||||||
|
github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM=
|
||||||
|
github.com/mitchellh/go-testing-interface v0.0.0-20171004221916-a61a99592b77 h1:7GoSOOW2jpsfkntVKaS2rAr1TJqfcxotyaUcuxoZSzg=
|
||||||
|
github.com/mitchellh/go-testing-interface v0.0.0-20171004221916-a61a99592b77/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
|
||||||
|
github.com/oklog/run v1.0.0 h1:Ru7dDtJNOyC66gQ5dQmaCa0qIsAUFY3sFpK1Xk8igrw=
|
||||||
|
github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA=
|
||||||
|
github.com/pelletier/go-toml v1.6.0 h1:aetoXYr0Tv7xRU/V4B4IZJ2QcbtMUFoNb3ORp7TzIK4=
|
||||||
|
github.com/pelletier/go-toml v1.6.0/go.mod h1:5N711Q9dKgbdkxHL+MEfF31hpT7l0S0s/t2kKREewys=
|
||||||
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
|
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
|
||||||
|
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||||
|
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d h1:g9qWBGx4puODJTMVyoPrpoxPFgVGd+z1DZwjfRu4d0I=
|
||||||
|
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
|
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4 h1:YUO/7uOKsKeq9UokNS62b8FYywz3ker1l1vDZRCRefw=
|
||||||
|
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sys v0.0.0-20190129075346-302c3dd5f1cc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a h1:1BGLXjeY4akVXGgbC9HugT3Jv3hCI0z56oJR5vAMgBU=
|
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a h1:1BGLXjeY4akVXGgbC9HugT3Jv3hCI0z56oJR5vAMgBU=
|
||||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
|
||||||
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
|
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8 h1:Nw54tB0rB7hY/N0NQvRW8DG4Yk3Q6T9cu9RcFQDu1tc=
|
||||||
|
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||||
|
google.golang.org/grpc v1.14.0 h1:ArxJuB1NWfPY6r9Gp9gqwplT0Ge7nqv9msgu03lHLmo=
|
||||||
|
google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
|
||||||
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||||
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
gopkg.in/yaml.v2 v2.2.4 h1:/eiJrUcujPVeJ3xlSWaiNi3uSVmDGBK1pDHUHAnao1I=
|
||||||
|
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
|
@ -1,36 +0,0 @@
|
|||||||
package internal
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/ChronosX88/zirconium/shared"
|
|
||||||
"github.com/google/logger"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
ModuleMgr *ModuleManager
|
|
||||||
router *Router
|
|
||||||
authManager *AuthManager
|
|
||||||
serverDomain string
|
|
||||||
)
|
|
||||||
|
|
||||||
func InitializeContext(sDomain string) {
|
|
||||||
var err error
|
|
||||||
ModuleMgr, err = NewModuleManager()
|
|
||||||
if err != nil {
|
|
||||||
logger.Fatalf("Unable to initialize module manager: %s", err.Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
router, err = NewRouter()
|
|
||||||
if err != nil {
|
|
||||||
logger.Fatalf("Unable to initialize router: %s", err.Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
authManager, err = NewAuthManager()
|
|
||||||
if err != nil {
|
|
||||||
logger.Fatalf("Unable to initialize authentication manager: %s", err.Error())
|
|
||||||
}
|
|
||||||
serverDomain = sDomain
|
|
||||||
|
|
||||||
for _, v := range shared.Plugins {
|
|
||||||
go v.Initialize() // Initialize provided plugins
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,50 +0,0 @@
|
|||||||
package internal
|
|
||||||
|
|
||||||
import (
|
|
||||||
"crypto/rand"
|
|
||||||
"reflect"
|
|
||||||
|
|
||||||
"github.com/ChronosX88/zirconium/internal/models"
|
|
||||||
)
|
|
||||||
|
|
||||||
func GenRandomBytes(size int) (blk []byte, err error) {
|
|
||||||
blk = make([]byte, size)
|
|
||||||
_, err = rand.Read(blk)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func StructToMap(item interface{}) map[string]interface{} {
|
|
||||||
res := map[string]interface{}{}
|
|
||||||
if item == nil {
|
|
||||||
return res
|
|
||||||
}
|
|
||||||
v := reflect.TypeOf(item)
|
|
||||||
reflectValue := reflect.ValueOf(item)
|
|
||||||
reflectValue = reflect.Indirect(reflectValue)
|
|
||||||
|
|
||||||
if v.Kind() == reflect.Ptr {
|
|
||||||
v = v.Elem()
|
|
||||||
}
|
|
||||||
for i := 0; i < v.NumField(); i++ {
|
|
||||||
tag := v.Field(i).Tag.Get("json")
|
|
||||||
field := reflectValue.Field(i).Interface()
|
|
||||||
if tag != "" && tag != "-" {
|
|
||||||
if v.Field(i).Type.Kind() == reflect.Struct {
|
|
||||||
res[tag] = StructToMap(field)
|
|
||||||
} else {
|
|
||||||
res[tag] = field
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return res
|
|
||||||
}
|
|
||||||
|
|
||||||
func PrepareMessageUnauthorized(msg models.BaseMessage) models.BaseMessage {
|
|
||||||
protocolError := models.ProtocolError{
|
|
||||||
ErrCode: "unauthorized",
|
|
||||||
ErrText: "Unauthorized access",
|
|
||||||
ErrPayload: make(map[string]interface{}),
|
|
||||||
}
|
|
||||||
errMsg := models.NewBaseMessage(msg.ID, msg.MessageType, serverDomain, msg.From, false, StructToMap(protocolError))
|
|
||||||
return errMsg
|
|
||||||
}
|
|
@ -1,5 +0,0 @@
|
|||||||
package shared
|
|
||||||
|
|
||||||
type Module interface {
|
|
||||||
Initialize()
|
|
||||||
}
|
|
@ -1,5 +0,0 @@
|
|||||||
package shared
|
|
||||||
|
|
||||||
var Plugins = map[string]Module{
|
|
||||||
// Add plugins here
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user