-
Niko Ehrenfeuchter authored
Currently this is almost entirely untested and configuration for email notifications is yet to be done. Refers to #3
Niko Ehrenfeuchter authoredCurrently this is almost entirely untested and configuration for email notifications is yet to be done. Refers to #3
AutoTxTray.cs 13.23 KiB
using System;
using System.Diagnostics;
using System.Timers;
using System.Drawing;
using System.IO;
using System.Windows.Forms;
using ATXCommon.Serializables;
using Microsoft.WindowsAPICodePack.Dialogs;
using NLog;
using NLog.Config;
using NLog.Targets;
using Timer = System.Timers.Timer;
namespace ATXTray
{
public class AutoTxTray : ApplicationContext
{
private static readonly Logger Log = LogManager.GetCurrentClassLogger();
private static readonly string AppTitle = Path.GetFileNameWithoutExtension(Application.ExecutablePath);
private static readonly Timer AppTimer = new Timer(1000);
private static bool _terminate = false;
private static readonly string BaseDir = AppDomain.CurrentDomain.BaseDirectory;
private static readonly string ConfigFile = Path.Combine(BaseDir, "configuration.xml");
private static readonly string StatusFile = Path.Combine(BaseDir, "status.xml");
private static DateTime _statusAge;
private static ServiceConfig _config;
private static ServiceStatus _status;
private static bool _statusChanged = false;
private static bool _svcRunning = false;
private static bool _svcSuspended = true;
private static string _svcSuspendReason;
private static bool _txInProgress = false;
private static long _txSize;
private readonly NotifyIcon _notifyIcon = new NotifyIcon();
private readonly Icon _tiDefault = new Icon("icon-default.ico");
private readonly Icon _tiStopped = new Icon("icon-stopped.ico");
private readonly Icon _tiSuspended = new Icon("icon-suspended.ico");
private readonly Icon _tiTx0 = new Icon("icon-tx-0.ico");
private readonly Icon _tiTx1 = new Icon("icon-tx-1.ico");
private readonly ContextMenuStrip _cmStrip = new ContextMenuStrip();
private readonly ToolStripMenuItem _miExit = new ToolStripMenuItem();
private readonly ToolStripMenuItem _miTitle = new ToolStripMenuItem();
private readonly ToolStripMenuItem _miSvcRunning = new ToolStripMenuItem();
private readonly ToolStripMenuItem _miSvcSuspended = new ToolStripMenuItem();
private readonly ToolStripMenuItem _miTxProgress = new ToolStripMenuItem();
private readonly ToolStripMenuItem _miTxEnqueue = new ToolStripMenuItem();
public AutoTxTray() {
#region logging configuration
var logConfig = new LoggingConfiguration();
var fileTarget = new FileTarget {
FileName = AppTitle + ".log",
Layout = @"${date:format=yyyy-MM-dd HH\:mm\:ss} [${level}] ${message}"
// Layout = @"${date:format=yyyy-MM-dd HH\:mm\:ss} [${level}] (${logger}) ${message}"
};
logConfig.AddTarget("file", fileTarget);
var logRule = new LoggingRule("*", LogLevel.Debug, fileTarget);
logConfig.LoggingRules.Add(logRule);
LogManager.Configuration = logConfig;
#endregion
Log.Info("{0} initializing...", AppTitle);
Log.Debug(" - config file: [{0}]", ConfigFile);
Log.Debug(" - status file: [{0}]", StatusFile);
_notifyIcon.Icon = _tiStopped;
_notifyIcon.Visible = true;
_notifyIcon.DoubleClick += StartNewTransfer;
// this doesn't work properly, the menu will not close etc. so we disable it for now:
// _notifyIcon.Click += ShowContextMenu;
Log.Trace("Trying to read service config and status files...");
try {
_config = ServiceConfig.Deserialize(ConfigFile);
ReadStatus();
Log.Trace("Completed reading service config and status files.");
SetupContextMenu();
}
catch (Exception ex) {
var msg = "Error during initialization: " + ex.Message;
Log.Error(msg);
_notifyIcon.ShowBalloonTip(5000, AppTitle, msg, ToolTipIcon.Error);
// we cannot terminate the message loop (Application.Run()) while the constructor
// is being run as it is not active yet - therefore we simply remember that we want
// to exit and evaluate this in the "Elapsed" handler:
_terminate = true;
System.Threading.Thread.Sleep(5000);
}
AppTimer.Elapsed += AppTimerElapsed;
AppTimer.Enabled = true;
Log.Trace("Enabled timer.");
Log.Info("AutoTxTray initialization completed.");
}
private void SetupContextMenu() {
Log.Trace("Building context menu...");
_miExit.Text = @"Exit";
_miExit.Click += MiExitClick;
_miTitle.Font = new Font(_cmStrip.Font, FontStyle.Bold);
_miTitle.Text = AppTitle;
_miTitle.Image = Image.FromFile("icon-default.ico");
_miTitle.BackColor = Color.LightCoral;
_miTitle.Click += ShowContextMenu;
_miSvcRunning.Text = @"Service NOT RUNNING!";
_miSvcRunning.BackColor = Color.LightCoral;
_miSvcRunning.Click += ShowContextMenu;
_miSvcSuspended.Text = @"No limits apply, service active.";
_miSvcSuspended.Click += ShowContextMenu;
_miTxProgress.Text = @"No transfer running.";
_miTxProgress.Click += ShowContextMenu;
_miTxEnqueue.Text = @"+++ Add new directory for transfer. +++";
_miTxEnqueue.Click += StartNewTransfer;
_cmStrip.Items.AddRange(new ToolStripItem[] {
_miTitle,
_miSvcRunning,
_miSvcSuspended,
_miTxProgress,
new ToolStripSeparator(),
_miTxEnqueue,
new ToolStripSeparator(),
_miExit
});
_notifyIcon.ContextMenuStrip = _cmStrip;
Log.Trace("Finished building context menu.");
}
private void AutoTxTrayExit() {
Log.Info("Shutting down {0}.", AppTitle);
_notifyIcon.Visible = false;
Application.Exit();
}
/// <summary>
/// Update the tooltip making sure not to exceed the 63 characters limit.
/// </summary>
/// <param name="msg"></param>
private void UpdateHoverText(string msg) {
if (msg.Length > 63) {
msg = msg.Substring(0, 60) + "...";
}
_notifyIcon.Text = msg;
}
private void AppTimerElapsed(object sender, ElapsedEventArgs e) {
if (_terminate) {
AutoTxTrayExit();
return;
}
UpdateSvcRunning();
var heartBeat = "?";
var serviceRunning = "stopped";
var txProgress = "No";
if (_svcRunning) {
serviceRunning = "OK";
ReadStatus();
UpdateSvcSuspended();
UpdateTxInProgress();
if ((DateTime.Now - _status.LastStatusUpdate).TotalSeconds < 60)
heartBeat = "OK";
if (_txInProgress)
txProgress = _txSize.ToString();
}
UpdateTrayIcon();
if (!_statusChanged)
return;
UpdateHoverText(string.Format("AutoTx [svc={0}] [hb={1}] [tx={2}]",
serviceRunning, heartBeat, txProgress));
}
private void MiExitClick(object sender, EventArgs e) {
AutoTxTrayExit();
}
private void ShowContextMenu(object sender, EventArgs e) {
// just show the menu again, to avoid that clicking the menu item closes the context
// menu without having to disable the item (which would grey out the text and icon):
_notifyIcon.ContextMenuStrip.Show();
}
private static void StartNewTransfer(object sender, EventArgs e) {
var dirDialog = new CommonOpenFileDialog {
Title = @"Select directory to be transferred",
IsFolderPicker = true,
EnsurePathExists = true,
DefaultDirectory = _config.SourceDrive
};
if (dirDialog.ShowDialog() == CommonFileDialogResult.Ok) {
MessageBox.Show("Directory\nselected:\n\n" + dirDialog.FileName +
"\n\nWARNING: adding new transfers is NOT YET IMPLEMENTED!",
"New transfer confirmation", MessageBoxButtons.YesNo, MessageBoxIcon.Question);
}
}
/// <summary>
/// Read (or re-read) the service status file if it has changed since last time.
/// </summary>
private static void ReadStatus() {
var age = new FileInfo(StatusFile).LastWriteTime;
if (age == _statusAge)
return;
Log.Debug("Status file was updated, trying to re-read...");
_statusAge = age;
_status = ServiceStatus.Deserialize(StatusFile, _config);
}
/// <summary>
/// Check if a process with the expeced name of the service is currently running.
/// </summary>
/// <returns>True if such a process exists, false otherwise.</returns>
private static bool ServiceProcessRunning() {
var plist = Process.GetProcessesByName("AutoTx");
return plist.Length > 0;
}
private void UpdateSvcRunning() {
var curSvcRunState = ServiceProcessRunning();
if (_svcRunning == curSvcRunState)
return;
_statusChanged = true;
_svcRunning = curSvcRunState;
if (_svcRunning) {
_miSvcRunning.Text = @"Service running.";
_miSvcRunning.BackColor = Color.LightGreen;
_miTitle.BackColor = Color.LightGreen;
_miSvcSuspended.Enabled = true;
_notifyIcon.ShowBalloonTip(500, AppTitle,
"Service running.", ToolTipIcon.Info);
} else {
_miSvcRunning.Text = @"Service NOT RUNNING!";
_miSvcRunning.BackColor = Color.LightCoral;
_miTitle.BackColor = Color.LightCoral;
_miSvcSuspended.Enabled = false;
_notifyIcon.ShowBalloonTip(500, AppTitle,
"Service stopped.", ToolTipIcon.Error);
}
}
private void UpdateSvcSuspended() {
// first update the suspend reason as this can possibly change even if the service
// never leaves the suspended state and we should still display the correct reason:
if (_svcSuspendReason == _status.LimitReason &&
_svcSuspended == _status.ServiceSuspended)
return;
_statusChanged = true;
_svcSuspended = _status.ServiceSuspended;
_svcSuspendReason = _status.LimitReason;
if (_svcSuspended) {
_miSvcSuspended.Text = @"Service suspended, reason: " + _svcSuspendReason;
_miSvcSuspended.BackColor = Color.LightSalmon;
/*
_notifyIcon.ShowBalloonTip(500, "AutoTx Monitor",
"Service suspended: " + _status.LimitReason, ToolTipIcon.Warning);
*/
} else {
_miSvcSuspended.Text = @"No limits apply, service active.";
_miSvcSuspended.BackColor = Color.LightGreen;
/*
_notifyIcon.ShowBalloonTip(500, "AutoTx Monitor",
"Service resumed, no limits apply.", ToolTipIcon.Info);
*/
}
}
private void UpdateTxInProgress() {
if (_txInProgress == _status.TransferInProgress &&
_txSize == _status.CurrentTransferSize)
return;
_statusChanged = true;
_txInProgress = _status.TransferInProgress;
_txSize = _status.CurrentTransferSize;
if (_txInProgress) {
_miTxProgress.Text = @"Transfer in progress (size: " + _txSize + ")";
_miTxProgress.BackColor = Color.LightGreen;
_notifyIcon.ShowBalloonTip(500, AppTitle,
"New transfer started (size: " + _txSize + ").", ToolTipIcon.Info);
} else {
_miTxProgress.Text = @"No transfer running.";
_miTxProgress.ResetBackColor();
_notifyIcon.ShowBalloonTip(500, AppTitle,
"Transfer completed.", ToolTipIcon.Info);
}
}
private void UpdateTrayIcon() {
if (_txInProgress &&
!_svcSuspended) {
if (DateTime.Now.Second % 2 == 0) {
_notifyIcon.Icon = _tiTx0;
} else {
_notifyIcon.Icon = _tiTx1;
}
}
if (!_statusChanged)
return;
if (!_svcRunning) {
_notifyIcon.Icon = _tiStopped;
return;
}
if (_svcSuspended) {
_notifyIcon.Icon = _tiSuspended;
return;
}
if (!_txInProgress) {
_notifyIcon.Icon = _tiDefault;
}
}
}
}