|
@@ -15,6 +15,7 @@ type ParserService interface {
|
|
|
ParseAlert(html string) (message string, err error)
|
|
|
GetRuleId(ctx context.Context, htmlBytes []byte) (string, error)
|
|
|
ParseSDKOnlineHTMLTable(htmlContent string) ([]v1.SDKInfo, error)
|
|
|
+ CheckSDKKeyStatus(htmlData string, sdkKeyToFind string) error
|
|
|
}
|
|
|
|
|
|
func NewParserService(
|
|
@@ -198,3 +199,72 @@ func extractFromComplexText(text string) string {
|
|
|
}
|
|
|
return "查看"
|
|
|
}
|
|
|
+
|
|
|
+// CheckSDKKeyStatus 检查SDKKey是否存在且过期
|
|
|
+func (s *parserService) CheckSDKKeyStatus(htmlData string, sdkKeyToFind string) error {
|
|
|
+ // 使用 strings.NewReader 将字符串转换为一个 io.Reader,这是 go-query 所需的输入格式。
|
|
|
+ // go-query 会加载并解析这个HTML,返回一个可供查询的文档对象(doc)。
|
|
|
+ doc, err := goquery.NewDocumentFromReader(strings.NewReader(htmlData))
|
|
|
+ if err != nil {
|
|
|
+ // 如果go-query无法加载或解析HTML,则返回错误。
|
|
|
+ return fmt.Errorf("无法解析HTML: %w", err)
|
|
|
+ }
|
|
|
+
|
|
|
+ // 定义两个变量用于在循环结束后判断状态
|
|
|
+ var keyFound bool = false // 标记是否找到了Key
|
|
|
+ var resultErr error = nil // 用于存储找到Key后的最终错误状态(如果是过期的话)
|
|
|
+
|
|
|
+ // 使用go-query的选择器找到class为 "table" 的表格(table.table)的主体(tbody)中的所有行(tr)。
|
|
|
+ // .EachWithBreak 方法会遍历每一行,并允许我们在满足特定条件时提前中断循环。
|
|
|
+ doc.Find("table.table tbody tr").EachWithBreak(func(i int, row *goquery.Selection) bool {
|
|
|
+ // 在当前行(row)中,查找第7个单元格(td:nth-of-type(7)),这是“SDK启动KEY”所在的列。
|
|
|
+ // Key本身被隐藏在一个 <pre> 标签内,我们直接定位它。
|
|
|
+ keyCell := row.Find("td:nth-of-type(7) pre")
|
|
|
+ fullKeyText := keyCell.Text() // 获取 <pre> 标签内的所有文本内容。
|
|
|
+
|
|
|
+ // 原始文本的格式是固定的,我们需要从中提取出真正的KEY。
|
|
|
+ // 格式: "原始内容:... >>> SDK启动KEY如下,复制后启动SDK使用 <<< [THE_ACTUAL_KEY]"
|
|
|
+ parts := strings.Split(fullKeyText, ">>> SDK启动KEY如下,复制后启动SDK使用 <<<")
|
|
|
+ if len(parts) < 2 {
|
|
|
+ // 如果当前行不符合这个格式,跳到下一行处理。
|
|
|
+ return true // `true` 在 EachWithBreak 中表示继续循环
|
|
|
+ }
|
|
|
+
|
|
|
+ // 提取并清理KEY字符串,去掉它前后的所有空格和换行符。
|
|
|
+ extractedKey := strings.TrimSpace(parts[1])
|
|
|
+ // 检查从页面提取出的KEY是否与我们要找的KEY相匹配。
|
|
|
+ if extractedKey == sdkKeyToFind {
|
|
|
+ keyFound = true // 首先,标记我们已经找到了Key
|
|
|
+ // 接着,在同一行中查找过期状态。
|
|
|
+ // 第11个单元格(td:nth-of-type(11))包含“过期时间”信息。
|
|
|
+ expirationCell := row.Find("td:nth-of-type(11)")
|
|
|
+ expirationText := expirationCell.Text() // 获取该单元格的文本内容。
|
|
|
+
|
|
|
+ // 检查过期时间文本中是否包含`(已过期)`
|
|
|
+ if strings.Contains(expirationText, "(已过期)") {
|
|
|
+ // 如果包含,我们将错误信息赋值给外部的 resultErr 变量
|
|
|
+ resultErr = fmt.Errorf("该KEY已过期")
|
|
|
+ }
|
|
|
+ // 注意:即使未过期,resultErr 仍然是 nil,这正是我们想要的结果。
|
|
|
+
|
|
|
+ // 我们已经找到了目标并处理完毕,没有必要再检查剩下的行了。
|
|
|
+ return false // `false` 在 EachWithBreak 中表示中断循环
|
|
|
+ }
|
|
|
+
|
|
|
+ // 如果当前行的KEY不匹配,继续下一行的查找。
|
|
|
+ return true
|
|
|
+ })
|
|
|
+
|
|
|
+ // --- 循环结束后的最终判断 ---
|
|
|
+
|
|
|
+ // 如果 keyFound 标志位仍然是 false,说明遍历了所有行都没有找到匹配的Key。
|
|
|
+ if !keyFound {
|
|
|
+ return fmt.Errorf("未找到指定的Key")
|
|
|
+ }
|
|
|
+
|
|
|
+ // 如果 keyFound 是 true,说明找到了Key。
|
|
|
+ // 此时,我们返回在循环中确定的 resultErr。
|
|
|
+ // - 如果Key未过期,resultErr 就是它初始的 nil 值。
|
|
|
+ // - 如果Key已过期,resultErr 就是我们在循环里设置的那个 error。
|
|
|
+ return resultErr
|
|
|
+}
|