UnityGame/Library/PackageCache/com.unity.collab-proxy/Editor/PlasticSCM/PlasticConnectionMonitor.cs

235 lines
6.6 KiB
C#
Raw Normal View History

2024-10-27 10:53:47 +03:00
using System;
using System.Threading;
using UnityEditor;
using Codice.Client.Common.EventTracking;
using Codice.Client.Common.Connection;
using Codice.Client.Common.Threading;
using Codice.CM.Common;
using Codice.LogWrapper;
using PlasticPipe;
using Unity.PlasticSCM.Editor.UI;
namespace Unity.PlasticSCM.Editor
{
internal class PlasticConnectionMonitor :
HandleCredsAliasAndServerCert.IHostUnreachableExceptionListener
{
internal bool IsTryingReconnection { get { return mIsTryingReconnection; } }
internal bool IsConnected { get { return PlasticPlugin.IsUnitTesting || mIsConnected; } }
internal void CheckConnection()
{
mIsTryingReconnection = true;
mResetEvent.Set();
}
internal void SetAsConnected()
{
mIsConnected = true;
}
internal void Stop()
{
if (!mIsMonitoringServerConnection)
return;
mLog.Debug("Stop");
mIsMonitoringServerConnection = false;
mResetEvent.Set();
}
internal void SetRepositorySpecForEventTracking(RepositorySpec repSpec)
{
mRepSpecForEventTracking = repSpec;
}
internal void OnConnectionError(Exception ex, string server)
{
lock (mOnConnectionErrorLock)
{
LogConnectionError(ex, mIsConnected);
if (!mIsConnected)
return;
mIsConnected = false;
}
HandleConnectionLost(
mRepSpecForEventTracking,
() => StartMonitoring(server));
}
void HandleCredsAliasAndServerCert.IHostUnreachableExceptionListener.OnHostUnreachableException(
Exception ex,
PlasticServer plasticServer)
{
OnConnectionError(ex, plasticServer.OriginalUrl);
}
void StartMonitoring(string server)
{
mLog.Debug("StartMonitoring");
mIsMonitoringServerConnection = true;
Thread thread = new Thread(MonitorServerConnection);
thread.IsBackground = true;
thread.Name = "Plastic SCM Connection Monitor thread";
thread.Start(server);
}
void MonitorServerConnection(object obj)
{
string server = (string)obj;
while (true)
{
if (!mIsMonitoringServerConnection)
break;
try
{
mResetEvent.Reset();
if (HasConnectionToServer(server))
{
mIsConnected = true;
HandleConnectionRestored(mRepSpecForEventTracking);
break;
}
RepaintPlasticWindowIfOpened();
mResetEvent.WaitOne(CONNECTION_POLL_TIME_MS);
}
catch (Exception ex)
{
mLog.Error("Error checking network connectivity", ex);
mLog.DebugFormat("Stacktrace: {0}", ex.StackTrace);
}
finally
{
mIsTryingReconnection = false;
}
}
}
static void HandleConnectionLost(
RepositorySpec repSpecForEventTracking,
Action startMonitoringAction)
{
TrackConnectionLostEvent(repSpecForEventTracking);
EditorDispatcher.Dispatch(() =>
{
PlasticPlugin.Disable();
startMonitoringAction();
PlasticWindow window = GetPlasticWindowIfOpened();
if (window != null)
window.Repaint();
});
}
static void HandleConnectionRestored(
RepositorySpec repSpecForEventTracking)
{
TrackConnectionRestoredEvent(repSpecForEventTracking);
EditorDispatcher.Dispatch(() =>
{
PlasticPlugin.Enable();
PlasticWindow window = GetPlasticWindowIfOpened();
if (window != null)
window.RefreshWorkspaceUI();
});
}
static void RepaintPlasticWindowIfOpened()
{
EditorDispatcher.Dispatch(() =>
{
PlasticWindow window = GetPlasticWindowIfOpened();
if (window != null)
window.Repaint();
});
}
static void LogConnectionError(Exception ex, bool isConnected)
{
mLog.WarnFormat(isConnected ?
"A network exception will cause the plugin to go offline" :
"A network exception happened while the plugin was offline!");
ExceptionsHandler.LogException("PlasticConnectionMonitor", ex);
}
static void TrackConnectionLostEvent(RepositorySpec repSpec)
{
if (repSpec == null)
return;
TrackFeatureUseEvent.For(
repSpec,
TrackFeatureUseEvent.Features.UnityPackage.DisableAutomatically);
}
static void TrackConnectionRestoredEvent(RepositorySpec repSpec)
{
if (repSpec == null)
return;
TrackFeatureUseEvent.For(
repSpec,
TrackFeatureUseEvent.Features.UnityPackage.EnableAutomatically);
}
static PlasticWindow GetPlasticWindowIfOpened()
{
if (!EditorWindow.HasOpenInstances<PlasticWindow>())
return null;
return EditorWindow.GetWindow<PlasticWindow>(null, false);
}
static bool HasConnectionToServer(string server)
{
try
{
mLog.DebugFormat("Checking connection to {0}...", server);
return PlasticGui.Plastic.API.CheckServerConnection(server);
}
catch (Exception ex)
{
mLog.DebugFormat("Checking connection to {0} failed: {1}",
server,
ex.Message);
return false;
}
}
volatile bool mIsMonitoringServerConnection;
volatile bool mIsTryingReconnection;
volatile bool mIsConnected = true;
RepositorySpec mRepSpecForEventTracking;
readonly object mOnConnectionErrorLock = new object();
readonly ManualResetEvent mResetEvent = new ManualResetEvent(false);
const int CONNECTION_POLL_TIME_MS = 30000;
static readonly ILog mLog = PlasticApp.GetLogger("PlasticConnectionMonitor");
}
}