Download File
Monkey Forums/Monkey Code/Download File
| ||
I tried to use both streams and httprequest to download a file but they both got kinda stuck in the process or misinterpreted the file length resulting in corrupted files. maybe it's just me, but it all felt so unintuitive that i had to fix things a little bit. anyway, if someone else is looking for a way to download files, here it is :) |
| ||
excellent just what I was looking for :D |
| ||
I am sorry - where is update() method? |
| ||
It uses the async socket methods and is updated by calling UpdateAsyncEvents() in you main loop (wont work without). This has the advantage that you application can do other things while donwloading (Reading the header is not async but shouldnt cause much of an overhead). You can detect changes in progress by providing a "onUpdate:IOnDownloadUpdate" for the "New" method. In the above example this is the HappyApp itself. Whenever a progress in download has been made the "DownloadUpdate" Method of HappyApp is called automatically. This is the mainloop in the above example: While D.Finished = False UpdateAsyncEvents() Wend |
| ||
I see, you don't use mojo Your code is working if change path to store file Local s:FileStream = FileStream.Open("monkey://data/test.gif", "w") |
| ||
I made some changes to the code for a project I am working on, seeing as levels are gonna be a few thousand bytes it works fine :) Heres the code: ' ' Updater.monkey - Originally coded by Pharmhaus, modified by EdzUp ' Programmed by Pharmhaus, modified by: Ed 'EdzUp' Upton ' #If TARGET<>"glfw" And TARGET<>"android" And TARGET<>"ios" And TARGET<>"stdcpp" #Error "Invalid target!" #Endif Strict Import brl.filestream Import brl.tcpstream Class UpdaterClass Implements IOnDownloadUpdate Method Check:String( url:String ) Local D:= New AsyncDownload( url, Self, 1024 ) ' Valid link While D.Finished = False UpdateAsyncEvents() Wend Print "finished... writing file" Local buf:DataBuffer = D.File If buf Then Return( buf.PeekString( 0 ) ) Endif Return( "" ) End Method Download:Void( url:String, targetfile:String ) Local D:= New AsyncDownload( url, Self, 1024 ) ' Valid link While D.Finished = False UpdateAsyncEvents() Wend Print "finished... writing file" Local buf:DataBuffer = D.File If buf Then Local s:FileStream = FileStream.Open( targetfile, "w" ) s.WriteAll(buf, 0, buf.Length) s.Close() Endif End Method DownloadUpdate:Void( D:AsyncDownload ) Print "Totalsize:" + D.Size Print "Percentage: " + D.Percentage + "%" Print "Remaining Bytes: " + D.Remaining If D.Finished Print "Download completed!" Endif If D.Alive = False Then Print "Download failed..." Endif If D.Remaining = 0 Print "No bytes remaining" Endif Print "~r~n" End End Global Update:UpdaterClass = New UpdaterClass Interface IOnDownloadUpdate Method DownloadUpdate:Void(D:AsyncDownload) End Class AsyncDownload Implements IOnReceiveComplete, IAsyncEventSource Private '///// Dataconnection Field socket:Socket Field stream:TcpStream Field Buffer:DataBuffer Field chunksize:Int ' how much to download per round '///// Download Info Field host:String ' name of the host Field file:String ' path of the file Field filesize:Int ' number of bytes to download Field downloaded:Int ' Number of bytes already download '///// Callback Field Callback:IOnDownloadUpdate Public Method UpdateAsyncEvents:Void() RemoveAsyncEventSource(Self) If Callback Then Callback.DownloadUpdate(Self) If filesize = -1 Then filesize = 0 EndIf End Method Method New(url:String, onUpdate:IOnDownloadUpdate, chunksize:int = 1024) 'Fix the URL so that everything will work properly url = url.Replace("http://", "") Local in:String = "." Local slashPos:Int = url.Find("/") 'Initialize Connection socket = New Socket stream = New TcpStream(socket) Self.chunksize = chunksize Callback = onUpdate 'seperate the file from the address If slashPos <> - 1 host = url[0 .. slashPos] file = url[slashPos ..] Else filesize = -1 stream.Close() socket = Null AddAsyncEventSource(Self) Return EndIf 'connect to the address If not (stream.Connect(host, 80)) Then filesize = -1 stream.Close() socket = Null AddAsyncEventSource(Self) Return Endif 'Send a request to Download the File.... stream.WriteLine "GET " + file + " HTTP/1.0" stream.WriteLine "Host: " + host stream.WriteLine "" 'Wait until the Server sends us all the information about the file, like size While in <> "" in = stream.ReadLine() If in.Find("Content-Length:") <> - 1 Then filesize = Int(in[15 ..].Trim()) EndIf Wend Buffer = New DataBuffer(filesize) 'Start the async part... DownloadChunk() End Method DownloadChunk:Void() If (filesize - downloaded) > chunksize Then socket.ReceiveAllAsync(Buffer, downloaded, chunksize, Self) Else socket.ReceiveAllAsync(Buffer, downloaded, (filesize - downloaded), Self) Endif End Method OnReceiveComplete:Void(data:DataBuffer, offset:Int, count:Int, source:Socket) downloaded += count If Callback Then Callback.DownloadUpdate(Self) If downloaded < filesize Then DownloadChunk() Else stream.Close() Endif End Method Size:Int() Property Return filesize End Method Remaining:Int() Property Return (filesize - downloaded) End Method Percentage:Int() Property If filesize <= 0 Then Return 0 Else Return Float(downloaded) / Float(filesize) * 100 Endif End Method Finished:Bool() Property Return (filesize = downloaded) End Method File:DataBuffer() Property Return Buffer End Method Alive:Bool() Property Return (socket <> Null) End End Basically you can use: Update.Check( url ) to return a string which contains a version number for example on my website I have version.txt that holds 0.1b(alpha) this is returned by the function If its different from the game I can call Update.Download( url, target file) to download the files :) All of this can be added by simply just including the file as a import and calling the Update methods :). I would like to thank Pharmhaus for the original code with a little adjustment it works perfectly for what I want it for :) |