using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Net.Http; using System.Threading.Tasks; using JD.LocalizationExport.Service.API; using JD.LocalizationExport.Service.Model.Options; using Microsoft.Win32; using NUnit; using Plume.Core.Logging; using Plume.Perforce.Service.Api; using Ubisoft.Perforce.Data; namespace JD.Oasis.Module.ViewModel { public class ExportServiceEventsHandler : IDisposable { private readonly string _perforceCodeHost; private readonly string _perforceDataHost; private static readonly HttpClient Client = new HttpClient(); private readonly Dictionary _perforceClientPerExportType; private readonly ILocalizationExportService _exportService; private readonly IPerforceService _perforceService; private readonly ILogger _logger; public ExportServiceEventsHandler(ILocalizationExportService exportService, IPerforceService perforceService, string dataServer, string codeServer, ILogger logger) { _exportService = exportService; _perforceService = perforceService; _logger = logger; _perforceCodeHost = codeServer; _perforceDataHost = dataServer; _perforceClientPerExportType = new Dictionary(); _exportService.ExportEvents.ExportStarted += ExportServiceEvents_ExportStarted; _exportService.ExportEvents.ExportEnded += ExportServiceEvents_ExportEnded; _exportService.ExportEvents.ExportFileStarted += ExportServiceEvents_ExportFileStarted; _exportService.ExportEvents.ExportFileEnded += ExportServiceEvents_ExportFileEnded; } public string ConsoleChangelistName { get; } = "[UI][Update] Update of console localizations"; public string MCAChangelistName { get; } = "[UI][Update] Update of phone localizations"; #region Cleanup public void Dispose() { _exportService.ExportEvents.ExportStarted -= ExportServiceEvents_ExportStarted; _exportService.ExportEvents.ExportEnded -= ExportServiceEvents_ExportEnded; _exportService.ExportEvents.ExportFileStarted -= ExportServiceEvents_ExportFileStarted; _exportService.ExportEvents.ExportFileEnded -= ExportServiceEvents_ExportFileEnded; } #endregion #region Public methods public string RegisterExportTypeAndGetRootPath(ExportType exportType, ExportOptionsModel exportOptions, ExportRepositoryType repositoryType) { string repositoryRoot = null; if (!string.IsNullOrEmpty(exportOptions.DestinationStream)) { _perforceClientPerExportType[exportType] = GetClientFromStream(exportOptions.DestinationStream, repositoryType); repositoryRoot = _perforceClientPerExportType[exportType].Root; } return repositoryRoot; } #endregion #region Export events handlers private Task ExportServiceEvents_ExportStarted(ExportType exportType) { Task returnTask = Task.CompletedTask; bool hasFailed = false; if (_perforceClientPerExportType.ContainsKey(exportType)) { ClientInfo client = _perforceClientPerExportType[exportType]; ExportRepositoryType repositoryType = _exportService.ExportConfigs[exportType].RepositoryType; string host = GetHostFromRepositoryType(repositoryType); string userName = Environment.UserName; string clientName = client.ClientName; string changelistDescription = string.Empty; switch (exportType) { case ExportType.Console: changelistDescription = ConsoleChangelistName; break; case ExportType.MCA: changelistDescription = MCAChangelistName; break; case ExportType.Online: returnTask = Task.FromException(new ArgumentException("There shouldn't be a P4 client for the Online export type", nameof(exportType))); hasFailed = true; break; default: returnTask = Task.FromException(new ArgumentException("Unknown export type", nameof(exportType))); hasFailed = true; break; } if (!hasFailed) { if (_perforceService.Connect(host, userName, clientName)) { _perforceService.CreateNewChangelist(changelistDescription); } else { returnTask = Task.FromException(new Exception($"Unable to connect on the server '{host}' with user '{userName}' on client '{clientName}'.")); } } } return returnTask; } private Task ExportServiceEvents_ExportEnded(ExportType exportType) { _perforceService.Connection?.RevertChangelist(_perforceService.CurrentPendingChangelist.Change, Ubisoft.Perforce.Helper.RevertOptions.UnchangedOnly); return Task.CompletedTask; } private async Task ExportServiceEvents_ExportFileStarted(ExportType exportType, string filePath, Uri requestUri = null) { if (requestUri == null && File.Exists(filePath) && _perforceService.Connection.IsSubmittedInDepot(filePath)) { _perforceService.Connection.OpenForEdit(filePath, _perforceService.CurrentPendingChangelist.Change); } else if (requestUri != null && (requestUri.Scheme == Uri.UriSchemeHttp || requestUri.Scheme == Uri.UriSchemeHttps)) { HttpResponseMessage response = await Client.GetAsync(requestUri); response.EnsureSuccessStatusCode(); using (FileStream stream = File.Create(filePath)) { await response.Content.CopyToAsync(stream); } } } private async Task ExportServiceEvents_ExportFileEnded(ExportType exportType, string filePath, Uri requestUri = null) { if (File.Exists(filePath)) { if (requestUri == null) { List changelistFilesList = _perforceService.CurrentPendingChangelist.FilesList; string fileDepotPath = _perforceService.Connection.WhereOnDepot(filePath); // TODO: Works with new file? (new language) if (!changelistFilesList.Contains(fileDepotPath)) // If file is not checked out, then mark it for add { _perforceService.Connection.OpenForAdd(filePath, _perforceService.CurrentPendingChangelist.Change); _perforceService.Connection.MoveFileToChangelist(fileDepotPath, _perforceService.CurrentPendingChangelist.Change); // Just in case the file is already in another changelist } } else if (requestUri.Scheme == Uri.UriSchemeHttp || requestUri.Scheme == Uri.UriSchemeHttps) { string fileName = Path.GetFileName(filePath); string fileContent = File.ReadAllText(filePath); _logger.Info("Uploading save to server..."); using (MultipartFormDataContent form = new MultipartFormDataContent()) { StringContent fileContentParam = new StringContent(fileContent); form.Add(fileContentParam, "file", fileName); form.Add(new StringContent(Environment.UserName), "author"); HttpResponseMessage response = await Client.PostAsync(requestUri, form); response.EnsureSuccessStatusCode(); } _logger.Info("Save file uploaded"); } } } #endregion #region Perforce helpers private ClientInfo GetClientFromStream(string streamName, ExportRepositoryType repositoryType) { string host = GetHostFromRepositoryType(repositoryType); List clients = _perforceService.RetrieveClients(host, Environment.UserName) .Where(client => Directory.Exists(client.Root) && client.Stream == streamName) .ToList(); if (!clients.Any()) { throw new Exception($"There are no workspaces on the stream '{streamName}' on your machine. Please choose another data stream for the export."); } ClientInfo selectedClient = clients[0]; if (clients.Count > 1) { _logger.Warn($"There are several workspaces for the stream '{streamName}' on your machine."); _logger.Warn($"Selecting {selectedClient.ClientName}."); } return selectedClient; } private string GetHostFromRepositoryType(ExportRepositoryType repositoryType) { string host; switch (repositoryType) { case ExportRepositoryType.Code: host = _perforceCodeHost; break; case ExportRepositoryType.Data: host = _perforceDataHost; break; default: throw new Exception($"Unknown repository type {repositoryType}. Please fix it in {_exportService.ConfigPath}."); } return host; } #endregion } }