' ============================================================
' A7P网络验证模块 - 易语言模块源码
' 对应Python示例: 卡密登录示例.py / 用户登录示例.py (API契约一比一对齐)
' API文档: https://docs.a7p.cn/api/
'
' 使用方法:
' 1. 打开易语言(5.9+), 文件→新建→"Windows易语言模块"
' 2. 把"模块程序集变量"粘贴到 程序集_模块; 把各"公开子程序"粘贴到程序集
' 3. 工具→支持库配置 勾选: 数据摘要支持库(取数据摘要用)
' 4. 编译 → 生成 A7P网络验证.ec
' 5. 主程序: 工具→模块引用→添加该 .ec, 即可直接调用下列公开命令
'
' 依赖说明:
' - MD5: 取数据摘要() 来自"数据摘要支持库"(dp1.fne, 易语言自带)
' - HTTP: MSXML2.XMLHTTP (系统组件, 同步模式, 超时10秒)
'
' 公开命令一览:
'   设置配置(APP_ID, APP_KEY)          ' 模块级配置, 控制台-产品设置获取
'   初始化握手() → 文本型               ' 返回 api_password; 失败返回空, 见 取最后错误()
'   发送请求(api_password, 明文) → 文本型   ' 低层: 返回原始JSON
'   取最新版本(api_password, 版本, 版本名称, 下载地址, 更新说明) → 逻辑型
'   取公告(api_password, 内容) → 逻辑型
'   卡密登录(api_password, 卡密, 机器码, 设备名, token, 用户名, 到期时间) → 逻辑型
'   用户登录(api_password, 用户名, 密码, token, 到期时间) → 逻辑型
'   用户注册(api_password, 用户名, 密码, 机器码, 到期时间) → 逻辑型
'   用户充值(api_password, 用户名, 卡密, 到期时间, 新增天数) → 逻辑型
'   修改密码(api_password, 用户名, 原密码, 新密码) → 逻辑型
'   换绑机器码(api_password, 用户名, 密码, 机器码, 新机器码) → 逻辑型
'   心跳(api_password, token, 后台消息) → 逻辑型
'   取JSON值(json, 键) → 文本型         ' 从原始JSON取字段值(自动解码\uXXXX)
'   取最后错误() → 文本型
'   RC4加密(key, data) → 文本型
'   取数据摘要(data) → 文本型           ' MD5 小写hex
'   获取机器码() → 文本型
'   取时间戳() → 长整数型
'   版本比较(版本A, 版本B) → 整数型      ' 1/-1/0, 分段数字逐段比较
' ============================================================

' ==================== 模块程序集变量 ====================
' .版本 2
'
' .程序集 程序集_模块
'
' -------- 配置区域 (请在控制台-产品设置获取你的AppId/AppKey) --------
' .程序集 变量 APP_ID, 文本型
' .程序集 变量 APP_KEY, 文本型
' .程序集 变量 BASE_URL, 文本型
'
' -------- 运行状态 --------
' .程序集 变量 last_error, 文本型

' ==================== 设置配置 ====================
' 子程序 设置配置, , 公开
'   .参数 新APP_ID, 文本型
'   .参数 新APP_KEY, 文本型
'   APP_ID ＝ 新APP_ID
'   APP_KEY ＝ 新APP_KEY
'   BASE_URL ＝ “https://www.a7p.cn/api/verify”
'   last_error ＝ “”

' ==================== 取最后错误 ====================
' 子程序 取最后错误, 文本型, 公开
'   返回 (last_error)

