using System.IO.Pipes;
using System.Text;
using Sunfish.Config;
using Sunfish.Host;
namespace Sunfish.WinForms;
internal static class Program
{
private const string MutexName = "Local\\Sunfish3-Gui";
private const string PipeName = "Sunfish3-Gui";
/// <summary>
/// Sunfish.exe [CARPETA...] [-c FICHERO] [--lang es|en]
/// Una carpeta como argumento (tambien arrastrandola sobre el .exe) se comparte al momento.
/// Si ya hay una ventana abierta, se le pasan las carpetas y esta instancia termina.
/// </summary>
[STAThread]
private static int Main(string[] args)
{
string? configPath = null;
var folders = new List<string>();
for (int i = 0; i < args.Length; i++)
{
if (args[i] is "-c" or "--config" && i + 1 < args.Length)
configPath = args[++i];
else if (args[i] == "--lang" && i + 1 < args.Length)
Strings.Force(args[++i]);
else
folders.Add(Path.GetFullPath(args[i]));
}
using var mutex = new Mutex(true, MutexName, out bool first);
if (!first)
{
SendToRunningInstance(folders);
return 0;
}
ApplicationConfiguration.Initialize();
SunfishConfig config;
string? found = ConfigLocator.Find(configPath);
if (folders.Count > 0 && (found is null || !File.Exists(found)))
{
// Modo rapido: las carpetas sin fichero de configuracion; no se guarda nada.
config = new SunfishConfig();
foreach (var folder in folders.Where(Directory.Exists))
{
string name = ShareSettings.SuggestName(config, Path.GetFileName(Path.TrimEndingDirectorySeparator(folder)));
config.Shares.Add(new ShareConfig
{
Name = name,
Location = config.Shares.Count == 0 ? "/" : ShareSettings.SuggestLocation(config, name),
Path = folder,
});
}
folders.Clear();
}
else if (found is not null && File.Exists(found))
{
config = SunfishConfig.Load(found);
}
else
{
var answer = MessageBox.Show(Texts.CreateConfigQuestion(ConfigLocator.PortablePath, ConfigLocator.UserPath),
"Sunfish", MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question);
if (answer == DialogResult.Cancel)
return 1;
string created = answer == DialogResult.Yes ? ConfigLocator.PortablePath : ConfigLocator.UserPath;
config = new SunfishConfig();
// Si hay una configuracion de la 2.0 a mano, se ofrece traer sus shares.
if (LegacyImport.Find() is { } legacy &&
MessageBox.Show(Strings.ImportQuestion(legacy), "Sunfish", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes)
{
var notes = new List<string>();
if (LegacyImport.FromV2(File.ReadAllText(legacy), notes) is { } imported)
{
int count = LegacyImport.Merge(config, imported, isNew: true);
MessageBox.Show(string.Join("\n", notes.Prepend(Strings.ImportDone(count, created)).Select((n, i) => i == 0 ? n : "• " + n)),
"Sunfish", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
else
{
MessageBox.Show(Strings.ImportInvalid(legacy), "Sunfish", MessageBoxButtons.OK, MessageBoxIcon.Warning);
}
}
config.Save(created);
}
var host = new SunfishHost(config);
foreach (var error in config.Errors)
host.Log.Warning(Strings.ConfigReloadError(error));
host.WatchConfigFile();
using var form = new MainForm(host, folders);
_ = ListenForOtherInstancesAsync(form);
Application.Run(form);
host.DisposeAsync().AsTask().GetAwaiter().GetResult();
return 0;
}
private static void SendToRunningInstance(List<string> folders)
{
try
{
using var pipe = new NamedPipeClientStream(".", PipeName, PipeDirection.Out);
pipe.Connect(2000);
var data = Encoding.UTF8.GetBytes(string.Join('\n', folders) + "\n");
pipe.Write(data, 0, data.Length);
}
catch (Exception e) when (e is IOException or TimeoutException) { }
}
/// <summary>Cada conexion trae carpetas (una por linea); sin carpetas solo se trae la ventana al frente.</summary>
private static async Task ListenForOtherInstancesAsync(MainForm form)
{
while (!form.IsDisposed)
{
try
{
await using var pipe = new NamedPipeServerStream(PipeName, PipeDirection.In, 1, PipeTransmissionMode.Byte, PipeOptions.Asynchronous);
await pipe.WaitForConnectionAsync();
using var reader = new StreamReader(pipe, Encoding.UTF8);
string text = await reader.ReadToEndAsync();
var folders = text.Split('\n', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries).ToList();
if (!form.IsDisposed)
form.BeginInvoke(() => form.ReceiveFromOtherInstance(folders));
}
catch (IOException)
{
await Task.Delay(500);
}
catch (ObjectDisposedException)
{
return;
}
}
}
}