RuneBook icon indicating copy to clipboard operation
RuneBook copied to clipboard

Auto Fetching of Images (continuation of PR #45)

Open Soundofdarkness opened this issue 5 years ago • 4 comments

From @TinyRaindrop:

Would this be a logical next step? Force recheck for new images whenever game version changes. So that users get new data even before a new Runebook update is released.

Generally this should be the way to go, after finding a backup in case something of DDragon doesn't work, fails to update or anything like that. Potentially just using a github repo as cdn-ish replacement with backup static data ?

Soundofdarkness avatar Jun 19 '20 20:06 Soundofdarkness

I think every installation can have such data stored locally in an Images folder, it's only 1-2 MB and users are querying for this data anyway every time they open Runebook.

Cache whatever is reasonable to cache (images, jsons), and when Runebook breaks on another update, users will have a fallback dataset.

TinyRaindrop avatar Jun 19 '20 20:06 TinyRaindrop

As for the pictures. I don't know if we have to redo every patch. That's like 2,5MB every patch for nothing. With the runes or champs the tooltips or something like that change from time to time. But the pictures of the runes?

If we do this we should do it right. Don't blunt download. But send HEAD requests to the server and compare the ETags. That way we can do a delta comparison and wouldn't have to update obtuse all the time.

We could also create a file for the ETags and use that for the downloads of the jsons. If possible I will make a proof of concept tomorrow which we can use for the pictures of the runes.

By the way, NOW is a good time for a new version. Since we are planning small structure changes now.

ghost avatar Jun 19 '20 20:06 ghost

@TinyRaindrop Yup, caching seems like the way to go definitely. @Rerago Absolutely, no need to spam the servers with requests In general we still have to make sure that in a situation where something with fetching it goes wrong, and a user is on a clean install without cache, we still have some kind of fallback to get the images.

And about release, will happen in a few minutes, since I would like to release auto upload with the same release.

Soundofdarkness avatar Jun 20 '20 13:06 Soundofdarkness

Here's how it works:

var Store  = require('electron-store');
var rp = require('request-promise-native');

const cacheStore = new Store({
    name: "cache"
});

async function requestCachedAsync(url, cachePath){
    // Determine etag from server
    var etagResponse = await rp({ method: 'HEAD', uri: url, resolveWithFullResponse: true }).then(function(response) {   
        return response.headers["etag"] ?? '';
    });

    // Return variable
    var response = null;

    // is there an Etag? Trying to determine cache
    if(etagResponse !== ''){
        // determine etag from cache and return cached data if necessary
        let etagCache = cacheStore.get(cachePath + '_etag');
        if(etagCache == etagResponse){
            response = cacheStore.get(cachePath);
            console.log('ETag-Cached: ' + url);
        }
    }

    // no cache? Download normally and store in cache
    if(response === null){
        // Downloading data normally
        let normalResponse = await rp({ uri: url, resolveWithFullResponse: true }).then(function(resp) { return resp; })

        // Error? Throw error
        if(normalResponse.statusCode !== 200){
			throw Error('Error Downloading: ' + url)
        }
        
        // determine etag
        let responseEtag = normalResponse.headers['etag'];

        // adapt return
        response = normalResponse.body

        // do you have data and a tag? => cache
        if(response !== null && responseEtag != ''){
            // Prepare cache data
            let cachToSave = {};
            cachToSave[cachePath] = response;
            cachToSave[cachePath + '_etag'] = responseEtag;

            // cache data
            cacheStore.set(cachToSave);
        }        
    }
     
    // Return
    return response;
}

And then like this for version.json

try{
	requestCachedAsync('https://ddragon.leagueoflegends.com/api/versions.json', 'catch.versions_json').then(function (responsData) {
		var ver = JSON.parse(responsData);
		freezer.get().set('lolversions', ver);
		freezer.emit("version:set", ver[0]);
	});
}
catch {
	throw Error("Couldn't get ddragon api version");
}

But I'm not really satisfied. The data is stored as JSON and not as a separate file. Which is later unfavorable for the images. Since we want to use them as reference.

This variant works quite well for JSON. But it is simply not worth it. Since we save ~200kb with it. But to do such a conversion is questionable.

For the pictures it would be worth it. The only problem is that the current pictures are bound to the exe and they are not located locally, so we can't replace them on the fly.

ghost avatar Jun 20 '20 19:06 ghost