' ==================== RC4加密 ====================
' 子程序 RC4加密, 文本型, 公开
'   .参数 key, 文本型
'   .参数 data, 文本型
'   .局部变量 S, 整数型, , "256"
'   .局部变量 i, 整数型
'   .局部变量 j, 整数型
'   .局部变量 a, 整数型
'   .局部变量 t, 整数型
'   .局部变量 v, 整数型
'   .局部变量 kLen, 整数型
'   .局部变量 dLen, 整数型
'   .局部变量 hexStr, 文本型
'   .局部变量 kb, 字节集
'   .局部变量 db, 字节集
'
'   kb ＝ 到字节集 (key)
'   db ＝ 到字节集 (data)
'   kLen ＝ 取字节集长度 (kb)
'   dLen ＝ 取字节集长度 (db)
'   .如果真 (kLen ＝ 0 或 dLen ＝ 0)
'     返回 (“”)
'   .如果真结束
'   .计次循环首 (256, i)
'     S[i] ＝ i － 1
'   .计次循环尾 ()
'   j ＝ 0
'   .计次循环首 (256, i)
'     j ＝ (j ＋ S[i] ＋ 取字节集数据 (kb, #字节型, (i － 1) ％ kLen ＋ 1)) ％ 256
'     t ＝ S[i]
'     S[i] ＝ S[j]
'     S[j] ＝ t
'   .计次循环尾 ()
'   a ＝ 0
'   j ＝ 0
'   hexStr ＝ “”
'   .计次循环首 (dLen, i)
'     a ＝ (a ＋ 1) ％ 256
'     j ＝ (j ＋ S[a]) ％ 256
'     t ＝ S[a]
'     S[a] ＝ S[j]
'     S[j] ＝ t
'     v ＝ 位异或 (取字节集数据 (db, #字节型, i), S[(S[a] ＋ S[j]) ％ 256 ＋ 1])
'     hexStr ＝ hexStr ＋ 补文本 (取十六进制文本 (位与 (v, 255)), 2, “0”, 真)
'   .计次循环尾 ()
'   返回 (到大写 (hexStr))

' ==================== 取数据摘要 (MD5小写hex) ====================
' 子程序 取数据摘要, 文本型, 公开
'   .参数 data, 文本型
'   返回 (到小写 (取数据摘要 (到字节集 (data))))   ' 数据摘要支持库

' ==================== 获取机器码 ====================
' 子程序 获取机器码, 文本型, 公开
'   .局部变量 tmp, 文本型
'   .局部变量 out, 文本型
'   .局部变量 result, 文本型
'   .局部变量 pos, 整数型
'   tmp ＝ 取临时目录 () ＋ “a7p_mac.txt”
'   运行 (“cmd /c getmac /fo csv /nh > ” ＋ #引号 ＋ tmp ＋ #引号, 真, #隐藏窗口)
'   out ＝ 到文本 (读入文件 (tmp))
'   删除文件 (tmp)
'   .如果真 (取文本长度 (out) ＜ 2)
'     返回 (“00:00:00:00:00:00”)
'   .如果真结束
'   pos ＝ 寻找文本 (out, “,”, , 假)
'   .如果真 (pos ＝ 0)
'     返回 (“00:00:00:00:00:00”)
'   .如果真结束
'   result ＝ 取文本左边 (out, pos － 1)
'   result ＝ 替换文本 (result, #引号, “”, , , 假)
'   result ＝ 替换文本 (result, “-”, “:”, , , 假)
'   返回 (到大写 (result))

' ==================== 取时间戳(秒) ====================
' 子程序 取时间戳, 长整数型, 公开
'   返回 (取日期时间差 (日期 (1970, 1, 1), 取现行时间 (), #秒))

' ==================== HTTP POST ====================
' 子程序 HttpPost, 文本型
'   .参数 url, 文本型
'   .参数 body, 文本型
'   .局部变量 http, 对象
'   .局部变量 result, 文本型
'   result ＝ “”
'   .如果真 (取文本长度 (url) ＝ 0 或 取文本长度 (body) ＝ 0)
'     返回 (“”)
'   .如果真结束
'   http ＝ 创建对象 (“MSXML2.XMLHTTP”)
'   http.写属性 (“timeout”, 10000)   ' 超时10秒
'   http.方法 (“open”, “POST”, url, 假)   ' 同步模式
'   http.方法 (“setRequestHeader”, “Content-Type”, “application/x-www-form-urlencoded”)
'   http.方法 (“send”, body)
'   .如果真 (http.读属性 (“status”) ＝ 200)
'     result ＝ http.读属性 (“responseText”)
'   .如果真结束
'   http.释放 ()
'   返回 (result)

