Added plugins folder location in config for the server.

Created get and ser plugin files.
Created server function to load plugins.
Moved Makefile inside server folder to build and run server.
This commit is contained in:
Kelvin Clement Mwinuka
2023-07-03 08:39:19 +08:00
parent 3961b3e7f6
commit 58d6664faa
4 changed files with 158 additions and 5 deletions

11
server/Makefile Normal file
View File

@@ -0,0 +1,11 @@
build-plugins:
go build -buildmode=plugin -o bin/plugins/commands/command_get.so plugins/commands/get/get.go
go build -buildmode=plugin -o bin/plugins/commands/command_set.so plugins/commands/set/set.go
build-server:
go build -o bin/server ./*.go
build: build-plugins build-server
run:
./bin/server

View File

@@ -5,14 +5,26 @@ import (
"crypto/tls"
"fmt"
"io"
"io/ioutil"
"log"
"net"
"net/http"
"path"
"plugin"
"strings"
"sync"
"github.com/kelvinmwinuka/memstore/serialization"
"github.com/kelvinmwinuka/memstore/utils"
)
type Plugin interface {
Name() string
Command() string
Description() string
HandleCommand(tokens []string, server interface{}) error
}
type Data struct {
mu sync.Mutex
data map[string]interface{}
@@ -21,6 +33,7 @@ type Data struct {
type Server struct {
config utils.Config
data Data
plugins []Plugin
}
func (server *Server) handleConnection(conn net.Conn) {
@@ -116,11 +129,69 @@ func (server *Server) StartHTTP() {
}
}
func (server *Server) LoadPlugins() {
conf := server.config
// Load plugins
pluginDirs, err := ioutil.ReadDir(conf.Plugins)
if err != nil {
log.Fatal(err)
}
for _, file := range pluginDirs {
if file.IsDir() {
switch file.Name() {
case "commands":
files, err := ioutil.ReadDir(path.Join(conf.Plugins, "commands"))
if err != nil {
log.Fatal(err)
}
for _, file := range files {
if !strings.HasSuffix(file.Name(), ".so") {
// Skip files that are not .so
continue
}
p, err := plugin.Open(path.Join(conf.Plugins, "commands", file.Name()))
if err != nil {
log.Fatal(err)
}
pluginSymbol, err := p.Lookup("Plugin")
if err != nil {
fmt.Printf("unexpected plugin symbol in plugin %s\n", file.Name())
continue
}
plugin, ok := pluginSymbol.(Plugin)
if !ok {
fmt.Printf("invalid plugin signature in plugin %s \n", file.Name())
continue
}
// Check if a plugin that handles the same command already exists
for _, loadedPlugin := range server.plugins {
if loadedPlugin.Command() == plugin.Command() {
fmt.Printf("plugin that handles %s command already exists. Please handle a different command.", plugin.Command())
}
}
server.plugins = append(server.plugins, plugin)
}
}
}
}
}
func (server *Server) Start() {
server.data.data = make(map[string]interface{})
conf := server.config
server.LoadPlugins()
if conf.TLS && (len(conf.Key) <= 0 || len(conf.Cert) <= 0) {
fmt.Println("Must provide key and certificate file paths for TLS mode.")
return
@@ -134,10 +205,9 @@ func (server *Server) Start() {
}
func main() {
conf := utils.GetConfig()
server := Server{
config: conf,
config: utils.GetConfig(),
plugins: []Plugin{},
}
server.Start()

View File

@@ -0,0 +1,36 @@
package main
type Server interface {
GetData(key string) interface{}
SetData(key string, value interface{})
}
type plugin struct {
name string
command string
description string
}
var Plugin plugin
func (p *plugin) Name() string {
return p.name
}
func (p *plugin) Command() string {
return p.command
}
func (p *plugin) Description() string {
return p.description
}
func (p *plugin) HandleCommand(tokens []string, server interface{}) error {
return nil
}
func init() {
Plugin.name = "GetCommand"
Plugin.command = "get"
Plugin.description = "Get the value from the specified key"
}

View File

@@ -0,0 +1,36 @@
package main
type Server interface {
GetData(key string) interface{}
SetData(key string, value interface{})
}
type plugin struct {
name string
command string
description string
}
var Plugin plugin
func (p *plugin) Name() string {
return p.name
}
func (p *plugin) Command() string {
return p.command
}
func (p *plugin) Description() string {
return p.description
}
func (p *plugin) HandleCommand(tokens []string, server interface{}) error {
return nil
}
func init() {
Plugin.name = "SetCommand"
Plugin.command = "set"
Plugin.description = "Set the value of the specified key"
}