//扫码传文件 import fonts.fontAwesome; import win.ui; /*DSG{{*/ var winform = win.form(text="qrfs - 扫码快传 v2.3";right=807;bottom=465;bgcolor=0xFFFFFF;border="none";max=false) winform.add( bk={cls="bk";left=-2;top=-5;right=810;bottom=29;bgcolor=15790320;dl=1;dr=1;dt=1;forecolor=12639424;linearGradient=0;z=10}; bkplus={cls="bkplus";text="qrfs - 扫码快传 v2.3";left=35;top=3;right=220;bottom=25;align="left";color=5921370;dl=1;dt=1;z=11}; 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=6}; btnOpenUpload={cls="plus";text="打开上传目录";left=161;top=86;right=302;bottom=115;dl=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=12}; 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=5}; 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=8}; editPassword={cls="plus";left=441;top=84;right=632;bottom=108;align="left";border={bottom=1;color=-8355712};dr=1;dt=1;editable=1;font=LOGFONT(h=-16);z=14}; editPort={cls="plus";left=550;top=49;right=628;bottom=73;align="left";border={bottom=1;color=-8355712};dr=1;dt=1;editable=1;font=LOGFONT(h=-16);z=9}; plus={cls="plus";text="访问密码:";left=332;top=90;right=433;bottom=114;align="right";dl=1;dr=1;dt=1;font=LOGFONT(h=-15);transparent=1;z=13}; plus2={cls="plus";left=38;top=128;right=472;bottom=422;align="left";border={color=-16744448;radius=8;width=1};db=1;dl=1;dr=1;dt=1;font=LOGFONT(h=-14);textPadding={left=16};valign="top";z=1}; qr={cls="plus";left=499;top=132;right=760;bottom=418;db=1;dr=1;dt=1;repeat="scale";z=7}; radioQrClipboard={cls="radiobutton";text="共享剪贴板";left=685;top=435;right=772;bottom=454;bgcolor=0xFFFFFF;db=1;dr=1;z=18}; radioQrRootDir={cls="radiobutton";text="根目录";left=502;top=435;right=589;bottom=454;bgcolor=0xFFFFFF;db=1;dr=1;z=16}; radioQrUploadDir={cls="radiobutton";text="上传目录";left=593;top=435;right=680;bottom=454;bgcolor=0xFFFFFF;db=1;dr=1;z=17}; 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=3}; 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=4}; syslink={cls="syslink";text='开源项目';left=43;top=437;right=176;bottom=457;bgcolor=0xFFFFFF;db=1;dl=1;z=15}; 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=2} ) /*}}*/ import fsys.update.simpleMain; if( fsys.update.simpleMain( "qrfs - 扫码快传", "http://d.aardio.com/qrfs/update/", io.appData("/aardio/std/qrfs/app/update"), function(version,description,status){})){ return 0; } import fsys.config; config = fsys.config(io.appData("aardio/std/qrfs")); import sessionHandler.default; sessionHandler.default.root = io.appData("aardio/std/qrfs/session") if( io.exist(config.winform.txtMessage) ){ winform.txtMessage.text = config.winform.txtMessage; } else { winform.txtMessage.text = io.getSpecial(0x5/*_CSIDL_MYDOCUMENTS*/) } if(config.winform.qrDir=="upload"){ winform.radioQrUploadDir.checked = true; } elseif(config.winform.qrDir=="clipboard"){ winform.radioQrClipboard.checked = true; } else { winform.radioQrRootDir.checked = true; } 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; sfi = fsys.info.get(path, 0x100/*_SHGFI_ICON*/ | 0x4000/*_SHGFI_SYSICONINDEX*/|0x10/*_SHGFI_USEFILEATTRIBUTES*/, ..fsys.isDir(path)?0x10/*_FILE_ATTRIBUTE_DIRECTORY*/?0x80/*_FILE_ATTRIBUTE_NORMAL*/); 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; } import win.clip; var cacheClientIps = {} srvHttp.run( function(response,request,session){ //添加禁止缓存的HTTP头 response.headers["Cache-Control"] = "no-cache, no-store, must-revalidate"; response.headers["Pragma"] = "no-cache"; response.headers["Expires"] = "0"; 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.startsWith(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) && 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(` qrfs - 扫码快传 v2.3 `) if(request.path!="//"){ response.write(`
`) } if(request.path=="//"){ response.write(`