' ==================== 取JSON值 ====================
' 子程序 取JSON值, 文本型, 公开
'   .参数 json, 文本型
'   .参数 key, 文本型
'   .局部变量 search, 文本型
'   .局部变量 pos, 整数型
'   .局部变量 start, 整数型
'   .局部变量 i, 整数型
'   .局部变量 ch, 文本型
'   .局部变量 value, 文本型
'   search ＝ #引号 ＋ key ＋ #引号 ＋ “:”
'   pos ＝ 寻找文本 (json, search, , 假)
'   .如果真 (pos ＝ 0)
'     返回 (“”)
'   .如果真结束
'   pos ＝ pos ＋ 取文本长度 (search)
'   .判断循环首 (pos ≤ 取文本长度 (json) 且 (取文本中间 (json, pos, 1) ＝ “ ” 或 取文本中间 (json, pos, 1) ＝ #制表符))
'     pos ＝ pos ＋ 1
'   .判断循环尾 ()
'   ch ＝ 取文本中间 (json, pos, 1)
'   .如果 (ch ＝ #引号)
'     pos ＝ pos ＋ 1
'     start ＝ pos
'     i ＝ pos
'     .判断循环首 (i ≤ 取文本长度 (json))
'       ch ＝ 取文本中间 (json, i, 1)
'       .如果真 (ch ＝ “\”)
'         i ＝ i ＋ 2
'         到循环尾 ()
'       .如果真结束
'       .如果真 (ch ＝ #引号)
'         跳出循环
'       .如果真结束
'       i ＝ i ＋ 1
'     .判断循环尾 ()
'     .如果 (i ＞ start)
'       value ＝ 取文本中间 (json, start, i － start)
'     .如果结束
'     返回 (解码JSON文本 (value))
'   .否则
'     start ＝ pos
'     i ＝ pos
'     .判断循环首 (i ≤ 取文本长度 (json))
'       ch ＝ 取文本中间 (json, i, 1)
'       .如果真 (ch ＝ “,” 或 ch ＝ “}” 或 ch ＝ “]” 或 ch ＝ “ ”)
'         跳出循环
'       .如果真结束
'       i ＝ i ＋ 1
'     .判断循环尾 ()
'     返回 (取文本中间 (json, start, i － start))
'   .如果结束

' ==================== JSON解码 (\uXXXX → 字符) ====================
' 子程序 解码JSON文本, 文本型
'   .参数 s, 文本型
'   .局部变量 i, 整数型
'   .局部变量 ch, 文本型
'   .局部变量 out, 文本型
'   i ＝ 1
'   out ＝ “”
'   .判断循环首 (i ≤ 取文本长度 (s))
'     ch ＝ 取文本中间 (s, i, 1)
'     .如果 (ch ＝ “\” 且 取文本中间 (s, i ＋ 1, 1) ＝ “u”)
'       out ＝ out ＋ 字符 (到整数 (“&H” ＋ 取文本中间 (s, i ＋ 2, 4)))
'       i ＝ i ＋ 6
'     .否则
'       out ＝ out ＋ ch
'       i ＝ i ＋ 1
'     .如果结束
'   .判断循环尾 ()
'   返回 (out)

' ==================== 版本比较(分段数字逐段比较) ====================
' 子程序 版本比较, 整数型, 公开
'   .参数 版本A, 文本型
'   .参数 版本B, 文本型
'   .局部变量 la, 文本型, , "0"
'   .局部变量 lb, 文本型, , "0"
'   .局部变量 i, 整数型
'   .局部变量 na, 整数型
'   .局部变量 nb, 整数型
'   .局部变量 max, 整数型
'   分割文本 (版本A, “.”, la)
'   分割文本 (版本B, “.”, lb)
'   max ＝ 取数组成员数 (la)
'   .如果真 (取数组成员数 (lb) ＞ max)
'     max ＝ 取数组成员数 (lb)
'   .如果真结束
'   .计次循环首 (max, i)
'     na ＝ 0
'     nb ＝ 0
'     .如果真 (i ≤ 取数组成员数 (la))
'       na ＝ 到整数 (la[i])
'     .如果真结束
'     .如果真 (i ≤ 取数组成员数 (lb))
'       nb ＝ 到整数 (lb[i])
'     .如果真结束
'     .如果 (na ＞ nb)
'       返回 (1)
'     .否则
'       .如果真 (na ＜ nb)
'         返回 (-1)
'       .如果真结束
'     .如果结束
'   .计次循环尾 ()
'   返回 (0)

