// // Copyright 2014 Perforce Software Inc. // using Perforce.Helper; using Perforce.Model; using Perforce.View; using Perforce.ViewModel; using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Net.Sockets; using System.Text; using System.Threading.Tasks; using System.Web; using System.Windows.Threading; namespace Perforce { public class Utility { // the basic method to retrieve a property in the App context public static object GetProperty(object key) { object value = null; if (key != null && App.Current != null) { value = App.Current.Properties[key]; } return value; } // the basic method to store a property in the App context public static void SetProperty(object key, object value) { if (key != null) { if (App.Current.Properties.Contains(key)) { App.Current.Properties.Remove(key); } App.Current.Properties.Add(key, value); } } public static void ClearProperty(object key) { if (key != null) { App.Current.Properties.Remove(key); } } // helper method to encode a path (i.e. change spaces to make valid URL) public static string EncodePath(string path) { return HttpUtility.UrlPathEncode(path); } // helper method to decode an encoded path public static string DecodePath(string encoded) { return HttpUtility.UrlDecode(encoded); } // helper method to normalize a depot path // - removes the trailing '/' // - removes the trailing '%' (used for doing a 'p4 where' to determine if a directory is mapped) public static string NormalizeDepotPath(string path) { return path.TrimEnd('%') .TrimEnd('/'); } // helper method to normalize a client path // - removes the trailing '%' // - removes the traliing directory separator (\) public static string NormalizeClientPath(string path) { return Path.GetFullPath(new Uri(path).LocalPath) .TrimEnd('%') .TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar); } // helper method to get the UNIX epoch time public static long GetEpochTime() { return GetEpochTime(DateTime.UtcNow); } // helper method to get the UNIX epoch time from a given .net DateTime public static long GetEpochTime(DateTime datetime) { TimeSpan t = datetime.ToUniversalTime() - new DateTime(1970, 1, 1); return (long)t.TotalSeconds; } // METHODS TO CONFIGURE HELPER CLASSES public static PerforceHelper SetupPerforceHelper() { PerforceHelper helper = null; var prefs = Utility.GetUserPreferences(); var p4port = prefs.LastP4Port; var p4user = prefs.LastP4User; var p4client = prefs.LastP4Client; try { if (!string.IsNullOrEmpty(p4port) && !string.IsNullOrEmpty(p4user)) { helper = new PerforceHelper(p4port, p4user); Utility.SetProperty(Constants.PERFORCE_HELPER, helper); if (helper.IsLoggedIn()) { if (!string.IsNullOrEmpty(prefs.LastP4Ticket)) { helper.Ticket = prefs.LastP4Ticket; } if (!string.IsNullOrEmpty(p4client) && helper.ClientExists(p4client)) { helper.SetClient(p4client); helper.CleanChangelist(); // commented out for now // helper.GatherOpenFilesInCurrentChangelist(); Utility.SetupSearchHelper(); Utility.SetupWorkspaceWatcher(); } } } } catch (Perforce.P4.P4Exception p4e) { Console.WriteLine(p4e.Message); } catch (ApplicationException ae) { Console.WriteLine(ae.Message); } return helper; } public static void SetupFavoritesHelper() { var favoritesHelper = GetFavoritesHelper(); if (favoritesHelper == null) { favoritesHelper = new FavoritesHelper(); SetProperty(Constants.FAVORITES_HELPER, favoritesHelper); } } public static void SetupFileMappings() { var extensionHelper = GetExtensionHelper(); if (extensionHelper == null) { extensionHelper = new ExtensionHelper(); SetProperty(Constants.EXTENSION_HELPER, extensionHelper); } } public static void SetupSearchHelper() { var searchHelper = GetSearchHelper(); if (searchHelper == null) { var p4Helper = GetPerforceHelper(check: false); if (p4Helper != null) { var url = p4Helper.GetKey(Constants.P4SEARCH_URL); if (url != null) { searchHelper = new SearchHelper(url); SetProperty(Constants.SEARCH_HELPER, searchHelper); } } } } public static void SetupBackgroundSyncWorker() { var syncWorker = GetSyncBackgroundWorker(); if (syncWorker == null) { syncWorker = new SyncBackgroundWorker(); } } public static void SetupWorkspaceWatcher() { var watchdog = GetWorkspaceWatcher(); if (watchdog == null) { watchdog = new WorkspaceWatcher(); SetProperty(Constants.WATCHDOG, watchdog); } } // BACKGROUND (WORKER) PROCESSES // start up the various background workers public static void StartBackgroundProcesses() { StartSyncWorker(); StartWatchdog(); } // start the sync background worker public static void StartSyncWorker() { var prefs = GetUserPreferences(); if (prefs.SyncEnabled) { var syncWorker = GetSyncBackgroundWorker(); if (syncWorker != null) syncWorker.StartSync(); } } // start the filesystem watcher public static void StartWatchdog() { var watchdog = GetWorkspaceWatcher(); if (watchdog != null) watchdog.Start(); } // shut down the various background workers public static void StopBackgroundProcesses() { StopSyncWorker(); //StopWatchdog(); } public static void StopSyncWorker() { var syncWorker = GetSyncBackgroundWorker(); if (syncWorker != null) syncWorker.StopSync(); } public static void StopWatchdog() { var watchdog = GetWorkspaceWatcher(); if (watchdog != null) watchdog.Stop(); } // CONVENIENCE METHODS TO GET THE VARIOUS HELPER CLASSES public static UserPreferences GetUserPreferences() { var prefs = GetProperty(Constants.USER_PREFERENCES) as UserPreferences; if (prefs == null) { prefs = new UserPreferences(); } return prefs; } public static ExtensionHelper GetExtensionHelper() { return GetProperty(Constants.EXTENSION_HELPER) as ExtensionHelper; } public static FavoritesHelper GetFavoritesHelper() { return GetProperty(Constants.FAVORITES_HELPER) as FavoritesHelper; } public static SyncBackgroundWorker GetSyncBackgroundWorker() { var worker = GetProperty(Constants.SYNC_WORKER) as SyncBackgroundWorker; if (worker == null) { worker = new SyncBackgroundWorker(); } return worker; } public static WorkspaceWatcher GetWorkspaceWatcher() { return GetProperty(Constants.WATCHDOG) as WorkspaceWatcher; } public static SearchHelper GetSearchHelper() { return GetProperty(Constants.SEARCH_HELPER) as SearchHelper; } public static ToolBarViewModel GetToolBarViewModel() { return GetProperty(Constants.TOOLBAR_VIEWMODEL) as ToolBarViewModel; } public static PerforceHelper GetPerforceHelper(bool check = true) { var helper = GetProperty(Constants.PERFORCE_HELPER) as PerforceHelper; if (check && helper != null) { var alive = helper.IsConnected(); if (!alive) { // stop the background workers StopBackgroundProcesses(); // use a dispatcher to invoke the dialog to determine if there are issues App.Current.Dispatcher.Invoke(DispatcherPriority.Normal, new Action(() => { var main = App.Current.MainWindow as MainWindow; var dialog = main.DialogManager.CreateMessageDialog("Server is not reachable. What do you want to do?", Technewlogic.WpfDialogManagement.DialogMode.YesNo); dialog.VerticalDialogAlignment = System.Windows.VerticalAlignment.Top; dialog.YesText = "Relaunch"; dialog.NoText = "Shutdown"; dialog.Yes = () => { // clear the ticket, if it is currently set var userprefs = Utility.GetUserPreferences(); userprefs.LastP4Ticket = string.Empty; userprefs.Save(); // restart the application -- this starts a new copy of the application System.Windows.Forms.Application.Restart(); // shutdown the current application System.Windows.Application.Current.Shutdown(); }; dialog.No = () => { System.Windows.Application.Current.Shutdown(); }; dialog.Show(); })); } } return helper; } public static SortedSet GetRecentSet() { var set = GetProperty(Constants.RECENT_LIST) as SortedSet; if (set == null) { set = new SortedSet(); SetProperty(Constants.RECENT_LIST, set); } return set; } public static List GetRecentList() { return GetRecentSet().ToList(); } public static LogWindow GetLogWindow() { var lw = GetProperty(Constants.LOG_WINDOW) as LogWindow; if (lw == null || !lw.IsOpen) { lw = new LogWindow(); SetProperty(Constants.LOG_WINDOW, lw); } return lw; } public static void CopyDirectory(string sourcePath, string destPath) { if (!Directory.Exists(destPath)) { Directory.CreateDirectory(destPath); } foreach (string file in Directory.GetFiles(sourcePath)) { CopyFileToDirectory(file, destPath); } foreach (string folder in Directory.GetDirectories(sourcePath)) { string dest = Path.Combine(destPath, Path.GetFileName(folder)); CopyDirectory(folder, dest); } } // CopyFileToDirectory -- copies file to a directory, adding (Copy n) to the filename. public static string CopyFileToDirectory(string filePath, string destDirPath, string filename = null) { Log.Debug(string.Format("Copying {0} -> {1}", filePath, destDirPath)); if (!Directory.Exists(destDirPath)) { Directory.CreateDirectory(destDirPath); } if (string.IsNullOrEmpty(filename)) { filename = Path.GetFileName(filePath); } var filenameWithoutExtension = Path.GetFileNameWithoutExtension(filename); var extension = Path.GetExtension(filename); var copynum = 0; var destFilePath = Path.Combine(destDirPath, filename); while (File.Exists(destFilePath)) { copynum++; var newFilename = string.Format("{0} (Copy){1}", filenameWithoutExtension, extension); if (copynum > 1) { newFilename = string.Format("{0} (Copy {1}){2}", filenameWithoutExtension, copynum, extension); } destFilePath = Path.Combine(destDirPath, newFilename); } File.Copy(filePath, destFilePath); return destFilePath; } public static bool CheckTCPConnection(string p4port = null, int timeout = 1) { var canPing = false; if (string.IsNullOrEmpty(p4port)) { var userPrefs = GetUserPreferences(); p4port = userPrefs.LastP4Port; } if (!string.IsNullOrEmpty(p4port)) { // remove ssl prefix if present if (p4port.StartsWith("ssl:")) { p4port = p4port.Substring(4); } var parts = p4port.Split(':'); if (parts.Length != 2) return canPing; var host = parts[0]; var port = Int32.Parse(parts[1]); var tcpClient = new TcpClient(); tcpClient.ReceiveTimeout = 2000; try { var result = tcpClient.BeginConnect(host, port, null, null); var success = result.AsyncWaitHandle.WaitOne(TimeSpan.FromSeconds(timeout)); if (!success) { throw new Exception("Failed to connect."); } // we have connected tcpClient.EndConnect(result); canPing = true; } catch (Exception e) { Console.WriteLine("CONNECTION {0}:{1} FAILED", host, port); } finally { tcpClient.Close(); } } return canPing; } } }