|
|
@ -0,0 +1,205 @@ |
|
|
|
using IllusionInjector.Logging; |
|
|
|
using SimpleJSON; |
|
|
|
using System; |
|
|
|
using System.Collections.Generic; |
|
|
|
using System.Collections; |
|
|
|
using System.Diagnostics; |
|
|
|
using System.IO; |
|
|
|
using System.Linq; |
|
|
|
using System.Runtime.Serialization; |
|
|
|
using System.Text; |
|
|
|
using System.Threading.Tasks; |
|
|
|
using UnityEngine.Networking; |
|
|
|
using UnityEngine; |
|
|
|
using IllusionPlugin; |
|
|
|
using System.Text.RegularExpressions; |
|
|
|
using Logger = IllusionInjector.Logging.Logger; |
|
|
|
|
|
|
|
namespace IllusionInjector.Updating |
|
|
|
{ |
|
|
|
class ModUpdater : MonoBehaviour |
|
|
|
{ |
|
|
|
public ModUpdater instance; |
|
|
|
|
|
|
|
public void Awake() |
|
|
|
{ |
|
|
|
instance = this; |
|
|
|
CheckForUpdates(); |
|
|
|
} |
|
|
|
|
|
|
|
public void CheckForUpdates() |
|
|
|
{ |
|
|
|
StartCoroutine(CheckForUpdatesCoroutine()); |
|
|
|
} |
|
|
|
|
|
|
|
struct UpdateCheckQueueItem |
|
|
|
{ |
|
|
|
public PluginManager.BSPluginMeta Plugin; |
|
|
|
public Uri UpdateUri; |
|
|
|
public string Name; |
|
|
|
} |
|
|
|
|
|
|
|
struct UpdateQueueItem |
|
|
|
{ |
|
|
|
public PluginManager.BSPluginMeta Plugin; |
|
|
|
public Uri DownloadUri; |
|
|
|
public string Name; |
|
|
|
public Version NewVersion; |
|
|
|
} |
|
|
|
|
|
|
|
private Regex commentRegex = new Regex(@"(?: \/\/.+)?$", RegexOptions.Compiled | RegexOptions.Multiline); |
|
|
|
private Dictionary<Uri, UpdateScript> cachedRequests = new Dictionary<Uri, UpdateScript>(); |
|
|
|
IEnumerator CheckForUpdatesCoroutine() |
|
|
|
{ |
|
|
|
Logger.log.Info("Checking for mod updates..."); |
|
|
|
|
|
|
|
var toUpdate = new List<UpdateQueueItem>(); |
|
|
|
var plugins = new Queue<UpdateCheckQueueItem>(PluginManager.BSMetas.Select(p => new UpdateCheckQueueItem { Plugin = p, UpdateUri = p.Plugin.UpdateUri, Name = p.Plugin.Name })); |
|
|
|
|
|
|
|
for (; plugins.Count > 0;) |
|
|
|
{ |
|
|
|
var plugin = plugins.Dequeue(); |
|
|
|
|
|
|
|
Logger.log.Debug($"Checking for updates for {plugin.Name}"); |
|
|
|
|
|
|
|
if (plugin.UpdateUri != null) |
|
|
|
{ |
|
|
|
if (!cachedRequests.ContainsKey(plugin.UpdateUri)) |
|
|
|
using (var request = UnityWebRequest.Get(plugin.UpdateUri)) |
|
|
|
{ |
|
|
|
yield return request.SendWebRequest(); |
|
|
|
|
|
|
|
if (request.isNetworkError) |
|
|
|
{ |
|
|
|
Logger.log.Error("Network error while trying to update mods"); |
|
|
|
Logger.log.Error(request.error); |
|
|
|
break; |
|
|
|
} |
|
|
|
if (request.isHttpError) |
|
|
|
{ |
|
|
|
Logger.log.Error($"Server returned an error code while trying to update mod {plugin.Name}"); |
|
|
|
Logger.log.Error(request.error); |
|
|
|
} |
|
|
|
|
|
|
|
var json = request.downloadHandler.text; |
|
|
|
|
|
|
|
json = commentRegex.Replace(json, ""); |
|
|
|
|
|
|
|
JSONObject obj = null; |
|
|
|
try |
|
|
|
{ |
|
|
|
obj = JSON.Parse(json).AsObject; |
|
|
|
} |
|
|
|
catch (InvalidCastException) |
|
|
|
{ |
|
|
|
Logger.log.Error($"Parse error while trying to update mod {plugin.Name}"); |
|
|
|
Logger.log.Error($"Response doesn't seem to be a JSON object"); |
|
|
|
continue; |
|
|
|
} |
|
|
|
catch (Exception e) |
|
|
|
{ |
|
|
|
Logger.log.Error($"Parse error while trying to update mod {plugin.Name}"); |
|
|
|
Logger.log.Error(e); |
|
|
|
continue; |
|
|
|
} |
|
|
|
|
|
|
|
UpdateScript ss; |
|
|
|
try |
|
|
|
{ |
|
|
|
ss = UpdateScript.Parse(obj); |
|
|
|
} |
|
|
|
catch (Exception e) |
|
|
|
{ |
|
|
|
Logger.log.Error($"Parse error while trying to update mod {plugin.Name}"); |
|
|
|
Logger.log.Error($"Script at {plugin.UpdateUri} doesn't seem to be a valid update script"); |
|
|
|
Logger.log.Debug(e); |
|
|
|
continue; |
|
|
|
} |
|
|
|
|
|
|
|
cachedRequests.Add(plugin.UpdateUri, ss); |
|
|
|
} |
|
|
|
|
|
|
|
var script = cachedRequests[plugin.UpdateUri]; |
|
|
|
if (script.Info.TryGetValue(plugin.Name, out UpdateScript.PluginVersionInfo info)) |
|
|
|
{ |
|
|
|
Logger.log.Debug($"Checking version info for {plugin.Name} ({plugin.Plugin.Plugin.Name})"); |
|
|
|
if (info.NewName != null || info.NewScript != null) |
|
|
|
plugins.Enqueue(new UpdateCheckQueueItem |
|
|
|
{ |
|
|
|
Plugin = plugin.Plugin, |
|
|
|
Name = info.NewName ?? plugin.Name, |
|
|
|
UpdateUri = info.NewScript ?? plugin.UpdateUri |
|
|
|
}); |
|
|
|
else |
|
|
|
{ |
|
|
|
Logger.log.Debug($"New version: {info.Version}, Current version: {plugin.Plugin.Plugin.Version}"); |
|
|
|
if (info.Version > plugin.Plugin.Plugin.Version) |
|
|
|
{ // we should update plugin
|
|
|
|
Logger.log.Debug($"Queueing update for {plugin.Name} ({plugin.Plugin.Plugin.Name})"); |
|
|
|
|
|
|
|
toUpdate.Add(new UpdateQueueItem |
|
|
|
{ |
|
|
|
Plugin = plugin.Plugin, |
|
|
|
DownloadUri = info.Download, |
|
|
|
Name = plugin.Name, |
|
|
|
NewVersion = info.Version |
|
|
|
}); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
Logger.log.Error($"Script defined for plugin {plugin.Name} doesn't define information for {plugin.Name}"); |
|
|
|
continue; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
Logger.log.Info($"{toUpdate.Count} mods need updating"); |
|
|
|
|
|
|
|
if (toUpdate.Count == 0) yield break; |
|
|
|
|
|
|
|
string tempDirectory = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName() + Path.GetRandomFileName()); |
|
|
|
Directory.CreateDirectory(tempDirectory); |
|
|
|
Logger.log.Debug($"Created temp download dirtectory {tempDirectory}"); |
|
|
|
foreach (var item in toUpdate) |
|
|
|
{ |
|
|
|
StartCoroutine(DownloadPluginCoroutine(tempDirectory, item)); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
IEnumerator DownloadPluginCoroutine(string tempdir, UpdateQueueItem item) |
|
|
|
{ |
|
|
|
var file = Path.Combine(tempdir, item.Name + ".dll"); |
|
|
|
|
|
|
|
using (var req = UnityWebRequest.Get(item.DownloadUri)) |
|
|
|
{ |
|
|
|
req.downloadHandler = new DownloadHandlerFile(file); |
|
|
|
yield return req.SendWebRequest(); |
|
|
|
|
|
|
|
if (req.isNetworkError) |
|
|
|
{ |
|
|
|
Logger.log.Error($"Network error while trying to download update for {item.Plugin.Plugin.Name}"); |
|
|
|
Logger.log.Error(req.error); |
|
|
|
yield break; |
|
|
|
} |
|
|
|
if (req.isHttpError) |
|
|
|
{ |
|
|
|
Logger.log.Error($"Server returned an error code while trying to download update for {item.Plugin.Plugin.Name}"); |
|
|
|
Logger.log.Error(req.error); |
|
|
|
yield break; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
var pluginDir = Path.GetDirectoryName(item.Plugin.Filename); |
|
|
|
var newFile = Path.Combine(pluginDir, item.Name + ".dll"); |
|
|
|
|
|
|
|
File.Delete(item.Plugin.Filename); |
|
|
|
if (File.Exists(newFile)) |
|
|
|
File.Delete(newFile); |
|
|
|
File.Move(file, newFile); |
|
|
|
|
|
|
|
Logger.log.Info($"{item.Plugin.Plugin.Name} updated to {item.NewVersion}"); |
|
|
|
} |
|
|
|
} |
|
|
|
} |