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 :) |