# 规则引擎

{% hint style="info" %}
规则执行脚本引擎使用的是<https://github.com/bilibili/gengine>

语法参考：[https://github.com/bilibili/gengine/wiki](https://github.com/bilibili/gengine/wiki/)
{% endhint %}

| 内核方式             | 参数                             | 返回值类型                   | 说明                             |
| ---------------- | ------------------------------ | ----------------------- | ------------------------------ |
| Core.Publish     | message                        | string                  | 转发消息到其他主题                      |
| Core.Http        | url,method,header,body,timeout | string                  | 转发到第三方http接口                   |
| Core.String      | \[]byte                        | string                  | 字节数组转换为字符串                     |
| Core.Bytes       | string                         | \[]byte                 | 字符串转为字节数组                      |
| Core.MakeMap     | 无                              | map\[string]interface{} | 实例化一个map\[string]interface{}对象 |
| Core.MakeMessage | 无                              |                         | 实例化一个mqtt消息对象                  |
| Core.FromJson    | \[]byte                        |                         | 反序列化json字符串                    |
| Core.ToJson      | map\[string]interface{}        |                         | 序列化对象为json字符串                  |
| Core.FromMsgPack | \[]byte                        |                         | 反序列化MessagePack包               |
| Core.ToMsgPack   | map\[string]interface{}        |                         | 序列化对象为MessagePack字符串           |
| Core.AddCron     | map,cronString,ruleNames       | int                     | 添加一个计划任务                       |
| Core.DelCron     | int                            | 无                       | 删除一个计划任务                       |
| Core.Bits.And    | x1,x2 byte                     | byte                    | 位与操作                           |
| Core.Bits.Or     | x1,x2 byte                     | byte                    | 位或操作                           |
| Core.Bits.Xor    | x1,x2 byte                     | byte                    | 位异或操作                          |
| Core.Bits.Not    | x1,x2 byte                     | byte                    | 位非操作                           |
| Core.Bits.Left   | data \[]byte, bits int         | \[]byte                 | 位左移操作                          |
| Core.Bits.Right  | data \[]byte, bits int         | \[]byte                 | 位右移操作                          |

{% hint style="info" %}
AddCron中的cronString参数为cron表达式，可自由设置年月时分秒周等触发器时间规则。祥情请参阅 <https://github.com/robfig/cron/blob/v3/doc.go>

生成工具：[https://cron.qqe2.com](https://cron.qqe2.com/)
{% endhint %}

### 功能模式

1. 编写规则脚本
2. 通过API提交到Coolpy7内核
3. 推送消息到内核验证脚本

#### 规则示例

```
//规则名称为rule1，规则备注，执行优先级
rule "rule1" "rule-describtion" salience  1
begin
  //过滤主题为aaa的消息才进行处理
  if Message.Topic == "a/b/c" {
    //反序列化消息中的载体
    payload = Core.FromJson(Message.Payload)
    //判断消息载体是否为空
    if isNil(payload) {
        println("parse error")
        return
    }
    //实例化一个map用于转换消息体格式
    res = Core.MakeMap()
    //把原消息的msg内容付值到新消息体的m键中
    res["m"] = payload["msg"]
    //序列化新的消息体为json
    reMsg = Core.ToJson(res)
    //传送序列化是否失败
    if isNil(reMsg) {
        println("format error")
        return
    }
    //打印序列化结果于服务端
    println(Core.String(reMsg))
    //实例化mqtt消息体
    newMsg = Core.MakeMessage()
    //设置新的接收主题
    newMsg.Topic = "bbb/#"
    //消息质量控制
    newMsg.QOS = 0
    newMsg.Retain = false
    //把新的载体付值到新消息载体中
    newMsg.Payload = reMsg
    //通过内核发布新消息
    err = Core.Publish(newMsg)
    if err != "" {
        println(err)
    }
  }
end
```

### 接口说明

| 接口                   | HTTP   | 说明                               |
| -------------------- | ------ | -------------------------------- |
| /api/rules           | POST   | 添加一个规则到内核                        |
| /api/rules           | GET    | 获取所有内核规则集合记录（支持分页）               |
| /api/rule/:ruleId    | GET    | 获取指定内核规则脚本                       |
| /api/rule?ruleid=xxx | DELETE | 删除一个规则记录（:ruleid为规则名,不指定时清空所有规则） |

#### 接口身份证验证方式需调用/api/login后取到token后放到http的header中，如下是消息格式转义后转发到另一个主题的示例：

```
curl --location --request POST 'http://localhost:8081/v1/rules' \
--header 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOiJDUDciLCJleHAiOjE2MjE1NzcxMjEsImp0aSI6ImFkbWluIiwiaWF0IjoxNjIxNTY5OTIxLCJpc3MiOiJjb29scHkubmV0IiwibmJmIjoxNjIxNTY5OTIxfQ.cE1YusJXYQbrU2Pa9gl6gqqsf93rkHB4ePNiXuDSdeg' \
--header 'Content-Type: text/plain' \
--data-raw '//规则名称为rule2，规则备注，执行优先级
rule "rule2" "rule-describtion" salience  1
begin
  //过滤主题为aaa的消息才进行处理
  if Message.Topic == "aaa" {
    //反序列化消息中的载体
    payload = Core.FromJson(Message.Payload)
    //判断消息载体是否为空
    if isNil(payload) {
        println("parse error")
        return
    }
    //实例化一个map用于转换消息体格式
    res = Core.MakeMap()
    //把原消息的msg内容付值到新消息体的m键中
    res["m"] = payload["msg"]
    //序列化新的消息体为json
    reMsg = Core.ToJson(res)
    //传送序列化是否失败
    if isNil(reMsg) {
        println("format error")
        return
    }
    //打印序列化结果于服务端
    println(Core.String(reMsg))
    //实例化mqtt消息体
    newMsg = Core.MakeMessage()
    //设置新的接收主题
    newMsg.Topic = "bbb/#"
    //消息质量控制
    newMsg.QOS = 0
    newMsg.Retain = false
    //把新的载体付值到新消息载体中
    newMsg.Payload = reMsg
    //通过内核发布新消息
    err = Core.Publish(newMsg)
    if err != "" {
        println(err)
    }
  }
end'
```

#### 如下是消息转义后以提交到第三方http服务接口 curl示例

```
curl --location --request POST 'http://localhost:8081/v1/rules' \
--header 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOiJDUDciLCJleHAiOjE2MjE1NzcxMjEsImp0aSI6ImFkbWluIiwiaWF0IjoxNjIxNTY5OTIxLCJpc3MiOiJjb29scHkubmV0IiwibmJmIjoxNjIxNTY5OTIxfQ.cE1YusJXYQbrU2Pa9gl6gqqsf93rkHB4ePNiXuDSdeg' \
--header 'Content-Type: text/plain' \
--data-raw 'rule "rule1" "rule-describtion" salience  10
begin
  //过滤主题为aaa的消息才进行处理
  if Message.Topic == "aaa" {
    //反序列化消息中的载体
    payload = Core.FromJson(Message.Payload)
    //判断消息载体是否为空
    if isNil(payload) {
        println("parse error")
        return
    }
    //实例化一个map用于转换消息体格式
    res = Core.MakeMap()
    //把原消息的msg内容付值到新消息体的m键中
    res["m"] = payload["msg"]
    //序列化新的消息体为json
    reMsg = Core.ToJson(res)
    //传送序列化是否失败
    if isNil(reMsg) {
        println("format error")
        return
    }
    //打印序列化结果于服务端
    println(Core.String(reMsg))
    //通过http转发消息
    //实例化一个map用于转换消息体格式
    header = Core.MakeMap()
    header["Authorization"] = "Bearer " + "token"
    err = Core.Http("http://localhost:8081/v1/test","POST",header,reMsg,2)
    if err != "" {
        println("format error")
    }
  }
end'
```

返回值：

```
{
    "success": true,
    "data": {
        "rule_desc": "rule-describtion",
        "rule_name": "rule2",
        "salience": 1
    }
}
```

#### 删除一个规则 curl示例

```
curl --location --request DELETE 'http://localhost:8081/v1/rules/rule1' \
--header 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOiJDUDciLCJleHAiOjE2MjIwMzA5OTUsImp0aSI6ImFkbWluIiwiaWF0IjoxNjIyMDIzNzk1LCJpc3MiOiJjb29scHkubmV0IiwibmJmIjoxNjIyMDIzNzk1fQ.XeNnwyWWFR-Rz2hByigNQVvTvTuXR7nzFcl7O6fqleQ'
```

返回值：

```
{
    "success": true,
    "data": "rule1"
}
```

#### 获取前100个规则 curl示例

```
curl --location --request GET 'http://localhost:8081/v1/rules?limit=100' \
--header 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOiJDUDciLCJleHAiOjE2MjIwMzA5OTUsImp0aSI6ImFkbWluIiwiaWF0IjoxNjIyMDIzNzk1LCJpc3MiOiJjb29scHkubmV0IiwibmJmIjoxNjIyMDIzNzk1fQ.XeNnwyWWFR-Rz2hByigNQVvTvTuXR7nzFcl7O6fqleQ'
```

返回值：

```
{
    "success": true,
    "data": {
        "current": 0,
        "list": [
            "rule2"
        ],
        "pageSize": 100,
        "total": 1
    }
}
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://coolpy7.gitbook.io/coolpy7book/kai-shi-shi-yong/gui-ze-yin-qing.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
