Simple Auto-Updater/Patcher Library

For some reason yesterday I got an urge to make some auto-updater/patchers for games of mine. I decided to start with C# since I assumed it would be easier, and after building the application in C# I was able to transfer the code to Java pretty easily. A few bugs arose but I squashed them. I also wanted to make this a library so that others could use it and it would be easier for me to use it with all of my games. In the end, I feel like it has grown to a helpful and simple auto-updater/patcher library which should be able to be used with many games. You should definitely check it out! To read more about how it works, head over to the repository (link below) where a massive README awaits you. Also, in the repository is Example.java which is the class that fuels the Example Launcher (download link below). As you can see, checking for an update is as simple as two lines. I feel like the simplicity for this is a very good thing.

Repository Link: https://github.com/Sammidysam/GamePatcher

Java Download Link: http://sammidysam.github.com/Libraries/GamePatcher.jar
C# Download Link: (to be posted soon, need to make sure they are on the same level of code)

Example Launcher Download Link: http://sammidysam.github.com/PixelZombies/Launcher.jar

I took a glance at the code and found some issues which should be fixed:

  • always close resources in finally-blocks
  • check wether delete() calls or any file operation actually succeeded
  • for caught exceptions, either log them or propagate them further up
  • decide after catching exceptions, if it makes sense to continue (like Downloader#downloadFiles() prints “success” after catching IOExceptions)
  • both Downloader constructers could share most of the same code
  • “user.dir” should be configurable
  • no hardcoded internet urls
  • instead of nesting if-statements, combine them with operator &&
  • classes and methods need comments
  • downloads should be cancable, making sure the original file is restored/still available

Thanks for the feedback. I am getting to work on the errors. The errors that I don’t quite understand are:

  • for caught exceptions, either log them or propagate them further up
  • “user.dir” should be configurable
  • no hardcoded internet urls

Can you elaborate on what you mean more for those and/or provide a solution to them? All of the others I understand and will try to fix.

EDIT: I will figure them out via Google as I do for most everything.

I figured out and fixed all those errors. They may still be lurking however. Thanks for the list! Tomorrow I will update the example launcher and actual library downloads. Until then, only the repository will be updated with the new code. Believe it or not, the hardest part of the whole thing was adding comments because I’ve never worked on a project with anyone (besides one that my friend adds about one line every two months) so I’ve never had to add comments to anything. I think my comments are on the level of barely decent.

EDIT: The new versions of the GamePatcher.jar and Launcher.zip should now be live at the same locations. They are both updated to be the new library and use the new library respectively. The new launcher also doesn’t try to run if the .jar doesn’t exist.

A software patcher should make absolutely sure that it will always leave a consistent runnable state behind. That requires to treat every possible error and exception properly.
If exceptions are unrecoverable, do not continue but log the problem, stop and maybe throw an appropriate exception and rollback unfinished changes.
Use a log library instead of printing to the console to make examing problems remotely even possible.
There are lots of possible problems when it comes to networking and file operations.
To test your patcher, see what happens (= means try it) when the firewall blocks, files can’t be deleted or copied, folder access is rejected, users kill the process while updating, connections break while downloading, etc., etc.

“user.dir” - not everyone would like to be forced to use that folder, add a setter to specify it

url - not everyone would like to ping a hardcoded address, add a setter to specify it

The last two I believe I have fixed properly. My solution to those two was to make a settings.txt file in the unchanged “user.dir” that allows you to change the “user.dir” and ping URL. I believe this is a good location as it is in the same location as the JAR of the launcher or other program this is being used for, but if it defeats the whole purpose let me know. I guess I could try to make a script that creates the settings.txt where you want it and then the code reflects that, but I feel like my solution is good enough as is. Would it be good to rename the file to gamepatchersettings.txt so that it is less likely for a game to have the same text file?

The one thing I forgot when logging the errors (to do so, I create a new file via the File.createTempFile() method with the arguments “error”, “.txt”, and new File(System.getProperty(“user.dir”)) is to actually notify the error in the console, but I will fix that today. The errors are logged to text files, however, as I noted. By the way, is a library for logging a necessity or is just writing the error message to a file good enough? I don’t know if a library would give me much more functionality than I already put in myself. I will add the date of the error to the error logs today though. Is there more functionality that a library would give me besides that? I will try to test the errors you specified to test (or just go through the catch blocks and try to make them happen). I have tested users killing the process mid-download and put in a method for fixed that yesterday: it scans for all files left in the temporary directory due to that (I call deleteOnExit() to that file being downloaded but it doesn’t work when the process is terminated) and deletes them if it fits the correct signature that the file should look like. I will try to test all of the possible errors if I can today after updating the code with the few changes I desire.

I only got in time today to look into the possible errors “users kill the process while updating” and “connections break while downloading”. The GitHub repository is updated but nothing else is. In the latter when I tested it the file just stopped downloading and nothing happened. The method transferFrom() seems to not throw an exception when it can’t connect but rather just keeps trying. I initially thought to solve this I could just check for internet connection each time a bit (not an actual bit) of the file is downloaded, but sadly the ping takes too long for this to be effective because pinging in Java takes a noticeable amount of time. Also sometimes the ping takes so long that it times out which could stop the download altogether. It’s disappointing because pinging in C# is nearly instantaneous. Obviously pinging in Java is difficult already, but that’s not the main point. Do you know the best way to fix this bug? I was thinking I could run the download on a separate thread then if a download of the specified number of bytes takes more than five times the number of bytes to be downloaded (I assume 5000 milliseconds for 1000 bytes is an insanely slow internet, but I may need to make the wait longer for really slow internet) the internet will be checked and if no internet is detected then the program will exit. It doesn’t matter if I delete the file that was being downloaded or not before exiting because if I don’t then the next time the program is run it will delete the file (this is a fix to the bug of users killing the process while updating). So does my method sound good or should it be done a different way?

For logging I wouldn’t even think of writing my own stuff. There have been various matured solutions for many years. It is boring and just a waste of time.
Except you are badly suffering from the not-built-here syndrom ;D

I don’t see why pinging in Java should be slower than in C#.

Not requiring a 3rd party logging library is a positive aspect IMHO. Dependencies on fiddly 3rd party libraries are annoying.

Cas :slight_smile:

especially logging! log to slf4j, which binds to commons logging, which appends to jul and ends as a S.o.println anyway :confused:

Writing my ErrorLogger class which logs error really didn’t take much time at all, and considering it’s already written I’m not sure if I should destroy it for a library now. If it wasn’t done then I would consider it. For now I’ll leave it in unless I get overwhelming feedback for a third-party library instead (2 to 1 is not overwhelming). I will do some tests for ping length.

After running 100 pings on both languages with the same desired website and the same programs open:
The website for both is github.com.
C# average ping length: 631 milliseconds
Java average ping length: 2112 milliseconds

They aren’t quite the same. But, what I’ve found from cmd is that GitHub is bad with pinging. Google had a maximum length of 47ms and GitHub had two requests time out. Obviously I shouldn’t use GitHub as my default site. But Google doesn’t work with Java’s pinging method! I found an alternate method for checking internet that isn’t pinging that I will try and see how it works. It should work with Google. I can either use that method or try to use the terminal to check internet: I could execute “ping -n 1 www.google.com” on Windows and “ping -c 1 www.google.com” on Mac and Linux. The problem there is that I could detect OS but then it would only work for Windows, Mac, and Unix environments, but those are just about all that are used today. I’ll let that be my backup plan, first I’ll try this alternate method.

The average ping-like method length for google.com with this alternate method (illustrated at http://stackoverflow.com/questions/1139547/detect-internet-connection-using-java with the final code block) is 176 milliseconds! That’s great! Now checking internet will be so much better! I don’t need to fall back to executing terminal work at all. I will add it as a “fall back” method though, so if the main method returns that no internet is detected it will test with the terminal and if the terminal agrees it will quit the download.

I implemented both, but the only problem is that checking for internet in each download round really slows down download speed. I’ll look into possible solutions to this where I won’t have to check internet every download round. Ugh I tested if stopping the internet connection in the middle of the download caused the download to stop but it still freezes because it’s the transferFrom() method that is running at the time the internet stops. :confused:

I put in a working method to stop if internet is lost. It’s the ugliest code ever though (mainly due to my inexperience with threads) so I really need to fix it. I’m not sure if it’s better for me to called a thread.stop() method or System.exit(1). Probably thread.stop().

Question is, if you even need to ping an arbitrary site at all.
Logging ErrorLogger errors with the ErrorLogger is not necessarily a good idea…
For stopping threads, take a look at the JavaDoc of Thread#stop() to know of what not to do.

Couldn’t you just try and fetch the files from the server, without pinging? If the http request fails, then there’s no connection to that site. Doesn’t matter if the rest of the internet works.

I agree. I will just have it print to the console. The thing is, I call “return;” when internet is lost (it is successfully identified and no download speed is lost) and yet the method still keeps going (I test it with a launcher and the launcher never does anything past checkForUpdate()). Could it be that I made a thread in it and that it can’t quit the method because of that?

EDIT: I removed the code since I figured out what’s up. The transferFrom method being called in my thread will not stop being run as it’s trying and trying to download but it can’t and I need to find a way to stop the called method. Sadly thread.interrupt() and thread.stop() don’t accomplish this. I’ll look for a way to do so.

Alright, I can’t fix this myself. Here’s the situation:

Under normal circumstances, the thread I make for downloading the file does it’s job and closes. If the internet is lost though while the thread is trying to download, it will keep trying. It won’t ever give up or throw an exception. So then the method that created the thread successfully ends and all is well except for that there is still that thread running. That thread will not end and thus the program in main() will not continue. This leaves the program just sitting there doing nothing. Do you know how I can stop that method in its tracks or is this impossible?


					Thread download = new Thread(new Runnable(){
						public void run(){
							try {
								if(hasInternet)
									finalFos.getChannel().transferFrom(finalRbc, finalPosition, chunkSize);
							} catch (IOException e) {
								e.printStackTrace();
							}
						}
					});

I think I’ll put this in Newbie & Debugging so that anybody else who happens to get this issue can easily find the fix because a fix to this is not easily found on the internet.

I will now move on to fixing the possible bugs in the following if they exist:

“when the firewall blocks, files can’t be deleted or copied, folder access is rejected”

This is because I am still completely stumped on connections breaking while downloading.

I believe I have fixed “folder access is rejected”. Repository is updated.

I have made this library more friendly towards someone who wants to allow the user to decide whether they want to update or not. You can still do the same thing as before to check for an update and if one is present then initiate the update with the method autoUpdate(), but you can also call methods to check for and download files on your own. This makes a neat little launcher like my PixelZombies one very simple. The download link is above and the library link is updated also. So is the repository. I feel like I am now at the point where I am done constantly trying to fix possible bug after bug. You can let me know if you’d like a new feature added or a possible bug fixed, but for now I feel like I can stop toying with the library and start making launchers for all of my games. Right now if internet is lost during download it will just keep trying to download but the window should be closeable. I could add Apache Commons IO in order to download with a timeout, but is the third party software worth it?

Hi

What’s the licence of your updater? Sorry for the dumb question but why isn’t it able to update itself?

I haven’t thought about licenses at this time, but I guess if people are going to use it I should. I assume the license here seems good as long as I change the copyright year and name, right? It just says “use it as you what, but don’t call it your own” I believe, which is what I’m looking for. I never guessed that updating a running application was possible since the Minecraft Launcher has a launcher and not just a game that updates itself, but based on this question it looks like that is not easily possible. I assume you could make a launcher launcher that would update the launcher, but then you could need a launcher launcher launcher that updates the … lol. That’s what you were asking, right?

This kind of ridiculous complexity is why I wrote MinLog, single class logging I can use in all my apps and libs, with the ability to have javac remove the logging at compile time.

How is this better or different from the GetDown library which seems to do the same?