Files
TeslaSuite/Console/TeslaConsole/PodInfo.cs
T
CydandClaude Fable 5 e0a3c72370 Console: survive a launcher-dropped connection during product installs
The launcher drops RPC sessions idle >30s (easily hit while the operator sits
in the install dialogs), but a dropped socket still reports Connected until an
I/O fails. InstallProductWorker then skipped its reopen, streamed the archive
on the fresh out-of-band connection, and died on the first progress poll —
and the install-completed handler registered launch entries without checking
e.Error, so AddApp's disconnected-guard exception crashed the whole console.

- PodInfo.EnsureConnectionAlive: probe an "open" connection with a Ping and
  reconnect when it is dead; used by the install and uninstall workers.
- SiteManagement.PodInfo_InstallProductCompleted: register launch entries only
  on success, and surface registration failures as the row's Install Failed
  state instead of an unhandled exception.
- Regression test pins the premise + recovery against vPOD's launcher server
  (stale socket reports open, Ping exposes it, reconnect restores service).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-09 21:40:14 -05:00

938 lines
26 KiB
C#

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Net;
using System.ServiceProcess;
using System.Threading;
using Tesla.Net;
namespace TeslaConsole;
public class PodInfo : Component
{
private delegate void ConnectWorkerEventHandler(AsyncOperation asyncOp, SendOrPostCallback completionMethodDelegate);
private delegate void LaunchAppWorkerEventHandler(Guid appId, AsyncOperation asyncOp, SendOrPostCallback completionMethodDelegate);
private delegate void KillAppWorkerEventHandler(Guid appId, AsyncOperation asyncOp, SendOrPostCallback completionMethodDelegate);
private delegate void ShutdownWorkerEventHandler(bool restart, AsyncOperation asyncOp, SendOrPostCallback completionMethodDelegate);
private delegate void InstallProductWorkerEventHandler(string uncPath, SendOrPostCallback progressCallback, AsyncOperation asyncOp, SendOrPostCallback completionMethodDelegate);
private delegate void UninstallProductWorkerEventHandler(AsyncOperation asyncOp, SendOrPostCallback completionMethodDelegate);
private delegate void ServiceWorkerEventHandler(string machineName, AsyncOperation asyncOp, SendOrPostCallback completionMethodDelegate);
private const int ManagePort = 53290;
private static Dictionary<Guid, PodInfo> mPods = new Dictionary<Guid, PodInfo>();
private AsyncDelegates<ConnectWorkerEventHandler> connectDelegates;
private SendOrPostCallback onLaunchAppCompletedDelegate;
private SendOrPostCallback launchAppCompletionMethodDelegate;
private SendOrPostCallback onKillAppCompletedDelegate;
private SendOrPostCallback killAppCompletionMethodDelegate;
private AsyncDelegates<InstallProductWorkerEventHandler> installProductDelegates;
private AsyncDelegates<UninstallProductWorkerEventHandler> uninstallProductDelegates;
private AsyncDelegates<ServiceWorkerEventHandler> serviceGetDelegates;
private AsyncDelegates<ServiceWorkerEventHandler> serviceStartDelegates;
private AsyncDelegates<ServiceWorkerEventHandler> serviceStopDelegates;
private Pod mPod;
private IPodManagerConnection mConnection = new PodManagerConnection();
private object mConnectSyncRoot = new object();
private AsyncOperation mConnectAsyncOp;
private Exception mLastConnectionException;
private Cached<LaunchData[]> mAllApps = new Cached<LaunchData[]>(TimeSpan.FromMinutes(30.0));
private Cached<List<LaunchedAppData>> mRunningApps = new Cached<List<LaunchedAppData>>(TimeSpan.FromSeconds(60.0));
private float mVolume = float.NaN;
private readonly List<Action<PodInfo>> rConnectActions = new List<Action<PodInfo>>();
private IContainer components;
public Pod Pod => mPod;
public bool IsConnecting => mConnectAsyncOp != null;
public bool IsConnected
{
get
{
if (!IsConnecting && mConnection != null)
{
return mConnection.IsOpen;
}
return false;
}
}
public Exception LastConnectionException => mLastConnectionException;
public LaunchData[] AllApplications
{
get
{
if (mAllApps.IsExpired && mConnection.IsOpen)
{
try
{
mAllApps.Item = mConnection.GetInstalledApps();
}
catch
{
mConnection.Close();
mAllApps.Expire();
return new LaunchData[0];
}
}
return mAllApps.Item;
}
}
public LaunchedAppData[] RunningApplications
{
get
{
if (!mConnection.IsOpen)
{
return new LaunchedAppData[0];
}
if (mRunningApps.IsExpired)
{
try
{
lock (mRunningApps.SyncRoot)
{
mRunningApps.Item = new List<LaunchedAppData>(mConnection.GetLaunchedApps());
}
}
catch
{
mConnection.Close();
lock (mRunningApps.SyncRoot)
{
mRunningApps.Expire();
}
return new LaunchedAppData[0];
}
}
if (mRunningApps.Item == null)
{
return null;
}
return mRunningApps.Item.ToArray();
}
}
public float Volume
{
get
{
if (float.IsNaN(mVolume) && mConnection.IsOpen)
{
try
{
mVolume = mConnection.VolumeLevel;
}
catch
{
mConnection.Close();
mVolume = float.NaN;
}
}
return mVolume;
}
set
{
if (mConnection.IsOpen)
{
mVolume = value;
try
{
mConnection.VolumeLevel = value;
}
catch
{
mConnection.Close();
mVolume = float.NaN;
}
}
}
}
public bool IsServiceRunning
{
get
{
try
{
ServiceController serviceController = new ServiceController("TeslaLauncherService", mPod.IPAddress.ToString());
return serviceController.Status == ServiceControllerStatus.Running;
}
catch
{
return false;
}
}
}
public event EventHandler<AsyncCompletedEventArgs> ConnectCompleted;
public event EventHandler<ApplicationCompletedEventArgs> LaunchApplicationCompleted;
public event EventHandler<ApplicationCompletedEventArgs> KillApplicationCompleted;
public event EventHandler<InstallProductProgressEventArgs> InstallProductProgress;
public event EventHandler<InstallProductCompletedEventArgs> InstallProductCompleted;
public event EventHandler<AsyncCompletedEventArgs> UninstallProductCompleted;
public event EventHandler<ServiceStatusEventArgs> ServiceStatusGetCompleted;
public event EventHandler<AsyncCompletedEventArgs> ServiceStartCompleted;
public event EventHandler<AsyncCompletedEventArgs> ServiceStopCompleted;
public PodInfo()
{
InitializeComponent();
InitializeDelegates();
}
public PodInfo(IContainer container)
{
container.Add(this);
InitializeComponent();
InitializeDelegates();
}
public PodInfo(Pod pod)
: this(pod, register: false)
{
}
public PodInfo(Pod pod, bool register)
: this()
{
mPod = pod;
if (register)
{
RegisterPod(this);
}
}
protected virtual void InitializeDelegates()
{
connectDelegates = new AsyncDelegates<ConnectWorkerEventHandler>(ConnectCompletedInternal, ConnectCompletionMethod);
onLaunchAppCompletedDelegate = LaunchAppCompleted;
launchAppCompletionMethodDelegate = LaunchAppCompletionMethod;
onKillAppCompletedDelegate = KillAppCompleted;
killAppCompletionMethodDelegate = KillAppCompletionMethod;
installProductDelegates = new AsyncDelegates<InstallProductWorkerEventHandler>(InstallProductReportProgress, InstallProductInternalCompleted, InstallProductCompletionMethod);
uninstallProductDelegates = new AsyncDelegates<UninstallProductWorkerEventHandler>(UninstallProductInternalCompleted, UninstallProductCompletionMethod);
serviceGetDelegates = new AsyncDelegates<ServiceWorkerEventHandler>(ServiceStatusGetCompletedInternal, ServiceStatusGetCompletionMethod);
serviceStartDelegates = new AsyncDelegates<ServiceWorkerEventHandler>(ServiceStartCompletedInternal, ServiceStartCompletionMethod);
serviceStopDelegates = new AsyncDelegates<ServiceWorkerEventHandler>(ServiceStopCompletedInternal, ServiceStopCompletionMethod);
}
public static void RegisterPod(PodInfo pod)
{
mPods[pod.Pod.ID] = pod;
}
public static PodInfo GetPod(Guid id)
{
PodInfo value = null;
if (mPods.TryGetValue(id, out value))
{
return value;
}
return null;
}
public bool EnqueueConnectAction(Action<PodInfo> action)
{
if (IsConnected)
{
action(this);
return true;
}
rConnectActions.Add(action);
return false;
}
public void Disconnect()
{
if (mConnectAsyncOp != null)
{
CancelConnectAsync();
}
else if (IsConnected)
{
mConnection.Close();
}
mLastConnectionException = null;
mAllApps.Expire();
mRunningApps.Expire();
mVolume = float.NaN;
}
public void Refresh()
{
if (!IsConnected)
{
throw new InvalidOperationException("Cannot refresh pod info while disconnected.");
}
try
{
FullUpdateData fullUpdateData = mConnection.FullUpdate();
mAllApps.Item = fullUpdateData.InstalledApps;
lock (mRunningApps.SyncRoot)
{
mRunningApps.Item = new List<LaunchedAppData>(fullUpdateData.LaunchedApps);
}
mVolume = fullUpdateData.VolumeLevel;
}
catch
{
mConnection.Close();
mAllApps.Expire();
lock (mRunningApps.SyncRoot)
{
mRunningApps.Expire();
}
mVolume = float.NaN;
}
}
public bool IsAppRunning(Guid appId)
{
LaunchedAppData[] runningApplications = RunningApplications;
return Array.Exists(runningApplications, (LaunchedAppData app) => app.LaunchKey == appId);
}
public void AddApp(LaunchData appData)
{
if (!IsConnected)
{
throw new InvalidOperationException("Application cannot be added while disconnected.");
}
try
{
mConnection.InstallApp(appData);
}
catch (Exception ex)
{
Program.LogException(ex, "Add Application Failed.");
mConnection.Close();
}
}
public void Shutdown(bool restart)
{
try
{
mConnection.Shutdown(restart);
}
catch (Exception ex)
{
Program.LogExceptionAndShowDialog(ex, "Remote Shutdown Failed.", "Remote Shutdown Failed.");
}
}
public void ClearStore()
{
mConnection.ClearStore();
}
private void ConnectCompletedInternal(object operationState)
{
AsyncCompletedEventArgs e = operationState as AsyncCompletedEventArgs;
OnConnectCompleted(e);
}
protected void OnConnectCompleted(AsyncCompletedEventArgs e)
{
if (IsConnected)
{
foreach (Action<PodInfo> rConnectAction in rConnectActions)
{
rConnectAction(this);
}
rConnectActions.Clear();
}
if (this.ConnectCompleted != null)
{
this.ConnectCompleted(this, e);
}
}
private void ConnectCompletionMethod(object completionState)
{
AsyncControlState asyncControlState = completionState as AsyncControlState;
AsyncCompletedEventArgs asyncCompletedEventArgs = new AsyncCompletedEventArgs(asyncControlState.ex, cancelled: false, asyncControlState.asyncOp.UserSuppliedState);
mLastConnectionException = asyncCompletedEventArgs.Error;
lock (mConnectSyncRoot)
{
if (mConnectAsyncOp != null)
{
mConnectAsyncOp.PostOperationCompleted(connectDelegates.OnCompleted, asyncCompletedEventArgs);
mConnectAsyncOp = null;
}
}
}
private void ConnectWorker(AsyncOperation asyncOp, SendOrPostCallback completionMethodDelegate)
{
Exception ex = null;
mAllApps.Expire();
mRunningApps.Expire();
mVolume = float.NaN;
try
{
if (!mConnection.IsOpen)
{
if (mPod.IPAddress == IPAddress.None)
{
throw new ArgumentException("Pod IP address cannot be empty.", "IPAddress");
}
if (mPod.Key == null || mPod.Key.Length == 0)
{
throw new ArgumentException("Pod encryption key cannot be empty.", "Key");
}
mConnection.Open(new IPEndPoint(mPod.IPAddress, 53290), mPod.Key);
}
}
catch (Exception ex2)
{
ex = ex2;
}
AsyncControlState state = new AsyncControlState(ex, asyncOp);
completionMethodDelegate(state);
}
public void ConnectAsync(object userState)
{
AsyncOperation asyncOp = AsyncOperationManager.CreateOperation(userState);
lock (mConnectSyncRoot)
{
if (mConnectAsyncOp != null)
{
throw new InvalidOperationException("Already connecting. Cannot connect again.");
}
mConnectAsyncOp = asyncOp;
}
ThreadPool.QueueUserWorkItem(delegate
{
ConnectWorker(asyncOp, connectDelegates.CompletionMethod);
});
}
public void CancelConnectAsync()
{
lock (mConnectSyncRoot)
{
if (mConnectAsyncOp != null)
{
AsyncCompletedEventArgs arg = new AsyncCompletedEventArgs(null, cancelled: true, mConnectAsyncOp.UserSuppliedState);
mConnectAsyncOp.PostOperationCompleted(connectDelegates.OnCompleted, arg);
mConnectAsyncOp = null;
}
}
}
private void LaunchAppCompleted(object operationState)
{
ApplicationCompletedEventArgs e = operationState as ApplicationCompletedEventArgs;
OnLaunchApplicationCompleted(e);
}
protected void OnLaunchApplicationCompleted(ApplicationCompletedEventArgs e)
{
if (this.LaunchApplicationCompleted != null)
{
this.LaunchApplicationCompleted(this, e);
}
}
private void LaunchAppCompletionMethod(object completionState)
{
AsyncControlState<Guid> asyncControlState = completionState as AsyncControlState<Guid>;
ApplicationCompletedEventArgs arg = new ApplicationCompletedEventArgs(asyncControlState.state, asyncControlState.ex, canceled: false, asyncControlState.asyncOp.UserSuppliedState);
asyncControlState.asyncOp.PostOperationCompleted(onLaunchAppCompletedDelegate, arg);
}
private void LaunchAppWorker(Guid appId, AsyncOperation asyncOp, SendOrPostCallback completionMethodDelegate)
{
Exception ex = null;
try
{
int processId = mConnection.LaunchApp(appId);
lock (mRunningApps.SyncRoot)
{
if (mRunningApps.Item == null)
{
mRunningApps.Item = new List<LaunchedAppData>();
}
mRunningApps.Item.Add(new LaunchedAppData
{
ProcessId = processId,
LaunchKey = appId
});
}
}
catch (Exception ex2)
{
ex = ex2;
}
completionMethodDelegate(new AsyncControlState<Guid>(appId, ex, asyncOp));
}
public void LaunchApplicationAsync(Guid appId, object userState)
{
if (!IsConnected)
{
throw new InvalidOperationException("Cannot launch application while disconnected.");
}
AsyncOperation asyncOp = AsyncOperationManager.CreateOperation(userState);
ThreadPool.QueueUserWorkItem(delegate
{
LaunchAppWorker(appId, asyncOp, launchAppCompletionMethodDelegate);
});
}
private void KillAppCompleted(object operationState)
{
ApplicationCompletedEventArgs e = operationState as ApplicationCompletedEventArgs;
OnKillApplicationCompleted(e);
}
protected void OnKillApplicationCompleted(ApplicationCompletedEventArgs e)
{
if (this.KillApplicationCompleted != null)
{
this.KillApplicationCompleted(this, e);
}
}
private void KillAppCompletionMethod(object completionState)
{
AsyncControlState<Guid> asyncControlState = completionState as AsyncControlState<Guid>;
ApplicationCompletedEventArgs arg = new ApplicationCompletedEventArgs(asyncControlState.state, asyncControlState.ex, canceled: false, asyncControlState.asyncOp.UserSuppliedState);
asyncControlState.asyncOp.PostOperationCompleted(onKillAppCompletedDelegate, arg);
}
private void KillAppWorker(Guid appId, AsyncOperation asyncOp, SendOrPostCallback completionMethodDelegate)
{
Exception ex = null;
try
{
mConnection.KillAllOfType(appId);
lock (mRunningApps.SyncRoot)
{
if (mRunningApps.Item != null)
{
for (int num = mRunningApps.Item.Count - 1; num >= 0; num--)
{
if (mRunningApps.Item[num].LaunchKey == appId)
{
mRunningApps.Item.RemoveAt(num);
}
}
}
}
}
catch (Exception ex2)
{
ex = ex2;
}
AsyncControlState<Guid> state = new AsyncControlState<Guid>(appId, ex, asyncOp);
completionMethodDelegate(state);
}
public void KillApplicationAsync(Guid appId, object userState)
{
if (!IsConnected)
{
throw new InvalidOperationException("Cannot kill application while disconnected.");
}
AsyncOperation asyncOp = AsyncOperationManager.CreateOperation(userState);
ThreadPool.QueueUserWorkItem(delegate
{
KillAppWorker(appId, asyncOp, killAppCompletionMethodDelegate);
});
}
private void InstallProductInternalCompleted(object operationState)
{
InstallProductCompletedEventArgs e = operationState as InstallProductCompletedEventArgs;
OnInstallProductCompleted(e);
}
private void InstallProductReportProgress(object state)
{
InstallProductProgressEventArgs e = state as InstallProductProgressEventArgs;
OnInstallProductProgress(e);
}
protected void OnInstallProductCompleted(InstallProductCompletedEventArgs e)
{
if (this.InstallProductCompleted != null)
{
this.InstallProductCompleted(this, e);
}
}
protected void OnInstallProductProgress(InstallProductProgressEventArgs e)
{
if (this.InstallProductProgress != null)
{
this.InstallProductProgress(this, e);
}
}
private void InstallProductCompletionMethod(object completionState)
{
AsyncControlState<string> asyncControlState = completionState as AsyncControlState<string>;
InstallProductCompletedEventArgs arg = new InstallProductCompletedEventArgs(asyncControlState.state, asyncControlState.ex, canceled: false, asyncControlState.asyncOp.UserSuppliedState);
asyncControlState.asyncOp.PostOperationCompleted(installProductDelegates.OnCompleted, arg);
}
/// <summary>
/// Opens the management connection if needed. A connection the launcher has
/// dropped still reports IsOpen (Connected is stale until an I/O fails), and
/// the launcher drops sessions idle for ~30s — easily hit while the operator
/// sits in the install dialogs — so probe an "open" connection with a Ping
/// and reconnect when it turns out to be dead.
/// </summary>
private void EnsureConnectionAlive()
{
if (mConnection.IsOpen)
{
try
{
mConnection.Ping(DateTime.Now);
return;
}
catch (Exception)
{
try
{
mConnection.Close();
}
catch
{
}
}
}
if (!mConnection.IsOpen)
{
mConnection.Open(new IPEndPoint(mPod.IPAddress, ManagePort), mPod.Key);
}
}
private void InstallProductWorker(string filePath, SendOrPostCallback progressCallback, AsyncOperation asyncOp, SendOrPostCallback completionMethodDelegate)
{
Exception ex = null;
try
{
for (int i = 0; i < 3; i++)
{
EnsureConnectionAlive();
Guid guid = mConnection.InstallProduct(filePath);
if (guid == Guid.Empty)
{
throw new Exception($"'{filePath}' is an invalid install file.");
}
OutOfBandProgress outOfBandProgress;
do
{
Thread.Sleep(250);
outOfBandProgress = mConnection.GetOutOfBandProgress(guid);
InstallProductProgressEventArgs arg = new InstallProductProgressEventArgs(outOfBandProgress.Status, outOfBandProgress.PercentComplete, asyncOp.UserSuppliedState);
asyncOp.Post(installProductDelegates.OnProgressReport, arg);
if (progressCallback != null)
{
asyncOp.Post(progressCallback, arg);
}
}
while (!outOfBandProgress.IsCompleted);
if (outOfBandProgress.PercentComplete == 99)
{
mAllApps.Expire();
break;
}
}
}
catch (Exception ex2)
{
Program.LogException(ex2, "Installation Failed");
ex = ex2;
}
AsyncControlState<string> state = new AsyncControlState<string>(filePath, ex, asyncOp);
completionMethodDelegate(state);
}
public void InstallProductAsync(string uncPath, object userState)
{
InstallProductAsync(uncPath, userState, null);
}
public void InstallProductAsync(string uncPath, object userState, Action<InstallProductProgressEventArgs> progressCallback)
{
if (!IsConnected)
{
throw new InvalidOperationException("Cannot install application while disconnected.");
}
AsyncOperation asyncOp = AsyncOperationManager.CreateOperation(userState);
ThreadPool.QueueUserWorkItem(delegate
{
InstallProductWorker(uncPath, delegate(object e)
{
progressCallback((InstallProductProgressEventArgs)e);
}, asyncOp, installProductDelegates.CompletionMethod);
});
}
private void UninstallProductInternalCompleted(object operationState)
{
AsyncCompletedEventArgs e = operationState as AsyncCompletedEventArgs;
OnUninstallProductCompleted(e);
}
protected void OnUninstallProductCompleted(AsyncCompletedEventArgs e)
{
if (this.UninstallProductCompleted != null)
{
this.UninstallProductCompleted(this, e);
}
}
private void UninstallProductCompletionMethod(object completionState)
{
AsyncControlState asyncControlState = completionState as AsyncControlState;
AsyncCompletedEventArgs arg = new AsyncCompletedEventArgs(asyncControlState.ex, cancelled: false, asyncControlState.asyncOp.UserSuppliedState);
asyncControlState.asyncOp.PostOperationCompleted(uninstallProductDelegates.OnCompleted, arg);
}
private void UninstallProductWorker(Guid launchKey, AsyncOperation asyncOp, SendOrPostCallback completionMethodDelegate)
{
Exception ex = null;
try
{
EnsureConnectionAlive();
mConnection.UninstallApp(launchKey);
mAllApps.Expire();
}
catch (Exception ex2)
{
Program.LogException(ex2, "Uninstallation Failed");
ex = ex2;
}
AsyncControlState state = new AsyncControlState(ex, asyncOp);
completionMethodDelegate(state);
}
public void UninstallProductAsync(Guid launchKey, object userState)
{
if (!IsConnected)
{
throw new InvalidOperationException("Cannot uninstall application while disconnected.");
}
AsyncOperation asyncOp = AsyncOperationManager.CreateOperation(userState);
ThreadPool.QueueUserWorkItem(delegate
{
UninstallProductWorker(launchKey, asyncOp, uninstallProductDelegates.CompletionMethod);
});
}
private void ServiceStatusGetCompletedInternal(object operationState)
{
ServiceStatusEventArgs e = operationState as ServiceStatusEventArgs;
OnServiceStatusGetCompleted(e);
}
protected void OnServiceStatusGetCompleted(ServiceStatusEventArgs e)
{
if (this.ServiceStatusGetCompleted != null)
{
this.ServiceStatusGetCompleted(this, e);
}
}
private void ServiceStatusGetCompletionMethod(object completionState)
{
AsyncControlState<ServiceControllerStatus> asyncControlState = completionState as AsyncControlState<ServiceControllerStatus>;
ServiceStatusEventArgs arg = new ServiceStatusEventArgs(asyncControlState.state, asyncControlState.ex, canceled: false, asyncControlState.asyncOp.UserSuppliedState);
asyncControlState.asyncOp.PostOperationCompleted(serviceGetDelegates.OnCompleted, arg);
}
private void ServiceStatusWorker(string machineName, AsyncOperation asyncOp, SendOrPostCallback completionMethodDelegate)
{
Exception ex = null;
ServiceControllerStatus state = ServiceControllerStatus.Stopped;
try
{
if (IPAddress.TryParse(machineName, out var address))
{
IPHostEntry hostEntry = Dns.GetHostEntry(address);
machineName = hostEntry.HostName;
}
using ServiceController serviceController = new ServiceController("TeslaLauncherService", machineName);
state = serviceController.Status;
}
catch (Exception ex2)
{
ex = ex2;
}
AsyncControlState<ServiceControllerStatus> state2 = new AsyncControlState<ServiceControllerStatus>(state, ex, asyncOp);
completionMethodDelegate(state2);
}
public void GetServiceStatusAsync(string machineName, object userState)
{
AsyncOperation asyncOp = AsyncOperationManager.CreateOperation(userState);
ThreadPool.QueueUserWorkItem(delegate
{
ServiceStatusWorker(machineName, asyncOp, serviceGetDelegates.CompletionMethod);
});
}
private void ServiceStartCompletedInternal(object operationState)
{
ServiceStatusEventArgs e = operationState as ServiceStatusEventArgs;
OnServiceStartCompleted(e);
}
protected void OnServiceStartCompleted(ServiceStatusEventArgs e)
{
if (this.ServiceStartCompleted != null)
{
this.ServiceStartCompleted(this, e);
}
}
private void ServiceStartCompletionMethod(object completionState)
{
AsyncControlState<ServiceControllerStatus> asyncControlState = completionState as AsyncControlState<ServiceControllerStatus>;
ServiceStatusEventArgs arg = new ServiceStatusEventArgs(asyncControlState.state, asyncControlState.ex, canceled: false, asyncControlState.asyncOp.UserSuppliedState);
asyncControlState.asyncOp.PostOperationCompleted(serviceGetDelegates.OnCompleted, arg);
}
private void ServiceStartWorker(string machineName, AsyncOperation asyncOp, SendOrPostCallback completionMethodDelegate)
{
Exception ex = null;
try
{
if (IPAddress.TryParse(machineName, out var address))
{
IPHostEntry hostEntry = Dns.GetHostEntry(address);
machineName = hostEntry.HostName;
}
using ServiceController serviceController = new ServiceController("TeslaLauncherService", machineName);
serviceController.Start();
serviceController.WaitForStatus(ServiceControllerStatus.Running, TimeSpan.FromSeconds(30.0));
}
catch (Exception ex2)
{
ex = ex2;
}
AsyncControlState state = new AsyncControlState(ex, asyncOp);
completionMethodDelegate(state);
}
public void ServiceStartAsync(string machineName, object userState)
{
AsyncOperation asyncOp = AsyncOperationManager.CreateOperation(userState);
ThreadPool.QueueUserWorkItem(delegate
{
ServiceStartWorker(machineName, asyncOp, serviceStartDelegates.CompletionMethod);
});
}
private void ServiceStopCompletedInternal(object operationState)
{
ServiceStatusEventArgs e = operationState as ServiceStatusEventArgs;
OnServiceStopCompleted(e);
}
protected void OnServiceStopCompleted(ServiceStatusEventArgs e)
{
if (this.ServiceStopCompleted != null)
{
this.ServiceStopCompleted(this, e);
}
}
private void ServiceStopCompletionMethod(object completionState)
{
AsyncControlState<ServiceControllerStatus> asyncControlState = completionState as AsyncControlState<ServiceControllerStatus>;
ServiceStatusEventArgs arg = new ServiceStatusEventArgs(asyncControlState.state, asyncControlState.ex, canceled: false, asyncControlState.asyncOp.UserSuppliedState);
asyncControlState.asyncOp.PostOperationCompleted(serviceGetDelegates.OnCompleted, arg);
}
private void ServiceStopWorker(string machineName, AsyncOperation asyncOp, SendOrPostCallback completionMethodDelegate)
{
Exception ex = null;
try
{
if (IPAddress.TryParse(machineName, out var address))
{
IPHostEntry hostEntry = Dns.GetHostEntry(address);
machineName = hostEntry.HostName;
}
using ServiceController serviceController = new ServiceController("TeslaLauncherService", machineName);
serviceController.Stop();
serviceController.WaitForStatus(ServiceControllerStatus.Stopped, TimeSpan.FromSeconds(30.0));
}
catch (Exception ex2)
{
ex = ex2;
}
AsyncControlState state = new AsyncControlState(ex, asyncOp);
completionMethodDelegate(state);
}
public void ServiceStopAsync(string machineName, object userState)
{
AsyncOperation asyncOp = AsyncOperationManager.CreateOperation(userState);
ThreadPool.QueueUserWorkItem(delegate
{
ServiceStopWorker(machineName, asyncOp, serviceStopDelegates.CompletionMethod);
});
}
protected override void Dispose(bool disposing)
{
if (disposing && components != null)
{
components.Dispose();
}
base.Dispose(disposing);
}
private void InitializeComponent()
{
components = new Container();
}
}