using UnityEditor;
using UnityEngine;
using System;
using System.Threading;
using System.Collections;
using System.Collections.Generic;
using Perforce.P4;
using System.Linq;
using System.Text;
using System.IO;
namespace P4Connect
{
///
/// Small class that encompasses a perforce connection
/// Always use it with the 'using' statement, so its
/// Dispose() method is called and the connection to
/// the server is properly closed.
///
public class PerforceConnection : IDisposable
{
// Give read-only access to the server we're connected to
public Server P4Server
{
get { return _P4Server; }
set { _P4Server = value; }
}
// Give read-only access to the current depot
public Repository P4Depot
{
get { return _P4Depot; }
set { _P4Depot = value; }
}
// Give read-only access to the current connection
public Connection P4Connection
{
get { return _P4Depot.Connection; }
}
// Give read-only access to the current client
public Client P4Client
{
get { return _P4Depot.Connection.Client; }
}
static Server _P4Server;
static Repository _P4Depot;
static int _ConnectionCount;
static DateTime _ConnectedTimestamp;
bool bDisposed;
// Used if display timings is turned on
DateTime _InnerStartTimestamp;
DateTime _StartTimestamp;
List _GetMetaDataTimingInfo;
static PerforceConnection()
{
_ConnectionCount = 0;
}
static bool Disconnected
{
get { return _P4Server == null || _P4Depot == null || _P4Depot.Connection == null || _P4Depot.Connection.Status != ConnectionStatus.Connected; }
}
static bool Connected
{
get { return _P4Server != null && _P4Depot != null && _P4Depot.Connection != null && _P4Depot.Connection.Status == ConnectionStatus.Connected; }
}
static void OpenConnection()
{
if (Disconnected)
{
// Fetch the configuration settings from Config
_P4Server = new Server(new ServerAddress(Config.ServerURI));
_P4Depot = new Repository(_P4Server);
_P4Depot.Connection.UserName = Config.Username;
_P4Depot.Connection.Client = new Client();
_P4Depot.Connection.Client.Name = Config.Workspace;
if (Config.OverrideCharset)
{
System.Environment.SetEnvironmentVariable("P4CHARSET", Config.Charset);
}
if (Config.OverrideHostname)
{
System.Environment.SetEnvironmentVariable("P4HOST", Config.Hostname);
}
if (Config.UseIgnore)
{
System.Environment.SetEnvironmentVariable("P4IGNORE", Config.IgnoreName);
}
// Open the connection, give its log entries a programname and version
Options opts = new Options();
opts.Add("ProgramName", "p4connect");
opts.Add("ProgramVersion", Version.p4ConnectVersion + "." + Version.build);
// opts.Add("cwd", Utils.GetProjectDirectory()); // Don't do this, it triggers p4config hunting
if (_P4Depot.Connection.Connect(opts))
{
// And set the credentials so that we can use secure connections
_P4Depot.Connection.Trust(new TrustCmdOptions(TrustCmdFlags.AutoAccept), "");
_P4Depot.Connection.Credential = _P4Depot.Connection.Login(Config.Password);
_P4Depot.Connection.CommandEcho += CommandEcho;
}
else
{
if (EditorUtility.DisplayDialog("Perforce connection Exception", "P4Connect could not connect to the server and will disable itself to prevent further slow downs\n(You'll need to \"Edit->Perforce Settings\" to turn it back on)\n\nP4Connect can attempt to cancel the current operation for you (to prevent your local files and the depot from going out of sync until you can fix the connection issue). Would you like to try?", "Yes", "No"))
{
Config.NeedToCheckSettings();
throw new Exception("P4Connect - Can't connect to server");
}
else
{
Config.NeedToCheckSettings();
}
}
}
if (_ConnectionCount == 0)
{
// De-register from update
EditorApplication.update -= UpdateConnection;
}
++_ConnectionCount;
}
static void CommandEcho(String data)
{
if (Config.DisplayP4Commands)
{
Debug.Log(data);
}
}
static void UpdateConnection()
{
double deltaTime = (DateTime.Now - _ConnectedTimestamp).TotalSeconds;
if (deltaTime > Config.ConnectionTimeOut)
{
ForceCloseConnection();
}
}
static void CloseConnection()
{
--_ConnectionCount;
if (_ConnectionCount == 0)
{
EditorApplication.update += UpdateConnection;
_ConnectedTimestamp = DateTime.Now;
}
}
public static void ForceCloseConnection()
{
// Close the connection
if (Connected)
{
_P4Depot.Connection.CommandEcho -= CommandEcho;
_P4Depot.Connection.Disconnect();
_P4Depot = null;
_P4Server = null;
// No need to be updated anymore
EditorApplication.update -= UpdateConnection;
}
}
///
/// Create the Perforce connection on construction
///
public PerforceConnection()
{
if (Config.DisplayP4Timings)
{
_StartTimestamp = DateTime.Now;
}
OpenConnection();
_P4Depot.Connection.TaggedOutputReceived += TaggedEcho;
if (Config.DisplayP4Timings)
{
_InnerStartTimestamp = DateTime.Now;
_GetMetaDataTimingInfo = new List();
}
}
public event Action FileEchoReceived;
void TaggedEcho(uint cmdId, int ObjId, TaggedObject Obj)
{
if (FileEchoReceived != null)
{
FileSpec fs = FileSpec.ClientSpec(Obj["clientFile"]);
FileEchoReceived(fs);
}
}
///
/// Dispose of the connection
/// to be safe, use "using" instead of calling this directly
///
public void Dispose()
{
// Simple call the dispose method
Dispose(true);
// Since Dispose cleans up everything, no need to call the finalizer on this
GC.SuppressFinalize(this);
}
///
/// Dispose virtual method
///
protected virtual void Dispose(bool abDisposing)
{
if (!bDisposed)
{
if (abDisposing)
{
_P4Depot.Connection.TaggedOutputReceived -= TaggedEcho;
if (Config.DisplayP4Timings)
{
double deltaInnerTime = (DateTime.Now - _InnerStartTimestamp).TotalMilliseconds;
CloseConnection();
double deltaTime = (DateTime.Now - _StartTimestamp).TotalMilliseconds;
StringBuilder builder = new StringBuilder();
builder.AppendLine("P4Connect - Timing for the last operation: " + deltaTime + " ms (Actual operation: " + deltaInnerTime + " ms)");
if (_GetMetaDataTimingInfo != null)
{
foreach (string line in _GetMetaDataTimingInfo)
{
builder.AppendLine(line);
}
}
Debug.Log(builder.ToString());
}
else
{
CloseConnection();
}
System.Environment.SetEnvironmentVariable("P4HOST", "");
}
bDisposed = true;
}
}
///
/// Used to track down timing issues
///
public void AppendTimingInfo(string aLine)
{
if (_GetMetaDataTimingInfo != null)
{
_GetMetaDataTimingInfo.Add(aLine);
}
}
///
/// Finalizer
///
~PerforceConnection()
{
Dispose(false);
}
}
}