diff --git a/src/BizHawk.Client.EmuHawk/AVOut/FFmpegDownloaderForm.cs b/src/BizHawk.Client.EmuHawk/AVOut/FFmpegDownloaderForm.cs index f908be73542..f534f4f711f 100644 --- a/src/BizHawk.Client.EmuHawk/AVOut/FFmpegDownloaderForm.cs +++ b/src/BizHawk.Client.EmuHawk/AVOut/FFmpegDownloaderForm.cs @@ -1,162 +1,38 @@ using System.IO; -using System.Linq; -using System.Threading; -using System.Windows.Forms; using BizHawk.Common; +using BizHawk.Common.IOExtensions; namespace BizHawk.Client.EmuHawk { - /// - /// Downloads FFmpeg - /// - public partial class FFmpegDownloaderForm : Form + public sealed class FFmpegDownloaderForm : DownloaderForm { - public FFmpegDownloaderForm() - { - InitializeComponent(); - - txtLocation.Text = FFmpegService.FFmpegPath; - txtUrl.Text = FFmpegService.Url; - - if (OSTailoredCode.IsUnixHost) textBox1.Text = string.Join("\n", textBox1.Text.Split('\n').Take(3)) + "\n\n(Linux user: If installing manually, you can use a symlink.)"; - } - - private int pct = 0; - private bool exiting = false; - private bool succeeded = false; - private bool failed = false; - - private void ThreadProc() - { - Download(); - } - - private void Download() - { - //the temp file is owned by this thread - var fn = TempFileManager.GetTempFilename("ffmpeg_download", ".7z", false); - - try - { - DirectoryInfo parentDir = new(Path.GetDirectoryName(FFmpegService.FFmpegPath)!); - if (!parentDir.Exists) parentDir.Create(); - using var fs = File.Create(FFmpegService.FFmpegPath); // check writable before bothering with the download - using (var evt = new ManualResetEvent(false)) - { - using (var client = new System.Net.WebClient()) - { - System.Net.ServicePointManager.SecurityProtocol = System.Net.SecurityProtocolType.Tls12; - client.DownloadFileAsync(new Uri(FFmpegService.Url), fn); - client.DownloadProgressChanged += (object sender, System.Net.DownloadProgressChangedEventArgs e) => - { - pct = e.ProgressPercentage; - }; - client.DownloadFileCompleted += (object sender, System.ComponentModel.AsyncCompletedEventArgs e) => - { - //we don't really need a status. we'll just try to unzip it when it's done - evt.Set(); - }; - - for (; ; ) - { - if (evt.WaitOne(10)) - break; - - //if the gui thread ordered an exit, cancel the download and wait for it to acknowledge - if (exiting) - { - client.CancelAsync(); - evt.WaitOne(); - break; - } - } - } - } - - //throw new Exception("test of download failure"); + protected override string ComponentName + => "FFmpeg"; - //if we were ordered to exit, bail without wasting any more time - if (exiting) - return; + protected override string DownloadTemp { get; } + = TempFileManager.GetTempFilename("ffmpeg_download", ".7z", delete: false); - //try acquiring file - using (var hf = new HawkFile(fn)) - { - using (var exe = OSTailoredCode.IsUnixHost ? hf.BindArchiveMember("ffmpeg") : hf.BindFirstOf(".exe")) - { - //last chance. exiting, don't dump the new ffmpeg file - if (exiting) - return; - exe!.GetStream().CopyTo(fs); - fs.Dispose(); - if (OSTailoredCode.IsUnixHost) - { - OSTailoredCode.ConstructSubshell("chmod", $"+x {FFmpegService.FFmpegPath}", checkStdout: false).Start(); - Thread.Sleep(50); // Linux I/O flush idk - } - } - } - - //make sure it worked - if (!FFmpegService.QueryServiceAvailable()) throw new Exception("download failed"); - - succeeded = true; - } - catch (Exception e) - { - failed = true; - Util.DebugWriteLine($"FFmpeg download failed with:\n{e}"); - } - finally - { - try { File.Delete(fn); } - catch { } - } - } - - private void btnDownload_Click(object sender, EventArgs e) + public FFmpegDownloaderForm() { - btnDownload.Text = "Downloading..."; - btnDownload.Enabled = false; - failed = false; - succeeded = false; - pct = 0; - var t = new Thread(ThreadProc); - t.Start(); + Description = "BizHawk relies on a specific version of FFmpeg. No other version will do. The wrong version will be ignored. There is no way to override this behavior." + + "\n\nThe required version could not be found." + + (OSTailoredCode.IsUnixHost + ? "\n\n(Linux user: If installing manually, you can use a symlink.)" + : "\n\nUse this dialog to download it automatically, or download it yourself from the URL below and place it in the specified location."); + DownloadFrom = FFmpegService.Url; + DownloadTo = FFmpegService.FFmpegPath; } - private void btnCancel_Click(object sender, EventArgs e) - { - Close(); - } + protected override Stream GetExtractionStream(HawkFile downloaded) + => (OSTailoredCode.IsUnixHost + ? downloaded.BindArchiveMember("ffmpeg")! + : downloaded.BindFirstOf(".exe")).GetStream(); - protected override void OnClosed(EventArgs e) - { - //inform the worker thread that it needs to try terminating without doing anything else - //(it will linger on in background for a bit til it can service this) - exiting = true; - } - - private void timer1_Tick(object sender, EventArgs e) - { - //if it's done, close the window. the user will be smart enough to reopen it - if (succeeded) - Close(); - if (failed) - { - failed = false; - pct = 0; - btnDownload.Text = "FAILED - Download Again"; - btnDownload.Enabled = true; - } - progressBar1.Value = pct; - } + protected override bool PostChmodCheck() + => FFmpegService.QueryServiceAvailable(); - private void linkLabel1_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e) - { - Util.OpenUrlExternal(FFmpegService.Url); - } + protected override bool PreChmodCheck(FileStream extracted) + => SHA256Checksum.ComputeDigestHex(extracted.ReadAllBytes()) == FFmpegService.DownloadSHA256Checksum; } } - diff --git a/src/BizHawk.Client.EmuHawk/AVOut/FFmpegDownloaderForm.resx b/src/BizHawk.Client.EmuHawk/AVOut/FFmpegDownloaderForm.resx deleted file mode 100644 index a14f7748ebb..00000000000 --- a/src/BizHawk.Client.EmuHawk/AVOut/FFmpegDownloaderForm.resx +++ /dev/null @@ -1,132 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - BizHawk relies on a specific version of FFmpeg. No other version will do. The wrong version will be ignored. There is no way to override this behavior. - -The required version could not be found. - -Use this dialog to download it automatically, or download it yourself from the URL below and place it in the specified location - - - - - 17, 17 - - \ No newline at end of file diff --git a/src/BizHawk.Client.EmuHawk/AVOut/FFmpegDownloaderForm.Designer.cs b/src/BizHawk.Client.EmuHawk/DownloaderForm.Designer.cs similarity index 92% rename from src/BizHawk.Client.EmuHawk/AVOut/FFmpegDownloaderForm.Designer.cs rename to src/BizHawk.Client.EmuHawk/DownloaderForm.Designer.cs index 79f079f9efe..3ebda1cbecb 100644 --- a/src/BizHawk.Client.EmuHawk/AVOut/FFmpegDownloaderForm.Designer.cs +++ b/src/BizHawk.Client.EmuHawk/DownloaderForm.Designer.cs @@ -1,6 +1,6 @@ namespace BizHawk.Client.EmuHawk { - partial class FFmpegDownloaderForm + partial class DownloaderForm { /// /// Required designer variable. @@ -29,7 +29,6 @@ protected override void Dispose(bool disposing) private void InitializeComponent() { this.components = new System.ComponentModel.Container(); - System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(FFmpegDownloaderForm)); this.btnCancel = new System.Windows.Forms.Button(); this.btnDownload = new System.Windows.Forms.Button(); this.textBox1 = new System.Windows.Forms.TextBox(); @@ -73,7 +72,7 @@ private void InitializeComponent() this.textBox1.ReadOnly = true; this.textBox1.Size = new System.Drawing.Size(699, 95); this.textBox1.TabIndex = 10; - this.textBox1.Text = resources.GetString("textBox1.Text"); + this.textBox1.Text = "%description%"; // // label3 // @@ -112,6 +111,7 @@ private void InitializeComponent() this.txtLocation.ReadOnly = true; this.txtLocation.Size = new System.Drawing.Size(613, 20); this.txtLocation.TabIndex = 15; + this.txtLocation.Text = "%downloadTo%"; // // label1 // @@ -138,8 +138,9 @@ private void InitializeComponent() this.txtUrl.ReadOnly = true; this.txtUrl.Size = new System.Drawing.Size(613, 20); this.txtUrl.TabIndex = 18; + this.txtUrl.Text = "%downloadFrom%"; // - // FFmpegDownloaderForm + // DownloaderForm // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; @@ -159,10 +160,10 @@ private void InitializeComponent() this.MaximizeBox = false; this.MinimizeBox = false; this.MinimumSize = new System.Drawing.Size(300, 160); - this.Name = "FFmpegDownloaderForm"; + this.Name = "DownloaderForm"; this.ShowIcon = false; this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; - this.Text = "Download FFmpeg"; + this.Text = "%windowTitle%"; this.ResumeLayout(false); this.PerformLayout(); diff --git a/src/BizHawk.Client.EmuHawk/DownloaderForm.cs b/src/BizHawk.Client.EmuHawk/DownloaderForm.cs new file mode 100644 index 00000000000..d406fc13662 --- /dev/null +++ b/src/BizHawk.Client.EmuHawk/DownloaderForm.cs @@ -0,0 +1,191 @@ +using System.IO; +using System.Net; +using System.Threading; +using System.Windows.Forms; + +using BizHawk.Common; + +namespace BizHawk.Client.EmuHawk +{ + public partial class DownloaderForm : Form + { + protected virtual string ComponentName { get; } = null!; + + public string Description + { + get => textBox1.Text; + init => textBox1.Text = value; + } + + public string DownloadFrom + { + get => txtUrl.Text; + init => txtUrl.Text = value; + } + + protected virtual string DownloadTemp { get; } = null!; + + public string DownloadTo + { + get => txtLocation.Text; + init => txtLocation.Text = value; + } + + public DownloaderForm() + { + InitializeComponent(); + Load += (_, _) => Text = $"Download {ComponentName ?? "COMPONENT UNSET"}"; + } + + private int _pct = 0; + private bool _exiting = false; + private bool _succeeded = false; + private bool _failed = false; + + private Thread/*?*/ _thread = null; + + public bool DownloadSucceeded() + { + // block until the thread dies + while (_thread is { IsAlive: true }) + { + Thread.Sleep(1); + } + + return _succeeded; + } + + private void ThreadProc() + { + Download(); + } + + private void Download() + { + try + { + DirectoryInfo parentDir = new(Path.GetDirectoryName(DownloadTo)!); + if (!parentDir.Exists) parentDir.Create(); + // check writable before bothering with the download + if (File.Exists(DownloadTo)) File.Delete(DownloadTo); + using var fs = File.Create(DownloadTo); + using (var evt = new ManualResetEvent(false)) + { + using var client = new WebClient(); + ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12; + client.DownloadFileAsync(new Uri(DownloadFrom), DownloadTemp); + client.DownloadProgressChanged += (_, progressArgs) => _pct = progressArgs.ProgressPercentage; + client.DownloadFileCompleted += (_, _) => evt.Set(); // we don't really need a status, we'll just try to unzip it when it's done + + while (true) + { + if (evt.WaitOne(10)) break; + + //if the gui thread ordered an exit, cancel the download and wait for it to acknowledge + if (_exiting) + { + client.CancelAsync(); + evt.WaitOne(); + break; + } + } + } + +// throw new Exception("test of download failure"); + + //if we were ordered to exit, bail without wasting any more time + if (_exiting) return; + + //try acquiring file + using (HawkFile hf = new(DownloadTemp)) + { + using var exStream = GetExtractionStream(hf); + //last chance. exiting, don't dump the new file + if (_exiting) return; + exStream.CopyTo(fs); + fs.Position = 0L; + if (!PreChmodCheck(fs)) throw new Exception("download failed (pre-chmod validation)"); + fs.Dispose(); + if (OSTailoredCode.IsUnixHost) + { + var proc = OSTailoredCode.ConstructSubshell("chmod", $"+x {DownloadTo}", checkStdout: false); + proc.Start(); + proc.WaitForExit(); + } + } + + //make sure it worked + if (!PostChmodCheck()) throw new Exception("download failed (post-chmod validation)"); + + _succeeded = true; + } + catch (Exception e) + { + _failed = true; + Util.DebugWriteLine($"{ComponentName} download failed with:\n{e}"); + } + finally + { + try + { + File.Delete(DownloadTemp); + } + catch + { + // ignore + } + } + } + + protected virtual Stream GetExtractionStream(HawkFile downloaded) + => throw new NotImplementedException(); + + protected virtual bool PostChmodCheck() + => true; + + protected virtual bool PreChmodCheck(FileStream extracted) + => true; + + private void btnDownload_Click(object sender, EventArgs e) + { + btnDownload.Text = "Downloading..."; + btnDownload.Enabled = false; + _failed = false; + _succeeded = false; + _pct = 0; + _thread = new(ThreadProc); + _thread.Start(); + } + + private void btnCancel_Click(object sender, EventArgs e) + { + Close(); + } + + protected override void OnClosed(EventArgs e) + { + //inform the worker thread that it needs to try terminating without doing anything else + //(it will linger on in background for a bit til it can service this) + _exiting = true; + } + + private void timer1_Tick(object sender, EventArgs e) + { + //if it's done, close the window. the user will be smart enough to reopen it + if (_succeeded) Close(); + if (_failed) + { + _failed = false; + _pct = 0; + btnDownload.Text = "FAILED - Download Again"; + btnDownload.Enabled = true; + } + progressBar1.Value = _pct; + } + + private void linkLabel1_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e) + { + Util.OpenUrlExternal(DownloadFrom); + } + } +} diff --git a/src/BizHawk.Client.EmuHawk/RetroAchievements/RAIntegrationDownloaderForm.resx b/src/BizHawk.Client.EmuHawk/DownloaderForm.resx similarity index 94% rename from src/BizHawk.Client.EmuHawk/RetroAchievements/RAIntegrationDownloaderForm.resx rename to src/BizHawk.Client.EmuHawk/DownloaderForm.resx index aac33d5a29f..29dcb1b3a35 100644 --- a/src/BizHawk.Client.EmuHawk/RetroAchievements/RAIntegrationDownloaderForm.resx +++ b/src/BizHawk.Client.EmuHawk/DownloaderForm.resx @@ -117,7 +117,4 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - 17, 17 - \ No newline at end of file diff --git a/src/BizHawk.Client.EmuHawk/RetroAchievements/RAIntegrationDownloaderForm.Designer.cs b/src/BizHawk.Client.EmuHawk/RetroAchievements/RAIntegrationDownloaderForm.Designer.cs deleted file mode 100644 index ad2438afc4a..00000000000 --- a/src/BizHawk.Client.EmuHawk/RetroAchievements/RAIntegrationDownloaderForm.Designer.cs +++ /dev/null @@ -1,170 +0,0 @@ -namespace BizHawk.Client.EmuHawk -{ - partial class RAIntegrationDownloaderForm - { - /// - /// Required designer variable. - /// - private System.ComponentModel.IContainer components = null; - - /// - /// Clean up any resources being used. - /// - /// true if managed resources should be disposed; otherwise, false. - protected override void Dispose(bool disposing) - { - if (disposing && (components != null)) - { - components.Dispose(); - } - base.Dispose(disposing); - } - - #region Windows Form Designer generated code - - /// - /// Required method for Designer support - do not modify - /// the contents of this method with the code editor. - /// - private void InitializeComponent() - { - this.components = new System.ComponentModel.Container(); - this.btnCancel = new System.Windows.Forms.Button(); - this.btnDownload = new System.Windows.Forms.Button(); - this.label3 = new BizHawk.WinForms.Controls.LocLabelEx(); - this.linkLabel1 = new System.Windows.Forms.LinkLabel(); - this.progressBar1 = new System.Windows.Forms.ProgressBar(); - this.timer1 = new System.Windows.Forms.Timer(this.components); - this.txtLocation = new System.Windows.Forms.TextBox(); - this.label1 = new System.Windows.Forms.Label(); - this.label2 = new System.Windows.Forms.Label(); - this.txtUrl = new System.Windows.Forms.TextBox(); - this.SuspendLayout(); - // - // btnCancel - // - this.btnCancel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); - this.btnCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel; - this.btnCancel.Location = new System.Drawing.Point(667, 86); - this.btnCancel.Name = "btnCancel"; - this.btnCancel.Size = new System.Drawing.Size(75, 23); - this.btnCancel.TabIndex = 7; - this.btnCancel.Text = "Cancel"; - this.btnCancel.UseVisualStyleBackColor = true; - this.btnCancel.Click += new System.EventHandler(this.btnCancel_Click); - // - // btnDownload - // - this.btnDownload.Location = new System.Drawing.Point(9, 86); - this.btnDownload.Name = "btnDownload"; - this.btnDownload.Size = new System.Drawing.Size(186, 23); - this.btnDownload.TabIndex = 6; - this.btnDownload.Text = "Download"; - this.btnDownload.UseVisualStyleBackColor = true; - this.btnDownload.Click += new System.EventHandler(this.btnDownload_Click); - // - // label3 - // - this.label3.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); - this.label3.Location = new System.Drawing.Point(6, -35); - this.label3.MaximumSize = new System.Drawing.Size(260, 0); - this.label3.Name = "label3"; - // - // linkLabel1 - // - this.linkLabel1.AutoSize = true; - this.linkLabel1.Location = new System.Drawing.Point(715, 61); - this.linkLabel1.Name = "linkLabel1"; - this.linkLabel1.Size = new System.Drawing.Size(27, 13); - this.linkLabel1.TabIndex = 12; - this.linkLabel1.TabStop = true; - this.linkLabel1.Text = "Link"; - this.linkLabel1.LinkClicked += new System.Windows.Forms.LinkLabelLinkClickedEventHandler(this.linkLabel1_LinkClicked); - // - // progressBar1 - // - this.progressBar1.Location = new System.Drawing.Point(201, 86); - this.progressBar1.Name = "progressBar1"; - this.progressBar1.Size = new System.Drawing.Size(186, 23); - this.progressBar1.TabIndex = 13; - // - // timer1 - // - this.timer1.Enabled = true; - this.timer1.Tick += new System.EventHandler(this.timer1_Tick); - // - // txtLocation - // - this.txtLocation.Location = new System.Drawing.Point(95, 12); - this.txtLocation.Name = "txtLocation"; - this.txtLocation.ReadOnly = true; - this.txtLocation.Size = new System.Drawing.Size(613, 20); - this.txtLocation.TabIndex = 15; - // - // label1 - // - this.label1.AutoSize = true; - this.label1.Location = new System.Drawing.Point(9, 15); - this.label1.Name = "label1"; - this.label1.Size = new System.Drawing.Size(80, 13); - this.label1.TabIndex = 16; - this.label1.Text = "Local Location:"; - // - // label2 - // - this.label2.AutoSize = true; - this.label2.Location = new System.Drawing.Point(57, 41); - this.label2.Name = "label2"; - this.label2.Size = new System.Drawing.Size(32, 13); - this.label2.TabIndex = 17; - this.label2.Text = "URL:"; - // - // txtUrl - // - this.txtUrl.Location = new System.Drawing.Point(96, 38); - this.txtUrl.Name = "txtUrl"; - this.txtUrl.ReadOnly = true; - this.txtUrl.Size = new System.Drawing.Size(613, 20); - this.txtUrl.TabIndex = 18; - // - // RAIntegrationDownloaderForm - // - this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); - this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; - this.CancelButton = this.btnCancel; - this.ClientSize = new System.Drawing.Size(754, 121); - this.Controls.Add(this.progressBar1); - this.Controls.Add(this.txtUrl); - this.Controls.Add(this.btnDownload); - this.Controls.Add(this.label2); - this.Controls.Add(this.linkLabel1); - this.Controls.Add(this.label1); - this.Controls.Add(this.txtLocation); - this.Controls.Add(this.btnCancel); - this.Controls.Add(this.label3); - this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog; - this.MaximizeBox = false; - this.MinimizeBox = false; - this.MinimumSize = new System.Drawing.Size(300, 160); - this.Name = "RAIntegrationDownloaderForm"; - this.ShowIcon = false; - this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; - this.Text = "Download RAIntegration"; - this.ResumeLayout(false); - this.PerformLayout(); - - } - - #endregion - private BizHawk.WinForms.Controls.LocLabelEx label3; - private System.Windows.Forms.Button btnCancel; - private System.Windows.Forms.Button btnDownload; - private System.Windows.Forms.LinkLabel linkLabel1; - private System.Windows.Forms.ProgressBar progressBar1; - private System.Windows.Forms.Timer timer1; - private System.Windows.Forms.TextBox txtLocation; - private System.Windows.Forms.Label label1; - private System.Windows.Forms.Label label2; - private System.Windows.Forms.TextBox txtUrl; - } -} \ No newline at end of file diff --git a/src/BizHawk.Client.EmuHawk/RetroAchievements/RAIntegrationDownloaderForm.cs b/src/BizHawk.Client.EmuHawk/RetroAchievements/RAIntegrationDownloaderForm.cs index cea938757ed..44a1a4f9a63 100644 --- a/src/BizHawk.Client.EmuHawk/RetroAchievements/RAIntegrationDownloaderForm.cs +++ b/src/BizHawk.Client.EmuHawk/RetroAchievements/RAIntegrationDownloaderForm.cs @@ -1,166 +1,32 @@ using System.IO; -using System.Threading; -using System.Windows.Forms; using BizHawk.Common; using BizHawk.Common.PathExtensions; +using BizHawk.Common.StringExtensions; namespace BizHawk.Client.EmuHawk { - /// - /// Downloads RAIntegration (largely a copy paste of ffmpeg's downloader) - /// - public partial class RAIntegrationDownloaderForm : Form + public sealed class RAIntegrationDownloaderForm : DownloaderForm { - public RAIntegrationDownloaderForm(string url) - { - _path = Path.Combine(PathUtils.DataDirectoryPath, "dll", "RA_Integration-x64.dll"); - _url = url; - - InitializeComponent(); - - txtLocation.Text = _path; - txtUrl.Text = _url; - } - - private readonly string _path; - private readonly string _url; - - private int _pct = 0; - private bool _exiting = false; - private bool _succeeded = false; - private bool _failed = false; - private Thread _thread; - - public bool DownloadSucceeded() - { - // block until the thread dies - while (_thread?.IsAlive ?? false) - { - Thread.Sleep(1); - } - - return _succeeded; - } - - private void ThreadProc() - { - Download(); - } - - private void Download() - { - //the temp file is owned by this thread - var fn = TempFileManager.GetTempFilename("RAIntegration_download", ".dll", false); - - try - { - using (var evt = new ManualResetEvent(false)) - { - using var client = new System.Net.WebClient(); - System.Net.ServicePointManager.SecurityProtocol = System.Net.SecurityProtocolType.Tls12; - client.DownloadFileAsync(new Uri(_url), fn); - client.DownloadProgressChanged += (object sender, System.Net.DownloadProgressChangedEventArgs e) => - { - _pct = e.ProgressPercentage; - }; - client.DownloadFileCompleted += (object sender, System.ComponentModel.AsyncCompletedEventArgs e) => - { - //we don't really need a status. we'll just try to unzip it when it's done - evt.Set(); - }; - - for (; ; ) - { - if (evt.WaitOne(10)) - break; - - //if the gui thread ordered an exit, cancel the download and wait for it to acknowledge - if (_exiting) - { - client.CancelAsync(); - evt.WaitOne(); - break; - } - } - } - - //throw new Exception("test of download failure"); + protected override string ComponentName + => "RAIntegration"; - //if we were ordered to exit, bail without wasting any more time - if (_exiting) - return; + protected override string DownloadTemp { get; } + = TempFileManager.GetTempFilename("RAIntegration_download", ".dll", delete: false); - //try acquiring file - using (var dll = new HawkFile(fn)) - { - var data = dll!.ReadAllBytes(); - - //last chance. exiting, don't dump the new RAIntegration file - if (_exiting) - return; - - DirectoryInfo parentDir = new(Path.GetDirectoryName(_path)!); - if (!parentDir.Exists) parentDir.Create(); - if (File.Exists(_path)) File.Delete(_path); - File.WriteAllBytes(_path, data); - } - - _succeeded = true; - } - catch - { - _failed = true; - } - finally - { - try { File.Delete(fn); } - catch { } - } - } - - private void btnDownload_Click(object sender, EventArgs e) - { - btnDownload.Text = "Downloading..."; - btnDownload.Enabled = false; - _failed = false; - _succeeded = false; - _pct = 0; - _thread = new Thread(ThreadProc); - _thread.Start(); - } - - private void btnCancel_Click(object sender, EventArgs e) - { - Close(); - } - - protected override void OnClosed(EventArgs e) + public RAIntegrationDownloaderForm(string downloadFrom) { - //inform the worker thread that it needs to try terminating without doing anything else - //(it will linger on in background for a bit til it can service this) - _exiting = true; - } - - private void timer1_Tick(object sender, EventArgs e) - { - //if it's done, close the window. the user will be smart enough to reopen it - if (_succeeded) - Close(); - if (_failed) + var downloadDomainName = downloadFrom.RemovePrefix("https://").SubstringBefore('/'); + if (!(downloadDomainName is "retroachievements.org" || downloadDomainName.EndsWith(".retroachievements.org"))) { - _failed = false; - _pct = 0; - btnDownload.Text = "FAILED - Download Again"; - btnDownload.Enabled = true; + throw new ArgumentException(paramName: nameof(downloadFrom), message: "untrusted hostname"); } - progressBar1.Value = _pct; + Description = string.Empty; + DownloadFrom = downloadFrom; + DownloadTo = Path.Combine(PathUtils.DataDirectoryPath, "dll", "RA_Integration-x64.dll"); } - private void linkLabel1_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e) - { - Util.OpenUrlExternal(_url); - } + protected override Stream GetExtractionStream(HawkFile downloaded) + => downloaded.GetStream(); } } - diff --git a/src/BizHawk.Common/FFmpegService.cs b/src/BizHawk.Common/FFmpegService.cs index 8557cc150be..f6e71e7179b 100644 --- a/src/BizHawk.Common/FFmpegService.cs +++ b/src/BizHawk.Common/FFmpegService.cs @@ -17,8 +17,15 @@ public static class FFmpegService private const string BIN_HOST_URI_WIN_X64 = "https://github.com/TASEmulators/ffmpeg-binaries/raw/master/ffmpeg-4.4.1-static-windows-x64.7z"; + private const string BIN_SHA256_LINUX_X64 = "3EA58083710F63BF920B16C7D5D24AE081E7D731F57A656FED11AF0410D4EB48"; + + private const string BIN_SHA256_WIN_X64 = "8436760AF8F81C95EFF92D854A7684E6D3CEDB872888420359FC45C8EB2664AC"; + private const string VERSION = "ffmpeg version 4.4.1"; + public static string DownloadSHA256Checksum + => OSTailoredCode.IsUnixHost ? BIN_SHA256_LINUX_X64 : BIN_SHA256_WIN_X64; + public static string FFmpegPath => Path.Combine(PathUtils.DataDirectoryPath, "dll", OSTailoredCode.IsUnixHost ? "ffmpeg" : "ffmpeg.exe"); public static readonly string Url = OSTailoredCode.IsUnixHost ? BIN_HOST_URI_LINUX_X64 : BIN_HOST_URI_WIN_X64;