2using System.Collections.Generic;
4using System.Runtime.InteropServices;
5using System.ServiceProcess;
8using System.Threading.Tasks;
17#pragma warning disable CA1416
26 private bool autoPaused =
false;
27 private bool starting =
false;
37 this.ServiceName = ServiceName;
38 if (!
string.IsNullOrEmpty(InstanceName))
39 this.ServiceName +=
" " + InstanceName;
42 this.CanHandlePowerEvent =
true;
43 this.CanHandleSessionChangeEvent =
true;
44 this.CanPauseAndContinue =
true;
45 this.CanShutdown =
true;
49 protected override void OnStart(
string[] args)
59 using PendingTimer Timer =
new(
this);
61 Directory.SetCurrentDirectory(AppDomain.CurrentDomain.BaseDirectory);
63 Gateway.GetDatabaseProvider +=
Program.GetDatabase;
64 Gateway.RegistrationSuccessful +=
Program.RegistrationSuccessful;
65 Gateway.OnTerminate += this.TerminateService;
74 this.starting =
false;
80 Log.
Alert(
"Gateway being started in another process.");
81 ThreadPool.QueueUserWorkItem(_ => this.Stop());
92 private Task TerminateService(
object Sender, EventArgs e)
95 ThreadPool.QueueUserWorkItem(_ => this.Stop());
96 return Task.CompletedTask;
99 private class PendingTimer : IDisposable
103 private bool disposed =
false;
107 this.service = Service;
108 this.timer =
new Timer(this.MoreTime,
null, 0, 1000);
111 public void Dispose()
113 this.disposed =
true;
114 this.timer?.Dispose();
118 private void MoreTime(
object State)
124 this.service.RequestAdditionalTime(2000);
126 catch (InvalidOperationException)
128 this.timer?.Dispose();
139 protected override void OnPause()
144 protected override void OnContinue()
154 using PendingTimer Timer =
new(
this);
156 this.starting =
true;
163 this.starting =
false;
169 Log.
Alert(
"Gateway being started in another process.");
170 ThreadPool.QueueUserWorkItem(_ => this.Stop());
181 protected override bool OnPowerEvent(PowerBroadcastStatus powerStatus)
185 case PowerBroadcastStatus.BatteryLow:
186 case PowerBroadcastStatus.OemEvent:
187 case PowerBroadcastStatus.PowerStatusChange:
188 case PowerBroadcastStatus.QuerySuspend:
192 case PowerBroadcastStatus.ResumeAutomatic:
193 case PowerBroadcastStatus.ResumeCritical:
194 case PowerBroadcastStatus.ResumeSuspend:
197 this.autoPaused =
false;
200 Log.
Warning(
"Gateway is in the process of starting, called from another source.");
209 case PowerBroadcastStatus.Suspend:
210 this.autoPaused =
true;
215 case PowerBroadcastStatus.QuerySuspendFailed:
221 protected override void OnSessionChange(SessionChangeDescription ChangeDescription)
223 int SessionId = ChangeDescription.SessionId;
224 List<KeyValuePair<string, object>> Tags =
new()
226 new(
"SessionId", SessionId),
230 AddWtsUserName(Tags, SessionId);
231 AddWtsName(Tags,
"Initial Program", SessionId,
WtsInfoClass.WTSInitialProgram);
232 AddWtsName(Tags,
"Application Name", SessionId,
WtsInfoClass.WTSApplicationName);
233 AddWtsName(Tags,
"Working Directory", SessionId,
WtsInfoClass.WTSWorkingDirectory);
234 AddWtsName(Tags,
"OEM ID", SessionId,
WtsInfoClass.WTSOEMId);
235 AddWtsName(Tags,
"Station Name", SessionId,
WtsInfoClass.WTSWinStationName);
236 AddWtsName(Tags,
"Connect State", SessionId,
WtsInfoClass.WTSConnectState);
237 AddWtsName(Tags,
"Client Build Number", SessionId,
WtsInfoClass.WTSClientBuildNumber);
238 AddWtsName(Tags,
"Client Name", SessionId,
WtsInfoClass.WTSClientName);
239 AddWtsName(Tags,
"Client Directory", SessionId,
WtsInfoClass.WTSClientDirectory);
240 AddWtsName(Tags,
"Client Product ID", SessionId,
WtsInfoClass.WTSClientProductId);
241 AddWtsName(Tags,
"Client Hardware ID", SessionId,
WtsInfoClass.WTSClientHardwareId);
242 AddWtsName(Tags,
"Client Address", SessionId,
WtsInfoClass.WTSClientAddress);
243 AddWtsName(Tags,
"Client Display", SessionId,
WtsInfoClass.WTSClientDisplay);
244 AddWtsName(Tags,
"Client Protocol Type", SessionId,
WtsInfoClass.WTSClientProtocolType);
245 AddWtsName(Tags,
"Idle Time", SessionId,
WtsInfoClass.WTSIdleTime);
246 AddWtsName(Tags,
"Logon Time", SessionId,
WtsInfoClass.WTSLogonTime);
247 AddWtsName(Tags,
"Incoming Bytes", SessionId,
WtsInfoClass.WTSIncomingBytes);
248 AddWtsName(Tags,
"Outgoing Bytes", SessionId,
WtsInfoClass.WTSOutgoingBytes);
249 AddWtsName(Tags,
"Incoming Frames", SessionId,
WtsInfoClass.WTSIncomingFrames);
250 AddWtsName(Tags,
"Outgoing Frames", SessionId,
WtsInfoClass.WTSOutgoingFrames);
251 AddWtsName(Tags,
"Client Info", SessionId,
WtsInfoClass.WTSClientInfo);
252 AddWtsName(Tags,
"Session Info", SessionId,
WtsInfoClass.WTSSessionInfo);
256 switch (ChangeDescription.Reason)
258 case SessionChangeReason.ConsoleConnect:
259 Message =
"User connected to machine via console interface.";
262 case SessionChangeReason.ConsoleDisconnect:
263 Message =
"User disconnected console interface.";
266 case SessionChangeReason.RemoteConnect:
267 Message =
"User connected remotely to machine.";
270 case SessionChangeReason.RemoteDisconnect:
271 Message =
"User disconnected remote interface.";
274 case SessionChangeReason.SessionLock:
275 Message =
"User session locked.";
278 case SessionChangeReason.SessionLogoff:
279 Message =
"User logged off.";
282 case SessionChangeReason.SessionLogon:
283 Message =
"User logged on.";
286 case SessionChangeReason.SessionRemoteControl:
287 Message =
"User remote control status of session has changed.";
290 case SessionChangeReason.SessionUnlock:
291 Message =
"User session unlocked.";
295 Tags.Add(
new KeyValuePair<string, object>(
"Reason", ChangeDescription.Reason.ToString()));
296 Message =
"Session changed.";
304 if ((Setup.NotificationConfiguration.Instance.Addresses?.Length ?? 0) == 0)
310 StringBuilder Markdown =
new();
313 Markdown.AppendLine();
314 Markdown.AppendLine(
"| Details ||");
315 Markdown.AppendLine(
"|:----|:---|");
317 foreach (KeyValuePair<string, object> Tag
in Tags)
319 Markdown.Append(
"| ");
321 Markdown.Append(
" | ");
323 Markdown.AppendLine(
" |");
331 private static void AddWtsUserName(List<KeyValuePair<string, object>> Tags,
int SessionId)
333 string Value = GetUserName(SessionId);
334 if (!
string.IsNullOrEmpty(Value))
335 Tags.Add(
new KeyValuePair<string, object>(
"User Name", Value));
338 private static void AddWtsName(List<KeyValuePair<string, object>> Tags,
string Key,
int SessionId,
WtsInfoClass InfoClass)
340 string Value = GetWtsName(SessionId, InfoClass);
341 if (!
string.IsNullOrEmpty(Value))
342 Tags.Add(
new KeyValuePair<string, object>(Key, Value));
345 private static string GetUserName(
int SessionId)
349 string UserName = GetWtsName(SessionId,
WtsInfoClass.WTSUserName);
350 if (
string.IsNullOrEmpty(UserName))
353 string Domain = GetWtsName(SessionId,
WtsInfoClass.WTSDomainName);
354 if (!
string.IsNullOrEmpty(Domain))
355 UserName = Domain +
"\\" + UserName;
366 private static string GetWtsName(
int SessionId,
WtsInfoClass InfoClass)
372 if (
Win32.WTSQuerySessionInformation(IntPtr.Zero, SessionId, InfoClass, out IntPtr Buffer, out
int StrLen) && StrLen > 1)
376 Result = Marshal.PtrToStringAnsi(Buffer);
377 Win32.WTSFreeMemory(Buffer);
378 Buffer = IntPtr.Zero;
382 if (Buffer != IntPtr.Zero)
383 Win32.WTSFreeMemory(Buffer);
395 if (!
string.IsNullOrEmpty(Result))
396 Result =
CommonTypes.
Escape(Result, specialCharactersToEscape, specialCharacterEscapes);
401 private static readonly
char[] specialCharactersToEscape =
new char[]
435 private static readonly
string[] specialCharacterEscapes =
new string[]
471 protected override void OnShutdown()
477 protected override void OnStop()
482 using PendingTimer Timer =
new(
this);
494 private static void Flush()
503 protected override void OnCustomCommand(
int command)
510#pragma warning restore CA1416
Helps with parsing of commong data types.
static string Escape(string s, char[] CharactersToEscape, string EscapeSequence)
Escapes a set of characters in a string.
Contains a markdown document. This markdown document class supports original markdown,...
static string Encode(string s)
Encodes all special characters in a string so that it can be included in a markdown document without ...
Static class managing the application event log. Applications and services log events on this static ...
static void Terminate()
Must be called when the application is terminated. Stops all event sinks that have been registered.
static void Exception(Exception Exception, string Object, string Actor, string EventId, EventLevel Level, string Facility, string Module, params KeyValuePair< string, object >[] Tags)
Logs an exception. Event type will be determined by the severity of the exception.
static void Warning(string Message, string Object, string Actor, string EventId, EventLevel Level, string Facility, string Module, string StackTrace, params KeyValuePair< string, object >[] Tags)
Logs a warning event.
static void Notice(string Message, string Object, string Actor, string EventId, EventLevel Level, string Facility, string Module, string StackTrace, params KeyValuePair< string, object >[] Tags)
Logs a notice event.
static void Alert(string Message, string Object, string Actor, string EventId, EventLevel Level, string Facility, string Module, string StackTrace, params KeyValuePair< string, object >[] Tags)
Logs an alert event.
Static class managing the runtime environment of the IoT Gateway.
static CaseInsensitiveString Domain
Domain name.
static Task< bool > Start(bool ConsoleOutput)
Starts the gateway.
static async Task Stop()
Stops the gateway.
static Task SendNotification(Graph Graph)
Sends a graph as a notification message to configured notification recipients.
static async Task< bool > ExecuteServiceCommand(int CommandNr)
Executes a service command.
GatewayService(string ServiceName, string InstanceName)
Gateway Service
IoT Gateway Windows Service Application.
Handles interaction with Windows Service API.
Represents a case-insensitive string.
string Value
String-representation of the case-insensitive string. (Representation is case sensitive....
static bool IsNullOrEmpty(CaseInsensitiveString value)
Indicates whether the specified string is null or an CaseInsensitiveString.Empty string.
Static interface for database persistence. In order to work, a database provider has to be assigned t...
static bool HasProvider
If a database provider is registered.
static IDatabaseProvider Provider
Registered database provider.
Static interface for ledger persistence. In order to work, a ledger provider has to be assigned to it...
static bool HasProvider
If a ledger provider is registered.
static ILedgerProvider Provider
Registered ledger provider.
Task Flush()
Persists any pending changes.
Task Flush()
Persists any pending changes.
WtsInfoClass
Windows Terminal Services Infomration class.