Java-Gaming.org    
Featured games (81)
games approved by the League of Dukes
Games in Showcase (497)
Games in Android Showcase (114)
games submitted by our members
Games in WIP (563)
games currently in development
News: Read the Java Gaming Resources, or peek at the official Java tutorials
 
    Home     Help   Search   Login   Register   
Pages: [1] 2
  ignore  |  Print  
  Simple Auto-Updater/Patcher Library  (Read 7990 times)
0 Members and 1 Guest are viewing this topic.
Offline Sammidysam
« Posted 2013-03-10 19:58:41 »

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
Offline 65K
« Reply #1 - Posted 2013-03-10 21:55:13 »

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

Offline Sammidysam
« Reply #2 - Posted 2013-03-10 22:11:32 »

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.
Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline Sammidysam
« Reply #3 - Posted 2013-03-11 03:55:23 »

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.
Offline 65K
« Reply #4 - Posted 2013-03-11 21:07:47 »

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?
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

Offline Sammidysam
« Reply #5 - Posted 2013-03-11 22:23:55 »

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.
Offline Sammidysam
« Reply #6 - Posted 2013-03-12 03:42:01 »

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?
Offline 65K
« Reply #7 - Posted 2013-03-12 06:48:48 »

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?
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 Grin

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

Offline princec

JGO Kernel


Medals: 378
Projects: 3
Exp: 16 years


Eh? Who? What? ... Me?


« Reply #8 - Posted 2013-03-12 09:40:19 »

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

Cas Smiley

Offline cylab

JGO Ninja


Medals: 49



« Reply #9 - Posted 2013-03-12 10:53:23 »

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

Mathias - I Know What [you] Did Last Summer!
Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline Sammidysam
« Reply #10 - Posted 2013-03-12 16:11:54 »

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.  :/

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().
Offline 65K
« Reply #11 - Posted 2013-03-12 17:42:50 »

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.

Offline Regenuluz
« Reply #12 - Posted 2013-03-12 17:47:33 »

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.
Offline Sammidysam
« Reply #13 - Posted 2013-03-12 17:48:28 »

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.

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?

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
               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.
Offline Sammidysam
« Reply #14 - Posted 2013-03-16 23:44:37 »

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.
Offline Sammidysam
« Reply #15 - Posted 2013-03-23 03:33:43 »

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?
Offline gouessej
« Reply #16 - Posted 2013-03-23 11:46:30 »

Hi

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

Offline Sammidysam
« Reply #17 - Posted 2013-03-23 14:04:38 »

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?
Offline Nate

JGO Kernel


Medals: 147
Projects: 4
Exp: 14 years


Esoteric Software


« Reply #18 - Posted 2013-03-23 14:24:20 »

especially logging! log to slf4j, which binds to commons logging, which appends to jul and ends as a S.o.println anyway :/
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.

Offline Grunnt

JGO Wizard


Medals: 68
Projects: 8
Exp: 5 years


Complex != complicated


« Reply #19 - Posted 2013-03-23 14:59:16 »

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

Offline Sammidysam
« Reply #20 - Posted 2013-03-23 16:11:49 »

In my opinion this just seems a lot simpler.  Besides that, I don't see a huge difference.  I would prefer this however since I can accomplish updating in 2 lines or if I want the user to accept or deny an update, 3 lines.  It isn't as configurable, but it gets its job done.

