//dlManager 下载线程管理器 import fsys; import thread.works; import thread.event; import thread.command; import util.metaProperty; namespace thread; class dlManager { ctor( limit,waitTime ){ this.works = ..thread.works( limit : 3, function( args ) { if( ! args.id) return; //取消任务 var eventId = ..string.format("thread/download/%s",tostring(args.id )); var event = thread.event(eventId,true);//参数2为真避免线程自动切换信号 var id = args.id; var hwndCommand = args.hwndCommand; var savepath = args.savedir; if( args.filename ) savepath = ..io.joinpath( savepath,args.filename ) var send = ..thread.command.send; var post = ..thread.command.post; var remoteFile = inet.httpFile(args.url,savepath,args.resumePath,args.userAgent,args.proxy,args.proxyBypass,args.httpFlags); if( !remoteFile ){ send( hwndCommand,"onError",id,"参数错误"); return; } var totalSize = 0; var filename = io.splitpath(remoteFile.path).file; remoteFile.onReceiveBegin = function(statusCode,contentLength,fileSize){ if( statusCode == 206/*断点续传*/ ){ send( hwndCommand,"onReceiveBegin",id,threadId,args.url,filename,"断点续传",statusCode,contentLength+fileSize,fileSize) totalSize = fileSize; } elseif(fileSize){ send( hwndCommand,"onReceiveBegin",id,threadId,args.url,filename,"重新下载",statusCode,contentLength,0) } else { send( hwndCommand,"onReceiveBegin",id,threadId,args.url,filename,"开始下载",statusCode,contentLength,0) } } var time_tick = ..time.tick; var tkPrev = 0; var sizePs = 0; remoteFile.onReceive = function(str,size,contentLength){ totalSize = totalSize + size; sizePs = sizePs + size; var tkCurrent = time_tick(); var ms = tkCurrent - tkPrev; if( ms > 1000 ){ post( hwndCommand,"onReceive",id,sizePs/(ms/1000),totalSize); sizePs = 0; tkPrev = tkCurrent; } return ! event.wait(1) /*检测主线程是否发出停止信号*/; } var ok,err,fileSize = remoteFile.download(args.headers,args.referer,args.accept,args.flags,args.postData); if( ok ){ send( hwndCommand,"onEnd",id,remoteFile.path,remoteFile.resumePath,remoteFile.contentLength ) } else { if( err ) send( hwndCommand,"onError",id,err ); else send( hwndCommand,"onEnd",id ); } remoteFile.close(); event.close(); },waitTime : 200,function(){ import fsys; import inet.http import inet.httpFile; import thread.command; import thread.event; ..threadId = ..thread.getId(); } ) this.threadIds = {}; this.listener = ..thread.command(); this.listener.onReceiveBegin = function(id,threadId,url,filename,statusText,httpStatusCode,contentLength,fileSize){ this.threadIds[threadId] = id;//线程正在下载的任务ID if( this.onReceiveBegin ){ this.onReceiveBegin(id,url,filename,statusText,httpStatusCode,contentLength,fileSize); } } ..table.gc(this,"quit"); }; cancel = function(id){ if( !id ) error("请指定id参数",2); //取消待执行任务 for( idx,args in this.works.each() ){ if( args.id == id ){ this.works.update(idx,{} );//取消下载 this.works.resume(); return; } } //取消正在执行任务 var eventId = ..string.format("thread/download/%s",tostring(id)); var event = ..thread.event(eventId,true); event.set(); event.close(); }; quit = function(){ for( idx,args in this.works.each() ){ this.works.update(idx,{} ); } for(tid,id in this.threadIds ){ var eventId = ..string.format("thread/download/%s",tostring(id)); var event = ..thread.event(eventId,true); event.set(); event.close(); } var r = this.works.wait(); this.works.quit(); return r; }; push = function(args){ if( !args[["id"]] ){ error("参数必须指定 id 属性",2) } if( !args[["url"]] ){ error("必须指定 url 属性",2) } if( !args[["savedir"]] ){ error("必须指定 savedir 属性",2) } if( !args[["hwndCommand"]] ){ args[["hwndCommand"]] = this.listener._form.hwnd; } for( idx,args2 in this.works.each() ){ if( args2.url == args.url ){ return; } } this.works.push( args ); return args; } @_metaProperty; } namespace dlManager{ _metaProperty = ..util.metaProperty( onReceive = { _get = function(){ return owner.listener.onReceive; } _set = function( value ){ owner.listener.onReceive = value; } }; onEnd = { _get = function(){ return owner.listener.onEnd; } _set = function( value ){ owner.listener.onEnd = value; } }; onError = { _get = function(){ return owner.listener.onError; } _set = function( value ){ owner.listener.onError = value; } }; ) } /**intellisense() thread.dlManager = 多线程下载管理器 thread.dlManager(.(线程数,等待延时) = 创建下载管理器\n参数@省略则默认创建2个下载线程可选用\n参数@2指定线程每次任务完成后的等待延时,默认为200毫秒 thread.dlManager() = !thread_dlManager. !thread_dlManager.push() = !thread_dlManager_task. !thread_dlManager_task.id = 任务id !thread_dlManager.push( 任务配置 ) = @.push( \n id = __/*必须指定任务唯一标志\n参数表也是此函数的返回值*/;\n url = "下载网址,重复的下载网址将被自动忽略";/;\n referer = "引用网址";\n savedir = "/download/";\n filename = 可选参数; \n) !thread_dlManager.cancel(.(任务ID) = 取消指定的下载任务 !thread_dlManager.quit() = 关闭全部下载线程 !thread_dlManager.works = !thread_work. !thread_dlManager.onReceiveBegin = @.onReceiveBegin = function(id,url,filename,statusText,httpStatusCode,totalSize,downSize){ __/*开始下载触发此事件*/ } !thread_dlManager.onReceive = @.onReceive = function(id,sizePs,downSize){ __/*下载触发此事件*/ } !thread_dlManager.onEnd = @.onEnd = function(id,savepath,resumePath,contentLength){ __/*下载完成触发此事件\n下载成功则savepath为存储路径,否则该参数为空\nresumePath为续传配置文件路径*/ } !thread_dlManager.onError = @.onError = function(id,err){ __/*下载错到错误触发此事件\n出错则err参数为错误信息,用户取消则err参数为空*/ } end intellisense**/