Skip to content

Commit

Permalink
重构http server
Browse files Browse the repository at this point in the history
  • Loading branch information
liwss committed Aug 3, 2023
1 parent 5939ab0 commit c0e94c5
Show file tree
Hide file tree
Showing 16 changed files with 369 additions and 2 deletions.
20 changes: 19 additions & 1 deletion conf/rulex.ini
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ update_server = http://localhost:8088/rulex
#
# Enable
#
enable = true
enable = false
#
# Server host, default allow all
#
Expand All @@ -85,6 +85,24 @@ port = 2580
#
dbpath = ./rulex.db
#
[plugin.api_server]
#
# Enable
#
enable = true
#
# Server host, default allow all
#
host = 0.0.0.0
#
# Server port
#
port = 8000
#
# Server port
#
dbpath = ./rulex.db
#
# Lightweight Mqtt protocol server
#
[plugin.mqtt_server]
Expand Down
9 changes: 9 additions & 0 deletions engine/runner.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package engine

import (
"github.com/hootrhino/rulex/plugin/api_server"
"os"
"os/signal"
"syscall"
Expand Down Expand Up @@ -45,6 +46,14 @@ func RunRulex(iniPath string) {
glogger.GLogger.Error(err)
return
}

// http server v2
apiServer := api_server.NewHttpPlugin()
if err := engine.LoadPlugin("plugin.api_server", apiServer); err != nil {
glogger.GLogger.Error(err)
return
}

mqttServer := mqttserver.NewMqttServer()
if err := engine.LoadPlugin("plugin.mqtt_server", mqttServer); err != nil {
glogger.GLogger.Error(err)
Expand Down
5 changes: 5 additions & 0 deletions global/global.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package global

import "gorm.io/gorm"

var RULEX_DB *gorm.DB
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ require (
github.com/wwhai/ntp v0.3.0
github.com/wwhai/tarmserial v1.0.0
github.com/wwhai/tinycache v0.0.0-20191004192108-46f407853014
github.com/xuri/excelize/v2 v2.7.1
go.bug.st/serial v1.5.0
go.mongodb.org/mongo-driver v1.11.6
go.uber.org/zap v1.15.0
Expand All @@ -66,7 +67,6 @@ require (
github.com/richardlehane/mscfb v1.0.4 // indirect
github.com/richardlehane/msoleps v1.0.3 // indirect
github.com/xuri/efp v0.0.0-20220603152613-6918739fd470 // indirect
github.com/xuri/excelize/v2 v2.7.1 // indirect
github.com/xuri/nfp v0.0.0-20220409054826-5e722a1d9e22 // indirect
)

Expand Down
1 change: 1 addition & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -1014,6 +1014,7 @@ golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EH
golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/image v0.5.0 h1:5JMiNunQeQw++mMOz48/ISeNu3Iweh/JaZU8ZLqHRrI=
golang.org/x/image v0.5.0/go.mod h1:FVC7BI/5Ym8R25iw5OLsgshdUBbT1h5jZTpA+mvAdZ4=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
Expand Down
77 changes: 77 additions & 0 deletions plugin/api_server/http_plugin.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
package api_server

import (
"fmt"
"github.com/hootrhino/rulex/global"
"github.com/hootrhino/rulex/plugin/api_server/initialize"
"github.com/hootrhino/rulex/typex"
"github.com/hootrhino/rulex/utils"
"gopkg.in/ini.v1"
"os"
"os/signal"
"strconv"
"syscall"
)

var apiPort int = 8000

type HttpPlugin struct {
uuid string
}

func NewHttpPlugin() *HttpPlugin {
return &HttpPlugin{
uuid: "HTTP PLUGIN",
}
}

func (*HttpPlugin) Init(config *ini.Section) error {
var apiConfig initialize.HttpConfig
if err := utils.InIMapToStruct(config, &apiConfig); err != nil {
return err
}
global.RULEX_DB = initialize.Gorm(apiConfig.DbPath)
apiPort = apiConfig.Port
if global.RULEX_DB != nil {
initialize.RegisterTables(global.RULEX_DB) // 初始化表
}

return nil
}

func (*HttpPlugin) Start(typex.RuleX) error {
// 优雅退出程序
router := initialize.Routers()
PORT := strconv.Itoa(apiPort)
go func() {
// 启动服务
if err := router.Run(fmt.Sprintf(":%s", PORT)); err != nil {
fmt.Println(fmt.Sprintf("服务启动失败:%s", err.Error()))
}
}()
exit := make(chan os.Signal)
signal.Notify(exit, syscall.SIGINT, syscall.SIGTERM)
<-exit
return nil
}

func (*HttpPlugin) Stop() error {
return nil
}

func (hp *HttpPlugin) PluginMetaInfo() typex.XPluginMetaInfo {
return typex.XPluginMetaInfo{
UUID: hp.uuid,
Name: "RULEX HTTP RESTFul Api Server",
Version: "v2.0.0",
Homepage: "https://hootrhino.github.io",
HelpLink: "https://hootrhino.github.io",
Author: "wwhai",
Email: "cnwwhai@gmail.com",
License: "MIT",
}
}

func (*HttpPlugin) Service(arg typex.ServiceArg) typex.ServiceResult {
return typex.ServiceResult{Out: "HTTP API SERVER"}
}
8 changes: 8 additions & 0 deletions plugin/api_server/initialize/config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package initialize

type HttpConfig struct {
Enable bool `ini:"enable"`
Host string `ini:"host"`
DbPath string `ini:"dbpath"`
Port int `ini:"port"`
}
49 changes: 49 additions & 0 deletions plugin/api_server/initialize/gorm.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package initialize

import (
"github.com/hootrhino/rulex/core"
"github.com/hootrhino/rulex/glogger"
"github.com/hootrhino/rulex/plugin/api_server/model"
"gorm.io/driver/sqlite"
"gorm.io/gorm"
"gorm.io/gorm/logger"
"os"
)

// Gorm 暂时写死sqlite,可根据实际扩展其他数据库
func Gorm(dbPath string) *gorm.DB {
return GormSqlite(dbPath)
}

func GormSqlite(dbPath string) *gorm.DB {
if core.GlobalConfig.AppDebugMode {
if db, err := gorm.Open(sqlite.Open(dbPath), &gorm.Config{
Logger: logger.Default.LogMode(logger.Info),
SkipDefaultTransaction: false,
}); err != nil {
return nil
} else {
return db
}
} else {
if db, err := gorm.Open(sqlite.Open(dbPath), &gorm.Config{
Logger: logger.Default.LogMode(logger.Error),
SkipDefaultTransaction: false,
}); err != nil {
return nil
} else {
return db
}
}
}

// RegisterTables 注册数据库表专用
func RegisterTables(db *gorm.DB) {
err := db.AutoMigrate(
model.MRule{},
)
if err != nil {
glogger.GLogger.Fatal(err)
os.Exit(0)
}
}
20 changes: 20 additions & 0 deletions plugin/api_server/initialize/router.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package initialize

import (
"github.com/gin-gonic/gin"
"github.com/hootrhino/rulex/plugin/api_server/middleware"
"github.com/hootrhino/rulex/plugin/api_server/router"
)

func Routers() *gin.Engine {
Router := gin.Default()
// 注册全局中间件,根据实际业务需求注册
Router.Use(
middleware.CorsMiddleWare(), // 跨域中间件
)
// 配置全局路径
ApiGroup := Router.Group("/api/v2/")
// 注册路由
router.InitRuleRouter(ApiGroup)
return Router
}
29 changes: 29 additions & 0 deletions plugin/api_server/middleware/CorsMiddleWare.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package middleware

import (
"github.com/gin-gonic/gin"
"net/http"
)

// CorsMiddleWare 跨域中间件
// CORS是跨源资源分享(Cross-Origin Resource Sharing)中间件
func CorsMiddleWare() gin.HandlerFunc {
return func(ctx *gin.Context) {
//指定允许其他域名访问
//ctx.Writer.Header().Set("Access-Control-Allow-Origin", "http://localhost:8080")
ctx.Writer.Header().Set("Access-Control-Allow-Origin", "*") //跨域:CORS(跨来源资源共享)策略
//预检结果缓存时间
ctx.Writer.Header().Set("Access-Control-Max-Age", "86400")
//允许的请求类型(GET,POST等)
ctx.Writer.Header().Set("Access-Control-Allow-Methods", "*")
//允许的请求头字段
ctx.Writer.Header().Set("Access-Control-Allow-Headers", "*")
//是否允许后续请求携带认证信息(cookies),该值只能是true,否则不返回
ctx.Writer.Header().Set("Access-Control-Allow-Credentials", "true")
if ctx.Request.Method == http.MethodOptions {
ctx.AbortWithStatus(200)
} else {
ctx.Next()
}
}
}
31 changes: 31 additions & 0 deletions plugin/api_server/model/base.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package model

import (
"database/sql/driver"
"gopkg.in/square/go-jose.v2/json"
"time"
)

type BaseModel struct {
ID uint `gorm:"primarykey"`
CreatedAt time.Time
}

type stringList []string

func (f stringList) Value() (driver.Value, error) {
b, err := json.Marshal(f)
return string(b), err
}

func (f *stringList) Scan(data interface{}) error {
return json.Unmarshal([]byte(data.(string)), f)
}

func (f stringList) String() string {
b, _ := json.Marshal(f)
return string(b)
}
func (f stringList) Len() int {
return len(f)
}
19 changes: 19 additions & 0 deletions plugin/api_server/model/m_rules.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package model

type MRule struct {
BaseModel
UUID string `gorm:"not null"`
Name string `gorm:"not null"`
Type string // 脚本类型,目前支持"lua"和"expr"两种
FromSource stringList `gorm:"not null type:string[]"`
FromDevice stringList `gorm:"not null type:string[]"`
Expression string `gorm:"not null"` // Expr脚本
Actions string `gorm:"not null"`
Success string `gorm:"not null"`
Failed string `gorm:"not null"`
Description string
}

func (*MRule) TableName() string {
return "m_rules"
}
8 changes: 8 additions & 0 deletions plugin/api_server/response/common.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package response

type PageResult struct {
List interface{} `json:"list"`
Total int64 `json:"total"`
Page int `json:"page"`
PageSize int `json:"pageSize"`
}
55 changes: 55 additions & 0 deletions plugin/api_server/response/response.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package response

import (
"net/http"

"github.com/gin-gonic/gin"
)

type Response struct {
Code int `json:"code"`
Data interface{} `json:"data"`
Msg string `json:"msg"`
}

const (
ERROR = 500
SUCCESS = 200
)

func Result(code int, data interface{}, msg string, c *gin.Context) {
// 开始时间
c.JSON(http.StatusOK, Response{
code,
data,
msg,
})
}

func Ok(c *gin.Context) {
Result(SUCCESS, map[string]interface{}{}, "Success", c)
}

func OkWithMessage(message string, c *gin.Context) {
Result(SUCCESS, map[string]interface{}{}, message, c)
}

func OkWithData(data interface{}, c *gin.Context) {
Result(SUCCESS, data, "查询成功", c)
}

func OkWithDetailed(data interface{}, message string, c *gin.Context) {
Result(SUCCESS, data, message, c)
}

func Fail(c *gin.Context) {
Result(ERROR, map[string]interface{}{}, "error", c)
}

func FailWithMessage(message string, c *gin.Context) {
Result(ERROR, map[string]interface{}{}, message, c)
}

func FailWithDetailed(data interface{}, message string, c *gin.Context) {
Result(ERROR, data, message, c)
}
Loading

0 comments on commit c0e94c5

Please sign in to comment.