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 { /// <summary> /// 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. /// </summary> 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<string> _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)) { Environment.SetEnvironmentVariable("P4CHARSET", Config.Charset); } if (!String.IsNullOrEmpty(Config.Hostname)) { Environment.SetEnvironmentVariable("P4HOST", Config.Hostname); } if (!String.IsNullOrEmpty(Config.IgnoreName)) { Environment.SetEnvironmentVariable("P4IGNORE", Config.IgnoreName); } if (_p4Depot.Connection.Connect(Version.ConnectOptions)) { // And set the credentials so that we can use secure connections _p4Depot.Connection.Credential = _p4Depot.Connection.Login(Config.Password, true); _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; } // Delegate Echos Perforce commands to log static void CommandEcho(String data) { if (Config.EchoP4Commands) { log.Debug(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; } } /// <summary> /// Create the Perforce connection on construction /// </summary> public PerforceConnection() { if (Config.DisplayP4Timings) { _startTimestamp = DateTime.Now; } OpenConnection(); _p4Depot.Connection.TaggedOutputReceived += TaggedEcho; if (Config.DisplayP4Timings) { _innerStartTimestamp = DateTime.Now; _getMetaDataTimingInfo = new List<string>(); } } public event Action<FileSpec> FileEchoReceived; void TaggedEcho(uint cmdId, int ObjId, TaggedObject Obj) { if (FileEchoReceived != null) { FileSpec fs = FileSpec.ClientSpec(Obj["clientFile"]); FileEchoReceived(fs); } } /// <summary> /// Dispose of the connection /// to be safe, use "using" instead of calling this directly /// </summary> 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); } /// <summary> /// Dispose virtual method /// </summary> 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; } } /// <summary> /// Used to track down timing issues /// </summary> public void AppendTimingInfo(string aLine) { if (_getMetaDataTimingInfo != null) { _getMetaDataTimingInfo.Add(aLine); } } /// <summary> /// Finalizer /// </summary> ~PerforceConnection() { Dispose(false); } } }
# | Change | User | Description | Committed | |
---|---|---|---|---|---|
#5 | 19384 | Norman Morse | update from 2016.2 changes in main | ||
#4 | 19129 | Norman Morse |
Merging //guest/perforce_software/p4connect/main/... to //guest/norman_morse/p4connect/main/... |
||
#3 | 18218 | Norman Morse | Working UI generating Perforce StyleSheet, colored buttons and blinking buttons. | ||
#2 | 16631 | Norman Morse | update development branch | ||
#1 | 16251 | Norman Morse | Update Dev branch to match reorganization in workshop | ||
//guest/perforce_software/p4connect/main/src/P4Connect/P4Connect/P4Connect.Connection.cs | |||||
#1 | 16209 | Norman Morse | Move entire source tree into "main" branch so workshop code will act correctly. | ||
//guest/perforce_software/p4connect/src/P4Connect/P4Connect/P4Connect.Connection.cs | |||||
#9 | 15401 | Norman Morse |
Fixed serialization of Config so P4Connect remains connected after a Game Run Cleaned up some menus. |
||
#8 | 15266 | Norman Morse |
Integrated "UpdateVersion" tool to update the VersionInfo and the DLL properties with information from "Version" EC generates the Version file for us in builds. Workshop users need to generate their own Release number with two zeros (like 2015.2.0.0) which will have the last two numbers replaced with change ID. |
||
#7 | 12568 | Norman Morse | Fixed some error handling during Perforce Configuration | ||
#6 | 12553 | Norman Morse |
integrate from internal main Build fixes for EC. Major changes to Configuration and re-initialization code. Bug fixes |
||
#5 | 12512 | Norman Morse | Integrate from Dev branch, preparing for Beta3 release | ||
#4 | 12251 | Norman Morse |
Fixes for Beta 2 release Mostly Configuration dialog bug fixes |
||
#3 | 12135 | Norman Morse |
Integrate dev branch changes into main. This code is the basiis of the 2.7 BETA release which provides Unity 5 compatibility |
||
#2 | 11280 | Norman Morse | Customize API Tags for P4Connect | ||
#1 | 10940 | Norman Morse |
Inital Workshop release of P4Connect. Released under BSD-2 license |