' ==================== 构建API请求体 ====================
' 子程序 BuildApiBody, 文本型
'   .参数 apiPwd, 文本型
'   .参数 plain, 文本型
'   .局部变量 ts, 长整数型
'   .局部变量 enc, 文本型
'   .局部变量 sign, 文本型
'   ts ＝ 取时间戳 ()
'   enc ＝ RC4加密 (apiPwd, plain)
'   sign ＝ 取数据摘要 (apiPwd ＋ 到文本 (ts) ＋ enc)
'   返回 (“TimeStamp=” ＋ 到文本 (ts) ＋ “&Sign=” ＋ sign ＋ “&Data=” ＋ enc)

' ==================== 初始化握手请求 ====================
' 子程序 InitRequest, 文本型
'   .局部变量 ts, 长整数型
'   .局部变量 sign, 文本型
'   .局部变量 body, 文本型
'   ts ＝ 取时间戳 ()
'   sign ＝ 取数据摘要 (APP_ID ＋ APP_KEY ＋ 到文本 (ts) ＋ APP_KEY)
'   body ＝ “AppId=” ＋ APP_ID ＋ “&AppKey=” ＋ APP_KEY ＋ “&TimeStamp=” ＋ 到文本 (ts) ＋ “&Sign=” ＋ sign
'   返回 (HttpPost (BASE_URL, body))

' ==================== 初始化握手 ====================
' 子程序 初始化握手, 文本型, 公开
'   .局部变量 result, 文本型
'   result ＝ InitRequest ()
'   .如果真 (取文本长度 (result) ＝ 0)
'     last_error ＝ “请求失败: 网络错误或超时”
'     返回 (“”)
'   .如果真结束
'   .如果 (到整数 (取JSON值 (result, “code”)) ＝ 200)
'     last_error ＝ “”
'     返回 (取JSON值 (result, “api_password”))
'   .否则
'     last_error ＝ 取JSON值 (result, “message”)
'     .如果真 (last_error ＝ “”)
'       last_error ＝ “未知错误”
'     .如果真结束
'     返回 (“”)
'   .如果结束

' ==================== 发送请求(低层, 返回原始JSON) ====================
' 子程序 发送请求, 文本型, 公开
'   .参数 api_password, 文本型
'   .参数 plain, 文本型
'   .局部变量 result, 文本型
'   result ＝ HttpPost (BASE_URL ＋ “/” ＋ api_password, BuildApiBody (api_password, plain))
'   .如果真 (取文本长度 (result) ＝ 0)
'     last_error ＝ “请求失败: 网络错误或超时”
'   .如果真结束
'   返回 (result)

' ==================== 取最新版本 ====================
' 子程序 取最新版本, 逻辑型, 公开
'   .参数 api_password, 文本型
'   .参数 版本, 文本型, 参考
'   .参数 版本名称, 文本型, 参考
'   .参数 下载地址, 文本型, 参考
'   .参数 更新说明, 文本型, 参考
'   .局部变量 result, 文本型
'   result ＝ 发送请求 (api_password, “action=GetLatestVersion”)
'   .如果真 (取文本长度 (result) ＝ 0)
'     返回 (假)
'   .如果真结束
'   .如果 (到整数 (取JSON值 (result, “code”)) ＝ 200)
'     版本 ＝ 取JSON值 (result, “version”)
'     版本名称 ＝ 取JSON值 (result, “version_name”)
'     下载地址 ＝ 取JSON值 (result, “download_url”)
'     更新说明 ＝ 取JSON值 (result, “version_data”)
'     last_error ＝ “”
'     返回 (真)
'   .否则
'     last_error ＝ 取JSON值 (result, “message”)
'     返回 (假)
'   .如果结束

