first commit

This commit is contained in:
阿甘 2024-06-12 23:11:03 +08:00
parent e768ddf76e
commit cc90031690
10 changed files with 683 additions and 0 deletions

2
config/appConfig.table Normal file
View File

@ -0,0 +1,2 @@
{
}

2
config/feishu.table Normal file
View File

@ -0,0 +1,2 @@
{
}

7
default.aproj Normal file
View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<project ver="10" name="飞书api调用demo" libEmbed="true" icon="..." ui="console" output="飞书api调用demo.exe" CompanyName="单位名称" FileDescription="飞书api调用demo" LegalCopyright="Copyright (C) 作者 2024" ProductName="飞书api调用demo" InternalName="飞书api调用demo" FileVersion="0.0.0.5" ProductVersion="0.0.0.5" publishDir="/dist/" dstrip="false" local="false" ignored="false">
<file name="main.aardio" path="main.aardio" comment="启动程序代码"/>
<folder name="资源文件" path="res" embed="true" local="false" ignored="false">
<file name="test.aardio" path="res\test.aardio" comment="res\test.aardio"/>
</folder>
</project>

Binary file not shown.

BIN
dist/飞书api调用demo.exe vendored Normal file

Binary file not shown.

68
lib/config.aardio Normal file
View File

@ -0,0 +1,68 @@
//config 配置文件
import fsys.config;
config = fsys.config("/config/");
//config = fsys.config( io.appData("/软件作者/应用程序名/") );
//不需要序列化的配置名字前请添加下划线
namespace config {
__appName = "xxxxxx";
__feishu = {
appConfig = {
app_id = "xxxx";
app_secret = "xxxx";
recipient_email = "";
recipient_mobile = "xxxx";
};
chat_bot_webhook = {
a = "xxxx";
b = "xxxx";
c = "xxxx";
//a = "xxxx";// test
};
api = {
access_token_url = "xxxx";
user_id_url = "xxxx";
file_upload_url = "xxxx";
messages_url = "xxxx";
};
chat_id = {
a = "xxxx";
//a = "xxxx";// test
};
user_id = {
a = "xxxx";
b = "xxxx";
c = "xxxx";
d = "xxxx";
};
};
__watchFolder = {
a = "xxxx";
b = "xxxx";
c = "xxxx";
};
__copy2Folder = {
a = "xxxx";
b = "xxxx";
c = "xxxx";
}
__user2ODM = {
a = "a";
b = "b";
c = "c";
}
}
/**intellisense(config)
__appName = 应用程序名
__feishu = 飞书配置
__feishu.appConfig = 飞书app配置
__feishu.appConfig.app_id = app id
__feishu.appConfig.app_secret = app secret
saveAll() = 写入所有配置到文件
? = 获取值时指定不以下划线开始的配置表名称,\n返回一个可自动序列化到同名配置文件的表对象。\n如果此对象名以下划线开始则可以正常读写值不会序列化为配置文件。\n否则不能对此对象直接赋值只能对配置表对象的成员赋值。\n\n配置表可自动自文件加载,退出线程前自动序列化并存入文件。\n仅序列化以字符串、数值为键的元素\n仅序列化值为字符串、数值、buffer 以及定义了 _serialize 元方法的成员。\n循环引用的值转换为 null序列化时忽略成员函数\n!fsys_table.
end intellisense**/

153
lib/feishu.aardio Normal file
View File

