aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHimbeerserverDE <himbeerserverde@gmail.com>2021-09-05 19:19:27 +0200
committerHimbeerserverDE <himbeerserverde@gmail.com>2021-09-05 19:19:27 +0200
commit1de8660e9d4c8f14a3b887e6f137d1c44a2664ef (patch)
treee8e6d717300f7eaca9d94a4c1aa42c7755b86cbe
parente2815094d1a00476ad0ab051e812b12c795dd5d2 (diff)
Add plugin API (#48)
-rw-r--r--client_conn.go44
-rw-r--r--config.go4
-rw-r--r--doc/config.md7
-rw-r--r--log.go4
-rw-r--r--main.go6
-rw-r--r--plugin.go45
6 files changed, 107 insertions, 3 deletions
diff --git a/client_conn.go b/client_conn.go
index 29db611..4898518 100644
--- a/client_conn.go
+++ b/client_conn.go
@@ -553,7 +553,49 @@ func handleClt(cc *clientConn) {
cc.log("-->", "no server")
break
}
- cc.server().SendCmd(cmd)
+
+ var handled bool
+ if strings.HasPrefix(cmd.Msg, conf().CmdPrefix) {
+ substrs := strings.Split(cmd.Msg, " ")
+ cmdName := strings.Replace(substrs[0], conf().CmdPrefix, "", 1)
+
+ var args []string
+ if len(substrs) > 1 {
+ args = substrs[1:]
+ }
+
+ cc.log("-->", append([]string{"cmd", cmdName}, args...))
+
+ pluginsMu.RLock()
+ for _, p := range plugins {
+ sym, err := p.Lookup("HandleChatCmd")
+ if err != nil {
+ cc.log("-->", err)
+ continue
+ }
+
+ if handler, ok := sym.(func(string, []string) bool); ok {
+ if handler(cmdName, args) {
+ handled = true
+ break
+ }
+ }
+ }
+ pluginsMu.RUnlock()
+
+ if !handled {
+ cc.SendCmd(&mt.ToCltChatMsg{
+ Type: mt.SysMsg,
+ Text: "Command not found.",
+ Timestamp: time.Now().Unix(),
+ })
+ handled = true
+ }
+ }
+
+ if !handled {
+ cc.server().SendCmd(cmd)
+ }
case *mt.ToSrvDeletedBlks:
if cc.server() == nil {
cc.log("-->", "no server")
diff --git a/config.go b/config.go
index 89249b6..2cd4efe 100644
--- a/config.go
+++ b/config.go
@@ -14,6 +14,7 @@ const maxPlayerNameLen = 20
const playerNameChars = "^[a-zA-Z0-9-_]+$"
const bytesPerMediaBunch = 5000
+const defaultCmdPrefix = ">"
const defaultSendInterval = 0.09
const defaultUserLimit = 10
const defaultAuthBackend = "sqlite3"
@@ -23,6 +24,8 @@ var config Config
var configMu sync.RWMutex
type Config struct {
+ NoPlugins bool
+ CmdPrefix string
RequirePasswd bool
SendInterval float32
UserLimit int
@@ -56,6 +59,7 @@ func loadConfig() error {
oldConf := config
+ config.CmdPrefix = defaultCmdPrefix
config.SendInterval = defaultSendInterval
config.UserLimit = defaultUserLimit
config.AuthBackend = defaultAuthBackend
diff --git a/doc/config.md b/doc/config.md
index 39164ed..47ef4a6 100644
--- a/doc/config.md
+++ b/doc/config.md
@@ -5,6 +5,13 @@ The file name is `config.json`.
## Format
The configuration file contains JSON data. The fields are as follows.
+> `NoPlugins`
+```
+Type: bool
+Default: false
+Description: Plugins are not loaded if this is true.
+```
+
> `RequirePasswd`
```
Type: bool
diff --git a/log.go b/log.go
index 0b44ffb..f4e25be 100644
--- a/log.go
+++ b/log.go
@@ -22,13 +22,13 @@ func (lw *LogWriter) Write(p []byte) (n int, err error) {
func init() {
executable, err := os.Executable()
if err != nil {
- log.Fatal(err)
+ log.Fatal("{←|⇶} ", err)
}
path := filepath.Dir(executable) + "/latest.log"
f, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0666)
if err != nil {
- log.Fatal(err)
+ log.Fatal("{←|⇶} ", err)
}
go func() {
diff --git a/main.go b/main.go
index 5c73ed2..c18b387 100644
--- a/main.go
+++ b/main.go
@@ -17,6 +17,12 @@ func main() {
log.Fatal("{←|⇶} ", err)
}
+ if !conf().NoPlugins {
+ if err := loadPlugins(); err != nil {
+ log.Fatal("{←|⇶} ", err)
+ }
+ }
+
var err error
switch conf().AuthBackend {
case "sqlite3":
diff --git a/plugin.go b/plugin.go
new file mode 100644
index 0000000..d4e3d27
--- /dev/null
+++ b/plugin.go
@@ -0,0 +1,45 @@
+package main
+
+import (
+ "log"
+ "os"
+ "path/filepath"
+ "plugin"
+ "sync"
+)
+
+var plugins []*plugin.Plugin
+var pluginsMu sync.RWMutex
+
+func loadPlugins() error {
+ executable, err := os.Executable()
+ if err != nil {
+ return err
+ }
+
+ path := filepath.Dir(executable) + "/plugins"
+ os.Mkdir(path, 0777)
+
+ dir, err := os.ReadDir(path)
+ if err != nil {
+ return err
+ }
+
+ pluginsMu.Lock()
+ defer pluginsMu.Unlock()
+
+ plugins = []*plugin.Plugin{}
+
+ for _, file := range dir {
+ p, err := plugin.Open(path + "/" + file.Name())
+ if err != nil {
+ log.Print("{←|⇶} ", err)
+ continue
+ }
+
+ plugins = append(plugins, p)
+ }
+
+ log.Print("{←|⇶} load plugins")
+ return nil
+}