' ==================== 取公告 ====================
' 子程序 取公告, 逻辑型, 公开
'   .参数 api_password, 文本型
'   .参数 内容, 文本型, 参考
'   .局部变量 result, 文本型
'   result ＝ 发送请求 (api_password, “action=GetBulletin”)
'   .如果真 (取文本长度 (result) ＝ 0)
'     返回 (假)
'   .如果真结束
'   .如果 (到整数 (取JSON值 (result, “code”)) ＝ 200)
'     内容 ＝ 取JSON值 (result, “content”)
'     last_error ＝ “”
'     返回 (真)
'   .否则
'     last_error ＝ 取JSON值 (result, “message”)
'     返回 (假)
'   .如果结束

' ==================== 卡密登录 ====================
' 子程序 卡密登录, 逻辑型, 公开
'   .参数 api_password, 文本型
'   .参数 卡密, 文本型
'   .参数 机器码, 文本型
'   .参数 设备名, 文本型
'   .参数 token, 文本型, 参考
'   .参数 用户名, 文本型, 参考
'   .参数 到期时间, 文本型, 参考
'   .局部变量 result, 文本型
'   result ＝ 发送请求 (api_password, “action=SingleLogin&Card=” ＋ 卡密 ＋ “&Mac=” ＋ 机器码 ＋ “&DeviceName=” ＋ 设备名)
'   .如果真 (取文本长度 (result) ＝ 0)
'     返回 (假)
'   .如果真结束
'   .如果 (到整数 (取JSON值 (result, “code”)) ＝ 200)
'     token ＝ 取JSON值 (result, “token”)
'     用户名 ＝ 取JSON值 (result, “username”)
'     到期时间 ＝ 取JSON值 (result, “expire_at”)
'     last_error ＝ “”
'     返回 (真)
'   .否则
'     last_error ＝ 取JSON值 (result, “message”)
'     .如果真 (last_error ＝ “”)
'       last_error ＝ “登录失败”
'     .如果真结束
'     返回 (假)
'   .如果结束

' ==================== 用户登录 ====================
' 子程序 用户登录, 逻辑型, 公开
'   .参数 api_password, 文本型
'   .参数 用户名, 文本型
'   .参数 密码, 文本型
'   .参数 token, 文本型, 参考
'   .参数 到期时间, 文本型, 参考
'   .局部变量 result, 文本型
'   result ＝ 发送请求 (api_password, “action=UserLogin&UserName=” ＋ 用户名 ＋ “&Password=” ＋ 密码)
'   .如果真 (取文本长度 (result) ＝ 0)
'     返回 (假)
'   .如果真结束
'   .如果 (到整数 (取JSON值 (result, “code”)) ＝ 200)
'     token ＝ 取JSON值 (result, “token”)
'     到期时间 ＝ 取JSON值 (result, “expire_at”)
'     last_error ＝ “”
'     返回 (真)
'   .否则
'     last_error ＝ 取JSON值 (result, “message”)
'     .如果真 (last_error ＝ “”)
'       last_error ＝ “登录失败”
'     .如果真结束
'     返回 (假)
'   .如果结束

' ==================== 用户注册 ====================
' 子程序 用户注册, 逻辑型, 公开
'   .参数 api_password, 文本型
'   .参数 用户名, 文本型
'   .参数 密码, 文本型
'   .参数 机器码, 文本型
'   .参数 到期时间, 文本型, 参考
'   .局部变量 result, 文本型
'   result ＝ 发送请求 (api_password, “action=UserRegin&UserName=” ＋ 用户名 ＋ “&Password=” ＋ 密码 ＋ “&Mac=” ＋ 机器码)
'   .如果真 (取文本长度 (result) ＝ 0)
'     返回 (假)
'   .如果真结束
'   .如果 (到整数 (取JSON值 (result, “code”)) ＝ 200)
'     到期时间 ＝ 取JSON值 (result, “expire_at”)
'     last_error ＝ “”
'     返回 (真)
'   .否则
'     last_error ＝ 取JSON值 (result, “message”)
'     .如果真 (last_error ＝ “”)
'       last_error ＝ “注册失败”
'     .如果真结束
'     返回 (假)
'   .如果结束

