auto software update.

Blitz3D Forums/Blitz3D Programming/auto software update.

Paul "Taiphoz"(Posted 2005) [#1]
I am about to work on a system, to add to my projects that will enable them to check for updates and then, update!.

I havent done this before and there are a few things in Max/B3D that I havent done that I can see I will need to do.

One thing being to download a file, the patch from the server.

My plan at the moment, is to have a database, in the database i will have..

Table [ Software (Name{PK},c_Version) ]
Table [ Patch (Name{FK},patch_Url,patchID)]

Software table holds the name of the software, or game, such as "Tinvaders" and its current version, in the form on "1.0.0.1" a simple form such as 1,2,3,4 ..

The patch table will hold Name as a fk from software, Patch url which will storm the link to the download patch, and patch id, as there could be a chain of patches for one product.

First of all, am I missing anything in the tables / database or do you think I have covered all of the important things.

Now to the Blitz side of things. I need the app/game to contact the database, send the games current version, get a reply which will be eaither, your ok play on, or oh wait a patch is here for you.

In the event of a patch being available, the game/app(blitz) is going to have to download the patch, close the game, execute the patch then run the game again. this is where i really need the help, I havent downloaded anything with blitz before and im sure this topic has been done a few times.

Anyone want to help out ? tips , tricks , code ?

thanks in advance.


jfk EO-11110(Posted 2005) [#2]
I think in the code archives is an example on how to download an image from a server.

It isn't such a big deal IMHO. I wouldnt mess around with real patches that are replacing PARTS of the Exe, but simply replace the entire main EXE, as long as it's only a few megs. So you can run one exe that will replace the file on the harddrive, then execute it with a special commandline parameter (eg: "/waituntilidie:"+Systemproperty("AppHWND")), so the updated Exe would wait in windowed mode until the calling old Exe finished, and then continue with eg. fullscreen mode.

One thing that seems to be important is an integrity check, to see if the new version is an integer file. I'd realize this with a checksum that is hard to analyze, eg. a 29 Bit Checksum. So you send the 29 Bit checksum, plus the file. The app will then compare the checksum received, and the one it generated from the downloaded file. This way you can make (pretty) sure the file wasn't corrupted or DNS-spoofed or something.


Erroneouss(Posted 2005) [#3]
This download from internet function, jfk?
And of course its not just an image. Its any file. :)

Made by BlitzSupport.
Very useful if I don't say so myself...
Nice one BlitzSupport!

Ok anyway... Heres the code (By BlitzSupport)
; -----------------------------------------------------------------------------
; BlitzGet Deluxe -- based on Mark Sibly's HTTPGet code...
; -----------------------------------------------------------------------------
; WARNING: WILL OVERWRITE EXISTING FILES OF THE SAME NAME!
; -----------------------------------------------------------------------------

; -----------------------------------------------------------------------------
; To do:
; -----------------------------------------------------------------------------
;
; NEED TO CHECK FOR CUTOFFS and... gulp... RESUME? Currently keeps d/l'ing
; nothing if the download is aborted by the server, until the full byte-count
; has been "downloaded"... maybe I'll just say "d/l bombed out" for now...! :)
;
; Parse headers for:
;	404
;
; More to come...
;
; -----------------------------------------------------------------------------

; -----------------------------------------------------------------------------
; Quick demo... downloads to your Windows "Temp" folder
; -----------------------------------------------------------------------------

AppTitle "BlitzGet Deluxe"
Graphics 640, 480, 0, 2
SetBuffer BackBuffer ()

; SMALL TEST (8K):
	download$	 = "http://www.google.com/images/title_homepage4.gif"			; Google homepage logo
;	download$	 = "http://www.blitzbasic.co.nz/zbrowse/blitzfaq/blitzfaq.html" ; Blitz FAQ

; BIG TEST (360K):
;	download$	 = "http://www.hi-toro.com/mp3/diffusion.mp3"					; Pretty music... :P

; SAVE LOCATION: Windows Temp folder:
	downloadDir$ = SystemProperty ("TempDir") ; "G:\My Documents\Downloads\"

If BlitzGet (download$, downloadDir$, "")
	result$ = "Download Complete!" + Chr (10) + "Saved in " + downloadDir$
Else
	result$ = "Download error!"
EndIf

RuntimeError result$

; Temporary, for quick results...

Global header$
Global bytesToRead
Global date$
Global server$
Global contentType$
Global initialReply$

; -----------------------------------------------------------------------------
; File download function
; -----------------------------------------------------------------------------
; webFile$  -- file to download
; saveDir$  -- directory to download into
; saveFile$ -- filename to save as (use "" to use name of downloaded file automatically)
; -----------------------------------------------------------------------------
; Note that if you just provide a web server address, the document downloaded will
; be named "Unknown file.txt"
; -----------------------------------------------------------------------------

Function BlitzGet (webFile$, saveDir$, saveFile$)

	; -------------------------------------------------------------------------
	; Strip "http://" if provided
	; -------------------------------------------------------------------------
	If Left (webFile$, 7) = "http://" Then webFile$ = Right (webFile$, Len (webFile$) - 7)

	; -------------------------------------------------------------------------
	; Split into hostname and path/filename to download
	; -------------------------------------------------------------------------
	slash = Instr (webFile$, "/")
	If slash
		webHost$ = Left (webFile$, slash - 1)
		webFile$ = Right (webFile$, Len (webFile$) - slash + 1)
	Else
		webHost$ = webFile$
		webFile$ = "/"
	EndIf
		
	; -------------------------------------------------------------------------
	; Add trailing slash to download dir if not given
	; -------------------------------------------------------------------------
	If Right (saveDir$, 1) <> "\" Then saveDir$ = saveDir$ + "\"

	; -------------------------------------------------------------------------
	; Save filename -- get from webFile$ if not provided
	; -------------------------------------------------------------------------
	If saveFile$ = ""
		If webFile = "/"
			saveFile$ = "Unknown file.txt"
		Else
			For findSlash = Len (webFile$) To 1 Step - 1
				testForSlash$ = Mid (webFile$, findSlash, 1)
				If testForSlash$ = "/"
					saveFile$ = Right (webFile$, Len (webFile$) - findSlash)
					Exit
				EndIf
			Next
			If saveFile$ = "" Then saveFile$ = "Unknown file.txt"
		EndIf
	EndIf

	; DEBUG
; RuntimeError "Web host: " + webHost$ + Chr (10) + "Web file: " + webFile$ + Chr (10) + "Save dir: " + saveDir$ + Chr (10) + "Save file: " + saveFile$

	www = OpenTCPStream (webHost$, 80)

	If www
	
		WriteLine www, "GET " + webFile$ + " HTTP/1.1" ; GET / gets default page...
		WriteLine www, "Host: " + webHost$
		WriteLine www, "User-Agent: BlitzGet Deluxe"
		WriteLine www, "Accept: */*"
		WriteLine www, ""
		
		; ---------------------------------------------------------------------
		; Find blank line after header data, where the action begins...
		; ---------------------------------------------------------------------
				
		Repeat

			Cls
			
			header$ = ReadLine (www)

			reply$ = ""
			pos = Instr (header$, ": ")
			If pos
				reply$ = Left (header$, pos + 1)
			EndIf

			Select Lower (reply$)
				Case "content-length: "
					bytesToRead = ReplyContent (header$, reply$)
				Case "date: "
					date$ = ReplyContent (header$, reply$)
				Case "server: "
					server$ = ReplyContent (header$, reply$)
				Case "content-type: "
					contentType$ = ReplyContent (header$, reply$)
				Default
					If gotReply = 0 Then initialReply$ = header$: gotReply = 1
			End Select

			DisplayResponse ()

			Flip
			
		Until header$ = "" Or (Eof (www))
				
		If bytesToRead = 0 Then Goto skipDownLoad
		
		; ---------------------------------------------------------------------
		; Create new file to write downloaded bytes into
		; ---------------------------------------------------------------------
		save = WriteFile (saveDir$ + saveFile$)
		If Not save Then Goto skipDownload

		; ---------------------------------------------------------------------
		; Incredibly complex download-to-file routine...
		; ---------------------------------------------------------------------

		For readWebFile = 1 To bytesToRead
		
			If Not Eof (www) Then WriteByte save, ReadByte (www)
			
			; Call BytesReceived with position and size every 100 bytes (slows down a LOT with smaller updates)
			
			tReadWebFile = readWebFile
			If tReadWebFile Mod 100 = 0 Then BytesReceived (readWebFile, bytesToRead)

		Next

		CloseFile save
		
		; Fully downloaded?
		If (readWebFile - 1) = bytesToRead
			success = 1
		EndIf
		
		; Final update (so it's not rounded to nearest 100 bytes!)
		BytesReceived (bytesToRead, bytesToRead)
		
		.skipDownload
		CloseTCPStream www
		
	Else
	
		RuntimeError "Failed to connect"
		
	EndIf
	
	Return success
	
End Function

; -----------------------------------------------------------------------------
; User-defined update function, called every 100 bytes of download -- alter to suit!
; -----------------------------------------------------------------------------
; TIP: Pass a user-defined type instead, with all data (this stuff plus URL, local filename, etc)
; -----------------------------------------------------------------------------
Function BytesReceived (posByte, totalBytes)
	; Example update code...
	Cls
	Text 0, 10, "Downloading file -- please wait..."
	Text 0, 30, "Received: " + posByte + "/" + totalBytes + " bytes (" + Percent (posByte, totalBytes) + "%)"
	DisplayResponse ()
	Flip
End Function

; -----------------------------------------------------------------------------
; Handy percentage function
; -----------------------------------------------------------------------------
Function Percent (part#, total#)
	Return Int (100 * (part / total))
End Function

Function ReplyContent$ (header$, reply$)
	Return Right (header$, Len (header$) - Len (reply$))
End Function

; Temporary, for quick results...

Function DisplayResponse ()
	Text 0, 80, "Header: " + initialReply$
	Text 0, 100, "Date: " + date$
	Text 0, 120, "Server: " + server$
	Text 0, 140, "Content-Type: " + contentType$
	Text 0, 160, "Content-Length: " + bytesToRead
End Function



Paul "Taiphoz"(Posted 2005) [#4]
thats for posting the source, that helps a lot.