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;
using log4net;
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
{
private static readonly ILog log = LogManager.GetLogger(typeof(PerforceConnection));
// 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 (!String.IsNullOrEmpty(Config.Charset))
{
System.Environment.SetEnvironmentVariable("P4CHARSET", Config.Charset);
}
if (!String.IsNullOrEmpty(Config.Hostname))
{
System.Environment.SetEnvironmentVariable("P4HOST", Config.Hostname);
}
if (!String.IsNullOrEmpty(Config.IgnoreName))
{
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.PerforceReleaseString);
if (_P4Depot.Connection.Connect(Version.ConnectOptions))
{
// 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
{
EditorUtility.DisplayDialog("Perforce connection Exception", "P4Connect could not connect to the server", "OK");
throw new Exception("P4Connect - Can't connect to server");
}
}
if (_ConnectionCount == 0)
{
// De-register from update
EditorApplication.update -= UpdateConnection;
}
++_ConnectionCount;
}
static void CommandEcho(String data)
{
#if DEBUG
log.Debug(data);
#endif
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);
}
}
}