PML 2 插件开发指南
内置函数
本文将介绍 PML 2 插件系统中条件与动作模板可用的内置函数与算术运算符。
一、内置函数概述
函数库是 PML 2 插件系统的重要组成部分。在编写插件时, 你可以在条件表达式和动作参数模板中直接调用内置函数, 对 ctx.data、ctx.variables 等上下文数据进行加工、计算与判断, 而无需编写任何代码。
内置函数由表达式求值器统一提供, 覆盖字符串与集合处理、数学运算、三角函数、日期时间操作等方面。函数名请统一使用小写书写, 参数按需取值, 支持字符串、数值与集合类型。
以下介绍中, 函数旁的版本标记表示该函数自对应版本及以上的 PML 2 中可用。请根据实际使用的 PML 2 版本选择合适的函数。
调用位置
内置函数可以出现在两类位置:
| 位置 | 写法 | 示例 |
|---|---|---|
条件表达式 (condition) | 直接书写表达式, 不使用 {{ }} | len(ctx.data.proxyName) > 0 -and upper(ctx.data.proxyName) -eq 'WEB' |
动作参数模板 (params) | 使用 {{ 表达式 }} 包裹, 一条字符串内可嵌入多个模板 | msg: "隧道 {{ctx.data.proxyName}} 已启动 (长度 {{len(ctx.data.proxyName)}})" |
如果函数名未知, 或参数个数 / 类型不合法, 表达式求值会抛出异常。插件引擎会将其记录为日志, 不会导致应用崩溃, 但该条触发器的本次执行会失败。请务必核对函数名与参数个数。
二、内置函数分类
| 分类 | 函数 |
|---|---|
| 字符串与集合函数 | len、lower、upper、coalesce |
| 数学函数 | abs、round、floor、ceil、sqrt、pow、min、max、ln、log10、log2、log |
| 三角函数 | sin、cos、tan、cot、sec、csc |
| 日期时间函数 | now、datetime.now.strftime |
三、内置函数详细介绍
1. 字符串与集合函数 26.3.1
| 函数名 | 参数 | 描述 | 用例 |
|---|---|---|---|
len(x) | x: 任意 | 返回长度或元素个数。null 返回 0; 字符串返回字符数; 集合返回元素个数; 其他类型返回其字符串表示的长度。 | len("abcd") 返回 4len(ctx.variables.list) 返回集合元素个数 |
lower(s) | s: 任意 | 转为字符串并转换为小写。null 返回空字符串。 | lower("Web") 返回 "web" |
upper(s) | s: 任意 | 转为字符串并转换为大写。null 返回空字符串。 | upper("Web") 返回 "WEB" |
coalesce(a, b, ...) | 1 个及以上 | 返回第一个既不为 null 也不为空字符串的参数; 若全部为空则返回 null。常用于为缺失字段提供默认值。 | coalesce(ctx.data.errorCategory, "timeout") 在字段缺失时返回 "timeout" |
len 对字符串与集合都有效, 因此可以用同一个函数判断隧道名长度或列表元素个数。2. 数学函数
min、max 自 26.3.1 起可用, 其余数学函数自 26.5 起可用。所有数学函数都要求参数能解析为数值, 否则会抛出异常。
| 函数名 | 参数 | 描述 | 用例 |
|---|---|---|---|
abs(x) | x: 数值 | 返回 x 的绝对值。 | abs(-5) 返回 5 |
round(x) | x: 数值 | 返回四舍六入五成双的结果 (银行家舍入, 即 .NET 默认的 MidpointRounding.ToEven)。 | round(4.5) 返回 4round(5.5) 返回 6 |
floor(x) | x: 数值 | 返回小于或等于 x 的最大整数。 | floor(4.9) 返回 4 |
ceil(x) | x: 数值 | 返回大于或等于 x 的最小整数。 | ceil(4.2) 返回 5 |
sqrt(x) | x: 数值 | 返回 x 的平方根。 | sqrt(9) 返回 3 |
pow(x, y) | x、y: 数值 | 返回 x 的 y 次方。 | pow(2, 10) 返回 1024 |
min(a, b, ...) | 2 个及以上数值 | 返回最小值。 | min(3, 5) 返回 3 |
max(a, b, ...) | 2 个及以上数值 | 返回最大值。 | max(3, 5) 返回 5 |
ln(x) | x: 数值 | 返回自然对数 (底数为 e)。 | ln(1) 返回 0 |
log10(x) | x: 数值 | 返回常用对数 (底数为 10)。 | log10(100) 返回 2 |
log2(x) | x: 数值 | 返回底数为 2 的对数。 | log2(8) 返回 3 |
log(x, base) | x、base: 数值 | 返回指定底数的对数, base 必须大于 0。 | log(8, 2) 返回 3 |
3. 三角函数 26.5
| 函数名 | 参数 | 描述 | 用例 |
|---|---|---|---|
sin(x) | x: 数值 | 返回正弦值。 | sin(0) 返回 0 |
cos(x) | x: 数值 | 返回余弦值。 | cos(0) 返回 1 |
tan(x) | x: 数值 | 返回正切值。 | tan(0) 返回 0 |
cot(x) | x: 数值 | 返回余切值, 即 1 / tan(x)。 | cot(1) |
sec(x) | x: 数值 | 返回正割值, 即 1 / cos(x)。 | sec(1) |
csc(x) | x: 数值 | 返回余割值, 即 1 / sin(x)。 | csc(1) |
三角函数参数默认采用角度制。若第二个参数传入
"true", 会以弧度制进行计算。求值前会先把参数中的 \pi 替换为圆周率 π 的数值, 便于书写含 π 的常量。4. 日期时间函数
now 自 26.3.1 起可用, datetime.now.strftime 自 26.5 起可用。
| 函数名 | 参数 | 描述 | 用例 |
|---|---|---|---|
now | 无 | 返回当前 UTC 时间的 Unix 时间戳 (秒)。 | now 返回 1759456000 |
datetime.now.strftime(format) | format (可选): 字符串 | 返回当前本地时间的格式化字符串; 省略 format 时使用 yyyy-MM-dd HH:mm:ss。 | datetime.now.strftime("yyyy/MM/dd") 返回 2026/10/03 |
datetime.now.strftime 的名称虽然包含 strftime, 但其格式化字符串遵循 .NET 的自定义日期和时间格式字符串, 不是 Python / C 的 strftime 语法。四、算术运算符
除了函数调用, PML 2 的表达式还支持算术运算, 并可用括号 () 改变优先级。算术运算符自 26.3.1 起可用。
| 运算符 | 说明 | 示例 |
|---|---|---|
+ | 加法, 计算左右两边的和。 | ctx.variables.count + 5 |
- | 减法, 计算左右两边的差。 | ctx.variables.count - 5 |
* | 乘法, 计算左右两边的积。 | ctx.variables.count * 5 |
/ | 除法, 计算左右两边的商 (浮点除法)。 | 5 / 2 返回 2.5 |
% | 取模, 计算左右两边的余数。 | 7 % 3 返回 1 |
** 或 ^ | 幂运算, 计算左边的值的右边的值次方。 | 2 ** 10 返回 1024 |
// | 整除, 计算左右两边的商的向下取整。 | 7 // 2 返回 3 |
算术运算符要求数值操作数; 若操作数为字符串, 会先尝试将其解析为数值, 解析失败则抛出异常。算术运算符与内置函数可以自由组合, 例如
max(len(ctx.data.proxyName), 3) * 2。五、完整示例
以下示例摘自官方示例插件 tech.rycb.plugin.demo-functions.yaml, 演示了内置函数与算术运算在条件表达式和动作参数模板中的用法:
triggers:
# 隧道名长度大于 0 且忽略大小写等于 web 时记录日志
- on: proxy.start
condition: "len(ctx.data.proxyName) > 0 -and upper(ctx.data.proxyName) -eq 'WEB'"
actions:
- name: log
params:
msg: "隧道 {{ctx.data.proxyName}} 已启动 (名称长度 {{len(ctx.data.proxyName)}})"
# 失败分类缺失时视为 timeout, 且重试次数不超过 3 次才通知
- on: proxy.failed
condition: "coalesce(ctx.data.errorCategory, 'timeout') -eq 'timeout' -and min(ctx.variables.retryCount, 3) -le 3"
actions:
- name: notify
params:
msg: "隧道 {{ctx.data.proxyName}} 失败: {{ctx.data.errorMessage}}"