aardio 文档
aardio 范例: asynHttpServer - 扫码快传
//扫码传文件
import fonts.fontAwesome;
import win.ui;
/*DSG{{*/
var winform = win.form(text="asynHttpServer - 扫码快传";right=807;bottom=465;bgcolor=16777215;border="none";max=false)
winform.add(
bk={cls="bk";left=-2;top=-5;right=810;bottom=29;bgcolor=12639424;z=9};
bkplus={cls="bkplus";text="asynHttpServer - 扫码传文件";left=18;top=4;right=203;bottom=26;align="left";color=5921370;z=10};
btnOpen={cls="plus";text='\uF115';left=444;top=50;right=479;bottom=75;dr=1;dt=1;font=LOGFONT(h=-16;name='FontAwesome');notify=1;z=5};
btnOpenUpload={cls="plus";text="打开上传目录";left=568;top=429;right=709;bottom=458;dr=1;dt=1;font=LOGFONT(h=-15);iconStyle={align="left";font=LOGFONT(h=-15;name='FontAwesome');padding={left=8;top=2}};iconText='\uF115';notify=1;textPadding={left=20};z=11};
btnStart={cls="plus";text="重启服务";left=655;top=47;right=755;bottom=76;bgcolor=14935259;dr=1;dt=1;font=LOGFONT(h=-15);iconStyle={align="left";font=LOGFONT(h=-15;name='FontAwesome');padding={left=8;top=2}};iconText='\uF233';notify=1;textPadding={left=20};z=4};
editDocumentRoot={cls="plus";left=131;top=49;right=430;bottom=73;align="right";border={bottom=1;color=-8355712};dl=1;dr=1;dt=1;editable=1;font=LOGFONT(h=-16);z=7};
editPassword={cls="plus";left=441;top=84;right=632;bottom=108;align="left";border={bottom=1;color=-8355712};dl=1;dr=1;dt=1;editable=1;font=LOGFONT(h=-16);z=13};
editPort={cls="plus";left=550;top=49;right=628;bottom=73;align="left";border={bottom=1;color=-8355712};dl=1;dr=1;dt=1;editable=1;font=LOGFONT(h=-16);z=8};
plus={cls="plus";text="访问密码:";left=332;top=90;right=433;bottom=114;align="right";dr=1;dt=1;font=LOGFONT(h=-15);transparent=1;z=12};
qr={cls="plus";left=499;top=132;right=760;bottom=418;db=1;dr=1;dt=1;repeat="scale";z=6};
static={cls="plus";text="端口:";left=484;top=52;right=547;bottom=76;align="right";dr=1;dt=1;font=LOGFONT(h=-15);transparent=1;z=2};
static2={cls="plus";text="网站根目录:";left=15;top=52;right=129;bottom=76;align="right";dl=1;dt=1;font=LOGFONT(h=-15);transparent=1;z=3};
txtMessage={cls="richedit";left=42;top=132;right=469;bottom=418;autohscroll=false;db=1;dl=1;dr=1;dt=1;link=1;multiline=1;vscroll=1;z=1}
)
/*}}*/
winform.btnStart.skin( {
background={
default=0x668FB2B0;
hover=0xFF928BB3;
disabled=0xFFCCCCCC;
}
})
winform.btnOpen.skin( {
background={
default=0;
hover=0xFF928BB3;
disabled=0xFFCCCCCC;
}
})
winform.btnOpenUpload.skin( {
background={
default=0;
hover=0xFF928BB3;
disabled=0xFFCCCCCC;
}
})
import fsys.config;
config = fsys.config("/config/");
if( io.exist(config.winform.txtMessage) ){
winform.txtMessage.text = config.winform.txtMessage;
}
else {
winform.txtMessage.text = io.getSpecial(0x5/*_CSIDL_MYDOCUMENTS*/)
}
import web.socket.server;
var wsrv = web.socket.server();
var srvHttp = wsrv.httpServer;
/*
wsrv.httpServer 是实现单线程异步 HTTP 服务端的 wsock.tcp.asynHttpServer 对象。
浏览器组件发起异步 HTTP 请求支持 wsock.tcp.asynHttpServer。请不要用 inet.http 等
阻塞请求同一线程创建的 asynHttpServer,这会导致 asynHttpServer 没有机会响应请求而导致死锁,
如果确有这样的需求,可创建线程发起请求,或改用基于多线程的 wsock.tcp.simpleHttpServer。
*/
srvHttp.documentRoot = winform.txtMessage.text;
srvHttp.userToken = string.random(18);
winform.editPassword.text = srvHttp.userToken;
import fsys.info;
var cacheSysIcons = {}
var getSysIconIndex = function(path){
var sfi = fsys.info.get(path, 0x100/*_SHGFI_ICON*/ | 0x4000/*_SHGFI_SYSICONINDEX*/);
if( !(sfi.returnValue ) ) {
return;
}
if(!cacheSysIcons[sfi.iIcon]){
var dataUrl;
var bmp = ..gdip.bitmap(sfi.hIcon,1/*_IMAGE_ICON*/);
if(bmp){
cacheSysIcons[sfi.iIcon] = bmp.saveToBuffer(".png");
bmp.dispose();
}
}
if(sfi.hIcon)::DestroyIcon(sfi.hIcon);
return sfi.iIcon;
}
var cacheClientIps = {}
srvHttp.run(
function(response,request,session){
var token = request.get["t"] : session["token"];
if( #srvHttp.userToken && (token != srvHttp.userToken) ){
winform.txtMessage.printf("客户端:%s 连接被拒绝",request.remoteAddr);
response.errorStatus(401)
return;
}
session["token"] = token;
if(!cacheClientIps[request.remoteAddr]){
winform.txtMessage.printf("客户端:%s 已连接",request.remoteAddr);
cacheClientIps[request.remoteAddr] = true;
}
response.headers["Access-Control-Allow-Origin"] = "*";
response.headers["Access-Control-Allow-Headers"] = "*"
if(request.path=="/main.aardio" && request.get["icon"]){
var iconIdx = tonumber(request.get["icon"]);
if(iconIdx!==null){
if(cacheSysIcons[iconIdx]){
response.contentType = "image/png";
response.write(cacheSysIcons[iconIdx])
return;
}
}
response.errorStatus(404);
return;
}
if(request.path=="/upload/main.aardio"){
if(request.method=="DELETE"){
var path = request.postData();
if(path && string.startWith(path,"/upload/")){
path = ..io.joinpath(srvHttp.documentRoot,path)
if(io.exist(path)){
io.remove(path);
winform.txtMessage.print("已删除:" + path);
response.close();
return;
}
}
response.errorStatus(404);
return;
}
fileData = request.postFileData()
if(fileData){
io.createDir(..io.joinpath(srvHttp.documentRoot,"upload"))
winform.txtMessage.print(..io.joinpath(srvHttp.documentRoot,"upload"))
var fileName = ..io.joinpath(srvHttp.documentRoot,"upload",fileData.filepond.filename)
var ok,err = fileData.filepond.save(fileName);
if(!ok){ response.error(err); }
winform.txtMessage.text = 'http服务端已启动: \n';
winform.txtMessage.print( srvHttp.getUrl(,true) + "/?t=" + srvHttp.userToken );
winform.txtMessage.print( "" );
winform.txtMessage.print( "上传成功:" + fileName );
response.contentType = "text/plain";
response.write("/upload/",fileData.filepond.filename)
return response.close()
}
}
if(!fsys.isDir(request.path) ) {
if( ..io.exist(request.path)
&& (!_STUDIO_INVOKED || request.path!="/main.aardio") )
return response.loadcode(request.path)
else {
request.path = fsys.getParentDir(request.path)
}
}
response.write(`
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<title>asynHttpServer - 扫码快传</title>
<link href="https://lib.baomitu.com/filepond/4.28.2/filepond.min.css" rel="stylesheet">
<script src="https://lib.baomitu.com/filepond/4.28.2/filepond.min.js"></script>
<script>
(function (doc, win) {
var docEl = doc.documentElement,
recalc = function () {
var clientWidth = docEl.clientWidth;
if (!clientWidth) return;
clientWidth=(clientWidth>640)?640:clientWidth;
docEl.style.fontSize = ( (docEl.clientWidth>docEl.clientHeight) ? 12 : 20) * (clientWidth / 320) + 'px';
};
if (!doc.addEventListener) return;
win.addEventListener('orientationchange' in window ? 'orientationchange' : 'resize', recalc, false);
doc.addEventListener('DOMContentLoaded', recalc, false);
})(document, window);
</script>
<style>
html {
padding:20px 0 0;
}
li{ list-style-type:none; }
</style>
</head>
<body>
<input type="file" class="filepond" name="filepond" multiple>
<script crossorigin="anonymous">
if(document.body.style.order === undefined){
alert("浏览器版本过低,请使用Chrome或IE11以上版本浏览器打开此页面!")
}
var inputElement = document.querySelector('input[type="file"]');
FilePond.create(inputElement);
FilePond.setOptions({
server: '/upload/?t=` + srvHttp.userToken + `',
labelIdle: '拖放需要上传的文件到这里或者 <span class="filepond--label-action"> 浏览文件 </span>',
labelFileProcessing: '上传中...',
labelFileProcessingComplete: '上传成功'
});
websocket = new WebSocket("`+wsrv.getUrl("ws",true)+`");
websocket.onmessage = function(evt) {
if(evt.data=="reload"){
window.location.pathname = "/";
window.location.reload(true)
}
};
</script>
<h2>当前目录:`
,request.path,`</h2><hr><ul>`)
if(request.path=="/" && ..io.exist("/upload/")){
response.write('<li><img src="/?icon='++getSysIconIndex("/upload/")+'"><a href="/upload?t=' + srvHttp.userToken + '">上传目录</a><br>\r\n');
}
var file,dir = fsys.list(request.path,,"*.*");
for(i=1;#dir;1){
if(dir[i]==="upload" && request.path=="/") continue;
var iconIdex = getSysIconIndex(dir[dir[ i ]])
response.write('<li><img src="/?icon='++(iconIdex)+'"><a href="'
,inet.url.append(request.path,dir[ i ])
,'?t=' + srvHttp.userToken + '">',dir[ i ],'</a><br>\r\n');
}
for(i=1;#file;1){
var iconIdex = getSysIconIndex(file[file[ i ]])
response.write('<li><img src="/?icon='++(iconIdex)+'"><a href="'
,inet.url.append(request.path,file[ i ])
,'?t=' + srvHttp.userToken + '">',file[ i ],'</a><br>\r\n');
}
response.write("</ul></body></html>")
}
);
import qrencode.bitmap;
var serverInfo = function(){
var ip,port = srvHttp.getLocalIp();
winform.editPort.text = port;
winform.editDocumentRoot.text = io.fullpath(srvHttp.documentRoot)
var url = srvHttp.getUrl(,true);
if(#srvHttp.userToken){
url = url + "/?t=" + srvHttp.userToken;
}
winform.txtMessage.text = 'http服务端已启动: \n';
winform.txtMessage.print( url );
var qrBmp = qrencode.bitmap( url );
winform.qr.setBackground(qrBmp.copyBitmap(winform.qr.width));
winform.txtMessage.print(
"手机扫码可自动打开此网页,可以方便地上传下载文件。
拖动文件或目录到窗口上客户端网页会自动刷新。
asynHttpServer 体积很小可嵌入任何 aardio 程序,
asynHttpServer 可以创建单线程异步模式的 HTTP 服务端,并可以同时创建 WebSocket 服务端(与HTTP服务端共享端口)。asynHttpServer 支持保持连接(Keep Alive),分块传输协议,支持断点续传,支持304缓存,支持文件表单上传,支持使用aardio编写的网站( 接口可兼容IIS/FastCGI下)。
"
);
}
serverInfo();
winform.btnStart.oncommand = function(id,event){
winform.txtMessage.text = "";
winform.btnStart.disabledText = {'\uF254';'\uF251';'\uF252';'\uF253';'\uF250'}
win.delay(500);
var port = tonumber(winform.editPort.text);
srvHttp.documentRoot = fsys.isDir(winform.editDocumentRoot.text) ? winform.editDocumentRoot.text;
srvHttp.userToken = winform.editPassword.text;
srvHttp.start("0.0.0.0",port);
serverInfo();
winform.btnStart.disabledText = null;
}
import win.ui.menu;
winform.txtMessage.enablePopMenu();
winform.txtMessage.onHyperlink = function(message,href){
if( message = 0x202/*_WM_LBUTTONUP*/ ) {
import process;
process.openUrl(href);
}
}
winform.onDropFiles = function(files){
var path = files[1]
if(!fsys.isDir(path)){
path = fsys.getParentDir(path)
}
winform.editDocumentRoot.text = path;
srvHttp.documentRoot = path;
config.winform.txtMessage = path;
config.winform.save();
wsrv.publish("reload");
}
import fsys.dlg.dir;
winform.btnOpen.oncommand = function(id,event){
var dir = fsys.dlg.dir(winform.editDocumentRoot.text,winform)
if(dir){
winform.editDocumentRoot.text = dir;
srvHttp.documentRoot = dir;
config.winform.txtMessage = dir;
config.winform.save();
wsrv.publish("reload");
}
}
import process;
winform.btnOpenUpload.oncommand = function(id,event){
var path = io.joinpath(winform.editDocumentRoot.text,"upload")
if(io.createDir(path)){
process.explore(path)
}
}
import win.ui.simpleWindow2;
win.ui.simpleWindow2(winform);
winform.show();
import fsys;
fsys.attrib("/config/",,2/*_FILE_ATTRIBUTE_HIDDEN*/)
win.loopMessage();
Markdown 格式