/共享剪贴板/ 📋 ⬑父目录

`) } elseif(request.path=="/upload/"){ response.write(`

当前目录:/upload/ 📤 ⬑父目录

    `) } elseif(#request.path>2){ if(string.find(request.path,"^/[^/]+/$")){ response.write(`

    当前目录:` ,request.path,` ⬑父目录

      `) } else{ response.write(`

      当前目录:` ,request.path,`

      ⬑父目录
        `) } } else { response.write(`

        当前目录:` ,request.path,`

          `) } if(request.path=="/" && ..io.exist("/upload/")){ response.write('
        • 上传目录 📤
          \r\n'); } if(request.path=="//"){ response.write(`
          `) return; } elseif(request.path=="/") { response.write('
        • 共享剪贴板 📋
          \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('
        • ',dir[ i ],'
          \r\n'); } for(i=1;#file;1){ var iconIdex = getSysIconIndex(file[file[ i ]]) response.write('
        • ',file[ i ],'
          \r\n'); } response.write("
        ") } ); import qrencode.bitmap; var serverInfo = function(){ var ip,port = srvHttp.getLocalIp(); winform.editPort.text = port; winform.editDocumentRoot.text = io.fullpath(srvHttp.documentRoot) var home = "/"; if(winform.radioQrUploadDir.checked){ home = "/upload/"; } elseif(winform.radioQrClipboard.checked){ home = "/%3Cclipboard%3E/"; } var url = srvHttp.getUrl(home,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( " 手机无线连接电脑局域网。 扫码打开网页,可上传下载文件、共享电脑剪贴板。 拖动文件或目录到窗口网页自动刷新。 aardio 实现的开源单线程异步 HTTP 服务端,体积仅数十 KB。 支持高速上传下载、断点续传、304 缓存、分块传输、Keep Alive。 支持 WebSocket / HTTP 双服务端(共享端口)。 可运行 aardio 开发的网站。 " ); } 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.clip; import win.clip.viewer; var clipViewer = win.clip.viewer(winform); clipViewer.onDrawClipboard=function(){ var str = win.clip.read(); if(str!=wsrv.lastReceivedClipboardData ){ wsrv.publish(#str?str:"") wsrv.lastReceivedClipboardData = null; } } wsrv.onMessage = function(hSocket,msg){ wsrv.lastReceivedClipboardData = msg.data; win.clip.write(msg.data); } var updateHomeDir = function(){ var home = "/"; if(winform.radioQrUploadDir.checked){ home = "/upload/"; } elseif(winform.radioQrClipboard.checked){ home = "/%3Cclipboard%3E/"; } var url = srvHttp.getUrl(home,true); if(#srvHttp.userToken){ url = url ++ "?t=" + srvHttp.userToken; } var qrBmp = qrencode.bitmap( url ); winform.qr.setBackground(qrBmp.copyBitmap(winform.qr.width)); } winform.radioQrRootDir.oncommand = function(id,event){ config.winform.qrDir = "root"; updateHomeDir(); } winform.radioQrUploadDir.oncommand = function(id,event){ config.winform.qrDir = "upload"; updateHomeDir(); } winform.radioQrClipboard.oncommand = function(id,event){ config.winform.qrDir = "clipboard"; updateHomeDir(); } import win.ui.simpleWindow2; win.ui.simpleWindow2(winform); winform.show(); 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; } }) win.loopMessage();