From eb46c706f4aa13b5f33c8ecc74af80e8f982634c Mon Sep 17 00:00:00 2001 From: liyong <228431028@qq.com> Date: Thu, 25 May 2023 20:21:40 +0800 Subject: [PATCH 1/2] dev: refactor plugin framework --- engine/engine.go | 35 ------------- engine/load_plugin.go | 46 +++++++++++++++++ gen_info.sh | 0 plugin/cs104_server/cs_104_server.go | 6 ++- plugin/demo_plugin/demo_plugin.go | 11 ++-- plugin/http_server/http_api_server.go | 14 ++++-- plugin/http_server/plugin_api.go | 34 +++++++++++++ plugin/http_server/system_api.go | 3 -- plugin/mqtt_server/mqtt_server.go | 17 +++---- plugin/mqtt_server/mqtt_server_services.go | 58 ++++++++++++++++++++++ plugin/net_discover/net_boardcast.go | 9 ++-- plugin/sensor_server/sensor_server.go | 9 ++-- plugin/ttyd_terminal/ttyd_terminal.go | 7 ++- plugin/usb_monitor/usb_mnitor_windows.go | 10 ++-- plugin/usb_monitor/usb_monitor_linux.go | 9 ++-- script/readme.md | 44 ++++++++++++++++ test/conf/rulex.ini | 4 +- typex/typex.md | 2 + typex/version.go | 4 +- typex/xplugin.go | 13 ++--- utils/uuid_util.go | 3 ++ 21 files changed, 258 insertions(+), 80 deletions(-) create mode 100644 engine/load_plugin.go mode change 100755 => 100644 gen_info.sh create mode 100644 plugin/http_server/plugin_api.go create mode 100644 plugin/mqtt_server/mqtt_server_services.go create mode 100644 script/readme.md create mode 100644 typex/typex.md diff --git a/engine/engine.go b/engine/engine.go index 89c37578b..b71b8053c 100644 --- a/engine/engine.go +++ b/engine/engine.go @@ -293,41 +293,6 @@ func (e *RuleEngine) RunDeviceCallbacks(Device *typex.Device, callbackArgs strin } } -// ┌──────┐ ┌──────┐ ┌──────┐ -// │ Init ├───►│ Load ├───►│ Stop │ -// └──────┘ └──────┘ └──────┘ -func (e *RuleEngine) LoadPlugin(sectionK string, p typex.XPlugin) error { - section := utils.GetINISection(core.INIPath, sectionK) - key, err1 := section.GetKey("enable") - if err1 != nil { - return err1 - } - enable, err2 := key.Bool() - if err2 != nil { - return err2 - } - if !enable { - glogger.GLogger.Infof("Plugin is not enable:%s", p.PluginMetaInfo().Name) - return nil - } - - if err := p.Init(section); err != nil { - return err - } - _, ok := e.Plugins.Load(p.PluginMetaInfo().Name) - if ok { - return errors.New("plugin already installed:" + p.PluginMetaInfo().Name) - } - - if err := p.Start(e); err != nil { - return err - } - - e.Plugins.Store(p.PluginMetaInfo().Name, p) - glogger.GLogger.Infof("Plugin start successfully:[%v]", p.PluginMetaInfo().Name) - return nil - -} // LoadHook func (e *RuleEngine) LoadHook(h typex.XHook) error { diff --git a/engine/load_plugin.go b/engine/load_plugin.go new file mode 100644 index 000000000..a927fabb8 --- /dev/null +++ b/engine/load_plugin.go @@ -0,0 +1,46 @@ +package engine + +import ( + "errors" + + "github.com/hootrhino/rulex/core" + "github.com/hootrhino/rulex/glogger" + "github.com/hootrhino/rulex/typex" + "github.com/hootrhino/rulex/utils" +) + +// ┌──────┐ ┌──────┐ ┌──────┐ +// │ Init ├───►│ Load ├───►│ Stop │ +// └──────┘ └──────┘ └──────┘ +func (e *RuleEngine) LoadPlugin(sectionK string, p typex.XPlugin) error { + section := utils.GetINISection(core.INIPath, sectionK) + key, err1 := section.GetKey("enable") + if err1 != nil { + return err1 + } + enable, err2 := key.Bool() + if err2 != nil { + return err2 + } + if !enable { + glogger.GLogger.Infof("Plugin is not enable:%s", p.PluginMetaInfo().Name) + return nil + } + + if err := p.Init(section); err != nil { + return err + } + _, ok := e.Plugins.Load(p.PluginMetaInfo().UUID) + if ok { + return errors.New("plugin already installed:" + p.PluginMetaInfo().Name) + } + + if err := p.Start(e); err != nil { + return err + } + + e.Plugins.Store(p.PluginMetaInfo().UUID, p) + glogger.GLogger.Infof("Plugin start successfully:[%v]", p.PluginMetaInfo().Name) + return nil + +} diff --git a/gen_info.sh b/gen_info.sh old mode 100755 new mode 100644 diff --git a/plugin/cs104_server/cs_104_server.go b/plugin/cs104_server/cs_104_server.go index 16ce3d35a..1714b5ceb 100644 --- a/plugin/cs104_server/cs_104_server.go +++ b/plugin/cs104_server/cs_104_server.go @@ -30,10 +30,11 @@ type cs104Server struct { Host string Port int LogMode bool + uuid string } func NewCs104Server() typex.XPlugin { - return &cs104Server{} + return &cs104Server{uuid: "CS104-SERVER"} } func (sf *cs104Server) InterrogationHandler(c asdu.Connect, asduPack *asdu.ASDU, qoi asdu.QualifierOfInterrogation) error { @@ -90,6 +91,7 @@ func (cs *cs104Server) Stop() error { func (cs *cs104Server) PluginMetaInfo() typex.XPluginMetaInfo { return typex.XPluginMetaInfo{ + UUID: cs.uuid, Name: "IEC104 server Plugin", Version: "0.0.1", Homepage: "www.github.com/hootrhino/rulex", @@ -105,6 +107,6 @@ func (cs *cs104Server) PluginMetaInfo() typex.XPluginMetaInfo { * 服务调用接口 * */ -func (cs *cs104Server) Service(arg typex.ServiceArg) error { +func (cs *cs104Server) Service(arg typex.ServiceArg) typex.ServiceResult { return nil } diff --git a/plugin/demo_plugin/demo_plugin.go b/plugin/demo_plugin/demo_plugin.go index 54f4a4fa7..3a7243020 100644 --- a/plugin/demo_plugin/demo_plugin.go +++ b/plugin/demo_plugin/demo_plugin.go @@ -2,14 +2,18 @@ package demo_plugin import ( "github.com/hootrhino/rulex/typex" + "github.com/hootrhino/rulex/utils" "gopkg.in/ini.v1" ) type DemoPlugin struct { + uuid string } func NewDemoPlugin() *DemoPlugin { - return &DemoPlugin{} + return &DemoPlugin{ + uuid: "DEMO01", + } } func (dm *DemoPlugin) Init(config *ini.Section) error { @@ -25,6 +29,7 @@ func (dm *DemoPlugin) Stop() error { func (hh *DemoPlugin) PluginMetaInfo() typex.XPluginMetaInfo { return typex.XPluginMetaInfo{ + UUID: hh.uuid, Name: "DemoPlugin", Version: "0.0.1", Homepage: "www.github.com/hootrhino/rulex", @@ -40,6 +45,6 @@ func (hh *DemoPlugin) PluginMetaInfo() typex.XPluginMetaInfo { * 服务调用接口 * */ -func (cs *DemoPlugin) Service(arg typex.ServiceArg) error { - return nil +func (cs *DemoPlugin) Service(arg typex.ServiceArg) typex.ServiceResult { + return typex.ServiceResult{} } diff --git a/plugin/http_server/http_api_server.go b/plugin/http_server/http_api_server.go index 598c389cc..b88f63690 100644 --- a/plugin/http_server/http_api_server.go +++ b/plugin/http_server/http_api_server.go @@ -44,10 +44,11 @@ type HttpApiServer struct { dbPath string ginEngine *gin.Engine ruleEngine typex.RuleX + uuid string } func NewHttpApiServer() *HttpApiServer { - return &HttpApiServer{} + return &HttpApiServer{uuid: "HTTP-API-SERVER"} } // HTTP服务器崩了, 重启恢复 @@ -229,6 +230,10 @@ func (hh *HttpApiServer) Start(r typex.RuleX) error { //---------------------------------------------------------------------------------------------- hh.ginEngine.GET(url("aibase"), hh.addRoute(AiBase)) hh.ginEngine.DELETE(url("aibase"), hh.addRoute(DeleteAiBase)) + //---------------------------------------------------------------------------------------------- + // Plugin + //---------------------------------------------------------------------------------------------- + hh.ginEngine.POST(url("plugin/service"), hh.addRoute(PluginService)) glogger.GLogger.Infof("Http server started on http://0.0.0.0:%v", hh.Port) return nil @@ -243,7 +248,8 @@ func (hh *HttpApiServer) Db() *gorm.DB { } func (hh *HttpApiServer) PluginMetaInfo() typex.XPluginMetaInfo { return typex.XPluginMetaInfo{ - Name: "Rulex Base Api Server", + UUID: hh.uuid, + Name: "Base Api Server", Version: typex.DefaultVersion.Version, Homepage: "https://rulex.pages.dev", HelpLink: "https://rulex.pages.dev", @@ -258,8 +264,8 @@ func (hh *HttpApiServer) PluginMetaInfo() typex.XPluginMetaInfo { * 服务调用接口 * */ -func (cs *HttpApiServer) Service(arg typex.ServiceArg) error { - return nil +func (cs *HttpApiServer) Service(arg typex.ServiceArg) typex.ServiceResult { + return typex.ServiceResult{Out: "HttpApiServer"} } // -------------------------------------------------------------------------------- diff --git a/plugin/http_server/plugin_api.go b/plugin/http_server/plugin_api.go new file mode 100644 index 000000000..8cd34105b --- /dev/null +++ b/plugin/http_server/plugin_api.go @@ -0,0 +1,34 @@ +package httpserver + +import ( + "github.com/hootrhino/rulex/typex" + + "github.com/gin-gonic/gin" +) + +/* +* +* 插件的服务接口 +* + */ + +func PluginService(c *gin.Context, hs *HttpApiServer, e typex.RuleX) { + type Form struct { + UUID string `json:"uuid" binding:"required"` + Name string `json:"name" binding:"required"` + } + form := Form{} + if err := c.ShouldBindJSON(&form); err != nil { + c.JSON(200, Error400(err)) + return + } + plugin, ok := e.AllPlugins().Load(form.UUID) + if ok { + result := plugin.(typex.XPlugin).Service(typex.ServiceArg{ + Name: form.Name, + }) + c.JSON(200, OkWithData(result.Out)) + return + } + c.JSON(200, Error("plugin not exists")) +} diff --git a/plugin/http_server/system_api.go b/plugin/http_server/system_api.go index 5cce8aa7c..31b8ab8bb 100644 --- a/plugin/http_server/system_api.go +++ b/plugin/http_server/system_api.go @@ -34,11 +34,8 @@ func Ping(c *gin.Context, hh *HttpApiServer, e typex.RuleX) { func Plugins(c *gin.Context, hh *HttpApiServer, e typex.RuleX) { data := []interface{}{} plugins := e.AllPlugins() - id := 0 plugins.Range(func(key, value interface{}) bool { pi := value.(typex.XPlugin).PluginMetaInfo() - pi.UUID = fmt.Sprintf("PLUGIN:%v", id) - id++ data = append(data, pi) return true }) diff --git a/plugin/mqtt_server/mqtt_server.go b/plugin/mqtt_server/mqtt_server.go index 15350f1e4..8cfb48d91 100644 --- a/plugin/mqtt_server/mqtt_server.go +++ b/plugin/mqtt_server/mqtt_server.go @@ -28,11 +28,15 @@ type MqttServer struct { mqttServer *mqttServer.Server clients map[string]*events.Client ruleEngine typex.RuleX + uuid string } func NewMqttServer() typex.XPlugin { return &MqttServer{ + Host: "127.0.0.1", + Port: 1884, clients: map[string]*events.Client{}, + uuid: "RULEX-MqttServer", } } @@ -72,7 +76,7 @@ func (s *MqttServer) Start(r typex.RuleX) error { } } s.mqttServer.Events.OnMessage = func(c events.Client, p events.Packet) (events.Packet, error) { - + glogger.GLogger.Debug("OnMessage:", c.ID, c.Username, p.TopicName, p.Payload) return p, nil } glogger.GLogger.Infof("MqttServer start at [%s:%v] successfully", s.Host, s.Port) @@ -90,6 +94,7 @@ func (s *MqttServer) Stop() error { func (s *MqttServer) PluginMetaInfo() typex.XPluginMetaInfo { return typex.XPluginMetaInfo{ + UUID: s.uuid, Name: "Light Weight MqttServer", Version: "0.0.1", Homepage: "www.github.com/hootrhino/rulex", @@ -100,14 +105,6 @@ func (s *MqttServer) PluginMetaInfo() typex.XPluginMetaInfo { } } -/* -* -* 服务调用接口 -* - */ -func (cs *MqttServer) Service(arg typex.ServiceArg) error { - return nil -} /* * @@ -118,8 +115,10 @@ type AuthController struct { } func (*AuthController) Authenticate(user, password []byte) bool { + glogger.GLogger.Debug("Client require Authenticate:", user, string(password)) return true } func (*AuthController) ACL(user []byte, topic string, write bool) bool { + glogger.GLogger.Debug("Client require ACL:", topic, write) return true } diff --git a/plugin/mqtt_server/mqtt_server_services.go b/plugin/mqtt_server/mqtt_server_services.go new file mode 100644 index 000000000..edd9a4a2b --- /dev/null +++ b/plugin/mqtt_server/mqtt_server_services.go @@ -0,0 +1,58 @@ +package mqttserver + +import ( + + "github.com/hootrhino/rulex/typex" +) + +/* +* +* 获取当前连接进来的MQTT客户端 +* + */ +type Client struct { + ID string `json:"id"` + Remote string `json:"remote"` + Listener string `json:"listener"` + Username string `json:"username"` + CleanSession bool `json:"cleanSession"` +} + +func (s *MqttServer) ListClients(offset, count int) []Client { + result := []Client{} + for _, v := range s.clients { + c := Client{ + ID: v.ID, + Remote: v.Remote, + Username: string(v.Username), + CleanSession: v.CleanSession, + } + result = append(result, c) + } + return result +} + +/* +* +* 把某个客户端给踢下线 +* + */ +func (s *MqttServer) KickOut(clientid string) bool { + if _, ok := s.clients[clientid]; ok { + return true + } + return false + +} + +/* +* +* 服务调用接口 +* + */ +func (s *MqttServer) Service(arg typex.ServiceArg) typex.ServiceResult { + if arg.Name == "clients" { + return typex.ServiceResult{Out: s.ListClients(0, 100)} + } + return typex.ServiceResult{} +} diff --git a/plugin/net_discover/net_boardcast.go b/plugin/net_discover/net_boardcast.go index 06b44f0f7..01ce8bd75 100644 --- a/plugin/net_discover/net_boardcast.go +++ b/plugin/net_discover/net_boardcast.go @@ -44,11 +44,13 @@ type NetDiscover struct { ctx context.Context cancel context.CancelFunc Neighbors map[string]gwnode // 邻居 + uuid string } func NewNetDiscover() typex.XPlugin { ctx, cancel := context.WithCancel(context.Background()) - return &NetDiscover{mainConfig: _serverConfig{}, ctx: ctx, cancel: cancel} + return &NetDiscover{mainConfig: _serverConfig{}, + ctx: ctx, cancel: cancel, uuid: "NewNetDiscover"} } func (dm *NetDiscover) Init(config *ini.Section) error { @@ -169,6 +171,7 @@ func calculateCpuPercent(cpus []float64) float64 { func (hh *NetDiscover) PluginMetaInfo() typex.XPluginMetaInfo { return typex.XPluginMetaInfo{ + UUID: hh.uuid, Name: "NetDiscover", Version: "0.0.1", Homepage: "www.github.com/hootrhino/rulex", @@ -184,6 +187,6 @@ func (hh *NetDiscover) PluginMetaInfo() typex.XPluginMetaInfo { * 服务调用接口 * */ -func (cs *NetDiscover) Service(arg typex.ServiceArg) error { - return nil +func (cs *NetDiscover) Service(arg typex.ServiceArg) typex.ServiceResult { + return typex.ServiceResult{} } diff --git a/plugin/sensor_server/sensor_server.go b/plugin/sensor_server/sensor_server.go index 09165bd08..d586889d9 100644 --- a/plugin/sensor_server/sensor_server.go +++ b/plugin/sensor_server/sensor_server.go @@ -9,6 +9,7 @@ import ( "github.com/hootrhino/rulex/glogger" "github.com/hootrhino/rulex/typex" + "github.com/hootrhino/rulex/utils" "gopkg.in/ini.v1" ) @@ -17,11 +18,12 @@ type SensorServer struct { cancelMain context.CancelFunc tcpPort int httpPort int + uuid string } func NewSensorServer() *SensorServer { ctx, cancel := context.WithCancel(context.Background()) - return &SensorServer{ctxMain: ctx, cancelMain: cancel} + return &SensorServer{ctxMain: ctx, cancelMain: cancel, uuid: "SENSOR-SERVER"} } func (dm *SensorServer) Init(config *ini.Section) error { @@ -42,6 +44,7 @@ func (dm *SensorServer) Stop() error { func (hh *SensorServer) PluginMetaInfo() typex.XPluginMetaInfo { return typex.XPluginMetaInfo{ + UUID: hh.uuid, Name: "GenericSensorServer", Version: "0.0.1", Homepage: "www.github.com/hootrhino/rulex", @@ -57,8 +60,8 @@ func (hh *SensorServer) PluginMetaInfo() typex.XPluginMetaInfo { * 服务调用接口 * */ -func (cs *SensorServer) Service(arg typex.ServiceArg) error { - return nil +func (cs *SensorServer) Service(arg typex.ServiceArg) typex.ServiceResult { + return typex.ServiceResult{} } // -------------------------------------------------------------------------------------------------- diff --git a/plugin/ttyd_terminal/ttyd_terminal.go b/plugin/ttyd_terminal/ttyd_terminal.go index 0f61c62f2..1311ac483 100644 --- a/plugin/ttyd_terminal/ttyd_terminal.go +++ b/plugin/ttyd_terminal/ttyd_terminal.go @@ -26,10 +26,12 @@ type _ttydConfig struct { type WebTTYPlugin struct { ttydCmd *exec.Cmd mainConfig _ttydConfig + uuid string } func NewWebTTYPlugin() *WebTTYPlugin { return &WebTTYPlugin{ + uuid: utils.PluginUuid(), mainConfig: _ttydConfig{}, } } @@ -87,6 +89,7 @@ func (tty *WebTTYPlugin) Stop() error { func (hh *WebTTYPlugin) PluginMetaInfo() typex.XPluginMetaInfo { return typex.XPluginMetaInfo{ + UUID: hh.uuid, Name: "WebTTYPlugin", Version: "0.0.1", Homepage: "https://github.com/tsl0922/ttyd", @@ -102,6 +105,6 @@ func (hh *WebTTYPlugin) PluginMetaInfo() typex.XPluginMetaInfo { * 服务调用接口 * */ -func (cs *WebTTYPlugin) Service(arg typex.ServiceArg) error { - return nil +func (cs *WebTTYPlugin) Service(arg typex.ServiceArg) typex.ServiceResult { + return typex.ServiceResult{} } diff --git a/plugin/usb_monitor/usb_mnitor_windows.go b/plugin/usb_monitor/usb_mnitor_windows.go index 7ba8ab26b..8dd21e067 100644 --- a/plugin/usb_monitor/usb_mnitor_windows.go +++ b/plugin/usb_monitor/usb_mnitor_windows.go @@ -19,10 +19,13 @@ import ( * */ type usbMonitor struct { + uuid string } func NewUsbMonitor() typex.XPlugin { - return &usbMonitor{} + return &usbMonitor{ + uuid: "USB-MONITOR" + } } func (usbm *usbMonitor) Init(_ *ini.Section) error { return nil @@ -44,6 +47,7 @@ func (usbm *usbMonitor) Stop() error { func (usbm *usbMonitor) PluginMetaInfo() typex.XPluginMetaInfo { return typex.XPluginMetaInfo{ + UUID: usbm.uuid, Name: "USB Monitor", Version: "0.0.1", Homepage: "https://github.com/hootrhino/rulex.git", @@ -59,6 +63,6 @@ func (usbm *usbMonitor) PluginMetaInfo() typex.XPluginMetaInfo { * 服务调用接口 * */ -func (usbm *usbMonitor) Service(arg typex.ServiceArg) error { - return nil +func (usbm *usbMonitor) Service(arg typex.ServiceArg) typex.ServiceResult { + return typex.ServiceResult{} } diff --git a/plugin/usb_monitor/usb_monitor_linux.go b/plugin/usb_monitor/usb_monitor_linux.go index 561d577bd..2710ff432 100644 --- a/plugin/usb_monitor/usb_monitor_linux.go +++ b/plugin/usb_monitor/usb_monitor_linux.go @@ -9,6 +9,7 @@ import ( "github.com/hootrhino/rulex/glogger" "github.com/hootrhino/rulex/typex" + "github.com/hootrhino/rulex/utils" "golang.org/x/sys/unix" "gopkg.in/ini.v1" ) @@ -19,10 +20,11 @@ import ( * */ type usbMonitor struct { + uuid string } func NewUsbMonitor() typex.XPlugin { - return &usbMonitor{} + return &usbMonitor{uuid: "USB-MONITOR"} } func (usbm *usbMonitor) Init(_ *ini.Section) error { return nil @@ -157,6 +159,7 @@ func (usbm *usbMonitor) Stop() error { func (usbm *usbMonitor) PluginMetaInfo() typex.XPluginMetaInfo { return typex.XPluginMetaInfo{ + UUID: usbm.uuid, Name: "USB Monitor", Version: "0.0.1", Homepage: "www.github.com/hootrhino/rulex", @@ -172,6 +175,6 @@ func (usbm *usbMonitor) PluginMetaInfo() typex.XPluginMetaInfo { * 服务调用接口 * */ -func (cs *usbMonitor) Service(arg typex.ServiceArg) error { - return nil +func (cs *usbMonitor) Service(arg typex.ServiceArg) typex.ServiceResult { + return typex.ServiceResult{} } diff --git a/script/readme.md b/script/readme.md new file mode 100644 index 000000000..286e9a234 --- /dev/null +++ b/script/readme.md @@ -0,0 +1,44 @@ +# 安装脚本 +此处介绍两类应用安装脚本。 +## Systemctl +Systemctl是Ubuntu系自带的进程管理器,这也是大部分人能接触到的最简单的一种,下面给出个示例。 +1. 配置脚本 + ```ini + [Unit] + Description=rulex + After=network-online.target rc-local.service nss-user-lookup.target + Wants=network-online.target + + [Service] + User=root + Type=simple + WorkingDirectory=/usr/local/rulexapp + ExecStart=/usr/local/rulexapp/rulex + Restart=on-failure + RestartSec=5s + [Install] + WantedBy=multi-user.target + + ``` +2. 操作指令 + ```sh + sudo systemctl start rulex + sudo systemctl enable rulex + sudo systemctl status rulex + ``` + +## Linux 原生脚本 +Linux 原生脚本一半放在 `/etc/network/interfaces.d`目录下。 +```sh +#! /bin/sh +APP_NAME="/root/rulex" +while true; do + APP_PROCESS_COUNT=`ps aux | grep ${APP_NAME} | grep -v grep |wc -l` + if [ "${APP_PROCESS_COUNT}" -lt "1" ];then + ${APP_NAME} -c 1 & + elif [ "${APP_PROCESS_COUNT}" -gt "1" ];then + killall -9 $APP_NAME + fi + sleep 5 +done +``` \ No newline at end of file diff --git a/test/conf/rulex.ini b/test/conf/rulex.ini index f2a3e012a..e9d47f1b2 100644 --- a/test/conf/rulex.ini +++ b/test/conf/rulex.ini @@ -90,7 +90,7 @@ dbpath = ./rulex.db # # Enable # -enable = false +enable = true # # Server host, default allow all # @@ -98,7 +98,7 @@ host = 0.0.0.0 # # Server port # -port = 1883 +port = 1884 # # A simple IEC-104 protocol server # diff --git a/typex/typex.md b/typex/typex.md new file mode 100644 index 000000000..d78f35fa2 --- /dev/null +++ b/typex/typex.md @@ -0,0 +1,2 @@ +# 全局类型 +这个包下面保存的是全局数据结构和类型等。这里很多接口设计的有不合理的地方,主要是前期没有考虑到能做到这么庞大。也许未来有时间精力以后再优化一下,当然现在不影响整体结构。 \ No newline at end of file diff --git a/typex/version.go b/typex/version.go index 7283a5f90..981d501cd 100644 --- a/typex/version.go +++ b/typex/version.go @@ -1,7 +1,7 @@ // // Warning: // This file is generated by go compiler, don't change it!!! -// Build on: Deepin GNU/Linux 20.8 \n \l +// Build on: Deepin GNU/Linux 20.9 \n \l // package typex @@ -18,6 +18,6 @@ func (v Version) String() string { var DefaultVersion = Version{ Version: `v0.4.4-hotfix`, - ReleaseTime: "2023-05-19 16:01:18", + ReleaseTime: "2023-05-25 16:53:07", } diff --git a/typex/xplugin.go b/typex/xplugin.go index bba7261ec..650a9e5bc 100644 --- a/typex/xplugin.go +++ b/typex/xplugin.go @@ -9,13 +9,14 @@ import "gopkg.in/ini.v1" // 3 LoadPlugin(sectionK string, p typex.XPlugin) // -// // 插件的服务参数 -// type ServiceArg struct { - UUID string `json:"uuid"` // 插件UUID - Name string `json:"name"` // 服务名 - Args interface{} `json:"args"` // 参数 + UUID string `json:"uuid"` // 插件UUID, Rulex用来查找插件的 + Name string `json:"name"` // 服务名, 在服务中响应识别 + Args interface{} `json:"args"` // 服务参数 +} +type ServiceResult struct { + Out interface{} `json:"out"` } /* @@ -42,7 +43,7 @@ type XPluginMetaInfo struct { type XPlugin interface { Init(*ini.Section) error // 参数为外部配置 Start(RuleX) error - Service(ServiceArg) error // 对外提供一些服务 + Service(ServiceArg) ServiceResult // 对外提供一些服务 Stop() error PluginMetaInfo() XPluginMetaInfo } diff --git a/utils/uuid_util.go b/utils/uuid_util.go index 0a7cc73dd..e9b65057f 100644 --- a/utils/uuid_util.go +++ b/utils/uuid_util.go @@ -23,6 +23,9 @@ func OutUuid() string { func DeviceUuid() string { return MakeUUID("DEVICE") } +func PluginUuid() string { + return MakeUUID("PLUGIN") +} func AppUuid() string { return MakeUUID("APP") } From 9fd7b9f63ab22daed51b5e3f39e5eb19849ed99b Mon Sep 17 00:00:00 2001 From: liyong <228431028@qq.com> Date: Tue, 6 Jun 2023 18:09:12 +0800 Subject: [PATCH 2/2] dev: optimized tty plugin and AIS --- device/generic_ais_txrx_device.go | 84 +++++++++++++++-- device/generic_camera_stream_linux_mipsle.go | 96 ++++++++++++++++++++ gen_info.sh | 12 +-- main.go | 7 ++ plugin/http_server/system_api.go | 19 ++-- plugin/mqtt_server/mqtt_server_services.go | 7 +- plugin/sensor_server/sensor_server.go | 1 - plugin/ttyd_terminal/ttyd_terminal.go | 2 +- test/device_generic_ais_rxtx_device_test.go | 77 +++++++++++++++- typex/version.go | 14 +-- utils/os_common.go | 5 +- 11 files changed, 276 insertions(+), 48 deletions(-) create mode 100644 device/generic_camera_stream_linux_mipsle.go diff --git a/device/generic_ais_txrx_device.go b/device/generic_ais_txrx_device.go index 7fa81a407..bfe1a0449 100644 --- a/device/generic_ais_txrx_device.go +++ b/device/generic_ais_txrx_device.go @@ -1,6 +1,12 @@ package device import ( + "bufio" + "fmt" + "net" + "strings" + + "github.com/hootrhino/rulex/glogger" "github.com/hootrhino/rulex/typex" "github.com/hootrhino/rulex/utils" ) @@ -53,14 +59,16 @@ type _AISDevicePacket struct { // -------------------------------------------------------------------------------------------------- type _AISDeviceConfig struct { - Host string `json:"host" validate:"required" title:"服务地址"` - Port int `json:"port" validate:"required" title:"服务端口"` + Mode string `json:"mode"` // TCP UDP UART + Host string `json:"host" validate:"required"` + Port int `json:"port" validate:"required"` } type AISDevice struct { typex.XStatus - status typex.DeviceState - mainConfig _AISDeviceConfig - RuleEngine typex.RuleX + status typex.DeviceState + mainConfig _AISDeviceConfig + RuleEngine typex.RuleX + tcpListener net.Listener // TCP 接收端 } /* @@ -71,7 +79,11 @@ type AISDevice struct { func NewAISDevice(e typex.RuleX) typex.XDevice { aisd := new(AISDevice) aisd.RuleEngine = e - aisd.mainConfig = _AISDeviceConfig{} + aisd.mainConfig = _AISDeviceConfig{ + Mode: "TCP", + Host: "0.0.0.0", + Port: 2600, + } return aisd } @@ -90,6 +102,15 @@ func (aisd *AISDevice) Start(cctx typex.CCTX) error { aisd.Ctx = cctx.Ctx aisd.CancelCTX = cctx.CancelCTX // + listener, err := net.Listen("tcp", + fmt.Sprintf("%s%v", aisd.mainConfig.Host, aisd.mainConfig.Port)) + if err != nil { + return err + } + aisd.tcpListener = listener + glogger.GLogger.Infof("AIS TCP server started on http://%s:%v", + aisd.mainConfig.Host, aisd.mainConfig.Port) + go aisd.handleConnect(listener) return nil } @@ -112,6 +133,9 @@ func (aisd *AISDevice) Status() typex.DeviceState { func (aisd *AISDevice) Stop() { aisd.status = typex.DEV_DOWN aisd.CancelCTX() + if aisd.tcpListener != nil { + aisd.tcpListener.Close() + } } // 设备属性,是一系列属性描述 @@ -147,3 +171,51 @@ func (aisd *AISDevice) OnDCACall(UUID string, Command string, Args interface{}) func (aisd *AISDevice) OnCtrl(cmd []byte, args []byte) ([]byte, error) { return []byte{}, nil } + +//-------------------------------------------------------------------------------------------------- +// 内部 +//-------------------------------------------------------------------------------------------------- +/* +* +* 处理连接 +* + */ +func (aisd *AISDevice) handleConnect(listener net.Listener) { + for { + select { + case <-aisd.Ctx.Done(): + { + return + } + default: + { + } + } + tcpcon, err := listener.Accept() + if err != nil { + glogger.GLogger.Error(err) + continue + } + go aisd.handleIO(tcpcon) + } + +} + +/* +* +* 数据处理 +* + */ +func (aisd *AISDevice) handleIO(conn net.Conn) { + defer conn.Close() + reader := bufio.NewReader(conn) + + s, err := reader.ReadString('\n') + if err != nil { + glogger.GLogger.Error(err) + return + } + if strings.HasSuffix(s, "\r\n") { + glogger.GLogger.Debug("Received data:", s) + } +} diff --git a/device/generic_camera_stream_linux_mipsle.go b/device/generic_camera_stream_linux_mipsle.go new file mode 100644 index 000000000..40b0e6587 --- /dev/null +++ b/device/generic_camera_stream_linux_mipsle.go @@ -0,0 +1,96 @@ +package device + +import ( + "fmt" + + "github.com/hootrhino/rulex/typex" +) + +// RTSP URL格式= rtsp://:@:, +type _MainConfig struct { + MaxThread int `json:"maxThread"` // 最大连接数, 防止连接过多导致摄像头拉流失败 + InputMode string `json:"inputMode"` // 视频输入模式:RTSP | LOCAL + Device string `json:"device"` // 本地视频设备路径,在输入模式=LOCAL时生效 + RtspUrl string `json:"rtspUrl"` // 远程视频设备地址,在输入模式=RTSP时生效 + OutputMode string `json:"outputMode"` // 输出模式:JPEG_STREAM | RTSP_STREAM + OutputAddr string `json:"outputAddr"` // 输出地址, 格式为: "Ip:Port",例如127.0.0.1:7890 +} + +// 摄像头 +type videoCamera struct { + typex.XStatus + status typex.DeviceState + mainConfig _MainConfig +} + +func NewVideoCamera(e typex.RuleX) typex.XDevice { + videoCamera := new(videoCamera) + videoCamera.RuleEngine = e + videoCamera.status = typex.DEV_DOWN + videoCamera.mainConfig = _MainConfig{ + Device: "video0", + RtspUrl: "rtsp://127.0.0.1", + InputMode: "LOCAL", + OutputMode: "JPEG_STREAM", + } + return videoCamera +} + +// 初始化 通常用来获取设备的配置 +func (vc *videoCamera) Init(devId string, configMap map[string]interface{}) error { + return fmt.Errorf("video camera not support windows") +} + +// 启动, 设备的工作进程 +func (vc *videoCamera) Start(cctx typex.CCTX) error { + vc.status = typex.DEV_UP + return nil +} + +func (vc *videoCamera) OnRead(cmd []byte, data []byte) (int, error) { + return 0, nil +} + +func (vc *videoCamera) OnWrite(cmd []byte, data []byte) (int, error) { + return 0, nil +} + +/* +* +* 外部指令,未来可以实现一些对摄像头的操作,例如拍照等 +* + */ +func (vc *videoCamera) OnCtrl(cmd []byte, args []byte) ([]byte, error) { + return nil, nil +} + +// 设备当前状态 +func (vc *videoCamera) Status() typex.DeviceState { + return vc.status +} + +func (vc *videoCamera) Stop() { + vc.status = typex.DEV_STOP + vc.CancelCTX() +} + +func (vc *videoCamera) Property() []typex.DeviceProperty { + return []typex.DeviceProperty{} +} + +func (vc *videoCamera) Details() *typex.Device { + return vc.RuleEngine.GetDevice(vc.PointId) + +} + +func (vc *videoCamera) SetState(_ typex.DeviceState) { + +} + +func (vc *videoCamera) Driver() typex.XExternalDriver { + return nil +} + +func (vc *videoCamera) OnDCACall(_ string, _ string, _ interface{}) typex.DCAResult { + return typex.DCAResult{} +} diff --git a/gen_info.sh b/gen_info.sh index 47a4868b1..f293ccf23 100644 --- a/gen_info.sh +++ b/gen_info.sh @@ -6,22 +6,16 @@ HASH=$(git rev-list --tags --max-count=1) ## Gen Version ####################################################################### cat >./typex/version.go < diff --git a/utils/os_common.go b/utils/os_common.go index 766d3a7ab..64fec16f5 100644 --- a/utils/os_common.go +++ b/utils/os_common.go @@ -94,7 +94,7 @@ func GetOSDistribution() (string, error) { } // Linux 有很多发行版, 目前特别要识别一下Openwrt if runtime.GOOS == "linux" { - cmd := exec.Command("cat", "/etc/issue") + cmd := exec.Command("cat", "/etc/os-release") output, err := cmd.Output() if err != nil { return runtime.GOOS, err @@ -112,6 +112,9 @@ func GetOSDistribution() (string, error) { if strings.Contains((osIssue), "armbian") { return "armbian", nil } + if strings.Contains((osIssue), "deepin") { + return "deepin", nil + } } return runtime.GOOS, nil }