Also, I will try to update the README with the new changes I have done soon because the README is out of date and it is rather disappointing for anyone wanting to use the library (though I assume I'll be the only one who does in the long run).

EDIT:  The README is updated.  I will add a license file if I learn that it is important.  I feel like the framework of the library is very good though Cheesy
Offline sproingie

JGO Kernel


Medals: 202



« Reply #21 - Posted 2013-03-23 17:13:49 »

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.


Offline gouessej
« Reply #22 - Posted 2013-03-23 23:18:59 »

That's what you were asking, right?
Yes. Why don't you use Java Web Start / Icedtea Web Start / NetX or Getdown? Your solution is simple but you'll have to maintain it by yourself. I think a JAR used at runtime can make a copy of itself, update this copy and run a script that stops its execution, overwrite the JAR and restart the updated program.

Offline Sammidysam
« Reply #23 - Posted 2013-03-23 23:29:11 »

I didn't do much research about other libraries for auto-updating.  I just wanted to program it, I guess.  I probably should've used a well-established library I guess.  But since I ended up making this, I'll use it.
Offline Grunnt

JGO Wizard


Medals: 68
Projects: 8
Exp: 5 years


Complex != complicated


« Reply #24 - Posted 2013-03-24 15:57:24 »

I would prefer this however since I can accomplish updating in 2 lines or if I want the user to accept or deny an update, 3 lines.  It isn't as configurable, but it gets its job done.

That's cool Grin I was just curious. Actually I've thought about doing the same a couple of times.

Offline Sammidysam
« Reply #25 - Posted 2013-04-03 22:50:03 »

I found a pretty embarrassing bug 3 days ago that I've forgotten to mention here.  I forgot to subtract one from the month variable to set it up so that January = 0 and so on when setting up Calendar so at the ends of months it could ignore updates submitted at the beginning of months.  I believe I added one to the month results to maintain compatibility with the C# version of the library (so that the two could work together), but I'm not sure.  Nonetheless, it is now fixed.  If anybody out there uses this though, be sure to update your launcher!  I also added a simple LICENSE file because I guess it should be done.
Offline Nate

JGO Kernel


Medals: 147
Projects: 4
Exp: 14 years


Esoteric Software


« Reply #26 - Posted 2013-04-03 23:57:17 »


Aye, but mine is a standard in absolute simplicity, everyone else wants to be a standard that covers all logging usage, evar. Why should I need to learn a DSL so I can edit a config file? That is, if I can find which of the 6 config files in 8 different JARs and 3 classpath locations I actually need to be editing. I'm looking at you, log4j! Then you have the crazy people who come along and tell me I need a layer on top of the horrible mess I already have which will abstract away the mess... it's just logging!

Offline sproingie

JGO Kernel


Medals: 202



« Reply #27 - Posted 2013-04-04 01:35:33 »

Log4j has exactly one jar, and one config file and it's anywhere in the classpath you want it to be.  slf4j means the rest of the world doesn't have to use log4j, they can direct it to whatever they're already using.  And it's one or at most two extra jars.  My build system takes care of it.  Would it be nice if there were a nice generic logging API using SPI the way JDBC does and not some pale imitation also-ran like j.u.l or this weird slf4j thing?  Sure.  It'd be nice of a lot of basic stuff came with the JDK.

Sure, I can see the use for a light drop-in logging system in an app that doesn't need to get along with everyone else's libraries, I'm not disparaging a tiny logger.  But it's really no excuse for outright refusing to learn something so gobsmackingly simple.
Offline Nate

JGO Kernel


Medals: 147
Projects: 4
Exp: 14 years


Esoteric Software


« Reply #28 - Posted 2013-04-04 02:49:42 »

Except you're wrong, of course. Cheesy JBoss/Tomcat often has log4j config files in multiple places. I've seen people copy them around because they couldn't figure out how to get their log config picked up. I've seen dependency JARs with a log4j config file inside, then it's a crap shoot which file actually gets picked up. It's still a DSL to learn just to log properly. Then you have JULI, whatever the hell that is. I've never used slf4j, but I'm traumatized. Also, the JDK does come with logging, it just sucks. Smiley It's not that I haven't used these things when forced to, I just find them ridiculous and won't let them near my pretty, pretty projects.

Offline sproingie

JGO Kernel


Medals: 202



« Reply #29 - Posted 2013-04-04 04:43:11 »

It's entirely possible that JBoss, Tomcat, and Log4J aren't all the same thing.

java.util.logging is a steaming pile of garbage.  The Tomcat folks decided it wasn't horrible enough and actually made their own independent implementation of it called JULI in order to make it even worse.  No one uses it unless they're stuck with Tomcat's brand of idiocy.

For all its features, log4j has its own serious problems in environments like app servers because of classloader leaks.  So the author of log4j created slf4j which is a generic API that lets you switch out different logging backends and use the same API for each, similar to how you use the same JDBC API for different database backends.  That was eight years ago.  The landscape has not significantly changed since except for more people using slf4j.  This is not a chaotic ever-changing landscape, unless you consider eight year old technology to be bleeding edge.
Pages: [1] 2
  ignore  |  Print  
 
 
You cannot reply to this message, because it is very, very old.

 

Add your game by posting it in the WIP section,
or publish it in Showcase.

The first screenshot will be displayed as a thumbnail.

BurntPizza (22 views)
2014-09-19 03:14:18

Dwinin (35 views)
2014-09-12 09:08:26

Norakomi (62 views)
2014-09-10 13:57:51

TehJavaDev (89 views)
2014-09-10 06:39:09

Tekkerue (44 views)
2014-09-09 02:24:56

mitcheeb (65 views)
2014-09-08 06:06:29

BurntPizza (47 views)
2014-09-07 01:13:42

Longarmx (35 views)
2014-09-07 01:12:14

Longarmx (40 views)
2014-09-07 01:11:22

Longarmx (36 views)
2014-09-07 01:10:19
List of Learning Resources
by Longor1996
2014-08-16 10:40:00

List of Learning Resources
by SilverTiger
2014-08-05 19:33:27

Resources for WIP games
by CogWheelz
2014-08-01 16:20:17

Resources for WIP games
by CogWheelz
2014-08-01 16:19:50

List of Learning Resources
by SilverTiger
2014-07-31 16:29:50

List of Learning Resources
by SilverTiger
2014-07-31 16:26:06

List of Learning Resources
by SilverTiger
2014-07-31 11:54:12

HotSpot Options
by dleskov
2014-07-08 01:59:08
java-gaming.org is not responsible for the content posted by its members, including references to external websites, and other references that may or may not have a relation with our primarily gaming and game production oriented community. inquiries and complaints can be sent via email to the info‑account of the company managing the website of java‑gaming.org
Powered by MySQL Powered by PHP Powered by SMF 1.1.18 | SMF © 2013, Simple Machines | Managed by Enhanced Four Valid XHTML 1.0! Valid CSS!