@ -0,0 +1,153 @@
//飞书接口
namespace feishu
import web.json;
import inet.http;
import web.rest.jsonLiteClient;
//import console.int;
//import console.progress;
class FeiShu{
ctor( appId, appSecret ){
this.app_id = appId;
this.app_secret = appSecret;
};
getAccessToken = function(url){
var result;
//创建 HTTP 客户端对象
var http = ..inet.http();
var response = http.post(url, {
app_id = this.app_id;
app_secret = this.app_secret;
});
response_data = ..web.json.parse(response);
if(0 == response_data["code"]){
result = response_data["tenant_access_token"];
}
else {
result = false;
}
http.close();
return result;
}
uploadFile = function(url, f_name, f_path, access_token){
var result;
//创建 REST 客户端
var http = ..web.rest.client();
//声明 HTTP API
var ftEllo = http.api(url);
//设置请求头
headers = {"Authorization" = "Bearer " + access_token};
http.setHeaders(headers);
//进度条
//var bar = ..console.progress();
//bar.doneText = f_name + "-上传完成。";
var response = ftEllo.sendMultipartForm( {
file_type = "stream";
file_name = f_name;
file = f_path;
},function(sendData,sendSize,contentLength,remainSize){
/*
sendData 为本次上传数据;
sendSize 为本次上传字节数;
contentLength 为要上传的总字节数;
remainSize 为剩余字节数;
*/
//bar.setProgress((1 - remainSize/contentLength) * 100,"正在上传 ......");
}
);
if(200 == http.lastStatusCode && null != response){
//{"code":0,"data":{"file_key":"file_v3_009o_e56a00e1-4670-4620-9392-12572b197c1g"},"msg":"success"}
response_data = ..web.json.parse(response);
result = response_data[["data"]][["file_key"]];
..logger.info("文件【"++file_name++"】已上传file_key="++result);
}
else {
..logger.error(http.lastResponseString());
result = false;
}
http.close();
return result;
}
downloadFile = function(url, message_id, file_key, file_name, save_path, access_token){
//创建 REST 客户端
var http = ..web.rest.client();
//声明 HTTP API
var ftEllo = http.api(url++"/"++message_id++"/resources/"++file_key);
//设置请求头
headers = {
"Authorization" = "Bearer " + access_token;
};
http.setHeaders(headers);
//进度条
//var bar = ..console.progress();
//bar.doneText = file_name + "-下载完成。";
var recvSizeAll = 0;
ftEllo.receiveFile(file_name,function(recvData,recvSize,contentLength){
/*
recvData 为当前下载数据。
recvSize 为当前下载数据字节数。
contentLength 为需要下载的总字节数。
*/
//recvSizeAll += recvSize;
//bar.setProgress((1 - (contentLength - recvSizeAll)/contentLength) * 100,file_name++"-正在下载 ......");
}, save_path).get({
type = "file";
});
http.close();
..logger.info("文件【"++file_name++"】已下载。");
return http.lastStatusCode;
}
getChatHistoryMsg = function(url, container_id, page_size, access_token){
/*
container_id 容器的ID可填写
chat_id群聊或单聊的 ID参见群ID 说明
thread_id话题 ID参见话题介绍
示例值:"oc_234jsi43d3ssi993d43545f"
page_size 分页大小
*/
var result;
//创建 REST 客户端
var http = ..web.rest.client();
//声明 HTTP API
var ftEllo = http.api(url);
//设置请求头
headers = {
"Authorization" = "Bearer " + access_token;
};
http.setHeaders(headers);
var response = ftEllo.get({
container_id_type = "chat";
container_id = container_id;
sort_type = "ByCreateTimeDesc";
page_size = page_size;
})
if(200 == http.lastStatusCode && null != response){
response_data = ..web.json.parse(response);
result = response_data[["data"]][["items"]];
}
else {
..logger.error(http.lastResponseString());
result = false;
}
http.close();
return result;
}
}

65
lib/logger.aardio Normal file
View File

@ -0,0 +1,65 @@
namespace logger
import console;
import debug;
import preg;
class Logger{
ctor(){
..console.open();
this.queryinfo = "select source,function,upvars,name,currentline,activelines";
this.regex = ..preg("(?<=//).+(?=\.\.\.)");
this.type_enum = {
[1] = "INFO ";
[2] = "DEBUG ";
[3] = "WARNING";
[4] = "ERROR ";
[5] = "SUCCESS";
}
this.type = 1;
this.color = ..console.color.white;
};
logMessage = function(msg, dInfo){
var _time = tostring(..time());
//var _file = this.regex.match(dInfo["source"]["src"]);
var _line = dInfo["currentline"];
var _function = dInfo["name"] == null ? "module" : dInfo["name"];
..console.writeColorText(_time, ..console.color.darkGreen);
..console.writeColorText(" | ");
..console.writeColorText(this.type_enum[this.type], this.color);
..console.writeColorText(" | ");
..console.writeColorText(_function++":"++_line, ..console.color.cyan);
..console.writeColorText(' - ');
..console.writeColorText(msg++'\n', this.color);
}
info = function(msg){
this.type = 1;
this.color = ..console.color.white;
var dInfo = ..debug.queryinfo(2, this.queryinfo);
this.logMessage(msg, dInfo);
}
debug = function(msg){
this.type = 2;
this.color = ..console.color.blue;
var dInfo = ..debug.queryinfo(2, this.queryinfo);
this.logMessage(msg, dInfo);
}
warning = function(msg){
this.type = 3;
this.color = ..console.color.darkGray;
var dInfo = ..debug.queryinfo(2, this.queryinfo);
this.logMessage(msg, dInfo);
}
error = function(msg){
this.type = 4;
this.color = ..console.color.red;
var dInfo = ..debug.queryinfo(2, this.queryinfo);
this.logMessage(msg, dInfo);
}
success = function(msg){
this.type = 5;
this.color = ..console.color.green;
var dInfo = ..debug.queryinfo(2, this.queryinfo);
this.logMessage(msg, dInfo);
}
}

