Initial commit: Predictalytics solution
Clean Architecture .NET 8 solution (Domain/Application/Infrastructure/Api/Worker/WinFormsHost) for analyzing Polymarket traders for copytrading/strategy-replication candidates. Includes EF Core InitialBaseline migration and DB secrets removed from source/config in preparation for version control.
This commit is contained in:
@@ -0,0 +1,203 @@
|
||||
using System.Reflection;
|
||||
using Predictalytics.WinFormsHost.Services;
|
||||
using Serilog;
|
||||
|
||||
namespace Predictalytics.WinFormsHost;
|
||||
|
||||
public partial class MainForm : Form
|
||||
{
|
||||
private EmbeddedWebServer? _webServer;
|
||||
private CancellationTokenSource? _workerCts;
|
||||
private bool _workerRunning;
|
||||
private bool _webServerRunning;
|
||||
private AppSettings _settings = null!;
|
||||
|
||||
/// <summary>Exposes the terminal RichTextBox for the Serilog sink.</summary>
|
||||
public RichTextBox Terminal => rtb_terminal;
|
||||
|
||||
public MainForm()
|
||||
{
|
||||
InitializeComponent();
|
||||
this.Text = "Predictalytics Analytics — Backend Server";
|
||||
rtb_terminal.BackColor = System.Drawing.Color.FromArgb(15, 15, 20);
|
||||
rtb_terminal.ForeColor = System.Drawing.Color.FromArgb(180, 180, 180);
|
||||
rtb_terminal.Font = new Font("Cascadia Code", 9.5f, FontStyle.Regular);
|
||||
rtb_terminal.ReadOnly = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called after Serilog is configured. Initializes the embedded web server.
|
||||
/// </summary>
|
||||
public void Initialize()
|
||||
{
|
||||
_settings = AppSettings.Load();
|
||||
pg_settings.SelectedObject = _settings;
|
||||
pg_settings.PropertyValueChanged += (s, e) => {
|
||||
_settings.Save();
|
||||
if (_webServer != null)
|
||||
{
|
||||
_webServer.ConnectionString = _settings.ConnectionString;
|
||||
_webServer.DbConnectionDebug = _settings.DbConnectionDebug;
|
||||
}
|
||||
};
|
||||
|
||||
_webServer = new EmbeddedWebServer();
|
||||
_webServer.ConnectionString = _settings.ConnectionString;
|
||||
_webServer.DbConnectionDebug = _settings.DbConnectionDebug;
|
||||
|
||||
// Build Version (Date of compilation/file creation)
|
||||
try {
|
||||
var buildDate = new FileInfo(this.GetType().Assembly.Location).LastWriteTime;
|
||||
label_buildVersion.Text = $"Build: {buildDate:yyyy-MM-dd HH:mm:ss}";
|
||||
} catch {
|
||||
label_buildVersion.Text = "Build: Unknown";
|
||||
}
|
||||
|
||||
UpdateStatusBar();
|
||||
|
||||
// Wire up button events
|
||||
btn_serverstart.Click += Btn_serverstart_Click;
|
||||
btn_localWebserver.Click += Btn_localWebserver_Click;
|
||||
btn_syncmarkets.Click += syncMarketsaToolStripMenuItem_Click;
|
||||
|
||||
Log.Information("MainForm initialized. Ready.");
|
||||
Log.Information("Press 'Start Server' to begin polling & discovery.");
|
||||
Log.Information("Press 'Start Local Webserver' to launch the WebUI on http://localhost:{Port}", _settings.WebserverPort);
|
||||
}
|
||||
|
||||
private async void Btn_serverstart_Click(object? sender, EventArgs e)
|
||||
{
|
||||
if (!_workerRunning)
|
||||
{
|
||||
// Start workers
|
||||
_workerCts = new CancellationTokenSource();
|
||||
_workerRunning = true;
|
||||
btn_serverstart.Text = "⏹ Stop Server";
|
||||
Log.Information("🚀 Starting background workers...");
|
||||
|
||||
try
|
||||
{
|
||||
_webServer!.ConnectionString = _settings.ConnectionString;
|
||||
_webServer!.DbConnectionDebug = _settings.DbConnectionDebug;
|
||||
await _webServer!.StartWorkersAsync(_workerCts.Token);
|
||||
}
|
||||
catch (OperationCanceledException) { }
|
||||
catch (Exception ex) { Log.Error(ex, "Worker error"); }
|
||||
}
|
||||
else
|
||||
{
|
||||
// Stop workers
|
||||
Log.Information("⏹ Stopping background workers...");
|
||||
_workerCts?.Cancel();
|
||||
_workerRunning = false;
|
||||
btn_serverstart.Text = "▶ Start Server";
|
||||
Log.Information("Workers stopped.");
|
||||
}
|
||||
UpdateStatusBar();
|
||||
}
|
||||
|
||||
private async void Btn_localWebserver_Click(object? sender, EventArgs e)
|
||||
{
|
||||
if (!_webServerRunning)
|
||||
{
|
||||
try
|
||||
{
|
||||
Log.Information("🌐 Starting embedded Kestrel webserver on http://localhost:{Port}...", _settings.WebserverPort);
|
||||
await _webServer!.StartWebServerAsync(_settings.WebserverPort);
|
||||
_webServerRunning = true;
|
||||
btn_localWebserver.Text = "⏹ Stop Webserver";
|
||||
Log.Information("✅ WebUI available at http://localhost:{Port}", _settings.WebserverPort);
|
||||
Log.Information("📄 Swagger API docs at http://localhost:{Port}/swagger", _settings.WebserverPort);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Error(ex, "Failed to start webserver");
|
||||
_webServerRunning = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.Information("⏹ Stopping webserver...");
|
||||
await _webServer!.StopWebServerAsync();
|
||||
_webServerRunning = false;
|
||||
btn_localWebserver.Text = "▶ Start Webserver";
|
||||
Log.Information("Webserver stopped.");
|
||||
}
|
||||
UpdateStatusBar();
|
||||
}
|
||||
|
||||
private void UpdateStatusBar()
|
||||
{
|
||||
var workerStatus = _workerRunning ? "[RUNNING] Workers" : "[STOPPED] Workers";
|
||||
var serverStatus = _webServerRunning ? $"[RUNNING] Webserver :{_settings.WebserverPort}" : "[STOPPED] Webserver";
|
||||
this.Text = $"Predictalytics Analytics — {workerStatus} | {serverStatus}";
|
||||
}
|
||||
|
||||
protected override void OnFormClosing(FormClosingEventArgs e)
|
||||
{
|
||||
_workerCts?.Cancel();
|
||||
_webServer?.StopWebServerAsync().GetAwaiter().GetResult();
|
||||
base.OnFormClosing(e);
|
||||
}
|
||||
|
||||
private void btn_openbrowser_Click(object sender, EventArgs e)
|
||||
{
|
||||
try
|
||||
{
|
||||
System.Diagnostics.Process.Start("explorer.exe", $"\"http://localhost:{_settings.WebserverPort}\"");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Serilog.Log.Error(ex, "Fehler beim Öffnen des Browsers");
|
||||
MessageBox.Show("Browser konnte nicht gestartet werden.", "Fehler", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||||
}
|
||||
}
|
||||
|
||||
private void btn_logfolder_Click(object sender, EventArgs e)
|
||||
{
|
||||
try
|
||||
{
|
||||
var logPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "logs");
|
||||
if (Directory.Exists(logPath))
|
||||
System.Diagnostics.Process.Start("explorer.exe", logPath);
|
||||
else
|
||||
System.Diagnostics.Process.Start("explorer.exe", Environment.CurrentDirectory);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Serilog.Log.Error(ex, "Fehler beim Öffnen des Log-Ordners");
|
||||
}
|
||||
}
|
||||
|
||||
private async void syncMarketsaToolStripMenuItem_Click(object sender, EventArgs e)
|
||||
{
|
||||
if (_workerRunning)
|
||||
{
|
||||
MessageBox.Show("Market sync cannot be started while background workers are running.",
|
||||
"Workers Busy", MessageBoxButtons.OK, MessageBoxIcon.Warning);
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
btn_syncmarkets.Enabled = false;
|
||||
Log.Information("Manual market sync triggered...");
|
||||
|
||||
// Use a temporary CTS for this operation
|
||||
using var cts = new CancellationTokenSource();
|
||||
await _webServer!.RunSingleMarketSyncAsync(cts.Token);
|
||||
|
||||
Log.Information("Manual market sync completed successfully.");
|
||||
MessageBox.Show("Market sync completed.", "Success", MessageBoxButtons.OK, MessageBoxIcon.Information);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Error(ex, "Manual market sync failed");
|
||||
MessageBox.Show($"Market sync failed: {ex.Message}", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||||
}
|
||||
finally
|
||||
{
|
||||
btn_syncmarkets.Enabled = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user