提交 0e712744 authored 作者: 张孟夏's avatar 张孟夏

修改1.1不兼容的用例,调整grpc客户端代码

上级 d48f651e
......@@ -13,7 +13,7 @@ ${path} /api/system/config/client
log ${content}
Should Be Equal As Strings ${content["code"]} 200
Should Be Equal As Strings ${content["message"]} 成功
Should Be Equal As Strings ${content["data"]} {\"grpc_host\":\"192.168.110.211:9090\",\"grpc_use_ssl\":false}
Should Contain ${content["data"]} \"grpc_host\":\"192.168.110.211:9090\",\"grpc_use_ssl\":false
反例-不传入token
[Tags] E
......@@ -22,7 +22,7 @@ ${path} /api/system/config/client
log ${content}
Should Be Equal As Strings ${content["code"]} 200
Should Be Equal As Strings ${content["message"]} 成功
Should Be Equal As Strings ${content["data"]} {\"grpc_host\":\"192.168.110.211:9090\",\"grpc_use_ssl\":false}
Should Contain ${content["data"]} \"grpc_host\":\"192.168.110.211:9090\",\"grpc_use_ssl\":false
反例-传入错误的token
[Tags] E
......@@ -31,4 +31,4 @@ ${path} /api/system/config/client
log ${content}
Should Be Equal As Strings ${content["code"]} 200
Should Be Equal As Strings ${content["message"]} 成功
Should Be Equal As Strings ${content["data"]} {\"grpc_host\":\"192.168.110.211:9090\",\"grpc_use_ssl\":false}
Should Contain ${content["data"]} \"grpc_host\":\"192.168.110.211:9090\",\"grpc_use_ssl\":false
......@@ -4,6 +4,7 @@ Resource res_zmx.resource
*** Variables ***
${path} /api/chat/write
${uploadpath} /api/file-ref/upload
${jpg_file} testpicture.jpg
${gif_file} testpicture.gif
${jpeg_file} testpicture.jpeg
......@@ -16,12 +17,13 @@ ${md_file} testfile.md
${txt_file} testfile.txt
${xls_file} testfile.xls
${xlsx_file} testfile.xlsx
${clientId} a68ad587830d41aebf418a919006353e
*** Test Cases ***
正例-正常发送文字消息
[Tags] F
create session URI ${URL}
${content} POST请求结果_PARAMS ${path} {"sessionId":"${sessionId}","text":"你好"} 200 ${token}
${content} POST请求结果_PARAMS ${path} {"sessionId":"${sessionId}","text":"你好","workerId":"${clientId}"} 200 ${token}
log ${content}
Should Be Equal As Strings ${content["code"]} 200
Should Be Equal As Strings ${content["message"]} 成功
......@@ -33,23 +35,18 @@ ${xlsx_file} testfile.xlsx
${file} Evaluate (r'${jpg_file}', open(r'${CURDIR}${/}testfiles${/}${jpg_file}', 'rb'))
${data} Create Dictionary sessionId=${sessionId}
${header} Create Dictionary Authorization=${token}
${files} Create Dictionary files=${file}
${resp} Post On Session URI ${path} files=${files} data=${data} headers=${header}
${files} Create Dictionary file=${file}
${resp} Post On Session URI ${uploadpath} files=${files} data=${data} headers=${header}
${content} Set Variable ${resp.json()}
log ${content}
Should Be Equal As Strings ${content["code"]} 200
Should Be Equal As Strings ${content["message"]} 成功
Set Global Variable ${jpg_streamId} ${content["data"]}
Set Global Variable ${jpg_streamId} ${content["data"]["id"]}
正例-正常发送jpg+文字消息
[Tags] F
create session URI ${URL}
${file} Evaluate (r'${jpg_file}', open(r'${CURDIR}${/}testfiles${/}${jpg_file}', 'rb'))
${data} Create Dictionary sessionId=${sessionId} text="这张图是什么格式"
${header} Create Dictionary Authorization=${token}
${files} Create Dictionary files=${file}
${resp} Post On Session URI ${path} files=${files} data=${data} headers=${header}
${content} Set Variable ${resp.json()}
${content} POST请求结果_PARAMS ${path} {"sessionId":"${sessionId}","text":"你好","workerId":"${clientId}","files":"${jpg_streamId}"} 200 ${token}
log ${content}
Should Be Equal As Strings ${content["code"]} 200
Should Be Equal As Strings ${content["message"]} 成功
......@@ -61,23 +58,18 @@ ${xlsx_file} testfile.xlsx
${file} Evaluate (r'${gif_file}', open(r'${CURDIR}${/}testfiles${/}${gif_file}', 'rb'))
${data} Create Dictionary sessionId=${sessionId}
${header} Create Dictionary Authorization=${token}
${files} Create Dictionary files=${file}
${resp} Post On Session URI ${path} files=${files} data=${data} headers=${header}
${files} Create Dictionary file=${file}
${resp} Post On Session URI ${uploadpath} files=${files} data=${data} headers=${header}
${content} Set Variable ${resp.json()}
log ${content}
Should Be Equal As Strings ${content["code"]} 200
Should Be Equal As Strings ${content["message"]} 成功
Set Global Variable ${gif_streamId} ${content["data"]}
Set Global Variable ${gif_streamId} ${content["data"]["id"]}
正例-正常发送gif+文字消息
[Tags] F
create session URI ${URL}
${file} Evaluate (r'${gif_file}', open(r'${CURDIR}${/}testfiles${/}${gif_file}', 'rb'))
${data} Create Dictionary sessionId=${sessionId} text="这张图是什么格式"
${header} Create Dictionary Authorization=${token}
${files} Create Dictionary files=${file}
${resp} Post On Session URI ${path} files=${files} data=${data} headers=${header}
${content} Set Variable ${resp.json()}
${content} POST请求结果_PARAMS ${path} {"sessionId":"${sessionId}","text":"你好","workerId":"${clientId}","files":"${gif_streamId}"} 200 ${token}
log ${content}
Should Be Equal As Strings ${content["code"]} 200
Should Be Equal As Strings ${content["message"]} 成功
......@@ -89,23 +81,18 @@ ${xlsx_file} testfile.xlsx
${file} Evaluate (r'${jpeg_file}', open(r'${CURDIR}${/}testfiles${/}${jpeg_file}', 'rb'))
${data} Create Dictionary sessionId=${sessionId}
${header} Create Dictionary Authorization=${token}
${files} Create Dictionary files=${file}
${resp} Post On Session URI ${path} files=${files} data=${data} headers=${header}
${files} Create Dictionary file=${file}
${resp} Post On Session URI ${uploadpath} files=${files} data=${data} headers=${header}
${content} Set Variable ${resp.json()}
log ${content}
Should Be Equal As Strings ${content["code"]} 200
Should Be Equal As Strings ${content["message"]} 成功
Set Global Variable ${jpeg_streamId} ${content["data"]}
Set Global Variable ${jpeg_streamId} ${content["data"]["id"]}
正例-正常发送jpeg+文字消息
[Tags] F
create session URI ${URL}
${file} Evaluate (r'${jpeg_file}', open(r'${CURDIR}${/}testfiles${/}${jpeg_file}', 'rb'))
${data} Create Dictionary sessionId=${sessionId} text="这张图是什么格式"
${header} Create Dictionary Authorization=${token}
${files} Create Dictionary files=${file}
${resp} Post On Session URI ${path} files=${files} data=${data} headers=${header}
${content} Set Variable ${resp.json()}
${content} POST请求结果_PARAMS ${path} {"sessionId":"${sessionId}","text":"你好","workerId":"${clientId}","files":"${jpeg_streamId}"} 200 ${token}
log ${content}
Should Be Equal As Strings ${content["code"]} 200
Should Be Equal As Strings ${content["message"]} 成功
......@@ -117,23 +104,18 @@ ${xlsx_file} testfile.xlsx
${file} Evaluate (r'${png_file}', open(r'${CURDIR}${/}testfiles${/}${png_file}', 'rb'))
${data} Create Dictionary sessionId=${sessionId}
${header} Create Dictionary Authorization=${token}
${files} Create Dictionary files=${file}
${resp} Post On Session URI ${path} files=${files} data=${data} headers=${header}
${files} Create Dictionary file=${file}
${resp} Post On Session URI ${uploadpath} files=${files} data=${data} headers=${header}
${content} Set Variable ${resp.json()}
log ${content}
Should Be Equal As Strings ${content["code"]} 200
Should Be Equal As Strings ${content["message"]} 成功
Set Global Variable ${png_streamId} ${content["data"]}
Set Global Variable ${png_streamId} ${content["data"]["id"]}
正例-正常发送png+文字消息
[Tags] F
create session URI ${URL}
${file} Evaluate (r'${png_file}', open(r'${CURDIR}${/}testfiles${/}${png_file}', 'rb'))
${data} Create Dictionary sessionId=${sessionId} text="这张图是什么格式"
${header} Create Dictionary Authorization=${token}
${files} Create Dictionary files=${file}
${resp} Post On Session URI ${path} files=${files} data=${data} headers=${header}
${content} Set Variable ${resp.json()}
${content} POST请求结果_PARAMS ${path} {"sessionId":"${sessionId}","text":"你好","workerId":"${clientId}","files":"${png_streamId}"} 200 ${token}
log ${content}
Should Be Equal As Strings ${content["code"]} 200
Should Be Equal As Strings ${content["message"]} 成功
......@@ -145,23 +127,18 @@ ${xlsx_file} testfile.xlsx
${file} Evaluate (r'${webp_file}', open(r'${CURDIR}${/}testfiles${/}${webp_file}', 'rb'))
${data} Create Dictionary sessionId=${sessionId}
${header} Create Dictionary Authorization=${token}
${files} Create Dictionary files=${file}
${resp} Post On Session URI ${path} files=${files} data=${data} headers=${header}
${files} Create Dictionary file=${file}
${resp} Post On Session URI ${uploadpath} files=${files} data=${data} headers=${header}
${content} Set Variable ${resp.json()}
log ${content}
Should Be Equal As Strings ${content["code"]} 200
Should Be Equal As Strings ${content["message"]} 成功
Set Global Variable ${webp_streamId} ${content["data"]}
Set Global Variable ${webp_streamId} ${content["data"]["id"]}
正例-正常发送webp+文字消息
[Tags] F
create session URI ${URL}
${file} Evaluate (r'${webp_file}', open(r'${CURDIR}${/}testfiles${/}${webp_file}', 'rb'))
${data} Create Dictionary sessionId=${sessionId} text="这张图是什么格式"
${header} Create Dictionary Authorization=${token}
${files} Create Dictionary files=${file}
${resp} Post On Session URI ${path} files=${files} data=${data} headers=${header}
${content} Set Variable ${resp.json()}
${content} POST请求结果_PARAMS ${path} {"sessionId":"${sessionId}","text":"你好","workerId":"${clientId}","files":"${webp_streamId}"} 200 ${token}
log ${content}
Should Be Equal As Strings ${content["code"]} 200
Should Be Equal As Strings ${content["message"]} 成功
......@@ -173,23 +150,18 @@ ${xlsx_file} testfile.xlsx
${file} Evaluate (r'${csv_file}', open(r'${CURDIR}${/}testfiles${/}${csv_file}', 'rb'))
${data} Create Dictionary sessionId=${sessionId}
${header} Create Dictionary Authorization=${token}
${files} Create Dictionary files=${file}
${resp} Post On Session URI ${path} files=${files} data=${data} headers=${header}
${files} Create Dictionary file=${file}
${resp} Post On Session URI ${uploadpath} files=${files} data=${data} headers=${header}
${content} Set Variable ${resp.json()}
log ${content}
Should Be Equal As Strings ${content["code"]} 200
Should Be Equal As Strings ${content["message"]} 成功
Set Global Variable ${csv_streamId} ${content["data"]}
Set Global Variable ${csv_streamId} ${content["data"]["id"]}
正例-正常发送csv+文字消息
[Tags] F
create session URI ${URL}
${file} Evaluate (r'${csv_file}', open(r'${CURDIR}${/}testfiles${/}${csv_file}', 'rb'))
${data} Create Dictionary sessionId=${sessionId} text="这个文件是什么格式"
${header} Create Dictionary Authorization=${token}
${files} Create Dictionary files=${file}
${resp} Post On Session URI ${path} files=${files} data=${data} headers=${header}
${content} Set Variable ${resp.json()}
${content} POST请求结果_PARAMS ${path} {"sessionId":"${sessionId}","text":"你好","workerId":"${clientId}","files":"${csv_streamId}"} 200 ${token}
log ${content}
Should Be Equal As Strings ${content["code"]} 200
Should Be Equal As Strings ${content["message"]} 成功
......@@ -201,23 +173,18 @@ ${xlsx_file} testfile.xlsx
${file} Evaluate (r'${doc_file}', open(r'${CURDIR}${/}testfiles${/}${doc_file}', 'rb'))
${data} Create Dictionary sessionId=${sessionId}
${header} Create Dictionary Authorization=${token}
${files} Create Dictionary files=${file}
${resp} Post On Session URI ${path} files=${files} data=${data} headers=${header}
${files} Create Dictionary file=${file}
${resp} Post On Session URI ${uploadpath} files=${files} data=${data} headers=${header}
${content} Set Variable ${resp.json()}
log ${content}
Should Be Equal As Strings ${content["code"]} 200
Should Be Equal As Strings ${content["message"]} 成功
Set Global Variable ${doc_streamId} ${content["data"]}
Set Global Variable ${doc_streamId} ${content["data"]["id"]}
正例-正常发送doc+文字消息
[Tags] F
create session URI ${URL}
${file} Evaluate (r'${doc_file}', open(r'${CURDIR}${/}testfiles${/}${doc_file}', 'rb'))
${data} Create Dictionary sessionId=${sessionId} text="这个文件是什么格式"
${header} Create Dictionary Authorization=${token}
${files} Create Dictionary files=${file}
${resp} Post On Session URI ${path} files=${files} data=${data} headers=${header}
${content} Set Variable ${resp.json()}
${content} POST请求结果_PARAMS ${path} {"sessionId":"${sessionId}","text":"你好","workerId":"${clientId}","files":"${doc_streamId}"} 200 ${token}
log ${content}
Should Be Equal As Strings ${content["code"]} 200
Should Be Equal As Strings ${content["message"]} 成功
......@@ -229,23 +196,18 @@ ${xlsx_file} testfile.xlsx
${file} Evaluate (r'${docx_file}', open(r'${CURDIR}${/}testfiles${/}${docx_file}', 'rb'))
${data} Create Dictionary sessionId=${sessionId}
${header} Create Dictionary Authorization=${token}
${files} Create Dictionary files=${file}
${resp} Post On Session URI ${path} files=${files} data=${data} headers=${header}
${files} Create Dictionary file=${file}
${resp} Post On Session URI ${uploadpath} files=${files} data=${data} headers=${header}
${content} Set Variable ${resp.json()}
log ${content}
Should Be Equal As Strings ${content["code"]} 200
Should Be Equal As Strings ${content["message"]} 成功
Set Global Variable ${docx_streamId} ${content["data"]}
Set Global Variable ${docx_streamId} ${content["data"]["id"]}
正例-正常发送docx+文字消息
[Tags] F
create session URI ${URL}
${file} Evaluate (r'${docx_file}', open(r'${CURDIR}${/}testfiles${/}${docx_file}', 'rb'))
${data} Create Dictionary sessionId=${sessionId} text="这个文件是什么格式"
${header} Create Dictionary Authorization=${token}
${files} Create Dictionary files=${file}
${resp} Post On Session URI ${path} files=${files} data=${data} headers=${header}
${content} Set Variable ${resp.json()}
${content} POST请求结果_PARAMS ${path} {"sessionId":"${sessionId}","text":"你好","workerId":"${clientId}","files":"${docx_streamId}"} 200 ${token}
log ${content}
Should Be Equal As Strings ${content["code"]} 200
Should Be Equal As Strings ${content["message"]} 成功
......@@ -257,23 +219,18 @@ ${xlsx_file} testfile.xlsx
${file} Evaluate (r'${md_file}', open(r'${CURDIR}${/}testfiles${/}${md_file}', 'rb'))
${data} Create Dictionary sessionId=${sessionId}
${header} Create Dictionary Authorization=${token}
${files} Create Dictionary files=${file}
${resp} Post On Session URI ${path} files=${files} data=${data} headers=${header}
${files} Create Dictionary file=${file}
${resp} Post On Session URI ${uploadpath} files=${files} data=${data} headers=${header}
${content} Set Variable ${resp.json()}
log ${content}
Should Be Equal As Strings ${content["code"]} 200
Should Be Equal As Strings ${content["message"]} 成功
Set Global Variable ${md_streamId} ${content["data"]}
Set Global Variable ${md_streamId} ${content["data"]["id"]}
正例-正常发送md+文字消息
[Tags] F
create session URI ${URL}
${file} Evaluate (r'${md_file}', open(r'${CURDIR}${/}testfiles${/}${md_file}', 'rb'))
${data} Create Dictionary sessionId=${sessionId} text="这个文件是什么格式"
${header} Create Dictionary Authorization=${token}
${files} Create Dictionary files=${file}
${resp} Post On Session URI ${path} files=${files} data=${data} headers=${header}
${content} Set Variable ${resp.json()}
${content} POST请求结果_PARAMS ${path} {"sessionId":"${sessionId}","text":"你好","workerId":"${clientId}","files":"${md_streamId}"} 200 ${token}
log ${content}
Should Be Equal As Strings ${content["code"]} 200
Should Be Equal As Strings ${content["message"]} 成功
......@@ -285,23 +242,18 @@ ${xlsx_file} testfile.xlsx
${file} Evaluate (r'${txt_file}', open(r'${CURDIR}${/}testfiles${/}${txt_file}', 'rb'))
${data} Create Dictionary sessionId=${sessionId}
${header} Create Dictionary Authorization=${token}
${files} Create Dictionary files=${file}
${resp} Post On Session URI ${path} files=${files} data=${data} headers=${header}
${files} Create Dictionary file=${file}
${resp} Post On Session URI ${uploadpath} files=${files} data=${data} headers=${header}
${content} Set Variable ${resp.json()}
log ${content}
Should Be Equal As Strings ${content["code"]} 200
Should Be Equal As Strings ${content["message"]} 成功
Set Global Variable ${txt_streamId} ${content["data"]}
Set Global Variable ${txt_streamId} ${content["data"]["id"]}
正例-正常发送txt+文字消息
[Tags] F
create session URI ${URL}
${file} Evaluate (r'${txt_file}', open(r'${CURDIR}${/}testfiles${/}${txt_file}', 'rb'))
${data} Create Dictionary sessionId=${sessionId} text="这个文件是什么格式"
${header} Create Dictionary Authorization=${token}
${files} Create Dictionary files=${file}
${resp} Post On Session URI ${path} files=${files} data=${data} headers=${header}
${content} Set Variable ${resp.json()}
${content} POST请求结果_PARAMS ${path} {"sessionId":"${sessionId}","text":"你好","workerId":"${clientId}","files":"${txt_streamId}"} 200 ${token}
log ${content}
Should Be Equal As Strings ${content["code"]} 200
Should Be Equal As Strings ${content["message"]} 成功
......@@ -313,23 +265,18 @@ ${xlsx_file} testfile.xlsx
${file} Evaluate (r'${xls_file}', open(r'${CURDIR}${/}testfiles${/}${xls_file}', 'rb'))
${data} Create Dictionary sessionId=${sessionId}
${header} Create Dictionary Authorization=${token}
${files} Create Dictionary files=${file}
${resp} Post On Session URI ${path} files=${files} data=${data} headers=${header}
${files} Create Dictionary file=${file}
${resp} Post On Session URI ${uploadpath} files=${files} data=${data} headers=${header}
${content} Set Variable ${resp.json()}
log ${content}
Should Be Equal As Strings ${content["code"]} 200
Should Be Equal As Strings ${content["message"]} 成功
Set Global Variable ${xls_streamId} ${content["data"]}
Set Global Variable ${xls_streamId} ${content["data"]["id"]}
正例-正常发送xls+文字消息
[Tags] F
create session URI ${URL}
${file} Evaluate (r'${xls_file}', open(r'${CURDIR}${/}testfiles${/}${xls_file}', 'rb'))
${data} Create Dictionary sessionId=${sessionId} text="这个文件是什么格式"
${header} Create Dictionary Authorization=${token}
${files} Create Dictionary files=${file}
${resp} Post On Session URI ${path} files=${files} data=${data} headers=${header}
${content} Set Variable ${resp.json()}
${content} POST请求结果_PARAMS ${path} {"sessionId":"${sessionId}","text":"你好","workerId":"${clientId}","files":"${xls_streamId}"} 200 ${token}
log ${content}
Should Be Equal As Strings ${content["code"]} 200
Should Be Equal As Strings ${content["message"]} 成功
......@@ -341,23 +288,18 @@ ${xlsx_file} testfile.xlsx
${file} Evaluate (r'${xlsx_file}', open(r'${CURDIR}${/}testfiles${/}${xlsx_file}', 'rb'))
${data} Create Dictionary sessionId=${sessionId}
${header} Create Dictionary Authorization=${token}
${files} Create Dictionary files=${file}
${resp} Post On Session URI ${path} files=${files} data=${data} headers=${header}
${files} Create Dictionary file=${file}
${resp} Post On Session URI ${uploadpath} files=${files} data=${data} headers=${header}
${content} Set Variable ${resp.json()}
log ${content}
Should Be Equal As Strings ${content["code"]} 200
Should Be Equal As Strings ${content["message"]} 成功
Set Global Variable ${xlsx_streamId} ${content["data"]}
Set Global Variable ${xlsx_streamId} ${content["data"]["id"]}
正例-正常发送xlsx+文字消息
[Tags] F
create session URI ${URL}
${file} Evaluate (r'${xlsx_file}', open(r'${CURDIR}${/}testfiles${/}${xlsx_file}', 'rb'))
${data} Create Dictionary sessionId=${sessionId} text="这个文件是什么格式"
${header} Create Dictionary Authorization=${token}
${files} Create Dictionary files=${file}
${resp} Post On Session URI ${path} files=${files} data=${data} headers=${header}
${content} Set Variable ${resp.json()}
${content} POST请求结果_PARAMS ${path} {"sessionId":"${sessionId}","text":"你好","workerId":"${clientId}","files":"${xlsx_streamId}"} 200 ${token}
log ${content}
Should Be Equal As Strings ${content["code"]} 200
Should Be Equal As Strings ${content["message"]} 成功
......@@ -366,7 +308,7 @@ ${xlsx_file} testfile.xlsx
反例-传入错误token
[Tags] E
create session URI ${URL}
${content} POST请求结果_PARAMS ${path} {"sessionId":"${sessionId}","text":"你好"} 401 {}
${content} POST请求结果_PARAMS ${path} {"sessionId":"${sessionId}","text":"你好","workerId":"${clientId}"} 401 {}
log ${content}
Should Be Equal As Strings ${content["code"]} 401
Should Be Equal As Strings ${content["message"]} 无效的access token
......@@ -374,7 +316,7 @@ ${xlsx_file} testfile.xlsx
反例-传入空白token
[Tags] E
create session URI ${URL}
${content} POST请求结果_PARAMS ${path} {"sessionId":"${sessionId}","text":"你好"} 401 ${EMPTY}
${content} POST请求结果_PARAMS ${path} {"sessionId":"${sessionId}","text":"你好","workerId":"${clientId}"} 401 ${EMPTY}
log ${content}
Should Be Equal As Strings ${content["code"]} 401
Should Be Equal As Strings ${content["message"]} 没有找到认证信息
......@@ -382,15 +324,24 @@ ${xlsx_file} testfile.xlsx
反例-不传入sessionId参数
[Tags] E
create session URI ${URL}
${content} POST请求结果_PARAMS ${path} {} 200 ${token}
${content} POST请求结果_PARAMS ${path} {"text":"你好","workerId":"${clientId}"} 200 ${token}
log ${content}
Should Be Equal As Strings ${content["code"]} 500
Should Be Equal As Strings ${content["message"]} Server busy, please try later
反例-不传入workerId参数
[Tags] E
create session URI ${URL}
${content} POST请求结果_PARAMS ${path} {"sessionId":"${sessionId}","text":"你好"} 200 ${token}
log ${content}
Should Be Equal As Strings ${content["code"]} 500
Should Be Equal As Strings ${content["message"]} Server busy, please try later
正例-正常发送文字消息,进入探索
[Tags] F
Sleep 10
create session URI ${URL}
${content} POST请求结果_PARAMS ${path} {"sessionId":"${sessionId}","text":"使用探索工具,打开boss直聘"} 200 ${token}
${content} POST请求结果_PARAMS ${path} {"sessionId":"${sessionId}","text":"使用探索工具,打开百度","workerId":"${clientId}"} 200 ${token}
log ${content}
Should Be Equal As Strings ${content["code"]} 200
Should Be Equal As Strings ${content["message"]} 成功
......
......@@ -5,20 +5,26 @@ Library get_expId.py
*** Variables ***
${path} /api/chat/read
${clientId} a68ad587830d41aebf418a919006353e
*** Test Cases ***
正例-正常读取消息
[Tags] F
Sleep 10
${resp} Get ExpId http://bitagent.sit.ninetechone.com/${path} ${sessionId} ${ex_streamId} ${token}
log ${resp}
Should Contain ${resp}[0] EXP_
Set Global Variable ${expId} ${resp}[0]
Should Contain ${resp["sessionId"]} P_EXP
Set Global Variable ${expId} ${resp["sessionId"]}
${content} GET请求结果 /api/chat/retry {"sessionId":"${expId}","workerId":"${clientId}"} 200 ${token}
Set Global Variable ${streamId} ${content["data"]}
${resp1} Get ExpId http://bitagent.sit.ninetechone.com/${path} ${expId} ${streamId} ${token}
log ${resp1}
正例-正常读取对话消息
[Tags] F
${resp} Get Message http://bitagent.sit.ninetechone.com/${path} ${sessionId} ${text_streamId} ${token}
log ${resp}
Should Contain ${resp}[0] 让我想想
Should Contain ${resp}[0] 你好
Should Contain ${resp}[-1] 关闭
反例-传入错误的token
......
......@@ -9,7 +9,7 @@ ${path} /api/chat/interrupt
正例-正常中断消息
[Tags] F
create session URI ${URL}
${content} GET请求结果 ${path} {"sessionId":"${sessionId}"} 200 ${token}
${content} GET请求结果 ${path} {"sessionId":"${sessionId}","streamId":"${ex_streamId}"} 200 ${token}
log ${content}
Should Be Equal As Strings ${content["code"]} 200
Should Be Equal As Strings ${content["message"]} 成功
......@@ -17,7 +17,7 @@ ${path} /api/chat/interrupt
反例-传入错误的token
[Tags] E
create session URI ${URL}
${content} GET请求结果 ${path} {"sessionId":"${sessionId}"} 401 testtoken
${content} GET请求结果 ${path} {"sessionId":"${sessionId}","streamId":"${ex_streamId}"} 401 testtoken
log ${content}
Should Be Equal As Strings ${content["code"]} 401
Should Be Equal As Strings ${content["message"]} 无效的access token
......@@ -25,7 +25,7 @@ ${path} /api/chat/interrupt
反例-传入空白token
[Tags] E
create session URI ${URL}
${content} GET请求结果 ${path} {"sessionId":"${sessionId}"} 401 ${EMPTY}
${content} GET请求结果 ${path} {"sessionId":"${sessionId}","streamId":"${ex_streamId}"} 401 ${EMPTY}
log ${content}
Should Be Equal As Strings ${content["code"]} 401
Should Be Equal As Strings ${content["message"]} 没有找到认证信息
......@@ -33,7 +33,15 @@ ${path} /api/chat/interrupt
反例-不传sessionId参数
[Tags] E
create session URI ${URL}
${content} GET请求结果 ${path} {} 200 ${token}
${content} GET请求结果 ${path} {"streamId":"${ex_streamId}"} 200 ${token}
log ${content}
Should Be Equal As Strings ${content["code"]} 500
Should Be Equal As Strings ${content["message"]} Server busy, please try later
反例-不传streamId参数
[Tags] E
create session URI ${URL}
${content} GET请求结果 ${path} {"sessionId":"${sessionId}"} 200 ${token}
log ${content}
Should Be Equal As Strings ${content["code"]} 500
Should Be Equal As Strings ${content["message"]} Server busy, please try later
......@@ -40,8 +40,9 @@ ${path} /api/ability/steps
反例-会话过期
[Tags] F
create session URI ${URL}
${content} GET请求结果 ${path} {"exploreSessionId":1,"chatbotSessionId":10} 200 ${token}
log ${content}
Should Be Equal As Strings ${content["code"]} BAE0001
Should Be Equal As Strings ${content["message"]} 会话已过期,请开启新对话
Comment 当前版本会话保持持久化,不会过期,此用例废弃
Comment create session URI ${URL}
Comment ${content} GET请求结果 ${path} {"exploreSessionId":1,"chatbotSessionId":10} 200 ${token}
Comment log ${content}
Comment Should Be Equal As Strings ${content["code"]} BAE0001
Comment Should Be Equal As Strings ${content["message"]} 会话已过期,请开启新对话
......@@ -12,7 +12,7 @@ ${path} /api/ability
${random_string} Generate Random String 12 [LOWER]
log ${random_string}
create session URI ${URL}
${content} POST请求结果 ${path} {"exploreSessionId":"${expId}","filteredStepIndices":[0],"draft":{"name":"${random_string}","description":"自动化测试能力","startPageUrl":"https://www.baidu.com","parameters":[{"name":"search_query","description":"用户希望在百度上搜索的关键词。","example": "天气预报","type": "string"}],"stepIndices": [0]}} 200 ${token}
${content} POST请求结果 ${path} {"exploreSessionId":"${expId}","filteredStepIndices":[0],"draft":{"name":"${random_string}","description":"自动化测试","parameters":[],"startPageUrl":"https://www.baidu.com","stepIndices":[0]}} 200 ${token}
log ${content}
Should Be Equal As Strings ${content["code"]} 200
Should Be Equal As Strings ${content["message"]} 成功
......@@ -45,7 +45,7 @@ ${path} /api/ability
反例-能力名已存在
[Tags] F
create session URI ${URL}
${content} POST请求结果 ${path} {"exploreSessionId":"${expId}","filteredStepIndices":[0],"draft":{"name":"outhagent","description":"该能力用于访问百度主页,以查看其内容和功能。用户可以通过此能力快速打开百度主页,进行信息搜索和浏览。","startPageUrl":"https://www.baidu.com","parameters":[{"name":"search_query","description":"用户希望在百度上搜索的关键词。","example": "天气预报","type": "string"}],"stepIndices": [0]}} 200 ${token}
${content} POST请求结果 ${path} {"exploreSessionId":"${expId}","filteredStepIndices":[0],"draft":{"name":"outhagent","description":"自动化测试","parameters":[],"startPageUrl":"https://www.baidu.com","stepIndices":[0]}} 200 ${token}
log ${content}
Should Be Equal As Strings ${content["code"]} BAE0008
Should Be Equal As Strings ${content["message"]} 此能力名已存在
......@@ -62,6 +62,6 @@ def get_message(url,sessionId,streamId,token,timeout=180):
return oplist
# print(get_expId('http://bitagent.sit.ninetechone.com/api/chat/read','CB_2a7714d1e41e4d0891fc5c13a39a4063','CB_a556efbc8502461ba473d789da439c55','Bearer c1391926-e8ba-46c0-a0d1-c5e3c38503da'))
# print(get_expId('http://bitagent.sit.ninetechone.com/api/chat/read','P_CB_f21b81ef55ab48f8b87530500ced227d','P_CB_976bebae52514b39a140e38f88cd2dee','Bearer d25c4717-087b-4472-aaaa-2a1939f22680'))
# print(get_expId('http://bitagent.sit.ninetechone.com/api/chat/read','CB_e48bea09fe1e4c8388883ff11384bef8','CB_0e7c9c99d6494d9f977b0c2fbb73e2e3','Bearer c1391926-e8ba-46c0-a0d1-c5e3c38503da'))
# print(get_message('http://bitagent.sit.ninetechone.com/api/chat/read','CB_e268fb27e7d146009d18e0912c23be58','CB_bc6ed32cc3e0476d90c7b243c75cf2a9','Bearer c1391926-e8ba-46c0-a0d1-c5e3c38503da'))
# print(get_message('http://bitagent.sit.ninetechone.com/api/chat/read','P_CB_f21b81ef55ab48f8b87530500ced227d','P_CB_976bebae52514b39a140e38f88cd2dee','Bearer d25c4717-087b-4472-aaaa-2a1939f22680'))
import json
import logging
from typing import Optional
from pydantic import BaseModel
from models import ResultModel
logger = logging.getLogger(__name__)
class RequestBodyModel(BaseModel):
path: str
data: str
headers: str
def parse_request_body(body: str) -> Optional[RequestBodyModel]:
if not body:
return None
parts = body.split("\n", maxsplit=2)
if len(parts) == 3:
return RequestBodyModel(
path=parts[0].strip("/"), headers=parts[1], data=parts[2]
)
else:
logger.error(f"指令格式错误:{body}")
return None
def format_response_body(consume_result: ResultModel):
responseBody = f"{consume_result.code}\n{consume_result.message}"
if consume_result.code == 200 and consume_result.data is not None:
try:
response_headers = json.dumps(
{},
default=lambda o: o.__dict__,
ensure_ascii=False,
)
response_data = json.dumps(
consume_result.data,
default=lambda o: o.__dict__,
ensure_ascii=False,
)
responseBody = f"{consume_result.code}\n{response_headers}\n{response_data}"
except Exception as e:
logger.exception(f"json encode error:{consume_result.data} {e}")
return responseBody
......@@ -5,8 +5,6 @@ from typing import Callable, List, Optional
import grpc
import grpc.aio
# from native.config import settings
# from native.utils.utils import singleton
from protos.BitAgentWorker_pb2_grpc import ConnectServiceStub
......@@ -15,13 +13,13 @@ logger = logging.getLogger(__name__)
class GrpcClient:
GRPC_CHANNEL_OPTIONS = [
("grpc.max_send_message_length", 1000),
("grpc.max_receive_message_length", 1000),
("grpc.max_send_message_length", 10*1024*1024),
("grpc.max_receive_message_length", 10*1024*1024),
# ("grpc.keep_alive_time", settings.GRPC_HEART_INTERVAL_SECONDS),
# ("grpc.keep_alive_timeout", settings.GRPC_HEART_INTERVAL_SECONDS),
# ("grpc.enable_retries", 1),
]
connect_timeout_seconds: int = 30
connect_timeout_seconds: int = 60
def __init__(self):
self._address: str = ""
......@@ -62,7 +60,7 @@ class GrpcClient:
if address is None or address == "":
raise ValueError("grpc address must be set")
logger.debug(
logger.info(
f"connect grpc to {address} use_ssl:{use_ssl} header:{str(self._header)}"
)
self._is_disconnected = False
......@@ -131,7 +129,7 @@ class GrpcClient:
# 创建通道
if not self._channel:
logger.debug("create channel")
logger.info("create channel")
if self._use_ssl:
credits: grpc.ChannelCredentials = (
grpc.ssl_channel_credentials()
......@@ -145,7 +143,7 @@ class GrpcClient:
)
# 等待连接
logger.debug(f"wait channel ready to {self._address}")
logger.info(f"wait channel ready to {self._address}")
await asyncio.wait_for(
self._channel.channel_ready(), timeout=self.connect_timeout_seconds
)
......
import asyncio
import json
import logging
from collections import deque
from typing import Callable, Coroutine, Optional
import grpc.aio
from result import ResultModel
from models import ResultModel
from body import format_response_body, parse_request_body
from grpc_client import GrpcClient
from protos.BitAgentWorker_pb2 import ReversalRequest, ReversalResponse
......@@ -30,6 +30,9 @@ class GrpcListener:
Optional[Callable[[str, str], Coroutine[None, None, ResultModel]]]
) = None
client.state_changed_handlers.append(self._on_channel_state_changed)
# 新增:发送队列和发送任务
self._send_queue = asyncio.Queue()
self._send_task: Optional[asyncio.Task] = None
def _on_channel_state_changed(self, connect: bool) -> None:
"""处理通道状态变更"""
......@@ -59,6 +62,9 @@ class GrpcListener:
self.is_running = True
self._listen_task = asyncio.create_task(self._listen_loop())
# 启动发送任务
if not self._send_task or self._send_task.done():
self._send_task = asyncio.create_task(self._send_loop())
async def _listen_loop(self) -> None:
read_pass_count = 0
......@@ -109,7 +115,7 @@ class GrpcListener:
await asyncio.sleep(1)
continue
except Exception as e:
logger.debug(f"ListenHandle exception:{type(e)}")
logger.info(f"ListenHandle exception:{type(e)}")
if not self.is_running:
break
if isinstance(e, grpc.aio.AioRpcError):
......@@ -142,50 +148,30 @@ class GrpcListener:
return
self._request_id_set.add(data.id)
self._request_id_deque.append(data.id)
if len(self._request_id_set) > 100000:
if len(self._request_id_set) > 3000:
self._request_id_set.remove(
self._request_id_deque.popleft()
) # 最早的指令移除
# 3. 消费指令
consume_result: ResultModel = ResultModel(code=500, message="client error")
consume_result: ResultModel = ResultModel.error("client error")
try:
if self.message_received:
parts = data.body.split("\n", maxsplit=2)
if len(parts) == 3:
request_path = parts[0].strip("/")
request_data = parts[2]
consume_result = await self.message_received(
request_path, request_data
)
else:
consume_result = ResultModel(code=500, message="指令格式错误")
logger.error(f"指令格式错误:{data.body}")
request_data = parse_request_body(data.body)
if request_data is None:
consume_result = ResultModel.error("指令格式错误")
elif self.message_received:
consume_result = await self.message_received(
request_data.path, request_data.data
)
except Exception as e:
consume_result = ResultModel(code=500, message=str(e))
consume_result = ResultModel.error(str(e))
logger.exception(f"消费指令异常:{data} {e}")
# 3. 回复执行结果
responseBody = f"{consume_result.code}\n{consume_result.message}"
if consume_result.code == 200 and consume_result.data is not None:
try:
response_headers = json.dumps(
{},
default=lambda o: o.__dict__,
ensure_ascii=False,
)
response_data = json.dumps(
consume_result.data,
default=lambda o: o.__dict__,
ensure_ascii=False,
)
responseBody = (
f"{consume_result.code}\n{response_headers}\n{response_data}"
)
except Exception as e:
logger.exception(f"json encode error:{consume_result.data} {e}")
await self.send_to_all_stream(data.id, responseBody, retry_count=3)
log = consume_result.log_str()
await self.send_to_all_stream(
data.id, format_response_body(consume_result), retry_count=3, log=log
)
except Exception as e:
logger.exception(f"on_message_received error:{e}")
......@@ -203,6 +189,11 @@ class GrpcListener:
self._listen_task.cancel()
self._listen_task = None
# 停止发送任务
if self._send_task:
self._send_task.cancel()
self._send_task = None
await self._close_call_stream()
async def _close_call_stream(self) -> None:
......@@ -219,68 +210,118 @@ class GrpcListener:
logger.exception("Stream dispose error")
self._call_stream = None
async def _send_loop(self):
while self.is_running:
try:
send_args = await self._send_queue.get()
*real_args, fut = send_args
try:
result = await self._do_send_to_all_stream(*real_args)
except Exception as e:
logger.exception(f"Send loop error: {e}")
result = False
finally:
if fut:
fut.set_result(result)
except asyncio.CancelledError:
break
async def send_to_all_stream(
self, requestId: str, body: str, type: int = 1, retry_count: int = 0
self,
requestId: str,
body: str,
type: int = 1,
retry_count: int = 0,
log: Optional[str] = None,
) -> bool:
"""发送数据到所有流"""
"""入队,串行发送数据"""
if type == -1:
if not self._send_queue.empty():
logger.debug("ignore:ping")
return True
if self._ping_count == 6:
self._ping_count = 0
self._ping_count += 1
if len(body) < 2000:
log = f"{requestId} content:{body}"
log = "#ping"
else:
log = f"{requestId} len:{len(body)} content:{body[:2000]}..."
count = retry_count
while count >= 0:
try:
# 判断是否可以发送数据
if retry_count > 0:
if count < retry_count:
logger.info("send retry ")
await self._client.wait_reconnecting(
30
)
else:
if not self._client.check_can_send(log):
await self._close_call_stream()
if not log:
log = f'"{requestId}":\n{body}'
else:
log = f'"{requestId}":\n{log}'
fut = asyncio.get_event_loop().create_future()
await self._send_queue.put((requestId, body, type, retry_count, log, fut))
return await fut
async def _do_send_to_all_stream(
self,
requestId: str,
body: str,
type: int = 1,
retry_count: int = 0,
log: Optional[str] = None,
) -> bool:
try:
count = retry_count
while count >= 0:
try:
# 判断是否可以发送数据
if retry_count > 0:
if count < retry_count:
logger.info("send retry ")
await self._client.wait_reconnecting(
60
)
else:
if not self._client.check_can_send(log or ""):
await self._close_call_stream()
continue
# 分段发送数据
partitionIndex = 0
stream = await self.call_stream
if not stream:
logger.error(f"call_stream is null:{log}")
continue
for i in range(0, len(body), 1024*1024*10):
if partitionIndex > 0:
logger.info(f"partition:{partitionIndex}")
data = ReversalResponse(
requestId=requestId,
type=type,
partitionIndex=partitionIndex,
partitionData=body[
i : i + 1024*1024*10
],
)
await stream.write(data)
partitionIndex += 1
# 分段发送数据
partitionIndex = 0
stream = await self.call_stream
if not stream:
logger.error(f"call_stream is null:{log}")
continue
for i in range(0, len(body), 1000):
if partitionIndex > 0:
logger.info(f"partition:{partitionIndex}")
data = ReversalResponse(
requestId=requestId,
type=type,
partitionIndex=partitionIndex,
partitionData=body[i : i + 1000],
)
await stream.write(data)
partitionIndex += 1
# 发送结束标志
if type == 1:
await stream.write(
ReversalResponse(requestId=data.requestId, type=2)
)
if type != -1 or self._ping_count == 1:
logger.info(f"send {log}")
return True
except Exception as e:
if isinstance(e, grpc.aio.AioRpcError):
logger.error(f"send RpcException:{log},{str(e)},{e.details()}")
await self._client._handle_rpc_exception(e)
elif isinstance(e, asyncio.InvalidStateError):
logger.error(f"send StateError:{log},{str(e)},{self._client.state}")
await self._close_call_stream()
await self._client.reconnect(force=True)
else:
logger.error(f"send Exception:{log},{str(e)},{self._client.state}")
finally:
count -= 1
return False
# 发送结束标志
if type == 1:
await stream.write(
ReversalResponse(requestId=data.requestId, type=2)
)
if type != -1 or self._ping_count == 1:
logger.info(f"send {log}")
return True
except Exception as e:
if isinstance(e, grpc.aio.AioRpcError):
logger.error(f"send RpcException:{log},{str(e)},{e.details()}")
await self._client._handle_rpc_exception(e)
elif isinstance(e, asyncio.InvalidStateError):
logger.error(
f"send StateError:{log},{str(e)},{self._client.state}"
)
await self._close_call_stream()
await self._client.reconnect(force=True)
else:
logger.error(
f"send Exception:{log},{str(e)},{self._client.state}"
)
finally:
count -= 1
return False
except Exception as e:
logger.exception(f"_do_send_to_all_stream error: {e}")
return False
import asyncio
import logging
import random
import time
import requests
import json
import grpc.aio
from grpc_client import GrpcClient
from grpc_listener import GrpcListener
from result import ResultModel
from models import ResultModel
# 配置日志
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
async def handle_message(request_path: str, request_data: str) -> ResultModel:
"""增强版消息处理函数"""
logging.info(f"收到请求路径: {request_path}, 数据: {request_data}")
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
#定义全局变量 fetchUI次数
isopentab = 0
isfetchui = 0
# 认证配置
auth_config = {
"headers": {
"Content-Type": "application/x-www-form-urlencoded",
"Sm4-Key": "dUVNkTJLlzMHPqBTZh085jT0N6S7930l6sgddJsYSC8=",
"Cookie": "ENCRYPT_KEY=f48bf3-05fe-4978"
},
"params": {
"username": "api_tester",
"password": "$SM4$Nd/e40vIS6UD9VMaSOmYGlrBORfo7r5/1z9D5d4E4es=$4MS$",
"tenantCode": "API_test",
"scope": "all",
"client_id": "a68ad587830d41aebf418a919006353e",
"client_secret": "Ninetech@123",
"grant_type": "password"
}
}
# 特定消息处理逻辑
async def handle_message(request_path, request_data):
global isopentab
global isfetchui
if request_path == "list_mcp_servers": # 特定指令1
return ResultModel(code=200, data=[])
return ResultModel(code=200, data=[], message="")
elif request_path == "adaptable_activities": # 特定指令2
return ResultModel(code=200, data=[ {"id": "sleep_seconds", "name": "sleep_seconds", "displayName": "等待", "description": "此工具的用途是在目标无法达成时进行等待,最多等待2次", "parametersSchema": {"description": "等待", "properties": {"wait_seconds": {"default": 5, "description": "默认5秒,可修改为1-5秒时间", "title": "Wait Seconds", "type": "integer"}}, "title": "SleepSeconds", "type": "object", "required": []}, "elementIdJsonPaths": [], "icon": "sleep_seconds", "timeout": 180}])
return ResultModel(code=200, data=[
{"id": "keyboard_entry", "name": "keyboard_entry", "displayName": "键盘输入", "description": "键盘输入", "parametersSchema": {"description": "键盘输入", "properties": {"key_code": {"description": "输入键盘码或组合快捷键,支持Playwright键盘码和组合快捷键,例如:[`F1`, `F2`, `F3`, `F4`, `F5`, `F6`, `F7`, `F8`, `F9`, `F10`, `F11`, `F12`, `Digit0`, `Digit1`, `Digit2`, `Digit3`, `Digit4`, `Digit5`, `Digit6`, `Digit7`, `Digit8`, `Digit9`, `KeyA`, `KeyB`, `KeyC`, `KeyD`, `KeyE`, `KeyF`, `KeyG`, `KeyH`, `KeyI`, `KeyJ`, `KeyK`, `KeyL`, `KeyM`, `KeyN`, `KeyO`, `KeyP`, `KeyQ`, `KeyR`, `KeyS`, `KeyT`, `KeyU`, `KeyV`, `KeyW`, `KeyX`, `KeyY`, `KeyZ`, `Backquote`, `Minus`, `Equal`, `Backslash`, `Backspace`, `Tab`,`Delete`, `Escape`, `ArrowDown`, `PageDown`, `PageUp`, `ArrowLeft`,`ArrowRight`, `ArrowUp`],Shortcuts such as `Control+o`, `Control++`, `Control+Shift+T` , `Alt+ArrowRight` or `Alt+ArrowLeft`", "title": "Key Code", "type": "string"}}, "required": ["key_code"], "title": "KeyboardEntry", "type": "object"}, "elementIdJsonPaths": [], "icon": "keyboard_entry", "timeout": 180}, {"id": "navigate_page", "name": "navigate_page", "displayName": "跳转到网页", "description": "跳转到网页", "parametersSchema": {"$defs": {"NavigatePageType": {"enum": ["go_to", "go_back", "go_forward", "refresh"], "title": "NavigatePageType", "type": "string"}}, "description": "跳转到网页", "properties": {"url": {"default": "", "description": "需要打开的url", "title": "Url", "type": "string"}, "type": {"$ref": "#/$defs/NavigatePageType", "description": "需要操作的类型"}}, "required": ["type"], "title": "NavigatePage", "type": "object"}, "elementIdJsonPaths": [], "icon": "navigate_page", "timeout": 180}, {"id": "sleep_seconds", "name": "sleep_seconds", "displayName": "等待", "description": "此工具的用途是在目标无法达成时进行等待,最多等待2次", "parametersSchema": {"description": "等待", "properties": {"wait_seconds": {"default": 5, "description": "默认5秒,可修改为1-5秒时间", "title": "Wait Seconds", "type": "integer"}}, "title": "SleepSeconds", "type": "object", "required": []}, "elementIdJsonPaths": [], "icon": "sleep_seconds", "timeout": 180}, {"id": "switch_page", "name": "switch_page", "displayName": "切换页面", "description": "切换页面", "parametersSchema": {"description": "切换页面", "properties": {"page_id": {"description": "需要切换的页面id,如果id对应的页面不存在将不会切换成功", "title": "Page Id", "type": "string"}}, "required": ["page_id"], "title": "SwitchPage", "type": "object"}, "elementIdJsonPaths": [], "icon": "switch_page", "timeout": 180}, {"id": "click", "name": "click", "displayName": "点击元素", "description": "点击某个元素", "parametersSchema": {"description": "点击某个元素", "properties": {"element_id": {"description": "需要操作元素的id", "title": "Element Id", "type": "string"}}, "required": ["element_id"], "title": "ClickElement", "type": "object"}, "elementIdJsonPaths": ["$.element_id"], "icon": "click", "timeout": 180}, {"id": "input_text", "name": "input_text", "displayName": "输入文本", "description": "输入文本", "parametersSchema": {"description": "输入内容", "properties": {"element_id": {"description": "需要操作元素的id", "title": "Element Id", "type": "string"}, "content": {"description": "需要输入的内容", "title": "Content", "type": "string"}}, "required": ["element_id", "content"], "title": "InputText", "type": "object"}, "elementIdJsonPaths": ["$.element_id"], "icon": "input_text", "timeout": 180}, {"id": "select_option", "name": "select_option", "displayName": "选择选项", "description": "选择某个选项,仅适用于radio,checkbox,select,option标签及点击后有dropdown menu效果的标签。label,value,index三者至少填一个", "parametersSchema": {"description": "选择某个选项", "properties": {"element_id": {"description": "需要操作元素的id", "title": "Element Id", "type": "string"}, "label": {"anyOf": [{"type": "string"}, {"type": "null"}], "default": None, "description": "需要选择的选项的label", "title": "Label"}, "value": {"anyOf": [{"type": "string"}, {"type": "null"}], "default": None, "description": "需要选择的选项的value", "title": "Value"}, "index": {"anyOf": [{"type": "integer"}, {"type": "null"}], "default": None, "description": "需要选择的选项的index索引", "title": "Index"}}, "required": ["element_id"], "title": "SelectOption", "type": "object"}, "elementIdJsonPaths": ["$.element_id"], "icon": "select_option", "timeout": 180}, {"id": "upload_file", "name": "upload_file", "displayName": "上传文件", "description": "上传文件", "parametersSchema": {"description": "上传文件", "properties": {"element_id": {"description": "需要操作元素的id", "title": "Element Id", "type": "string"}, "file_id": {"description": "文件ID,从文件空间中选取", "title": "File Id", "type": "string"}}, "required": ["element_id", "file_id"], "title": "UploadFile", "type": "object"}, "elementIdJsonPaths": ["$.element_id"], "icon": "upload_file", "timeout": 180}],
message="")
elif request_path == "get_current_tab":
return ResultModel(code=200, data={"id":"test_tab","url":"https://www.zhipin.com/chengdu/?seoRefer=index","title":"BOSS直聘-找工作上BOSS直聘直接谈!招聘求职找工作!","screenshot":[]})
return ResultModel(code=200, data={
"id": "test_tab",
"url": "https://www.baidu.com/",
"title": "百度一下,你就知道",
"screenshot": []
}, message="")
elif request_path == "open_tab":
isopentab = 1
return ResultModel(code=200, data={
"id": "test_tab",
"url": "https://www.baidu.com/",
"title": "百度一下,你就知道",
"screenshot": []
}, message="")
elif request_path == "fetch_ui":
if isopentab == 1 or isfetchui == 1 :
isopentab = 0
isfetchui = 0
time.sleep(5)
return ResultModel(code=200, data= {"url": "https://www.baidu.com/", "content": "<a href=\"http://news.baidu.com\" id=\"pcWI\">新闻</a><a href=\"https://www.hao123.com?src=from_pc\" id=\"KkD4\">hao123</a><a href=\"http://map.baidu.com\" id=\"ZsH9\">地图</a><a href=\"http://tieba.baidu.com/\" id=\"Ggy7\">贴吧</a><a href=\"https://haokan.baidu.com/?sfrom=baidu-top\" id=\"AOeX\">视频</a><a href=\"http://image.baidu.com/\" id=\"Xd1C\">图片</a><a href=\"https://pan.baidu.com?from=1026962h\" id=\"8IWL\">网盘</a><a href=\"https://wenku.baidu.com/?fr=bdpcindex\" id=\"lCsO\">文库</a><a href=\"https://chat.baidu.com/search?isShowHello=1&pd=csaitab&setype=csaitab&extParamsJson=%7B%22enter_type%22%3A%22home_tab%22%7D\" id=\"b5rX\"><img class=\"s-top-tab-image\" id=\"5QSr\"></a><a href=\"http://www.baidu.com/more/\" name=\"tj_briicon\" id=\"lduS\">更多</a><a href=\"https://senode.baidu.com/seop-landing/knowledge_question?ref_sa=searchpromo_selftask_dati_shouyetab\" id=\"SnLp\"><div class=\"operate-image\" id=\"5eWj\"></div></a><span name=\"tj_settingicon\" id=\"LoOR\">设置</span><a href=\"https://passport.baidu.com/v2/?login&tpl=mn&u=http%3A%2F%2Fwww.baidu.com%2F&sms=5\" name=\"tj_login\" id=\"iGko\">登录</a><span class=\"soutu-btn\" id=\"XlOq\"></span><input name=\"wd\" value maxlength=\"255\" placeholder=\"王曼昱亮相美国大满贯海报\" id=\"Ie3z\"><input type=\"submit\" value=\"百度一下\" id=\"zqXv\"><a href=\"https://chat.baidu.com/search?extParams=%7B%22enter_type%22%3A%22ai_explore_home%22%7D&isShowHello=1\" id=\"E13Q\"><div class=\"new_search_guide_bub_container_left\" id=\"jv0S\"><svg></svg><svg></svg></div><div class=\"new_search_guide_bub_container_center\" id=\"j8J7\">AI搜索已支持「DeepSeek-R1」最新版</div><div class=\"new_search_guide_bub_container_right\" id=\"dHgS\">立即体验</div></a><div aria-label=\"百度热搜\" id=\"E7v6\"><i class=\"c-icon hot-title-icon\" id=\"y7ZQ\"></i><i class=\"c-icon arrow\" id=\"Ekyf\"></i></div><a class=\"hot-refresh c-font-normal c-color-gray2\" id=\"lNcM\"><i class=\"c-icon refresh-icon\" id=\"XZkU\"></i><span class=\"hot-refresh-text\" id=\"hF5v\">换一换</span></a><a href=\"{{_86d720161c56c8c50ca074b8addea74e08f618a7d03681af9f56b5bf60a6e109}}\" id=\"914C\"><i class=\"c-icon title-content-top-icon c-color-red c-gap-right-small\" id=\"6EZe\"></i><span class=\"title-content-title\" id=\"R5B4\">世界上最大的政党是如何炼成的</span></a><a href=\"{{_0609df375efd9ef496de58f77a745debd62d2390ee7b5c6861d3c38f98b4f2b6}}\" id=\"7t6N\"><span class=\"title-content-index c-index-single c-index-single-hot5 \" id=\"p5Zy\">5</span><span class=\"title-content-title\" id=\"FqiJ\">《新华字典》称小孩是累赘</span></a><a href=\"{{_0d7c4837c7faf638c147babd6e8a213b9a1cd92f94e8e24f5c502940e96c5833}}\" id=\"ayzg\"><span class=\"title-content-index c-index-single c-index-single-hot1 \" id=\"vJa0\">1</span><span class=\"title-content-title\" id=\"RQ4p\">高校引进高层次人才 第2名举报第1名</span></a><span class=\"title-content-mark ie-vertical c-text c-gap-left-small c-text-new\" id=\"z7Cd\">新</span><a href=\"{{_e6b1b4573d70f6f8f7fd7d217d73aff2aba5b9e3746e6a9783470b3330bd1917}}\" id=\"ff9J\"><span class=\"title-content-index c-index-single c-index-single-hot6 \" id=\"ovY0\">6</span><span class=\"title-content-title\" id=\"0rtw\">党的旗帜所指 即是网警铁翼所向</span></a><a href=\"{{_13ec6819a42ac28f147cb75ea1b8877a3a7296df40f4a456963f38d2adcba54d}}\" id=\"6TtQ\"><span class=\"title-content-index c-index-single c-index-single-hot2 \" id=\"EAry\">2</span><span class=\"title-content-title\" id=\"DVrk\">韦东奕晋升北大长聘副教授?校方回应</span></a><span class=\"title-content-mark ie-vertical c-text c-gap-left-small c-text-new\" id=\"Y2ua\">新</span><a href=\"{{_4d4c744b982ab1cd8436ea8806a2785a8c2d258bfdd57828e543080616d50704}}\" id=\"4240\"><span class=\"title-content-index c-index-single c-index-single-hot7 \" id=\"dXlE\">7</span><span class=\"title-content-title\" id=\"k2E1\">广州男子开车看手机撞人致3死3伤</span></a><span class=\"title-content-mark ie-vertical c-text c-gap-left-small c-text-new\" id=\"JA4p\">新</span><a href=\"{{_2d2cb344298e3c01a7eb639603d5d60037253006c48d5a997856bc86d5e01c9b}}\" id=\"ORRe\"><span class=\"title-content-index c-index-single c-index-single-hot3 \" id=\"j3h2\">3</span><span class=\"title-content-title\" id=\"Bmkd\">香港回归祖国28周年</span></a><a href=\"{{_c938881ae5de8a4a2a8395ee6482ca79a7d140eb1c5a7b0d0ddf48d57e9869b9}}\" id=\"hSRq\"><span class=\"title-content-index c-index-single c-index-single-hot8 \" id=\"aTwd\">8</span><span class=\"title-content-title\" id=\"9XGF\">男子8公斤黄金卖了612万赚312万</span></a><a href=\"{{_833e2addd1c5511c52653c92a46d9a996b7bfa3b7ba32168502057514e315095}}\" id=\"Qb7j\"><span class=\"title-content-index c-index-single c-index-single-hot4 \" id=\"iegt\">4</span><span class=\"title-content-title\" id=\"ubEb\">女子遇已故同学父亲摆摊:买下所有瓜</span></a><span class=\"title-content-mark ie-vertical c-text c-gap-left-small c-text-new\" id=\"PSS1\">新</span><a href=\"{{_8ae1eeb912dc25e1f8532a67bee6c7923fbf8fbf6b9ecc3cc0e13641c7d8e826}}\" id=\"qDqK\"><span class=\"title-content-index c-index-single c-index-single-hot9 \" id=\"ToGA\">9</span><span class=\"title-content-title\" id=\"3IYi\">客机高空急坠亲历者:给老公写了遗书</span></a><span class=\"title-content-mark ie-vertical c-text c-gap-left-small c-text-hot\" id=\"ZSGD\">热</span><a href=\"//home.baidu.com\" id=\"G6xr\">关于百度</a><a href=\"http://ir.baidu.com\" id=\"F2zX\">About Baidu</a><a href=\"//www.baidu.com/duty\" id=\"cN4M\">使用百度前必读</a><a href=\"https://help.baidu.com/question?prod_id=1\" id=\"nvcN\">帮助中心</a><a href=\"https://e.baidu.com/?refer=1271\" id=\"2xUA\">企业推广</a><span class=\"c-icon\" id=\"6r4L\"></span><span class=\"c-icon c-color-gray2\" id=\"Bdmj\"></span>", "elementIdSelectorMapping": {}, "screenshotsBase64": [], "text": "", "page_tabs": [{"id": "B9EF2368E1361855B8603FE716C87B69", "title": "百度一下,你就知道", "url": "https://www.baidu.com/", "active": True, "children": []}]}, message="")
else:
isfetchui = 1
return ResultModel(code=200, data= {"url": "about:blank", "content": "当前页面为空白页", "elementIdSelectorMapping": {}, "screenshotsBase64": [], "text": "", "page_tabs": []}, message="")
# 默认响应
return ResultModel(code=200, data={"message": "请求处理成功"})
async def send_ping(listener: GrpcListener):
"""心跳维护任务"""
async def send_ping(listener):
while True:
try:
await listener.send_to_all_stream("ping", "#ping", type=-1, retry_count=3)
logging.info("心跳包已发送")
except Exception as e:
logging.error(f"发送心跳异常: {e}")
await asyncio.sleep(5) # 每5秒发送一次
async def respond_to_server(listener: GrpcListener):
"""服务端消息响应器"""
while True:
try:
# 实际业务中可添加消息检测逻辑
# 示例:当收到特定通知时发送响应
# if 收到特殊通知:
# response = {"status": "OK", "timestamp": int(time.time())}
# await listener.send_to_all_stream("response", json.dumps(response))
await asyncio.sleep(1) # 防止CPU过载
except Exception as e:
logging.error(f"响应器异常: {e}")
await asyncio.sleep(5) # 异常时延长等待
await asyncio.sleep(5)
await listener.send_to_all_stream(requestId="ping", body="#ping", type=-1)
async def main():
# 认证配置
auth_config = {
"headers": {
"Content-Type": "application/x-www-form-urlencoded",
"Sm4-Key": "dUVNkTJLlzMHPqBTZh085jT0N6S7930l6sgddJsYSC8=",
"Cookie": "ENCRYPT_KEY=f48bf3-05fe-4978"
},
"params": {
"username": "api_tester",
"password": "$SM4$Nd/e40vIS6UD9VMaSOmYGlrBORfo7r5/1z9D5d4E4es=$4MS$",
"tenantCode": "API_test",
"scope": "all",
"client_id": "a68ad587830d41aebf418a919006353e",
"client_secret": "Ninetech@123",
"grant_type": "password"
}
}
try:
# 获取访问令牌
token_res = requests.post(
......@@ -93,41 +98,33 @@ async def main():
}
logging.info(f"gRPC配置加载完成: {grpc_config}")
# 初始化gRPC客户端
# 创建 gRPC 客户端
client = GrpcClient()
client.set_header(grpc_config["token"], grpc_config["client_id"])
# 建立连接
if not await client.connect(grpc_config["host"], grpc_config["is_ssl"]):
logging.error("gRPC服务器连接失败")
client.set_header(token=grpc_config["token"], client_id=grpc_config["client_id"])
connected = await client.connect(address=grpc_config["host"], use_ssl=grpc_config["is_ssl"])
if not connected:
logger.error("Failed to connect to gRPC server.")
return
# 启动消息监听器
# 创建 gRPC 监听器
listener = GrpcListener(client)
listener.message_received = handle_message
listener.start()
# 启动后台任务
tasks = [
asyncio.create_task(send_ping(listener)),
asyncio.create_task(respond_to_server(listener))
]
# 启动 ping 任务
ping_task = asyncio.create_task(send_ping(listener))
# 主循环
try:
while True:
await asyncio.sleep(1)
except KeyboardInterrupt:
logging.info("正在关闭服务...")
await asyncio.gather(ping_task)
except asyncio.CancelledError:
await listener.stop()
await client.disconnect()
for task in tasks:
task.cancel()
await asyncio.gather(*tasks, return_exceptions=True)
except requests.RequestException as e:
logger.error(f"Request error: {e}")
except grpc.aio.AioRpcError as e:
logger.error(f"gRPC error: {e}")
except Exception as e:
logging.error(f"服务启动失败: {e}")
logger.error(f"Unexpected error: {e}")
if __name__ == "__main__":
asyncio.run(main())
\ No newline at end of file
import json
from copy import deepcopy
from enum import Flag, auto
from typing import Any
from pydantic import BaseModel
class ActivityType(Flag):
BROWSER = auto() # 1
APP = auto() # 2
def truncate_base64_fields(data: Any, truncate_length: int = 10) -> Any:
if isinstance(data, dict):
new_data = {}
for key, value in data.items():
# 如果是base64图片字段,截断
if key in [
"screenshots",
"screenshotsBase64",
"screenshots_base64",
] and isinstance(value, list):
truncated_list = [
(item[:truncate_length] + "...")
if isinstance(item, str) and len(item) > truncate_length
else item
for item in value
]
new_data[key] = truncated_list
else:
new_data[key] = truncate_base64_fields(value, truncate_length)
return new_data
elif isinstance(data, list):
return [truncate_base64_fields(item, truncate_length) for item in data]
else:
return data
class ResultModel(BaseModel):
code: int
data: Any = None
message: str = ""
@staticmethod
def success(data: Any = None, message: str = "") -> "ResultModel":
return ResultModel(code=200, data=data, message=message)
@staticmethod
def error(
message: str,
code: int = 500,
data: Any = None,
) -> "ResultModel":
return ResultModel(code=code, message=message, data=data)
def log_str(self) -> str:
try:
raw_dict = self.dict()
safe_dict = deepcopy(raw_dict)
log = truncate_base64_fields(safe_dict)
return json.dumps(
log,
default=lambda o: o.__dict__,
ensure_ascii=False,
)
except Exception:
return json.dumps(
self,
default=lambda o: o.__dict__,
ensure_ascii=False,
)
......@@ -3,8 +3,7 @@
import grpc
import protos.BitAgentWorker_pb2 as BitAgentWorker__pb2
import grpc_manager.protos.BitAgentWorker_pb2 as BitAgentWorker__pb2
GRPC_GENERATED_VERSION = "1.69.0"
GRPC_VERSION = grpc.__version__
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论