' ==================== 用户充值 ====================
' 子程序 用户充值, 逻辑型, 公开
'   .参数 api_password, 文本型
'   .参数 用户名, 文本型
'   .参数 卡密, 文本型
'   .参数 到期时间, 文本型, 参考
'   .参数 新增天数, 文本型, 参考
'   .局部变量 result, 文本型
'   result ＝ 发送请求 (api_password, “action=UserRecharge&UserName=” ＋ 用户名 ＋ “&Card=” ＋ 卡密)
'   .如果真 (取文本长度 (result) ＝ 0)
'     返回 (假)
'   .如果真结束
'   .如果 (到整数 (取JSON值 (result, “code”)) ＝ 200)
'     到期时间 ＝ 取JSON值 (result, “expire_at”)
'     新增天数 ＝ 取JSON值 (result, “added_days”)
'     last_error ＝ “”
'     返回 (真)
'   .否则
'     last_error ＝ 取JSON值 (result, “message”)
'     .如果真 (last_error ＝ “”)
'       last_error ＝ “充值失败”
'     .如果真结束
'     返回 (假)
'   .如果结束

' ==================== 修改密码 ====================
' 子程序 修改密码, 逻辑型, 公开
'   .参数 api_password, 文本型
'   .参数 用户名, 文本型
'   .参数 原密码, 文本型
'   .参数 新密码, 文本型
'   .局部变量 result, 文本型
'   result ＝ 发送请求 (api_password, “action=UpdatePwd&UserName=” ＋ 用户名 ＋ “&OldPassword=” ＋ 原密码 ＋ “&NewPassword=” ＋ 新密码)
'   .如果真 (取文本长度 (result) ＝ 0)
'     返回 (假)
'   .如果真结束
'   .如果 (到整数 (取JSON值 (result, “code”)) ＝ 200)
'     last_error ＝ “”
'     返回 (真)
'   .否则
'     last_error ＝ 取JSON值 (result, “message”)
'     .如果真 (last_error ＝ “”)
'       last_error ＝ “修改失败”
'     .如果真结束
'     返回 (假)
'   .如果结束

' ==================== 换绑机器码 ====================
' 子程序 换绑机器码, 逻辑型, 公开
'   .参数 api_password, 文本型
'   .参数 用户名, 文本型
'   .参数 密码, 文本型
'   .参数 机器码, 文本型
'   .参数 新机器码, 文本型, 参考
'   .局部变量 result, 文本型
'   result ＝ 发送请求 (api_password, “action=ChangeBind&UserName=” ＋ 用户名 ＋ “&Password=” ＋ 密码 ＋ “&Mac=” ＋ 机器码)
'   .如果真 (取文本长度 (result) ＝ 0)
'     返回 (假)
'   .如果真结束
'   .如果 (到整数 (取JSON值 (result, “code”)) ＝ 200)
'     新机器码 ＝ 取JSON值 (result, “device_id”)
'     last_error ＝ “”
'     返回 (真)
'   .否则
'     last_error ＝ 取JSON值 (result, “message”)
'     .如果真 (last_error ＝ “”)
'       last_error ＝ “换绑失败”
'     .如果真结束
'     返回 (假)
'   .如果结束

' ==================== 心跳 ====================
' 子程序 心跳, 逻辑型, 公开
'   .参数 api_password, 文本型
'   .参数 token, 文本型
'   .参数 后台消息, 文本型, 参考
'   .局部变量 result, 文本型
'   result ＝ 发送请求 (api_password, “action=UserHeartbeat&Token=” ＋ token ＋ “&Type=user”)
'   .如果真 (取文本长度 (result) ＝ 0)
'     返回 (假)
'   .如果真结束
'   .如果 (到整数 (取JSON值 (result, “code”)) ＝ 200)
'     后台消息 ＝ 取JSON值 (result, “msg”)
'     last_error ＝ “”
'     返回 (真)
'   .否则
'     last_error ＝ 取JSON值 (result, “message”)
'     .如果真 (last_error ＝ “”)
'       last_error ＝ “未知”
'     .如果真结束
'     返回 (假)
'   .如果结束
