经过和chatGPT多次友好耐心的沟通,终于把这个脚本写好了。
使用的是ChatGPT-o1-preview,还不能全信它,还是要看看代码的,否则它会一个问题里打转,永远出不来。
# 定义要监测的接口名称 :local interfaceName "wireguard1-usa5-ros2" :log info "脚本开始执行,监测接口:$interfaceName" # 定义 Kuma ID 变量 :local kumaID "3333333" # 处理接口名称,移除文件名中不支持的字符(如空格、斜杠等) :local sanitizedInterfaceName "" :for i from=0 to=([:len $interfaceName] - 1) do={ :local char [:pick $interfaceName $i] :if ($char ~ "[a-zA-Z0-9_-]") do={ :set sanitizedInterfaceName ($sanitizedInterfaceName . $char) } else={ :set sanitizedInterfaceName ($sanitizedInterfaceName . "_") } } :log info "处理后的接口名称:$sanitizedInterfaceName" # 定义输出文件名,使用接口名称区分 :local outputFileName ("ping_output_" . $sanitizedInterfaceName . ".txt") :local ipID [/ip address find interface=$interfaceName] :if ($ipID != "") do={ # 获取 IP 地址并去掉子网掩码部分 :local ipAddress [/ip address get $ipID address] :set ipAddress [:pick $ipAddress 0 [:find $ipAddress "/"]] :log info "获取到 IP 地址:$ipAddress" # 解析 IP 地址的各个部分 :local pos1 [:find $ipAddress "."] :local pos2 [:find $ipAddress "." ($pos1 + 1)] :local pos3 [:find $ipAddress "." ($pos2 + 1)] # 检查是否成功找到三个点的位置 :if (($pos1 != "") && ($pos2 != "") && ($pos3 != "")) do={ # 提取每个八位组 :local octet1 [:pick $ipAddress 0 $pos1] :local octet2 [:pick $ipAddress ($pos1 + 1) $pos2] :local octet3 [:pick $ipAddress ($pos2 + 1) $pos3] # 将对端 IP 的最后一个八位组设置为 1 :local octet4 "1" # 构建对端 IP 地址 :local peerIP ($octet1 . "." . $octet2 . "." . $octet3 . "." . $octet4) :log info "构建对端 IP 地址:$peerIP" :log info "正在 Ping 对端 IP $peerIP" # 定义 Ping 参数 :local pingCount 10 :local maxLossPercent 50 # 执行 Ping 命令并将输出保存到唯一的文件 :log info "开始执行 Ping 命令,输出文件:$outputFileName" :execute "/ping $peerIP count=$pingCount" file=$outputFileName :log info "Ping 命令已启动" # 等待 Ping 命令完成 :delay ($pingCount * 1s) :log info "等待 Ping 命令完成" # 检查是否生成了输出文件 :if ([/file find name=$outputFileName] != "") do={ :log info "成功生成 $outputFileName 文件" # 读取 Ping 输出文件的内容 :local pingOutput [/file get [find name=$outputFileName] contents] :log info "读取 $outputFileName 文件内容" # 删除临时文件 /file remove $outputFileName :log info "删除临时文件 $outputFileName" # 输出 pingOutput 内容到日志,供调试使用 #:log info "Ping Output:\n$pingOutput" # 初始化变量 :local sent "" :local received "" :local packetLoss "" :local avgRtt 0 # 将 pingOutput 按行分割为数组 :local lines [:toarray ""] :local line "" :local lineEnd 0 :while ([:len $pingOutput] > 0) do={ :set lineEnd [:find $pingOutput "\r\n"] :if ($lineEnd = -1) do={ :set line $pingOutput :set pingOutput "" } else={ :set line [:pick $pingOutput 0 $lineEnd] :set pingOutput [:pick $pingOutput ($lineEnd + 2) [:len $pingOutput]] } :if ([:len $line] > 0) do={ :set lines ($lines, $line) } } # 检查是否包含 "max-rtt" :local containsMaxRtt false :foreach l in=$lines do={ :if ([:find $l "max-rtt="] != -1) do={ :set containsMaxRtt true } } :log info "Ping 输出是否包含 'max-rtt=':$containsMaxRtt" # 获取统计信息行 :local summaryLine "" :if ($containsMaxRtt) do={ # 取最后两行合并 :local lineCount [:len $lines] :if ($lineCount >= 2) do={ :set summaryLine (($lines->($lineCount - 2)) . " " . ($lines->($lineCount - 1))) :log info "合并最后两行为统计信息行:$summaryLine" } else={ :log error "Ping 输出行数不足,无法获取统计信息" } } else={ # 取最后一行 :local lineCount [:len $lines] :if ($lineCount >= 1) do={ :set summaryLine ($lines->($lineCount - 1)) :log info "使用最后一行为统计信息行:$summaryLine" } else={ :log error "Ping 输出行数不足,无法获取统计信息" } } # 检查是否获取到统计信息行 :if ([:len $summaryLine] > 0) do={ # 提取 sent :local sentPos [:find $summaryLine "sent="] :local sentEnd [:find $summaryLine " " ($sentPos + 5)] :if ($sentEnd = -1) do={ :set sentEnd [:len $summaryLine] } :local sentStr [:pick $summaryLine ($sentPos + 5) $sentEnd] :set sent [:tonum $sentStr] :log info "解析到 sent=$sent" # 提取 received :local recvPos [:find $summaryLine "received="] :local recvEnd [:find $summaryLine " " ($recvPos + 9)] :if ($recvEnd = -1) do={ :set recvEnd [:len $summaryLine] } :local recvStr [:pick $summaryLine ($recvPos + 9) $recvEnd] :set received [:tonum $recvStr] :log info "解析到 received=$received" # 提取 packet-loss :local lossPos [:find $summaryLine "packet-loss="] :local lossEnd [:find $summaryLine "%" ($lossPos + 12)] :if ($lossEnd = -1) do={ :set lossEnd [:len $summaryLine] } :local lossStr [:pick $summaryLine ($lossPos + 12) $lossEnd] :set packetLoss [:tonum $lossStr] :log info "解析到 packetLoss=$packetLoss" # 提取 avg-rtt :local avgPos [:find $summaryLine "avg-rtt="] :if ($avgPos != -1) do={ :local avgEnd [:find $summaryLine " " ($avgPos + 8)] :if ($avgEnd = -1) do={ :set avgEnd [:len $summaryLine] } :local avgRttStr [:pick $summaryLine ($avgPos + 8) $avgEnd] :log info "解析到 avgRttStr=$avgRttStr" # 将 avgRttStr 转换为毫秒数 # 处理类似于 "166ms277us" 的字符串 :local msPos [:find $avgRttStr "ms"] :local usPos [:find $avgRttStr "us"] :local msValue 0 :local usValue 0 :if ($msPos != -1) do={ :set msValue [:tonum [:pick $avgRttStr 0 $msPos]] } :if ($usPos != -1) do={ :set usValue [:tonum [:pick $avgRttStr ($msPos + 2) $usPos]] } :set avgRtt ($msValue + ($usValue / 1000)) :log info "解析到 avgRtt=$avgRtt ms" } else={ :set avgRtt 0 :log warning "未能解析到 avg-rtt" } # 判断并提交到 Kuma :if ($packetLoss < $maxLossPercent) do={ :log info "Ping 成功,丢包率=$packetLoss%,平均 RTT: $avgRtt ms" :local msg ("PingOK_Loss" . $packetLoss . "%") :log info "提交结果到 Kuma:状态=up,消息=$msg,ping=$avgRtt" /tool fetch url=("http://kuma2.ffffff.com:3001/api/push/" . $kumaID . "?status=up&msg=" . $msg . "&ping=" . $avgRtt) keep-result=no } else={ :log error "Ping 失败,丢包率=$packetLoss%" :log info "状态为 down,不向 Kuma 提交结果" } } else={ :log error "未获取到统计信息行,Ping 失败" :log info "状态为 down,不向 Kuma 提交结果" } } else={ :log error "未生成 $outputFileName 文件,Ping 命令可能失败" } } else={ :log error "无法解析 IP 地址 $ipAddress" } } else={ :log error "接口 $interfaceName 未分配 IP 地址" } :log info "脚本执行完毕"