diff --git a/alfred.go b/alfred.go index 799adcf..ee15b37 100644 --- a/alfred.go +++ b/alfred.go @@ -2,13 +2,14 @@ * @Author: Bartuccio Antoine * @Date: 2018-07-23 15:24:22 * @Last Modified by: klmp200 -* @Last Modified time: 2018-07-24 20:55:53 +* @Last Modified time: 2018-07-25 12:04:44 */ package main import ( "./commands" + "./plugin_manager" "./settings" "./shared" tb "gopkg.in/tucnak/telebot.v2" @@ -53,6 +54,9 @@ func main() { b.Handle(key, value) } + plugin_manager.Init("plugin", b) + b.Handle(tb.OnText, plugin_manager.HandleMessage) + plugin_manager.StartPlugins() log.Println("Starting bot") b.Start() } diff --git a/plugin.go b/plugin.go new file mode 100644 index 0000000..0408dac --- /dev/null +++ b/plugin.go @@ -0,0 +1,68 @@ +package main + +import ( + "./plugin_manager" + tb "gopkg.in/tucnak/telebot.v2" +) + +type plugin string + +func (g plugin) GetCommands() []string { + return []string{"plugin"} +} + +func (g plugin) HandleCommand(bot *tb.Bot, msg *tb.Message, cmd string, args []string) { + if cmd == "plugin" { + ok := false + if len(args) >= 1 { + if args[0] == "list" { + lst := "" + for _, pName := range plugin_manager.GetPluginList() { + lst = lst + "-" + pName + " (status: " + if plugin_manager.IsPluginEnable(pName) { + lst += "enable, " + } else { + lst += "disable, " + } + if plugin_manager.IsPluginRunning(pName) { + lst += "running" + } else { + lst += "stopped" + } + lst += ")\n" + } + bot.Send(msg.Chat, "liste des plugins disponible:\n"+lst) + ok = true + } + if args[0] == "enable" && len(args) >= 2 { + for _, name := range args[1:] { + if plugin_manager.ExistPlugin(name) { + plugin_manager.EnablePlugin(name, true) + bot.Send(msg.Chat, "enable plugin "+name) + } + } + ok = true + } + if args[0] == "disable" && len(args) >= 2 { + for _, name := range args[1:] { + if plugin_manager.ExistPlugin(name) { + plugin_manager.EnablePlugin(name, false) + bot.Send(msg.Chat, "disable plugin "+name) + } + } + ok = true + } + } + if !ok { + bot.Send(msg.Chat, "command inconnue\n"+ + "liste de plugin:\n"+ + "/plugin list\n"+ + "activer un/des plugins\n"+ + "/plugin enable nom_plugin\n"+ + "désactiver un/des plugins\n"+ + "/plugin disable nom_plugin") + } + } +} + +var Plugin plugin diff --git a/plugin_manager/context.go b/plugin_manager/context.go new file mode 100644 index 0000000..fa34617 --- /dev/null +++ b/plugin_manager/context.go @@ -0,0 +1,9 @@ +package plugin_manager + +import ( + tb "gopkg.in/tucnak/telebot.v2" +) + +type Context struct { + bot *tb.Bot +} diff --git a/plugin_manager/manager.go b/plugin_manager/manager.go new file mode 100644 index 0000000..919a7ae --- /dev/null +++ b/plugin_manager/manager.go @@ -0,0 +1,161 @@ +/** + * @Author: KLIPFEL Arthur + * @Date: 2018-08-24 12:17:17 + */ +package plugin_manager + +import ( + tb "gopkg.in/tucnak/telebot.v2" + "log" + "strings" + "sync" +) + +type PluginCtrl struct { + plugin Plugin + mux sync.Mutex + running bool + enable bool +} + +var pluginDir string +var pluginsRunning bool +var plugins map[string]PluginCtrl +var context Context + +func Init(_pluginDir string, bot *tb.Bot) { + pluginDir = _pluginDir + pluginsRunning = false + plugins = make(map[string]PluginCtrl) + context.bot = bot + for _, fileName := range GetSoFiles(pluginDir) { + var p PluginCtrl + p.plugin = LoadSoFile(pluginDir + "/" + fileName) + if p.plugin != nil { + p.running = false + p.enable = true + plugins[fileName[:len(fileName)-3]] = p + } + } +} + +func GetPluginList() []string { + var lst []string + for name, _ := range plugins { + lst = append(lst, name) + } + return lst +} + +func IsPluginRunning(name string) bool { + if p, ok := plugins[name]; ok { + return p.running + } + return false +} + +func ExistPlugin(name string) bool { + if _, ok := plugins[name]; ok { + return true + } + return false +} + +func GetPlugin(name string) Plugin { + if p, ok := plugins[name]; ok { + return p + } + return nil +} + +func IsPluginEnable(name string) bool { + if p, ok := plugins[name]; ok { + return p.enable + } + return false +} + +func EnablePlugin(name string, enable bool) { + if p, ok := plugins[name]; ok { + if enable != p.enable { + p.enable = enable + plugins[name] = p + if pluginsRunning { + if enable { + if !p.running { + startPlugin(name) + } + } else { + if p.running { + stopPlugin(name) + } + } + } + } + } else { + log.Fatal("error: plugin " + name + " not founded") + } +} + +func StopPlugins() { + for k, _ := range plugins { + stopPlugin(k) + } + pluginsRunning = false +} + +func HandleMessage(msg *tb.Message) { + for _, val := range plugins { + if val.enable && val.running { + if strings.HasPrefix(msg.Text, "/") { + split := strings.Split(msg.Text, " ") + split[0] = split[0][1:] + if Contains(split[0], ExecGetCommands(val.plugin)) { + ExecHandleCommand(val.plugin, context.bot, msg, split[0], split[1:]) + } + } else { + ExecHandleMessage(val.plugin, context.bot, msg) + } + } + } +} + +func StartPlugins() { + for k, val := range plugins { + if val.enable { + startPlugin(k) + } + } + pluginsRunning = true +} + +func startPlugin(name string) { + if p, ok := plugins[name]; ok { + //p.mux.Lock() + if !p.running && p.enable { + p.running = ExecLoad(p.plugin) + plugins[name] = p + } + //p.mux.Unlock() + } +} + +func stopPlugin(name string) { + if p, ok := plugins[name]; ok { + //p.mux.Lock() + if p.running { + p.running = false + plugins[name] = p + ExecUnload(p.plugin) + } + //p.mux.Unlock() + } +} + +func Exit() { + for _, p := range plugins { + if p.running { + ExecUnload(p.plugin) + } + } +} diff --git a/plugin_manager/tools.go b/plugin_manager/tools.go new file mode 100644 index 0000000..3e15f72 --- /dev/null +++ b/plugin_manager/tools.go @@ -0,0 +1,127 @@ +/** + * @Author: KLIPFEL Arthur + * @Date: 2018-08-24 12:17:17 + */ +package plugin_manager + +import ( + tb "gopkg.in/tucnak/telebot.v2" + "io/ioutil" + "log" + "plugin" + "strings" +) + +type TestGetCommands interface { + GetCommands() []string +} + +type TestLoad interface { + Load() bool +} + +type TestHandleMessage interface { + HandleMessage(bot *tb.Bot, msg *tb.Message) +} + +type TestHandleCommand interface { + HandleCommand(bot *tb.Bot, msg *tb.Message, cmd string, args []string) +} + +type TestUnload interface { + Unload() bool +} + +type Plugin interface { /* + GetCommandes() []string + Load() bool + HandleMessage(bot *tb.Bot, msg *tb.Message) + HandleCommand(bot *tb.Bot, msg *tb.Message, cmd string, args []string) + Unload() bool*/ +} + +func GetSoFiles(dir string) []string { + var slice []string + + files, err := ioutil.ReadDir(dir) + if err != nil { + log.Fatal(err) + } else { + for _, f := range files { + if strings.HasSuffix(f.Name(), ".so") { + slice = append(slice, f.Name()) + } + } + } + return slice +} + +func LoadSoFile(file string) Plugin { + plug, err := plugin.Open(file) + if err != nil { + log.Fatal(err) + return nil + } + + symPlugin, err := plug.Lookup("Plugin") + if err != nil { + log.Fatal(err) + return nil + } + + var plugin Plugin + //plugin, _ = symPlugin.(Plugin) + plugin, ok := symPlugin.(Plugin) + if !ok { + log.Fatal(file + ": unexpected type from module symbol") + return nil + } + return plugin +} + +func ExecGetCommands(plugin Plugin) []string { + p, ok := plugin.(TestGetCommands) + if ok { + return p.GetCommands() + } + return []string{} +} + +func ExecLoad(plugin Plugin) bool { + p, ok := plugin.(TestLoad) + if ok { + return p.Load() + } + return true +} + +func ExecHandleMessage(plugin Plugin, bot *tb.Bot, msg *tb.Message) { + p, ok := plugin.(TestHandleMessage) + if ok { + p.HandleMessage(bot, msg) + } +} + +func ExecHandleCommand(plugin Plugin, bot *tb.Bot, msg *tb.Message, cmd string, args []string) { + p, ok := plugin.(TestHandleCommand) + if ok { + p.HandleCommand(bot, msg, cmd, args) + } +} + +func ExecUnload(plugin Plugin) bool { + p, ok := plugin.(TestUnload) + if ok { + return p.Unload() + } + return true +} + +func Contains(e string, s []string) bool { + for _, a := range s { + if a == e { + return true + } + } + return false +} diff --git a/settings.json b/settings.json index a43accc..6c494ad 100644 --- a/settings.json +++ b/settings.json @@ -3,4 +3,4 @@ "history size": 10, "history file": "history.json", "users file": "users.json" -} \ No newline at end of file +} diff --git a/test.go b/test.go new file mode 100644 index 0000000..6fc0446 --- /dev/null +++ b/test.go @@ -0,0 +1,40 @@ +package main + +import ( + tb "gopkg.in/tucnak/telebot.v2" + "log" +) + +type plugin string + +func (g plugin) GetCommands() []string { + return []string{"ping", "test"} +} + +func (g plugin) Load() bool { + log.Println("plugin test loaded!") + return true +} + +func (g plugin) HandleMessage(bot *tb.Bot, msg *tb.Message) { + log.Println("plugin test message: " + msg.Text) +} + +func (g plugin) HandleCommand(bot *tb.Bot, msg *tb.Message, cmd string, args []string) { + if cmd == "ping" { + bot.Send(msg.Chat, "pong!") + } + argsS := "" + for _, arg := range args { + argsS = argsS + " " + arg + } + log.Print("plugin test cmd: " + cmd + " (args:" + argsS + ")") + +} + +func (g plugin) Unload() bool { + log.Println("plugin test unloaded!") + return true +} + +var Plugin plugin diff --git a/test2.go b/test2.go new file mode 100644 index 0000000..9883f11 --- /dev/null +++ b/test2.go @@ -0,0 +1,22 @@ +package main + +import ( + tb "gopkg.in/tucnak/telebot.v2" + "log" +) + +type plugin string + +func (g plugin) Load() { + log.Println("plugin test2 loaded!") +} + +func (g plugin) HandleMessage(bot *tb.Bot, msg string) { + log.Println("test2 message: " + msg) +} + +func (g plugin) Unload() { + log.Println("plugin test2 unloaded!") +} + +var Plugin plugin