aardio 文档
aardio 范例: WebDAV 服务器 - 图形界面版
import win.ui;
import fsys.dlg;
import fonts.fontAwesome;
/*DSG{{*/
mainForm = win.form(text="WebDAV 服务器 - 图形界面版";right=805;bottom=584;bgcolor=0xF5F7FA;border="dialog frame";max=false)
mainForm.add(
bgConfig={cls="bkplus";left=20;top=20;right=779;bottom=280;bgcolor=0xFFFFFF;border=1;dl=1;dr=1;dt=1;z=1};
bgLog={cls="bkplus";left=20;top=300;right=779;bottom=560;bgcolor=0xFFFFFF;border=1;db=1;dl=1;dr=1;dt=1;z=2};
btnBrowse={cls="plus";text="浏览";left=516;top=113;right=586;bottom=143;dr=1;dt=1;font=LOGFONT(h=-13);z=11};
btnClear={cls="plus";text="清空";left=698;top=310;right=748;bottom=335;dr=1;dt=1;z=20};
btnRestart={cls="plus";text="重启";left=526;top=210;right=586;bottom=250;dr=1;dt=1;font=LOGFONT(h=-13);notify=1;z=18};
btnStart={cls="plus";text="启动服务";left=413;top=210;right=503;bottom=250;dr=1;dt=1;font=LOGFONT(h=-13);notify=1;z=17};
chkPublicAddress={cls="plus";text="公网 IP";left=615;top=254;right=720;bottom=285;align="left";font=LOGFONT(h=-15);iconStyle={align="left";font=LOGFONT(h=-15;name='FontAwesome')};iconText='\uF0C8 ';notify=1;textPadding={left=24};z=24};
editIp={cls="edit";text="0.0.0.0";left=105;top=66;right=368;bottom=96;dl=1;dt=1;edge=1;font=LOGFONT(h=-13);z=5};
editLog={cls="richedit";left=40;top=345;right=748;bottom=540;db=1;dl=1;dr=1;dt=1;edge=1;font=LOGFONT(name='Consolas');link=1;multiline=1;readonly=1;vscroll=1;z=21};
editPass={cls="edit";text="123456";left=446;top=158;right=586;bottom=188;dr=1;dt=1;edge=1;font=LOGFONT(h=-13);password=1;z=15};
editPort={cls="edit";text="8081";left=446;top=66;right=586;bottom=96;dr=1;dt=1;edge=1;font=LOGFONT(h=-13);num=1;z=7};
editRoot={cls="edit";left=105;top=112;right=508;bottom=142;dl=1;dr=1;dt=1;edge=1;font=LOGFONT(h=-13);z=23};
editThread={cls="edit";text="10";left=680;top=66;right=748;bottom=96;dr=1;dt=1;edge=1;font=LOGFONT(h=-13);num=1;z=9};
editUser={cls="edit";text="admin";left=105;top=158;right=368;bottom=188;dl=1;dt=1;edge=1;font=LOGFONT(h=-13);z=13};
lblConfig={cls="bkplus";text="服务配置";left=40;top=30;right=150;bottom=55;color=0x333333;dl=1;dt=1;font=LOGFONT(h=-16;weight=600);z=3};
lblIp={cls="bkplus";text="监听 IP:";left=18;top=69;right=98;bottom=94;align="right";color=0x666666;dl=1;dt=1;font=LOGFONT(h=-13);z=4};
lblLog={cls="bkplus";text="运行日志";left=40;top=310;right=150;bottom=335;color=0x333333;db=1;dl=1;dt=1;font=LOGFONT(h=-16;weight=600);z=19};
lblPass={cls="bkplus";text="密码:";left=379;top=161;right=439;bottom=186;align="right";color=0x666666;dl=1;dr=1;dt=1;font=LOGFONT(h=-13);z=14};
lblPort={cls="bkplus";text="端口:";left=379;top=69;right=439;bottom=94;align="right";color=0x666666;dl=1;dr=1;dt=1;font=LOGFONT(h=-13);z=6};
lblRoot={cls="bkplus";text="根目录:";left=18;top=115;right=98;bottom=140;align="right";color=0x666666;dl=1;dt=1;font=LOGFONT(h=-13);z=10};
lblStatus={cls="plus";text='\u25CF 未启动';left=40;top=213;right=200;bottom=243;align="left";color=0x999999;dl=1;dt=1;font=LOGFONT(h=-14;weight=600);iconStyle={align="left";font=LOGFONT(name='FontAwesome');padding={left=10}};iconText='\uF111';textPadding={left=30};z=16};
lblThread={cls="bkplus";text="线程数:";left=600;top=69;right=670;bottom=94;align="right";color=0x666666;dr=1;dt=1;font=LOGFONT(h=-13);z=8};
lblUser={cls="bkplus";text="用户名:";left=18;top=161;right=98;bottom=186;align="right";color=0x666666;dl=1;dt=1;font=LOGFONT(h=-13);z=12};
qr={cls="plus";text='\uF029';left=610;top=112;right=748;bottom=250;border={color=0xFF808080;radius=8;width=1};db=1;dr=1;dt=1;font=LOGFONT(h=-22;name='FontAwesome');foreRepeat="scale";repeat="scale";z=22}
)
/*}}*/
// 全局变量
var isRunning = false;
var webdavServerId = null;
// 更新状态显示
var updateStatus = function(status, color){
mainForm.lblStatus.text = "● " + status;
mainForm.lblStatus.color = color;
}
// 浏览目录
mainForm.btnBrowse.oncommand = function(id,event){
import fsys.dlg.dir;
var dir = fsys.dlg.dir(mainForm.editRoot.text, mainForm, "选择 WebDAV 根目录");
if(dir){
mainForm.editRoot.text = dir;
}
}
mainForm.editRoot.text = io.fullpath("/")
// 清空日志
mainForm.btnClear.oncommand = function(id,event){
mainForm.editLog.text = "";
}
// 停止服务
var stopServer = function(){
if(mainForm.webdavServerId){
import wsock.tcp.server;
wsock.tcp.server.closeById(mainForm.webdavServerId);
mainForm.webdavServerId = null;
isRunning = false;
updateStatus("已停止", 0xFF999999);
mainForm.btnStart.text = "启动服务";
mainForm.editLog.print("[" + tostring(time(), "%H:%M:%S") + "] 服务已停止");
}
}
// 启动服务
var startServer = function(){
mainForm.editLog.text = "";
var ip = mainForm.editIp.text;
var port = tonumber(mainForm.editPort.text);
var threadNum = tonumber(mainForm.editThread.text);
var rootDir = mainForm.editRoot.text;
var username = mainForm.editUser.text;
var password = mainForm.editPass.text;
// 验证输入
if(!port || port < 1 || port > 65535){
mainForm.msgbox("请输入有效的端口号 (1-65535)", "错误", "error");
return;
}
if(!threadNum || threadNum < 1){
mainForm.msgbox("请输入有效的线程数 (≥1)", "错误", "error");
return;
}
if(!#rootDir){
mainForm.msgbox("请选择 WebDAV 根目录", "错误", "error");
return;
}
import fsys;
if(!fsys.isDir(rootDir)){
mainForm.msgbox("指定的根目录不存在", "错误", "error");
return;
}
if(!#username || !#password){
mainForm.msgbox("请输入用户名和密码", "错误", "error");
return;
}
// 启动服务
thread.invoke(
function(mainForm, ip, port, threadNum, rootDir, username, password){
import web.dav.server;
var webdav = web.dav.server(ip, tonumber(port));
webdav.threadNum = threadNum;
webdav.resourceRoot = rootDir;
mainForm.webdavServerId = webdav.id;
var url = webdav.getUrl(true);
var tUrl = inet.url.split(url);
if(mainForm.chkPublicAddress.checked){
import wsock.udp.stunClient;
var sutn = wsock.udp.stunClient();
var resp = sutn.getPublicAddress();
if(resp){
tUrl.host = resp.ip;
url = tostring(tUrl);
}
}
tUrl.user = username;
tUrl.password = password;
mainForm.qr.setUrl( tostring(tUrl) );
mainForm.editLog.print("[" + tostring(time(), "%H:%M:%S") + "] 服务已启动: " + url + " 手机扫码可连接");
mainForm.editLog.print("[" + tostring(time(), "%H:%M:%S") + "] 根目录: " + rootDir);
mainForm.editLog.print("[" + tostring(time(), "%H:%M:%S") + "] 线程数: " + threadNum);
import win.ts;
if(win.ts.session.isRemote()){
mainForm.editLog.appendLink("关闭远程桌面并继续运行服务");
}
webdav.threadGlobal = {
mainForm = mainForm;
authData = [username, password]
}
webdav.run(
function(response, request, session){
// HTTP 认证
if(!request.auth(
function(user){
if(user == ..authData[1]) return ..authData[2];
}, "WebDAV"
)){
return false;
}
// WebDAV 不可能向目录发送 GET 请求
if(request.method=="GET" && string.endsWith(request.path,"/")){
// 返回 WebDAV 客户端 Web 版
response.write($"~\lib\web\dav\webdav.html")
return false;
}
// 记录请求
..mainForm.editLog.print(
"[" + tostring(time(), "%H:%M:%S") + "] " +
request.method + " " + request.path
);
}
)
mainForm.editLog.print("[" + tostring(time(), "%H:%M:%S") + "] 服务已退出");
},
mainForm, ip, port, threadNum, rootDir, username, password
)
isRunning = true;
webdavServerId = mainForm.webdavServerId;
updateStatus("运行中", 0xFF4CAF50);
mainForm.btnStart.text = "停止服务";
mainForm.editLog.print("[" + tostring(time(), "%H:%M:%S") + "] 正在启动服务...");
}
mainForm.editLog.onHyperlink =function(message,href){
if( message = 0x202/*_WM_LBUTTONUP*/ ) {
if(href=="关闭远程桌面并继续运行服务"){
import win.ts;
win.ts.session().connect();
return;
}
raw.execute(href);
}
}
mainForm.qr.setUrl = function(url){
import qrencode.bitmap
var qrBmp = qrencode.bitmap( url );
mainForm.qr.border = null;
mainForm.qr.text = null;
mainForm.qr.setForeground(qrBmp.copyBitmap(mainForm.qr.width));
}
// 启动/停止按钮
mainForm.btnStart.oncommand = function(id,event){
if(isRunning){
stopServer();
} else {
startServer();
}
}
import win.version;
if(win.version.isServer){
import win.ts;
if( win.ts.session.isRemote() ){
// 检测到当前是通过远程桌面登录的服务器环境,默认使用公网 IP
mainForm.chkPublicAddress.checked = true;
import wsock.tcp.server;
if( wsock.tcp.server.isFreePort(80)) mainForm.editPort.text = 80;
}
}
// 重启按钮
mainForm.btnRestart.oncommand = function(id,event){
if(isRunning){
stopServer();
thread.delay(500);
}
startServer();
}
// 按钮样式
mainForm.btnStart.skin({
background={default=0xFF4CAF50;hover=0xFF45A049;active=0xFF3D8B40};
color={default=0xFFFFFFFF};
border={default={radius=6}}
});
mainForm.btnRestart.skin({
background={default=0xFFFF9800;hover=0xFFFB8C00;active=0xFFE67E00};
color={default=0xFFFFFFFF};
border={default={radius=6}}
});
mainForm.btnBrowse.skin({
background={default=0xFF2196F3;hover=0xFF1E88E5;active=0xFF1976D2};
color={default=0xFFFFFFFF};
border={default={radius=6}}
});
mainForm.btnClear.skin({
background={default=0xFFEEEEEE;hover=0xFFE0E0E0;active=0xFFD0D0D0};
color={default=0xFF666666};
border={default={radius=4}}
});
mainForm.chkPublicAddress.skin({
color={
active=0xFF00FF00;
default=0xFF000000;
disabled=0xEE666666;
hover=0xFFFF0000
};
checked={
iconText='\uF14A'
}
})
// 窗口退出时停止服务
mainForm.onDestroy = function(){
if(isRunning){
stopServer();
}
}
mainForm.chkPublicAddress.oncommand = function(id,event){
mainForm.btnRestart.oncommand();
}
import win.ts.changeNotification;
var changeNotification = win.ts.changeNotification(winform);
changeNotification.onSessionChange = function(sessionId,statusText,statusCode){
if(statusCode&1) mainForm.enableDpiScaling(); //恢复远程桌面会话时必须更新 DPI 缩放大小
}
mainForm.show();
win.loopMessage();
Markdown 格式