mirror of
https://github.com/chylex/TweetDuck.git
synced 2025-05-28 08:34:06 +02:00
Move debug resource hot swap into a separate class
This commit is contained in:
parent
92716ea3e0
commit
a6963a18d4
@ -14,7 +14,6 @@
|
|||||||
using TweetDuck.Core.Other.Analytics;
|
using TweetDuck.Core.Other.Analytics;
|
||||||
using TweetDuck.Core.Other.Settings.Dialogs;
|
using TweetDuck.Core.Other.Settings.Dialogs;
|
||||||
using TweetDuck.Core.Utils;
|
using TweetDuck.Core.Utils;
|
||||||
using TweetDuck.Resources;
|
|
||||||
using TweetDuck.Updates;
|
using TweetDuck.Updates;
|
||||||
using TweetLib.Core.Features.Plugins;
|
using TweetLib.Core.Features.Plugins;
|
||||||
using TweetLib.Core.Features.Plugins.Events;
|
using TweetLib.Core.Features.Plugins.Events;
|
||||||
@ -371,14 +370,7 @@ public void ReinjectCustomCSS(string css){
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void ReloadToTweetDeck(){
|
public void ReloadToTweetDeck(){
|
||||||
#if DEBUG
|
Program.Resources.OnReloadTriggered();
|
||||||
ScriptLoader.HotSwap();
|
|
||||||
#else
|
|
||||||
if (ModifierKeys.HasFlag(Keys.Shift)){
|
|
||||||
ScriptLoader.ClearCache();
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
ignoreUpdateCheckError = false;
|
ignoreUpdateCheckError = false;
|
||||||
browser.ReloadToTweetDeck();
|
browser.ReloadToTweetDeck();
|
||||||
AnalyticsFile.BrowserReloads.Trigger();
|
AnalyticsFile.BrowserReloads.Trigger();
|
||||||
|
@ -59,7 +59,12 @@ static Program(){
|
|||||||
Reporter.SetupUnhandledExceptionHandler("TweetDuck Has Failed :(");
|
Reporter.SetupUnhandledExceptionHandler("TweetDuck Has Failed :(");
|
||||||
|
|
||||||
Config = new ConfigManager();
|
Config = new ConfigManager();
|
||||||
|
|
||||||
|
#if DEBUG
|
||||||
|
Resources = new ScriptLoaderDebug();
|
||||||
|
#else
|
||||||
Resources = new ScriptLoader();
|
Resources = new ScriptLoader();
|
||||||
|
#endif
|
||||||
|
|
||||||
Lib.Initialize(new App.Builder{
|
Lib.Initialize(new App.Builder{
|
||||||
ErrorHandler = Reporter,
|
ErrorHandler = Reporter,
|
||||||
|
@ -7,36 +7,33 @@
|
|||||||
using TweetDuck.Core.Other;
|
using TweetDuck.Core.Other;
|
||||||
using TweetLib.Core.Application;
|
using TweetLib.Core.Application;
|
||||||
|
|
||||||
#if DEBUG
|
|
||||||
using System.Diagnostics;
|
|
||||||
using System.Reflection;
|
|
||||||
using TweetDuck.Core;
|
|
||||||
using TweetLib.Core.Features.Plugins;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace TweetDuck.Resources{
|
namespace TweetDuck.Resources{
|
||||||
sealed class ScriptLoader : IAppResourceHandler{
|
class ScriptLoader : IAppResourceHandler{
|
||||||
private static readonly Dictionary<string, string> CachedData = new Dictionary<string, string>(16);
|
private readonly Dictionary<string, string> cache = new Dictionary<string, string>(16);
|
||||||
|
|
||||||
public static void ClearCache(){
|
|
||||||
CachedData.Clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
private Control sync;
|
private Control sync;
|
||||||
|
|
||||||
public void Initialize(Control sync){
|
public void Initialize(Control sync){
|
||||||
this.sync = sync;
|
this.sync = sync;
|
||||||
}
|
}
|
||||||
|
|
||||||
public string Load(string path){
|
protected void ClearCache(){
|
||||||
return LoadInternal(path, silent: false);
|
cache.Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
public string LoadSilent(string path){
|
public virtual void OnReloadTriggered(){
|
||||||
return LoadInternal(path, silent: true);
|
if (Control.ModifierKeys.HasFlag(Keys.Shift)){
|
||||||
|
ClearCache();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private string LoadInternal(string name, bool silent){
|
public string Load(string path) => LoadInternal(path, silent: false);
|
||||||
|
public string LoadSilent(string path) => LoadInternal(path, silent: true);
|
||||||
|
|
||||||
|
protected virtual string LocateFile(string path){
|
||||||
|
return Path.Combine(Program.ScriptPath, path);
|
||||||
|
}
|
||||||
|
|
||||||
|
private string LoadInternal(string path, bool silent){
|
||||||
if (sync == null){
|
if (sync == null){
|
||||||
throw new InvalidOperationException("Cannot use ScriptLoader before initialization.");
|
throw new InvalidOperationException("Cannot use ScriptLoader before initialization.");
|
||||||
}
|
}
|
||||||
@ -44,23 +41,15 @@ private string LoadInternal(string name, bool silent){
|
|||||||
return null; // better than crashing I guess...?
|
return null; // better than crashing I guess...?
|
||||||
}
|
}
|
||||||
|
|
||||||
if (CachedData.TryGetValue(name, out string resourceData)){
|
if (cache.TryGetValue(path, out string resourceData)){
|
||||||
return resourceData;
|
return resourceData;
|
||||||
}
|
}
|
||||||
|
|
||||||
string path = Program.ScriptPath;
|
string location = LocateFile(path);
|
||||||
|
|
||||||
#if DEBUG
|
|
||||||
if (Directory.Exists(HotSwapTargetDir)){
|
|
||||||
path = Path.Combine(HotSwapTargetDir, "scripts");
|
|
||||||
Debug.WriteLine($"Hot swap active, redirecting {name}");
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
string resource;
|
string resource;
|
||||||
|
|
||||||
try{
|
try{
|
||||||
string contents = File.ReadAllText(Path.Combine(path, name), Encoding.UTF8);
|
string contents = File.ReadAllText(location, Encoding.UTF8);
|
||||||
int separator;
|
int separator;
|
||||||
|
|
||||||
// first line can be either:
|
// first line can be either:
|
||||||
@ -68,7 +57,7 @@ private string LoadInternal(string name, bool silent){
|
|||||||
// #<version>\n
|
// #<version>\n
|
||||||
|
|
||||||
if (contents[0] != '#'){
|
if (contents[0] != '#'){
|
||||||
ShowLoadError(silent ? null : sync, $"File {name} appears to be corrupted, please try reinstalling the app.");
|
ShowLoadError(silent ? null : sync, $"File {path} appears to be corrupted, please try reinstalling the app.");
|
||||||
separator = 0;
|
separator = 0;
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
@ -76,98 +65,21 @@ private string LoadInternal(string name, bool silent){
|
|||||||
string fileVersion = contents.Substring(1, separator-1).TrimEnd();
|
string fileVersion = contents.Substring(1, separator-1).TrimEnd();
|
||||||
|
|
||||||
if (fileVersion != Program.VersionTag){
|
if (fileVersion != Program.VersionTag){
|
||||||
ShowLoadError(silent ? null : sync, $"File {name} is made for a different version of TweetDuck ({fileVersion}) and may not function correctly in this version, please try reinstalling the app.");
|
ShowLoadError(silent ? null : sync, $"File {path} is made for a different version of TweetDuck ({fileVersion}) and may not function correctly in this version, please try reinstalling the app.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
resource = contents.Substring(separator).TrimStart();
|
resource = contents.Substring(separator).TrimStart();
|
||||||
}catch(Exception ex){
|
}catch(Exception ex){
|
||||||
ShowLoadError(silent ? null : sync, $"Could not load {name}. The program will continue running with limited functionality.\n\n{ex.Message}");
|
ShowLoadError(silent ? null : sync, $"Could not load {path}. The program will continue running with limited functionality.\n\n{ex.Message}");
|
||||||
resource = null;
|
resource = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return CachedData[name] = resource;
|
return cache[path] = resource;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void ShowLoadError(Control sync, string message){
|
private static void ShowLoadError(Control sync, string message){
|
||||||
sync?.InvokeSafe(() => FormMessage.Error("Resource Error", message, FormMessage.OK));
|
sync?.InvokeSafe(() => FormMessage.Error("Resource Error", message, FormMessage.OK));
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO move hot swap to another implementation
|
|
||||||
|
|
||||||
#if DEBUG
|
|
||||||
private static readonly string HotSwapProjectRoot = FixPathSlash(Path.GetFullPath(Path.Combine(Program.ProgramPath, "../../../")));
|
|
||||||
private static readonly string HotSwapTargetDir = FixPathSlash(Path.Combine(HotSwapProjectRoot, "bin", "tmp"));
|
|
||||||
private static readonly string HotSwapRebuildScript = Path.Combine(HotSwapProjectRoot, "bld", "post_build.exe");
|
|
||||||
|
|
||||||
static ScriptLoader(){
|
|
||||||
if (File.Exists(HotSwapRebuildScript)){
|
|
||||||
Debug.WriteLine("Activating resource hot swap...");
|
|
||||||
|
|
||||||
ResetHotSwap();
|
|
||||||
Application.ApplicationExit += (sender, args) => ResetHotSwap();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void HotSwap(){
|
|
||||||
if (!File.Exists(HotSwapRebuildScript)){
|
|
||||||
Debug.WriteLine($"Failed resource hot swap, missing rebuild script: {HotSwapRebuildScript}");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
ResetHotSwap();
|
|
||||||
Directory.CreateDirectory(HotSwapTargetDir);
|
|
||||||
|
|
||||||
Stopwatch sw = Stopwatch.StartNew();
|
|
||||||
|
|
||||||
using(Process process = Process.Start(new ProcessStartInfo{
|
|
||||||
FileName = HotSwapRebuildScript,
|
|
||||||
Arguments = $"\"{HotSwapTargetDir}\\\" \"{HotSwapProjectRoot}\\\" \"Debug\" \"{Program.VersionTag}\"",
|
|
||||||
WindowStyle = ProcessWindowStyle.Hidden
|
|
||||||
})){
|
|
||||||
// ReSharper disable once PossibleNullReferenceException
|
|
||||||
if (!process.WaitForExit(8000)){
|
|
||||||
Debug.WriteLine("Failed resource hot swap, script did not finish in time");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
else if (process.ExitCode != 0){
|
|
||||||
Debug.WriteLine($"Failed resource hot swap, script exited with code {process.ExitCode}");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
sw.Stop();
|
|
||||||
Debug.WriteLine($"Finished rebuild script in {sw.ElapsedMilliseconds} ms");
|
|
||||||
|
|
||||||
ClearCache();
|
|
||||||
|
|
||||||
// Force update plugin manager setup scripts
|
|
||||||
|
|
||||||
string newPluginRoot = Path.Combine(HotSwapTargetDir, "plugins");
|
|
||||||
|
|
||||||
const BindingFlags flagsInstance = BindingFlags.Instance | BindingFlags.NonPublic;
|
|
||||||
|
|
||||||
Type typePluginManager = typeof(PluginManager);
|
|
||||||
Type typeFormBrowser = typeof(FormBrowser);
|
|
||||||
|
|
||||||
// ReSharper disable PossibleNullReferenceException
|
|
||||||
object instPluginManager = typeFormBrowser.GetField("plugins", flagsInstance).GetValue(FormManager.TryFind<FormBrowser>());
|
|
||||||
typePluginManager.GetField("pluginFolder", flagsInstance).SetValue(instPluginManager, newPluginRoot);
|
|
||||||
|
|
||||||
Debug.WriteLine("Reloading hot swapped plugins...");
|
|
||||||
((PluginManager)instPluginManager).Reload();
|
|
||||||
// ReSharper restore PossibleNullReferenceException
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void ResetHotSwap(){
|
|
||||||
try{
|
|
||||||
Directory.Delete(HotSwapTargetDir, true);
|
|
||||||
}catch(DirectoryNotFoundException){}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static string FixPathSlash(string path){
|
|
||||||
return path.TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar) + '\\';
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
100
Resources/ScriptLoaderDebug.cs
Normal file
100
Resources/ScriptLoaderDebug.cs
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
#if DEBUG
|
||||||
|
using System;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.IO;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Windows.Forms;
|
||||||
|
using TweetDuck.Core;
|
||||||
|
using TweetLib.Core.Features.Plugins;
|
||||||
|
|
||||||
|
namespace TweetDuck.Resources{
|
||||||
|
sealed class ScriptLoaderDebug : ScriptLoader{
|
||||||
|
private static readonly string HotSwapProjectRoot = FixPathSlash(Path.GetFullPath(Path.Combine(Program.ProgramPath, "../../../")));
|
||||||
|
private static readonly string HotSwapTargetDir = FixPathSlash(Path.Combine(HotSwapProjectRoot, "bin", "tmp"));
|
||||||
|
private static readonly string HotSwapRebuildScript = Path.Combine(HotSwapProjectRoot, "bld", "post_build.exe");
|
||||||
|
|
||||||
|
private static string FixPathSlash(string path){
|
||||||
|
return path.TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar) + '\\';
|
||||||
|
}
|
||||||
|
|
||||||
|
public ScriptLoaderDebug(){
|
||||||
|
if (File.Exists(HotSwapRebuildScript)){
|
||||||
|
Debug.WriteLine("Activating resource hot swap...");
|
||||||
|
|
||||||
|
ResetHotSwap();
|
||||||
|
Application.ApplicationExit += (sender, args) => ResetHotSwap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void OnReloadTriggered(){
|
||||||
|
HotSwap();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override string LocateFile(string path){
|
||||||
|
if (Directory.Exists(HotSwapTargetDir)){
|
||||||
|
Debug.WriteLine($"Hot swap active, redirecting {path}");
|
||||||
|
return Path.Combine(HotSwapTargetDir, "scripts", path);
|
||||||
|
}
|
||||||
|
|
||||||
|
return base.LocateFile(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void HotSwap(){
|
||||||
|
if (!File.Exists(HotSwapRebuildScript)){
|
||||||
|
Debug.WriteLine($"Failed resource hot swap, missing rebuild script: {HotSwapRebuildScript}");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ResetHotSwap();
|
||||||
|
Directory.CreateDirectory(HotSwapTargetDir);
|
||||||
|
|
||||||
|
Stopwatch sw = Stopwatch.StartNew();
|
||||||
|
|
||||||
|
using(Process process = Process.Start(new ProcessStartInfo{
|
||||||
|
FileName = HotSwapRebuildScript,
|
||||||
|
Arguments = $"\"{HotSwapTargetDir}\\\" \"{HotSwapProjectRoot}\\\" \"Debug\" \"{Program.VersionTag}\"",
|
||||||
|
WindowStyle = ProcessWindowStyle.Hidden
|
||||||
|
})){
|
||||||
|
// ReSharper disable once PossibleNullReferenceException
|
||||||
|
if (!process.WaitForExit(8000)){
|
||||||
|
Debug.WriteLine("Failed resource hot swap, script did not finish in time");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else if (process.ExitCode != 0){
|
||||||
|
Debug.WriteLine($"Failed resource hot swap, script exited with code {process.ExitCode}");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sw.Stop();
|
||||||
|
Debug.WriteLine($"Finished rebuild script in {sw.ElapsedMilliseconds} ms");
|
||||||
|
|
||||||
|
ClearCache();
|
||||||
|
|
||||||
|
// Force update plugin manager setup scripts
|
||||||
|
|
||||||
|
string newPluginRoot = Path.Combine(HotSwapTargetDir, "plugins");
|
||||||
|
|
||||||
|
const BindingFlags flagsInstance = BindingFlags.Instance | BindingFlags.NonPublic;
|
||||||
|
|
||||||
|
Type typePluginManager = typeof(PluginManager);
|
||||||
|
Type typeFormBrowser = typeof(FormBrowser);
|
||||||
|
|
||||||
|
// ReSharper disable PossibleNullReferenceException
|
||||||
|
object instPluginManager = typeFormBrowser.GetField("plugins", flagsInstance).GetValue(FormManager.TryFind<FormBrowser>());
|
||||||
|
typePluginManager.GetField("pluginFolder", flagsInstance).SetValue(instPluginManager, newPluginRoot);
|
||||||
|
|
||||||
|
Debug.WriteLine("Reloading hot swapped plugins...");
|
||||||
|
((PluginManager)instPluginManager).Reload();
|
||||||
|
// ReSharper restore PossibleNullReferenceException
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ResetHotSwap(){
|
||||||
|
try{
|
||||||
|
Directory.Delete(HotSwapTargetDir, true);
|
||||||
|
}catch(DirectoryNotFoundException){}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
@ -256,6 +256,7 @@
|
|||||||
<DependentUpon>Resources.resx</DependentUpon>
|
<DependentUpon>Resources.resx</DependentUpon>
|
||||||
</Compile>
|
</Compile>
|
||||||
<Compile Include="Reporter.cs" />
|
<Compile Include="Reporter.cs" />
|
||||||
|
<Compile Include="Resources\ScriptLoaderDebug.cs" />
|
||||||
<Compile Include="Updates\FormUpdateDownload.cs">
|
<Compile Include="Updates\FormUpdateDownload.cs">
|
||||||
<SubType>Form</SubType>
|
<SubType>Form</SubType>
|
||||||
</Compile>
|
</Compile>
|
||||||
|
Loading…
Reference in New Issue
Block a user