module csgs.task; import slf4d; import scheduled; import scheduled.taskpool_scheduler; import std.datetime; import std.typecons; import std.json; import std.string; import std.file; import std.stdio; import csgs.extract; void startScheduledTasks() { JobScheduler scheduler = new TaskPoolScheduler(); Job cleanJob = new FunctionJob(&cleanOldExtracts); scheduler.addJob(cleanJob, new FixedIntervalSchedule(days(1))); Job updateCheckJob = new FunctionJob(&checkForExtractorUpdate); scheduler.addJob(updateCheckJob, new FixedIntervalSchedule(hours(1))); scheduler.start(); } private void cleanOldExtracts() { import std.file; immutable MAX_AGE = days(5); info("Cleaning old extracts."); if (!exists(EXTRACTS_DIR)) return; immutable SysTime now = Clock.currTime(); foreach (DirEntry entry; dirEntries(EXTRACTS_DIR, SpanMode.shallow, false)) { if (entry.isDir) { infoF!"Removing directory %s."(entry.name); rmdirRecurse(entry.name); } else if (entry.isFile) { immutable Duration age = now - entry.timeLastModified(); if (age > MAX_AGE) { infoF!"Removing extract %s because it's too old."(entry.name); std.file.remove(entry.name); } } } } private void checkForExtractorUpdate() { import requests; import std.json; import std.stdio; import std.string; import std.file; info("Checking for MaterialsExtractor program updates."); // First request the latest release from GitHub API: Request req = Request(); req.addHeaders(["Accept": "application/vnd.github+json"]); Response resp = req.get("https://api.github.com/repos/andrewlalis/MaterialsExtractor/releases/latest"); if (resp.code() != 200) { warnF!"Failed to get the latest MaterialsExtractor release. Status code %d."(resp.code); return; } JSONValue responseJson = parseJSON(resp.responseBody.toString()); // Get the release's version, compare it with our current version. immutable string releaseVersion = responseJson.object["tag_name"].str; infoF!"Found release version %s"(releaseVersion); Nullable!string currentVersion = getCurrentExtractorVersion(); if (!currentVersion.isNull && currentVersion.get() >= releaseVersion) { infoF!"Skipping this version since it's not newer than the current %s."(currentVersion.get); return; } // Find the release's asset, and download it. Nullable!JSONValue nullableAsset = findJarAsset(responseJson); if (nullableAsset.isNull) { warn("Latest release has no asset. Ignoring."); return; } JSONValue asset = nullableAsset.get(); immutable string filename = asset.object["name"].str; immutable string downloadUrl = asset.object["browser_download_url"].str; infoF!"Found asset: %s. Downloading from %s."(filename, downloadUrl); if (exists(filename)) { std.file.remove(filename); } Request downloadRequest = Request(); downloadRequest.useStreaming = true; Response downloadResponse = downloadRequest.get(downloadUrl); File f = File(filename, "wb"); auto stream = downloadResponse.receiveAsRange(); while (!stream.empty) { f.rawWrite(stream.front); stream.popFront(); } f.close(); infoF!"Downloaded file to %s"(f.name); } private Nullable!JSONValue findJarAsset(ref JSONValue response) { foreach (JSONValue asset; response.object["assets"].array) { immutable string name = asset.object["name"].str; if ( startsWith(name, "materials-extractor") && endsWith(name, ".jar") && asset.object["content_type"].str == "application/java-archive" ) { return nullable(asset); } } return Nullable!JSONValue.init; }