361
main.aardio Normal file
View File

@ -0,0 +1,361 @@
import config;
import process;
import fsys.dirWatcher;
import win.ui;
//import godking.vlistEx;
import sqlite.latest;
import console;
import time;
import logger;
/*DSG{{*/
var mainForm = win.form(text=config.__appName;right=1088;bottom=652)
mainForm.add(
//vlist={cls="vlistEx";left=10;top=8;right=1079;bottom=646;db=1;dl=1;dr=1;dt=1;edge=1;transparent=1;z=1}
)
/*}}*/
console.setTitle(config.__appName);
logger = logger.Logger();
import feishu;
var Transsioner = feishu.FeiShu(config.__feishu.appConfig.app_id, config.__feishu.appConfig.app_secret);
mainForm.feishuGetChatMsg = function(msg_count){
var access_token = Transsioner.getAccessToken(config.__feishu.api.access_token_url);
//mainForm.info(access_token);
//var file_key = Transsioner.uploadFile(config.__feishu.api.file_upload_url, "test.txt", "@F:\ZTools\aardio\test.txt", access_token);
//console.log(file_key);
var chat_history_msg = Transsioner.getChatHistoryMsg(config.__feishu.api.messages_url, "oc_580423c5700a2108036400310c634dcb", msg_count, access_token);
return chat_history_msg;
}
mainForm.feishuDownloadFile = function(message_id, file_key, file_name){
var access_token = Transsioner.getAccessToken(config.__feishu.api.access_token_url);
logger.info(access_token);
var file_data = Transsioner.downloadFile(config.__feishu.api.messages_url, message_id, file_key, file_name, "./temp", access_token);
}
//==========================================test============================================
var test = function(){
var db = sqlite("/sqlite.db"); //创建数据库
if( not db.existsTable("chat") ){
db.exec( "CREATE TABLE [chat](create_time, chat_id, message_id, msg_type, body);"); //创建表
}
var result = db.stepQuery("SELECT * FROM [chat]",{ create_time = "1712827756523"})
var data = web.json.parse(result["body"]["content"]);
//console.dump(data["file_key"]);
//console.dump(data["file_name"]);
//mainForm.feishuDownloadFile(result["message_id"], data["file_key"], data["file_name"]);
var data = mainForm.feishuDownloadFile("om_3e712824a2a698aef85af022ce5c9dbc", "file_v3_009r_efb97b0b-0b50-41ba-a41e-97af82e0fa9g", "LC2002_it8010_sp.pac");
}
//test();
//=========================使用单独的线程操作文件下载、上传、消息提醒=========================================
var downAndUpFileThread = function(mainForm, data, odm){
thread.invoke(
function(mainForm, data, odm){
import fsys;
import time;
import sqlite.latest;
import feishu;
import config;
import logger;
logger = logger.Logger();
var db = sqlite("/sqlite.db");
var status = false;
var feishuWebhookBotSendMsg = function(webhook, msg){
import inet.http;
//创建 HTTP 客户端对象
try{
var http = ..inet.http();
var response = http.post(webhook, web.json.stringify({
msg_type = "text";
content = {
text = msg;
}
}));
//{"StatusCode":0,"StatusMessage":"success","code":0,"data":{},"msg":"success"}
var response_data = web.json.parse(response);
http.close();
if(response_data["StatusCode"] == 0){
logger.success("机器人通知已发出:"++msg);
return true;
}
else {
logger.error("机器人通知发送失败:"++response);
return false;
}
}
catch(e){
logger.error(e);
}
}
try{
var Transsioner = feishu.FeiShu(config.__feishu.appConfig.app_id, config.__feishu.appConfig.app_secret);
var access_token = Transsioner.getAccessToken(config.__feishu.api.access_token_url);
var _create_time = data["create_time"];
var _message_id = data["message_id"];
var file_data = web.json.parse(data["body"]["content"]);
var file_key = file_data["file_key"];
var file_name = file_data["file_name"];
//mainForm.vlist.addRow("[@rowindex]", _create_time, odm, file_name, "正在下载...");
//var row_index = mainForm.vlist.find(_create_time,1,mainForm.vlist.count,2,false,false);
//下载文件
var download_to = ".\feishu2ftp\" ++ _create_time;
var download_result = Transsioner.downloadFile(config.__feishu.api.messages_url, _message_id, file_key, file_name, download_to, access_token);
if(download_result == 200){
var file_path_local = download_to ++ "\" ++ file_name;
if(io.exist(file_path_local)){
var copy_to = config.__copy2Folder[odm] ++ "\" ++ _create_time;//飞书上的文件复制到服务器该目录下
var copy_result = fsys.copy(".\feishu2ftp\"++_create_time, copy_to);
if(copy_result){
logger.success("新文件已上传至:" ++ copy_to);
logger.debug("即将调用机器人发送通知webhook="++config.__feishu.chat_bot_webhook[odm]);
feishuWebhookBotSendMsg(config.__feishu.chat_bot_webhook[odm], "文件【" ++ file_name ++ "】已放入该路径:" ++ copy_to);
//mainForm.vlist.setRowText(row_index, {"序号"="[@rowindex]", "时间"=_create_time, "ODM"=odm, "文件"=file_name, "状态"="已上传"});
status = true;
}
}
else {
logger.error("本地临时目录未找到下载的文件:" ++ file_path_local);
}
}
else {
logger.error("文件下载失败。")
//mainForm.vlist.setRowText(row_index, {"序号"="[@rowindex]", "时间"=_create_time, "ODM"=odm, "文件"=file_name, "状态"="文件下载失败"});
}
db.exec("UPDATE chat SET status = @status WHERE message_id = @message_id;",{
status = status;
message_id = _message_id;
} );
}
catch(e){
logger.error(e);
}
},mainForm, data, odm
)
}
//=========================使用单独的线程操作文件下载、上传、消息提醒=end=====================================
//==========================================监视消息============================================
mainForm.chatWatcherProc = function(){
thread.invoke(
function(mainForm, downAndUpFileThread){
import sqlite.latest;
import fsys;
import time;
import feishu;
import config;
import logger;
logger = logger.Logger();
var Transsioner = feishu.FeiShu(config.__feishu.appConfig.app_id, config.__feishu.appConfig.app_secret);
var db = sqlite("/sqlite.db"); //创建数据库
if( not db.existsTable("chat") ){
db.exec( "CREATE TABLE [chat](create_time, chat_id, message_id, msg_type, body, data, status);"); //创建表
}
//=========================循环读取群组历史消息,检查是否有用户上传文件========================================
while(true){
try{
//获取群组历史消息
var msg_count = 10;
var access_token = Transsioner.getAccessToken(config.__feishu.api.access_token_url);
var chat_history_msg = Transsioner.getChatHistoryMsg(config.__feishu.api.messages_url, config.__feishu.chat_id.a, msg_count, access_token);
//end
for(k, data in chat_history_msg){
var _sender_type = data["sender"]["sender_type"];
if(_sender_type != "user"){continue;}
var _create_time = data["create_time"];
var _chat_id = data["chat_id"];
var _message_id = data["message_id"];
var _msg_type = data["msg_type"];
var _body = data["body"];
var _data = data;
//查询该消息是否已记录
var result = db.stepQuery("SELECT * FROM [chat]",{ message_id = _message_id})
if(result != null){continue;}
//新消息加入数据库记录
var cmd = db.prepare("REPLACE INTO chat VALUES (@create_time, @chat_id, @message_id, @msg_type, @body, @data, @status);" )
cmd.step(
create_time = _create_time;
chat_id = _chat_id;
message_id = _message_id;
msg_type = _msg_type;
body = _body;
data = _data;
status = "";
)
//判断是否为文件消息
if(_msg_type == "file"){
var _sender_id = data["sender"]["id"];
var sender_user = null;
for(k,v in config.__feishu.user_id){
if( v == _sender_id){
sender_user = k;//获取发送该消息的用户,用于将文件放入对应路径,以及在对应群聊中发送提醒。
}
}
if(sender_user == null){
logger.error("未定义该用户发送的文件将拷贝到何处。");
continue;
}
logger.debug("检测到新文件,发送自用户【"++sender_user++"】:"++_sender_id);
var odm = null;
for(k,v in config.__user2ODM){
if( k == sender_user){
odm = v;
}
}
logger.debug("新文件即将上传至【"++odm++"】:"++config.__copy2Folder[odm]);
//用新线程
downAndUpFileThread(mainForm, data, odm);
//end
}
}
}
catch(e){
logger.error(e);
}
//检测频率
sleep(1000);
}
//=========================循环读取群组历史消息,检查是否有用户上传文件=end=====================================
},mainForm,downAndUpFileThread
)
}
//mainForm.chatWatcherProc();
//==========================================监视文件有新增文件时上传至osstodo========================================
var fileWatcherProc = function(){
for(odm, dir in config.__watchFolder){
var watchDir = dir;
//创建监视线程
mainForm.thrdWatcher = fsys.dirWatcher.thread(
function(filename,action,actionText){
var fullname = watchDir + "\" + filename;
var newDirs = {};
select(action) {
case 1 {//添加文件
//mainForm.richedit.print(fullname);
if(fsys.isDir(fullname)){
table.push(newDirs, fullname);
}
//创建新的工作线程-用于处理耗时的事情,不阻塞下一个新文件的处理
thread.invoke(
function(mainForm){
sleep(5000)
},mainForm
)
}
case 2 {//移除文件
}
case 3 {//文件被修改
}
case 4 {//重命名:原文件名
}
case 5 {//重命名:新文件名
}
else {}
}
}, watchDir);
}
}
//fileWatcherProc();
//==========================================vlist============================================
/*
mainForm.vlist.setHeaderHeight(30);
mainForm.vlist.onlyText = true;
mainForm.vlist.ellipsion = true;
var t = { fields={"序号","时间","ODM","文件","状态"} };
*/
/*
for(i=1;10;1){
var tt={};
tt["序号"]="[@rowindex]"; // 行序号标记是不允许编辑修改的
tt["时间"]=time.now();
tt["ODM"]=string.random("易景","萨瑞","英迈");
tt["文件"]=math.random(1000,9999);
tt["状态"]=math.random(0,100);
..table.push(t,tt);
}
*/
//mainForm.vlist.setTable(t,,{60,150,60,-1,100},1);
//mainForm.vlist.setSortMark("▲" /*升序符号*/,"▼" /*降序符号*/,"" /*默认符号*/);
//mainForm.vlist.onSortColumn = function(col,desc){
// /*点击列标题进行排序。col列号从1开始。desc是否倒序。*/
// owner.sort( col, desc, 0 /*数据转换0默认 1时间 2数值 3文本*/ ,false /*使用微软api进行文本排序*/ );
//}
/**
mainForm.vlist.onDrawCellRect = function(row,col,hdc,rc,bkcolor,text,font,colalign){
/*绘制单元格有效区域背景不含内容返回ture则忽略原有效区域背景否则继续绘制有效区域原背景*/
/*如果定义的drawCellRect()函数返回true则本函数无效。*/
var num = tonumber(text);
if (col==5){
gdi.fillRect(hdc,0xEECCFF,rc);
var w = math.round(rc.width()*num/100);
for(i=0;w-1;5){
var left = rc.left+i;
var right = rc.left+i+4;
if right>left+w right=left+w;
var rect = ::RECT(left,rc.top,right,rc.bottom);
gdi.fillRect(hdc,0x55cc55,rect);
}
var f = ..table.clone(font)
f.color=0xFFFFFF
var rc1=table.clone(rc)
rc1.offset(-1,-1)
gdi.drawText(hdc,f,text++"%",rc1,colalign|4/*_DT_VCENTER*/|0x20/*_DT_SINGLELINE*/)
rc1.offset(2,2)
gdi.drawText(hdc,f,text++"%",rc1,colalign|4/*_DT_VCENTER*/|0x20/*_DT_SINGLELINE*/)
rc1.offset(-2,0)
gdi.drawText(hdc,f,text++"%",rc1,colalign|4/*_DT_VCENTER*/|0x20/*_DT_SINGLELINE*/)
rc1.offset(2,-2)
gdi.drawText(hdc,f,text++"%",rc1,colalign|4/*_DT_VCENTER*/|0x20/*_DT_SINGLELINE*/)
font.color = 0x000000
gdi.drawText(hdc,font,text++"%",rc,colalign|4/*_DT_VCENTER*/|0x20/*_DT_SINGLELINE*/)
return true;
}
}
**/
var main = function(){
mainForm.chatWatcherProc();
logger.info("已开始监测群聊文件消息");
}
main();
import fsys.file;
import thread.event;
mainForm.onClose = function(hwnd,message,wParam,lParam){
if(!mainForm.thrdWatcher) return;
mainForm.thrdWatcher.close(); //停止监视文件
}
mainForm.show(true);
win.loopMessage();
return mainForm;

25
res/test.aardio Normal file
View File

@ -0,0 +1,25 @@
//test.aardio
import logger;
logger = logger.Logger();
newDirs = {};
dir1 = "C:\Users\Hang\Desktop\临时目录\英迈\新建文件夹";
dir2 = "C:\Users\Hang\Desktop\临时目录\英迈\新建文件夹\2";
table.push(newDirs, dir1);
console.dump(newDirs);
table.push(newDirs, dir2);
console.dump(newDirs);
for i in table.eachArgs(newDirs){
for j in string.each(newDirs[i], dir1,){
console.dump(j)
}
}
console.pause();