Implemented remaining JS bridge functions for Win launcher.
This commit is contained in:
220
OpenRA.Launcher/Download.cs
Normal file
220
OpenRA.Launcher/Download.cs
Normal file
@@ -0,0 +1,220 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.IO;
|
||||
using System.ComponentModel;
|
||||
using System.IO.Pipes;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace OpenRA.Launcher
|
||||
{
|
||||
public enum DownloadStatus
|
||||
{
|
||||
NOT_REGISTERED, AVAILABLE, DOWNLOADING, DOWNLOADED, EXTRACTING, EXTRACTED, ERROR
|
||||
}
|
||||
|
||||
class Download : IDisposable
|
||||
{
|
||||
DownloadStatus status = DownloadStatus.NOT_REGISTERED;
|
||||
string url = "", target = "", key = "";
|
||||
BackgroundWorker downloadBGWorker, extractBGWorker;
|
||||
int bytesTotal = 0, bytesDone = 0;
|
||||
string errorMessage = "";
|
||||
HtmlDocument document;
|
||||
|
||||
public string ErrorMessage
|
||||
{
|
||||
get { return errorMessage; }
|
||||
}
|
||||
|
||||
public int BytesDone
|
||||
{
|
||||
get { return bytesDone; }
|
||||
}
|
||||
|
||||
public int BytesTotal
|
||||
{
|
||||
get { return bytesTotal; }
|
||||
}
|
||||
|
||||
public DownloadStatus Status
|
||||
{
|
||||
get { return status; }
|
||||
}
|
||||
|
||||
public Download(HtmlDocument document, string key, string url, string filename)
|
||||
{
|
||||
this.url = url;
|
||||
this.key = key;
|
||||
this.document = document;
|
||||
target = Path.Combine(Path.GetTempPath(), filename);
|
||||
if (File.Exists(target))
|
||||
status = DownloadStatus.DOWNLOADED;
|
||||
else
|
||||
status = DownloadStatus.AVAILABLE;
|
||||
|
||||
downloadBGWorker = new BackgroundWorker()
|
||||
{
|
||||
WorkerReportsProgress = true,
|
||||
WorkerSupportsCancellation = true
|
||||
};
|
||||
|
||||
downloadBGWorker.DoWork += RunDownload;
|
||||
downloadBGWorker.ProgressChanged += UpdateProgress;
|
||||
downloadBGWorker.RunWorkerCompleted += DownloadFinished;
|
||||
|
||||
extractBGWorker = new BackgroundWorker();
|
||||
|
||||
extractBGWorker.DoWork += DoExtraction;
|
||||
extractBGWorker.RunWorkerCompleted += ExtractionFinished;
|
||||
}
|
||||
|
||||
public void StartDownload()
|
||||
{
|
||||
if (!downloadBGWorker.IsBusy)
|
||||
{
|
||||
status = DownloadStatus.DOWNLOADING;
|
||||
downloadBGWorker.RunWorkerAsync(new string[] { url, target });
|
||||
}
|
||||
}
|
||||
|
||||
public void CancelDownload()
|
||||
{
|
||||
if (downloadBGWorker.IsBusy)
|
||||
downloadBGWorker.CancelAsync();
|
||||
}
|
||||
|
||||
public void ExtractDownload(string destPath)
|
||||
{
|
||||
if (!extractBGWorker.IsBusy)
|
||||
{
|
||||
status = DownloadStatus.EXTRACTING;
|
||||
extractBGWorker.RunWorkerAsync(new string[] { target, destPath });
|
||||
}
|
||||
}
|
||||
|
||||
static void RunDownload(object sender, DoWorkEventArgs e)
|
||||
{
|
||||
var bgWorker = sender as BackgroundWorker;
|
||||
string[] args = e.Argument as string[];
|
||||
string url = args[0];
|
||||
string dest = args[1];
|
||||
var p = UtilityProgram.CallWithAdmin("--download-url", url, dest);
|
||||
Regex r = new Regex(@"(\d{1,3})% (\d+)/(\d+) bytes");
|
||||
|
||||
NamedPipeClientStream pipe = new NamedPipeClientStream(".", "OpenRA.Utility", PipeDirection.In);
|
||||
pipe.Connect();
|
||||
|
||||
using (var response = new StreamReader(pipe))
|
||||
{
|
||||
while (!p.HasExited)
|
||||
{
|
||||
string s = response.ReadLine();
|
||||
if (string.IsNullOrEmpty(s)) continue;
|
||||
if (Util.IsError(ref s))
|
||||
throw new Exception(s);
|
||||
|
||||
if (bgWorker.CancellationPending)
|
||||
{
|
||||
e.Cancel = true;
|
||||
p.Kill();
|
||||
return;
|
||||
}
|
||||
if (!r.IsMatch(s)) continue;
|
||||
var m = r.Match(s);
|
||||
bgWorker.ReportProgress(int.Parse(m.Groups[1].Value),
|
||||
new string[] { m.Groups[2].Value, m.Groups[3].Value });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateProgress(object sender, ProgressChangedEventArgs e)
|
||||
{
|
||||
string[] s = e.UserState as string[];
|
||||
bytesDone = int.Parse(s[0]);
|
||||
bytesTotal = int.Parse(s[1]);
|
||||
document.InvokeScript("downloadProgressed", new object[] { key });
|
||||
}
|
||||
|
||||
void DownloadFinished(object sender, RunWorkerCompletedEventArgs e)
|
||||
{
|
||||
if (e.Error != null)
|
||||
{
|
||||
status = DownloadStatus.ERROR;
|
||||
errorMessage = e.Error.Message;
|
||||
//if (File.Exists(target))
|
||||
// File.Delete(target);
|
||||
document.InvokeScript("downloadProgressed", new object[] { key });
|
||||
return;
|
||||
}
|
||||
|
||||
if (e.Cancelled)
|
||||
{
|
||||
status = DownloadStatus.ERROR;
|
||||
errorMessage = "Download Cancelled";
|
||||
//if (File.Exists(target))
|
||||
// File.Delete(target);
|
||||
document.InvokeScript("downloadProgressed", new object[] { key });
|
||||
return;
|
||||
}
|
||||
|
||||
status = DownloadStatus.DOWNLOADED;
|
||||
document.InvokeScript("downloadProgressed", new object[] { key });
|
||||
}
|
||||
|
||||
void DoExtraction(object sender, DoWorkEventArgs e)
|
||||
{
|
||||
var bgWorker = sender as BackgroundWorker;
|
||||
string[] args = e.Argument as string[];
|
||||
string zipFile = args[0];
|
||||
string destPath = args[1];
|
||||
|
||||
var p = UtilityProgram.CallWithAdmin("--extract-zip", zipFile, destPath);
|
||||
var pipe = new NamedPipeClientStream(".", "OpenRA.Utility", PipeDirection.In);
|
||||
|
||||
pipe.Connect();
|
||||
|
||||
using (var reader = new StreamReader(pipe))
|
||||
{
|
||||
while (!p.HasExited)
|
||||
{
|
||||
string s = reader.ReadLine();
|
||||
if (string.IsNullOrEmpty(s)) continue;
|
||||
if (Util.IsError(ref s))
|
||||
throw new Exception(s);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ExtractionFinished(object sender, RunWorkerCompletedEventArgs e)
|
||||
{
|
||||
if (e.Error != null)
|
||||
{
|
||||
status = DownloadStatus.ERROR;
|
||||
errorMessage = e.Error.Message;
|
||||
document.InvokeScript("extractProgressed", new object[] { key });
|
||||
}
|
||||
|
||||
|
||||
status = DownloadStatus.EXTRACTED;
|
||||
document.InvokeScript("extractProgressed", new object[] { key });
|
||||
}
|
||||
|
||||
bool disposed = false;
|
||||
|
||||
~Download()
|
||||
{
|
||||
if (!disposed)
|
||||
Dispose();
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (status == DownloadStatus.DOWNLOADING && File.Exists(target))
|
||||
File.Delete(target);
|
||||
disposed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,21 +4,34 @@ using System.Linq;
|
||||
using System.Text;
|
||||
using System.IO;
|
||||
using System.Diagnostics;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace OpenRA.Launcher
|
||||
{
|
||||
public class JSBridge
|
||||
{
|
||||
Dictionary<string, Mod> allMods;
|
||||
Dictionary<string, Mod> allMods = new Dictionary<string,Mod>();
|
||||
|
||||
public JSBridge(Dictionary<string, Mod> allMods)
|
||||
public Dictionary<string, Mod> AllMods
|
||||
{
|
||||
this.allMods = allMods;
|
||||
get { return allMods; }
|
||||
set { allMods = value; }
|
||||
}
|
||||
Dictionary<string, Download> downloads = new Dictionary<string,Download>();
|
||||
|
||||
public bool fileExistsInMod(string file, string mod)
|
||||
HtmlDocument document = null;
|
||||
|
||||
public HtmlDocument Document
|
||||
{
|
||||
return File.Exists(string.Format("mods{0}{1}{0}{2}", Path.DirectorySeparatorChar, mod, file));
|
||||
get { return document; }
|
||||
set { document = value; }
|
||||
}
|
||||
|
||||
public bool existsInMod(string file, string mod)
|
||||
{
|
||||
string cleanedPath = CleanPath(file);
|
||||
return File.Exists(string.Format("mods{0}{1}{0}{2}", Path.DirectorySeparatorChar, mod, cleanedPath));
|
||||
}
|
||||
|
||||
public void log(string message)
|
||||
@@ -26,12 +39,16 @@ namespace OpenRA.Launcher
|
||||
Console.WriteLine("js: " + message);
|
||||
}
|
||||
|
||||
public void launchMod(string mod)
|
||||
public bool launchMod(string mod)
|
||||
{
|
||||
string m = mod;
|
||||
List<string> modList = new List<string>();
|
||||
modList.Add(m);
|
||||
if (!allMods.ContainsKey(m)) System.Windows.Forms.MessageBox.Show("allMods does not contain " + m);
|
||||
if (!allMods.ContainsKey(m))
|
||||
{
|
||||
System.Windows.Forms.MessageBox.Show("allMods does not contain " + m);
|
||||
return false;
|
||||
}
|
||||
while (!string.IsNullOrEmpty(allMods[m].Requires))
|
||||
{
|
||||
m = allMods[m].Requires;
|
||||
@@ -42,6 +59,93 @@ namespace OpenRA.Launcher
|
||||
p.StartInfo.FileName = "OpenRA.Game.exe";
|
||||
p.StartInfo.Arguments = "Game.Mods=" + string.Join(",", modList.ToArray());
|
||||
p.Start();
|
||||
return true;
|
||||
}
|
||||
|
||||
Regex p = new Regex(@"\.\.[/\\]?");
|
||||
string CleanPath(string path)
|
||||
{
|
||||
string root = Path.GetPathRoot(path);
|
||||
string cleanedPath = path.Remove(0, root.Length);
|
||||
return p.Replace(cleanedPath, "");
|
||||
}
|
||||
|
||||
public void registerDownload(string key, string url, string filename)
|
||||
{
|
||||
string cleanedPath = CleanPath(filename);
|
||||
if (!downloads.ContainsKey(key))
|
||||
downloads.Add(key, new Download(document, key, url, cleanedPath));
|
||||
else
|
||||
downloads[key] = new Download(document, key, url, cleanedPath);
|
||||
}
|
||||
|
||||
public bool startDownload(string key)
|
||||
{
|
||||
if (!downloads.ContainsKey(key))
|
||||
return false;
|
||||
|
||||
downloads[key].StartDownload();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool cancelDownload(string key)
|
||||
{
|
||||
if (!downloads.ContainsKey(key))
|
||||
return false;
|
||||
|
||||
downloads[key].CancelDownload();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public string downloadStatus(string key)
|
||||
{
|
||||
if (!downloads.ContainsKey(key))
|
||||
return DownloadStatus.NOT_REGISTERED.ToString();
|
||||
|
||||
return downloads[key].Status.ToString();
|
||||
}
|
||||
|
||||
public string downloadError(string key)
|
||||
{
|
||||
if (!downloads.ContainsKey(key))
|
||||
return "";
|
||||
|
||||
return downloads[key].ErrorMessage;
|
||||
}
|
||||
|
||||
public int bytesCompleted(string key)
|
||||
{
|
||||
if (!downloads.ContainsKey(key))
|
||||
return -1;
|
||||
|
||||
return downloads[key].BytesDone;
|
||||
}
|
||||
|
||||
public int bytesTotal(string key)
|
||||
{
|
||||
if (!downloads.ContainsKey(key))
|
||||
return -1;
|
||||
|
||||
return downloads[key].BytesTotal;
|
||||
}
|
||||
|
||||
public bool extractDownload(string key, string targetDir, string mod)
|
||||
{
|
||||
string cleanedPath = CleanPath(targetDir);
|
||||
|
||||
string targetPath = Path.Combine(mod, cleanedPath);
|
||||
|
||||
if (!downloads.ContainsKey(key))
|
||||
return false;
|
||||
|
||||
if (downloads[key].Status != DownloadStatus.DOWNLOADED)
|
||||
return false;
|
||||
|
||||
downloads[key].ExtractDownload(targetPath);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,9 +29,13 @@ namespace OpenRA.Launcher
|
||||
|
||||
//treeView.Nodes["ModsNode"].ImageIndex = 1;
|
||||
//treeView.Nodes["ModsNode"].SelectedImageIndex = 1;
|
||||
|
||||
webBrowser.ObjectForScripting = new JSBridge();
|
||||
webBrowser.DocumentCompleted += (o, e) =>
|
||||
{
|
||||
var b = o as WebBrowser;
|
||||
(b.ObjectForScripting as JSBridge).Document = b.Document;
|
||||
};
|
||||
RefreshMods();
|
||||
webBrowser.ObjectForScripting = new JSBridge(allMods);
|
||||
}
|
||||
|
||||
Mod GetMetadata(string mod)
|
||||
@@ -102,6 +106,8 @@ namespace OpenRA.Launcher
|
||||
|
||||
allMods = mods.ToDictionary(x => x, x => GetMetadata(x));
|
||||
|
||||
(webBrowser.ObjectForScripting as JSBridge).AllMods = allMods;
|
||||
|
||||
RefreshModTree(treeView, allMods.Keys.ToArray());
|
||||
}
|
||||
|
||||
@@ -176,6 +182,7 @@ namespace OpenRA.Launcher
|
||||
string modHtmlPath = string.Format("mods{0}{1}{0}mod.html", Path.DirectorySeparatorChar, e.Node.Name);
|
||||
if (!File.Exists(modHtmlPath)) return;
|
||||
webBrowser.Navigate(Path.GetFullPath(modHtmlPath));
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,6 +42,7 @@
|
||||
</Target>
|
||||
-->
|
||||
<ItemGroup>
|
||||
<Compile Include="Download.cs" />
|
||||
<Compile Include="JSBridge.cs" />
|
||||
<Compile Include="Launcher.cs">
|
||||
<SubType>Form</SubType>
|
||||
|
||||
Reference in New Issue
Block a user