From 20a469d3cd21a452a854fcc0e56df48a7632b507 Mon Sep 17 00:00:00 2001 From: =?utf8?q?V=C3=A1s=C3=A1ry=20D=C3=A1niel?= Date: Thu, 16 Nov 2017 23:00:43 +0000 Subject: [PATCH] git-tfs-id: [http://tfs.userrendszerhaz.hu:8080/tfs/DefaultCollection]$/MediaCube;C30738 --- client/DxPlay/DxPlay.csproj | 6 +- .../IntegrationTests/IntegrationTests.csproj | 4 + client/IntegrationTests/MaestroIT.cs | 12 +- client/Maestro/Maestro.csproj | 27 +- client/Maestro/MaestroForm.Metadata.cs | 14 +- client/Maestro/MaestroForm.Source.cs | 24 +- client/Maestro/MaestroForm.Target.cs | 29 +- client/Maestro/MaestroForm.cs | 8 +- client/Maestro/MeastroFormNotifyIcon.cs | 2 +- client/Maestro/Program.cs | 16 +- .../Configuration/ConfigurationInfo.cs | 2 +- .../Configuration/KeysJsonConverter.cs | 2 +- .../Configuration/KnownTypesBinder.cs | 2 +- client/MaestroShared/MaestroShared.csproj | 104 +++++ .../MaestroShared/Metadata/ArchiveMetadata.cs | 47 +++ .../Metadata/MetadataType.cs | 2 +- .../Metadata}/MovieSegment.cs | 2 +- .../Metadata}/Timecode.cs | 3 +- .../MaestroShared/Properties/AssemblyInfo.cs | 36 ++ .../Targets/FTPTargetProcessor.cs | 152 ++++++++ .../Targets/FXPTargetProcessor.cs | 116 ++++++ .../MaestroShared/Targets/ITargetProcessor.cs | 19 + .../MaestroShared/Targets/TargetProcessor.cs | 196 ++++++++++ .../Targets/TargetProcessorParameter.cs | 23 ++ .../Targets/UNCTargetProcessor.cs | 357 ++++++++++++++++++ client/MaestroShared/packages.config | 6 + client/MediaCube.sln | 19 +- client/MediaCubeClient/Model/Model.cs | 11 +- .../build-remote-sqlj.bat | 7 +- .../database/structure.sql | 2 + server/user.jobengine.osgi.db/settings.bat | 19 - .../sql/2-CreateStructure.db2 | 1 + .../src/user/jobengine/db/WorkflowAction.java | 85 +++-- .../user/jobengine/db/WorkflowActionDAO.sqlj | 15 +- 34 files changed, 1205 insertions(+), 165 deletions(-) rename client/{Maestro => MaestroShared}/Configuration/ConfigurationInfo.cs (96%) rename client/{Maestro => MaestroShared}/Configuration/KeysJsonConverter.cs (91%) rename client/{Maestro => MaestroShared}/Configuration/KnownTypesBinder.cs (90%) create mode 100644 client/MaestroShared/MaestroShared.csproj create mode 100644 client/MaestroShared/Metadata/ArchiveMetadata.cs rename client/{Maestro => MaestroShared}/Metadata/MetadataType.cs (87%) rename client/{DxPlay => MaestroShared/Metadata}/MovieSegment.cs (82%) rename client/{DxPlay => MaestroShared/Metadata}/Timecode.cs (95%) create mode 100644 client/MaestroShared/Properties/AssemblyInfo.cs create mode 100644 client/MaestroShared/Targets/FTPTargetProcessor.cs create mode 100644 client/MaestroShared/Targets/FXPTargetProcessor.cs create mode 100644 client/MaestroShared/Targets/ITargetProcessor.cs create mode 100644 client/MaestroShared/Targets/TargetProcessor.cs create mode 100644 client/MaestroShared/Targets/TargetProcessorParameter.cs create mode 100644 client/MaestroShared/Targets/UNCTargetProcessor.cs create mode 100644 client/MaestroShared/packages.config delete mode 100644 server/user.jobengine.osgi.db/settings.bat diff --git a/client/DxPlay/DxPlay.csproj b/client/DxPlay/DxPlay.csproj index 504dc315..e83e3db1 100644 --- a/client/DxPlay/DxPlay.csproj +++ b/client/DxPlay/DxPlay.csproj @@ -191,7 +191,6 @@ Component - @@ -208,7 +207,6 @@ True StringResource.resx - Component @@ -268,6 +266,10 @@ + + {d4417174-f21e-4ce2-ae5c-8eb30c9a9625} + MaestroShared + {bf494ee9-1e70-44e8-8942-dd726510a766} MXFFileParser diff --git a/client/IntegrationTests/IntegrationTests.csproj b/client/IntegrationTests/IntegrationTests.csproj index e086cdb7..0b541ad5 100644 --- a/client/IntegrationTests/IntegrationTests.csproj +++ b/client/IntegrationTests/IntegrationTests.csproj @@ -158,6 +158,10 @@ {0b44b3d7-52d7-4c0e-9b1c-f48ceeda36fe} DxPlay + + {d4417174-f21e-4ce2-ae5c-8eb30c9a9625} + MaestroShared + {baf3e174-5d82-40fa-9e62-8c76adbea1e4} Maestro diff --git a/client/IntegrationTests/MaestroIT.cs b/client/IntegrationTests/MaestroIT.cs index 6615d49e..ea881c89 100644 --- a/client/IntegrationTests/MaestroIT.cs +++ b/client/IntegrationTests/MaestroIT.cs @@ -1,21 +1,19 @@ -using Maestro.Configuration; -using Maestro.Targets; -using Maestro; -using Microsoft.VisualStudio.TestTools.UnitTesting; +using Microsoft.VisualStudio.TestTools.UnitTesting; using System; -using Maestro.Commons; using System.Diagnostics; using SharpCifs.Smb; -using Commons; using System.Runtime.InteropServices; using Microsoft.Win32.SafeHandles; using System.Runtime.ConstrainedExecution; using System.Security; -using BethesdaConsentFormWCFSvc; using System.IO; using System.Text.RegularExpressions; using MySql.Data.MySqlClient; using System.Text; +using MaestroShared.Configuration; +using MaestroShared.Commons; +using MaestroShared.Targets; +using MaestroShared.Target; namespace IntegrationTests { public sealed class SafeTokenHandle : SafeHandleZeroOrMinusOneIsInvalid { diff --git a/client/Maestro/Maestro.csproj b/client/Maestro/Maestro.csproj index 18a7638b..e38d6009 100644 --- a/client/Maestro/Maestro.csproj +++ b/client/Maestro/Maestro.csproj @@ -164,15 +164,8 @@ ArchiveMetadataForm.cs - - - - - - - Form @@ -182,13 +175,13 @@ Form - - + + Form + Component - Form @@ -222,12 +215,6 @@ - - - - - - ArchiveMetadataForm.cs @@ -324,6 +311,10 @@ {0b44b3d7-52d7-4c0e-9b1c-f48ceeda36fe} DxPlay + + {d4417174-f21e-4ce2-ae5c-8eb30c9a9625} + MaestroShared + {cefd0348-ded4-453e-bf3a-0b52f8890ab3} MediaCubeClient @@ -332,10 +323,6 @@ {8cc7c930-9dbf-487b-aed5-776937a649d5} OctopusClient - - {8c51d508-1759-4c10-84a4-80965fd074ff} - PasswordEncrypter - {a7a21311-cb0e-465f-8ad6-829faf093f00} TrafficClient diff --git a/client/Maestro/MaestroForm.Metadata.cs b/client/Maestro/MaestroForm.Metadata.cs index 0b81ad46..48213df3 100644 --- a/client/Maestro/MaestroForm.Metadata.cs +++ b/client/Maestro/MaestroForm.Metadata.cs @@ -1,5 +1,4 @@ -using Maestro.Configuration; -using Maestro.Metadata; +using Maestro.Metadata; using OctopusClient; using System.Linq; using System; @@ -11,6 +10,8 @@ using System.ComponentModel; using System.Text.RegularExpressions; using MediaCubeClient; using Model; +using MaestroShared.Configuration; +using MaestroShared.Metadata; namespace Maestro { public partial class MaestroForm { @@ -405,7 +406,8 @@ namespace Maestro { private void Lookup(string id) { MetadataProvider config = null; - switch (SelectedMetadata?.Kind) { + MetadataType metadataType = GuessMetadataType(id); + switch (metadataType) { case MetadataType.TrafficAD: case MetadataType.TrafficMaterial: case MetadataType.TrafficPromo: @@ -417,13 +419,15 @@ namespace Maestro { config = Configuration.GetMetadataProvider(); if (config == null) return; - octopusIDSelector.LookupByPlaceHolder(id); + if (!octopusIDSelector.LookupByPlaceHolder(id)) + MessageBox.Show("Nincs találat."); break; case MetadataType.OctopusStory: config = Configuration.GetMetadataProvider(); if (config == null) return; - octopusIDSelector.LookupByStory(id); + if (!octopusIDSelector.LookupByStory(id)) + MessageBox.Show("Nincs találat."); break; } } diff --git a/client/Maestro/MaestroForm.Source.cs b/client/Maestro/MaestroForm.Source.cs index b631363b..1f0ee28f 100644 --- a/client/Maestro/MaestroForm.Source.cs +++ b/client/Maestro/MaestroForm.Source.cs @@ -1,15 +1,14 @@ using DxPlay; -using Maestro.Configuration; using Maestro.Metadata; using Maestro.Sources; -using Maestro.Sources.Messages; +using MaestroShared.Configuration; +using MaestroShared.Metadata; using System; using System.Collections.Generic; using System.Drawing; using System.IO; using System.Linq; using System.Windows.Forms; -using TrafficClient; namespace Maestro { @@ -90,6 +89,7 @@ namespace Maestro { if (selectedrows == null) return; if (e.ColumnIndex == 0) { + UpdateCheckStates(selectedrows); return; } @@ -205,23 +205,7 @@ namespace Maestro { } private void OnLookupBySource(object sender, EventArgs e) { - Lookup(SelectedMetadata.ID); - //Cursor.Current = Cursors.WaitCursor; - //MetadataType metadataType = GuessMetadataType(SelectedSource?.Prefix); - //switch (metadataType) { - // case MetadataType.TrafficMaterial: - // case MetadataType.TrafficPromo: - // case MetadataType.TrafficAD: - // LookupTraffic(metadataType); - // break; - // case MetadataType.OctopusPlaceHolder: - // LookupOctopus(); - // break; - //} - //trafficIDSelector.ClearSelection(); - //octopusIDSelector.ClearSelection(); - - //Cursor.Current = Cursors.Default; + Lookup(SelectedSource.Prefix); } private void picClearFilter_Click(object sender, EventArgs e) { diff --git a/client/Maestro/MaestroForm.Target.cs b/client/Maestro/MaestroForm.Target.cs index d16c82ce..2ae663c6 100644 --- a/client/Maestro/MaestroForm.Target.cs +++ b/client/Maestro/MaestroForm.Target.cs @@ -1,33 +1,17 @@ -using Maestro.Configuration; -using Maestro.Sources; -using Maestro.Targets; +using Maestro.Sources; using System; using System.Linq; using System.Windows.Forms; using Maestro.Metadata; using System.Collections.Generic; using TrafficClient; -using MediaCubeClient; -using DxPlay; +using MaestroShared.Configuration; +using MaestroShared.Metadata; +using MaestroShared.Targets; +using MaestroShared.Target; namespace Maestro { - public class TargetProcessorParameter { - public Source SourceConfig { get; set; } - public Target TargetConfig { get; set; } - public string InputFileName { get; set; } - public string ID { get; set; } - public string MetadataText { get; set; } - public List Segments { get; set; } - public List MovieSegments { get; set; } - public MediaCubeApi MediaCubeApi { get; set; } - public ArchiveMetadata ArchiveMetadata { get; set; } - public TrafficAPI TrafficApi { get; set; } - public int VariantID { get; set; } - - public MetadataType MetadataKind { get; set; } - } - public partial class MaestroForm { private SegmentConverter segmentConverter; @@ -164,7 +148,8 @@ namespace Maestro { MovieSegments = movieSegments == null ? null : movieSegments.ToList(), ArchiveMetadata = ArchiveMetadata.DeepClone(archiveMetadata), VariantID = selectedMetadata == null ? 0 : selectedMetadata.VariantID, - MetadataKind = selectedMetadata == null ? MetadataType.None : selectedMetadata.Kind + MetadataKind = selectedMetadata == null ? MetadataType.None : selectedMetadata.Kind, + UserName = TrayApplicationContext.UserName }; } diff --git a/client/Maestro/MaestroForm.cs b/client/Maestro/MaestroForm.cs index 50081ba6..8635e3c4 100644 --- a/client/Maestro/MaestroForm.cs +++ b/client/Maestro/MaestroForm.cs @@ -1,7 +1,4 @@ using LinkDotNet.MessageHandling.Contracts; -using Maestro.Commons; -using Maestro.Configuration; -using Maestro.Targets; using NLog; using System; using System.Collections.Concurrent; @@ -15,6 +12,9 @@ using OctopusClient; using System.IO; using MediaCubeClient; using LinkDotNet.MessageHandling; +using MaestroShared.Configuration; +using MaestroShared.Targets; +using MaestroShared.Commons; namespace Maestro { @@ -87,7 +87,7 @@ namespace Maestro { private void OnMessage(IMessage message) { var pi = message.GetType().GetProperty("Content"); string text = pi.GetValue(message) as string; - ObjectExtensions.SafeCall(dgMessages, () => { + dgMessages.SafeCall(() => { systemMessageBindingSource.Insert(0, new SystemMessage() { Time = DateTime.Now, Message = text }); ActivateTab(1); }); diff --git a/client/Maestro/MeastroFormNotifyIcon.cs b/client/Maestro/MeastroFormNotifyIcon.cs index 97f8f204..8afff418 100644 --- a/client/Maestro/MeastroFormNotifyIcon.cs +++ b/client/Maestro/MeastroFormNotifyIcon.cs @@ -1,6 +1,6 @@ using LinkDotNet.MessageHandling.Contracts; -using Maestro.Configuration; using Maestro.Sources.Messages; +using MaestroShared.Configuration; using System; using System.Windows.Forms; diff --git a/client/Maestro/Program.cs b/client/Maestro/Program.cs index 5746cdb2..a4c70ac8 100644 --- a/client/Maestro/Program.cs +++ b/client/Maestro/Program.cs @@ -1,8 +1,7 @@ using LinkDotNet.MessageHandling; using LinkDotNet.MessageHandling.Contracts; -using Maestro.Commons; -using Maestro.Configuration; using Maestro.Properties; +using MaestroShared.Configuration; using NLog; using System; using System.Collections.Concurrent; @@ -87,6 +86,8 @@ namespace Maestro { private ConcurrentBag forms = new ConcurrentBag(); private IMessageBus messageBus = new MessageBus(); + public static string UserName { get; set; } + public TrayApplicationContext() { string str = Regex.Replace("Aéá.ú-óüöA", "[^0-9A-Za-z-._]", "_"); Debug.WriteLine(str); @@ -136,10 +137,11 @@ namespace Maestro { } private bool IsDomainUser(string userName, string domainName) { - string[] domain = userName.Split('\\'); - if (domain.Length < 2) + string[] userInfo = userName.Split('\\'); + if (userInfo.Length < 2) throw new Exception(DOMAIN_QUERY_ERROR); - string userDomainName = domain[0]; + string userDomainName = userInfo[0]; + UserName = userInfo[1]; if (userDomainName.Contains(".")) userDomainName = userDomainName.Split('.')[0]; if (domainName.ToLower().Equals(userDomainName.ToLower())) @@ -164,8 +166,10 @@ namespace Maestro { using (PrincipalContext pc = new PrincipalContext(ContextType.Domain, domainName)) { while (true) { bool isValid = pc.ValidateCredentials(userName, password); - if (isValid) + if (isValid) { + UserName = userName; break; + } if (loginForm == null) loginForm = new LoginForm(); diff --git a/client/Maestro/Configuration/ConfigurationInfo.cs b/client/MaestroShared/Configuration/ConfigurationInfo.cs similarity index 96% rename from client/Maestro/Configuration/ConfigurationInfo.cs rename to client/MaestroShared/Configuration/ConfigurationInfo.cs index 876ffa75..95b89b0a 100644 --- a/client/Maestro/Configuration/ConfigurationInfo.cs +++ b/client/MaestroShared/Configuration/ConfigurationInfo.cs @@ -4,7 +4,7 @@ using System.Linq; using System.Collections.Generic; using System.IO; -namespace Maestro.Configuration { +namespace MaestroShared.Configuration { public class Loader { public static T Get(string fileName) { diff --git a/client/Maestro/Configuration/KeysJsonConverter.cs b/client/MaestroShared/Configuration/KeysJsonConverter.cs similarity index 91% rename from client/Maestro/Configuration/KeysJsonConverter.cs rename to client/MaestroShared/Configuration/KeysJsonConverter.cs index e24d6872..9a712f85 100644 --- a/client/Maestro/Configuration/KeysJsonConverter.cs +++ b/client/MaestroShared/Configuration/KeysJsonConverter.cs @@ -2,7 +2,7 @@ using PasswordEncrypter; using System; -namespace Maestro.Configuration { +namespace MaestroShared.Configuration { public class KeysJsonConverter : JsonConverter { public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) { } diff --git a/client/Maestro/Configuration/KnownTypesBinder.cs b/client/MaestroShared/Configuration/KnownTypesBinder.cs similarity index 90% rename from client/Maestro/Configuration/KnownTypesBinder.cs rename to client/MaestroShared/Configuration/KnownTypesBinder.cs index 19b41f51..606bb339 100644 --- a/client/Maestro/Configuration/KnownTypesBinder.cs +++ b/client/MaestroShared/Configuration/KnownTypesBinder.cs @@ -3,7 +3,7 @@ using System; using System.Collections.Generic; using System.Linq; -namespace Maestro.Configuration { +namespace MaestroShared.Configuration { public class KnownTypesBinder : ISerializationBinder { public IList KnownTypes { get; set; } diff --git a/client/MaestroShared/MaestroShared.csproj b/client/MaestroShared/MaestroShared.csproj new file mode 100644 index 00000000..27d07984 --- /dev/null +++ b/client/MaestroShared/MaestroShared.csproj @@ -0,0 +1,104 @@ + + + + + Debug + AnyCPU + {D4417174-F21E-4CE2-AE5C-8EB30C9A9625} + Library + Properties + MaestroShared + MaestroShared + v4.6.1 + 512 + SAK + SAK + SAK + SAK + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + ..\packages\FluentFTP.19.1.2\lib\net45\FluentFTP.dll + + + ..\packages\Newtonsoft.Json.10.0.3\lib\net45\Newtonsoft.Json.dll + + + ..\packages\NLog.4.4.12\lib\net45\NLog.dll + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {cefd0348-ded4-453e-bf3a-0b52f8890ab3} + MediaCubeClient + + + {8cc7c930-9dbf-487b-aed5-776937a649d5} + OctopusClient + + + {8c51d508-1759-4c10-84a4-80965fd074ff} + PasswordEncrypter + + + {a7a21311-cb0e-465f-8ad6-829faf093f00} + TrafficClient + + + + \ No newline at end of file diff --git a/client/MaestroShared/Metadata/ArchiveMetadata.cs b/client/MaestroShared/Metadata/ArchiveMetadata.cs new file mode 100644 index 00000000..15e42ece --- /dev/null +++ b/client/MaestroShared/Metadata/ArchiveMetadata.cs @@ -0,0 +1,47 @@ +using System; +using Newtonsoft.Json; +using System.Runtime.Serialization.Formatters.Binary; +using System.IO; + +namespace MaestroShared.Metadata { + + [Serializable()] + public class ArchiveMetadata { + + //todo rename a Stuffra?? + public string itemHouseId { get; set; } + public string itemTitle { get; set; } + public string itemDescription { get; set; } + public string mediaHouseId { get; set; } + public string mediaTitle { get; set; } + public string mediaDescription { get; set; } + + public override string ToString() { + return JsonConvert.SerializeObject(this); + //return String.Format("{{\n \"Anyag azonosító\": \"{0}\",\n, \"Anyag cím\": \"{1}\",\n \"Anyag leírása\": \"{2}\",\n \"Média azonosító\": \"{3}\",\n \"Média cím\": \"{4}\",\n \"Média leírás\": \"{5}\" \n}}", + // StuffID, StuffTitle, StuffDescription, MediaID, MediaTitle, MediaDescription); + } + + [JsonIgnore] + public bool IsFilled { + get { + return + !String.IsNullOrEmpty(itemHouseId) && + !String.IsNullOrEmpty(itemTitle) && + !String.IsNullOrEmpty(mediaHouseId) && + !String.IsNullOrEmpty(mediaTitle); + } + } + + public static ArchiveMetadata DeepClone(ArchiveMetadata obj) { + if (obj == null) + return null; + using (var ms = new MemoryStream()) { + var formatter = new BinaryFormatter(); + formatter.Serialize(ms, obj); + ms.Position = 0; + return (ArchiveMetadata)formatter.Deserialize(ms); + } + } + } +} diff --git a/client/Maestro/Metadata/MetadataType.cs b/client/MaestroShared/Metadata/MetadataType.cs similarity index 87% rename from client/Maestro/Metadata/MetadataType.cs rename to client/MaestroShared/Metadata/MetadataType.cs index 67a96adf..5d54ef7a 100644 --- a/client/Maestro/Metadata/MetadataType.cs +++ b/client/MaestroShared/Metadata/MetadataType.cs @@ -1,6 +1,6 @@ using TrafficClient; -namespace Maestro.Metadata { +namespace MaestroShared.Metadata { public enum MetadataType { None = 6, MediaCube = 5, OctopusStory = 4, OctopusPlaceHolder = 3, TrafficMaterial = TrafficMetadataType.TrafficMaterial, TrafficPromo = TrafficMetadataType.TrafficPromo, TrafficAD = TrafficMetadataType.TrafficAD } diff --git a/client/DxPlay/MovieSegment.cs b/client/MaestroShared/Metadata/MovieSegment.cs similarity index 82% rename from client/DxPlay/MovieSegment.cs rename to client/MaestroShared/Metadata/MovieSegment.cs index 935fbe93..92827c0d 100644 --- a/client/DxPlay/MovieSegment.cs +++ b/client/MaestroShared/Metadata/MovieSegment.cs @@ -1,4 +1,4 @@ -namespace DxPlay { +namespace MaestroShared.Metadata { public class MovieSegment { public Timecode TCIn { get; set; } public Timecode TCOut { get; set; } diff --git a/client/DxPlay/Timecode.cs b/client/MaestroShared/Metadata/Timecode.cs similarity index 95% rename from client/DxPlay/Timecode.cs rename to client/MaestroShared/Metadata/Timecode.cs index a8142773..6d92c1f1 100644 --- a/client/DxPlay/Timecode.cs +++ b/client/MaestroShared/Metadata/Timecode.cs @@ -1,7 +1,6 @@ using System; -using System.Diagnostics; -namespace DxPlay { +namespace MaestroShared.Metadata { public class Timecode { private const int MEDIATIME_REFERENCE = 10000000; internal float frameRate = 0; diff --git a/client/MaestroShared/Properties/AssemblyInfo.cs b/client/MaestroShared/Properties/AssemblyInfo.cs new file mode 100644 index 00000000..14af195f --- /dev/null +++ b/client/MaestroShared/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("MaestroShared")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("MaestroShared")] +[assembly: AssemblyCopyright("Copyright © 2017")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("d4417174-f21e-4ce2-ae5c-8eb30c9a9625")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/client/MaestroShared/Targets/FTPTargetProcessor.cs b/client/MaestroShared/Targets/FTPTargetProcessor.cs new file mode 100644 index 00000000..9819fb85 --- /dev/null +++ b/client/MaestroShared/Targets/FTPTargetProcessor.cs @@ -0,0 +1,152 @@ +using FluentFTP; +using MaestroShared.Configuration; +using MaestroShared.Target; +using NLog; +using System; +using System.IO; +using System.Linq; +using System.Net; +using System.Windows.Forms; + +namespace MaestroShared.Targets { + + public class FTPTargetProcessor : UNCTargetProcessor { + private const string PATTERN_CONCAT = "{0}{1}"; + private const string _226 = "226"; + private const string UPLOAD_ERROR = "Feltöltési hiba."; + private readonly Logger logger = LogManager.GetCurrentClassLogger(); + protected FtpClient targetFTP; + + public FTPTargetProcessor(Control parent, TargetProcessorParameter parameters) + : base(parent, parameters) { + FtpTrace.LogFunctions = false; + if (!(parameters.SourceConfig is UNCSource)) { + inputFile = null; + Uri inputUri = new Uri(String.Format(PATTERN_CONCAT, parameters.SourceConfig.Remote.Address, parameters.InputFileName)); + Input = inputUri.ToString(); + } + } + + protected override void BeforeExecute() { + base.BeforeExecute(); + targetFTP = CreateClient(parameters.TargetConfig.Remote); + } + + protected override void AfterExecute() { + base.AfterExecute(); + TerminateClient(targetFTP); + } + + protected override void DeleteFile(string currentFile) { + targetFTP.DeleteFile(currentFile); + } + + protected override void UploadFile() { + using (FileStream istream = File.OpenRead(Input)) { + using (Stream ostream = targetFTP.OpenWrite(OutputName)) { + try { + CopyStream(istream, inputFile.Length, ostream); + } + catch (Exception e) { + logger.Error(e.Message); + throw e; + } + finally { + ostream.Close(); + } + } + } + FtpReply reply = targetFTP.GetReply(); + if (!reply.Success || !_226.Equals(reply.Code)) { + throw new Exception(UPLOAD_ERROR); + } + } + + protected void reconnect() { + TerminateClient(targetFTP); + targetFTP = CreateClient(parameters.TargetConfig.Remote); + EnsureDirectoryExistence(workingDir); + } + + protected override void UploadContent(string outputPath, byte[] content) { + using (Stream ostream = targetFTP.OpenWrite(outputPath, FtpDataType.Binary, false)) { + try { + ostream.Write(content, 0, content.Length); + } + catch (Exception e) { + logger.Error(e.Message); + throw e; + } + finally { + ostream.Close(); + } + } + FtpReply reply = targetFTP.GetReply(); + if (!reply.Success || !_226.Equals(reply.Code)) { + throw new Exception(UPLOAD_ERROR); + } + } + + protected override bool FileExists(string path) { + long x = -1; + try { + x = targetFTP.GetFileSize(path); + } + catch (Exception e) { + logger.Warn(e.Message); + } + return x > -1; + } + + protected override string GetOutputFilePath(string path, string fileName) { + return fileName; + } + + protected override void EnsureDirectoryExistence(string path) { + if (!targetFTP.DirectoryExists(path)) + targetFTP.CreateDirectory(path, true); + targetFTP.SetWorkingDirectory(path); + } + + protected FtpClient CreateClient(Connection connection) { + Uri address = connection.Address; + FtpClient result = new FtpClient() { + Host = address.Host, + Port = address.Port, + InternetProtocolVersions = FtpIpVersion.IPv4, + UploadDataType = FtpDataType.Binary, + DownloadDataType = FtpDataType.Binary, + Credentials = new NetworkCredential(connection.UserName, connection.Password) + }; + result.Connect(); + return result; + } + + protected override string DetermineWorkingDirectory(Connection connection) { + string result = null; + if (!String.IsNullOrEmpty(parameters.TargetConfig.SubFolderFormat)) { + string name = GetDynamicName(parameters.TargetConfig.SubFolderFormat); + //TODO ellenőrizni, hogy mi van placeholder esetén + if (parameters.TargetConfig.SubFolderFormat.Contains(PATTERN_TEXT)) { + string pattern = name.Split(HYPHEN[0])[0] + HYPHEN; + targetFTP.SetWorkingDirectory(connection.Address.LocalPath); + FtpListItem item = targetFTP.GetListing()?.Where(i => i.Type.Equals(FtpFileSystemObjectType.Directory) && i.Name.StartsWith(pattern)).FirstOrDefault(); + if (item != null) + name = item.Name; + targetFTP.SetWorkingDirectory(SLASH); + } + result = Path.Combine(connection.Address.LocalPath, name); + } else + result = connection.Address.LocalPath; + return result; + } + + protected void TerminateClient(FtpClient ftpClient) { + if (ftpClient != null) { + ftpClient.Disconnect(); + ftpClient.Dispose(); + } + } + + } +} diff --git a/client/MaestroShared/Targets/FXPTargetProcessor.cs b/client/MaestroShared/Targets/FXPTargetProcessor.cs new file mode 100644 index 00000000..89d2ed2f --- /dev/null +++ b/client/MaestroShared/Targets/FXPTargetProcessor.cs @@ -0,0 +1,116 @@ +using FluentFTP; +using MaestroShared.Configuration; +using MaestroShared.Target; +using NLog; +using System; +using System.IO; +using System.Text.RegularExpressions; +using System.Threading; +using System.Windows.Forms; + +namespace MaestroShared.Targets { + + public class FXPTargetProcessor : FTPTargetProcessor { + private const string LITERAL_SPACE = "%20"; + private const string SPACE = " "; + private Logger logger = LogManager.GetCurrentClassLogger(); + private Source sourceConfig; + Uri inputUri; + + public FXPTargetProcessor(Control parent, TargetProcessorParameter parameters) : + base(parent, parameters) { + sourceConfig = parameters.SourceConfig; + //inputUri = new Uri(String.Format("{0}/{1}", parameters.SourceConfig.Remote.Address, parameters.InputFileName)); + inputUri = new Uri(Path.Combine(parameters.SourceConfig.Remote.Address.ToString(), parameters.InputFileName)); + Input = inputUri.ToString(); + } + + protected override void UploadFile() { + FtpClient sourceFTP = null; + FtpClient monitorFTP = null; + + try { + sourceFTP = CreateClient(sourceConfig.Remote); + + string input = inputUri.AbsolutePath.Replace(LITERAL_SPACE, SPACE); + long ilength = sourceFTP.GetFileSize(input); + if (parameters.TargetConfig.NexioServer) + ilength = ilength / 2; + + FtpReply replyPASV = targetFTP.Execute("PASV"); + if (!replyPASV.Success) + throw new Exception(replyPASV.ErrorMessage); + + Regex regex = new Regex(Regex.Escape("(") + "(.*)" + Regex.Escape(")")); + var v = regex.Match(replyPASV.Message); + string port = v.Groups[1].ToString(); + + FtpReply replyPORT = sourceFTP.Execute("PORT " + port); + if (!replyPORT.Success) + throw new Exception(replyPORT.ErrorMessage); + + + FtpReply sourceReplyTYPE = sourceFTP.Execute("TYPE I"); + if (!sourceReplyTYPE.Success) + throw new Exception(sourceReplyTYPE.ErrorMessage); + + if (input.LastIndexOf("/") == 0) + input = input.Replace("/", ""); + FtpReply replyRETR = sourceFTP.Execute("RETR " + input); + + if (!replyRETR.Success) { + input = inputUri.Segments[inputUri.Segments.Length - 1]; + input = input.Replace("%20", " "); + replyRETR = sourceFTP.Execute("RETR " + input); + + if (!replyRETR.Success) + throw new Exception(replyRETR.ErrorMessage); + } + + FtpReply targetReplyTYPE = targetFTP.Execute("TYPE I"); + if (!targetReplyTYPE.Success) + throw new Exception(targetReplyTYPE.ErrorMessage); + + string currentWorkingDir = targetFTP.GetWorkingDirectory(); + logger.Debug("Current target working directory is {0}", currentWorkingDir); + FtpReply replySTOR = targetFTP.Execute("STOR " + OutputName); + if (!replySTOR.Success) + throw new Exception(replySTOR.ErrorMessage); + + + monitorFTP = CreateClient(parameters.TargetConfig.Remote); + monitorFTP.SetWorkingDirectory(workingDir); + FtpReply monitorReplyTYPE = monitorFTP.Execute("TYPE I"); + if (!monitorReplyTYPE.Success) + throw new Exception(targetReplyTYPE.ErrorMessage); + if (!monitorFTP.FileExists(OutputName)) + throw new Exception("A cél állomány nem jött létre."); + long overall = 0; + long lastSize = 0; + while (overall != ilength) { + overall = monitorFTP.GetFileSize(OutputName); + if (overall == lastSize) { + Progress = 100; + break; + } else { + int currentProgress = (int)((double)overall / ilength * 100); + Progress = currentProgress > 100 ? 100 : currentProgress; + lastSize = overall; + } + Thread.Sleep(1000); + } + + } + catch (Exception e) { + throw e; + } + finally { + TerminateClient(monitorFTP); + TerminateClient(sourceFTP); + } + + //logger.Debug("Done"); + } + + } +} diff --git a/client/MaestroShared/Targets/ITargetProcessor.cs b/client/MaestroShared/Targets/ITargetProcessor.cs new file mode 100644 index 00000000..d8c13118 --- /dev/null +++ b/client/MaestroShared/Targets/ITargetProcessor.cs @@ -0,0 +1,19 @@ +using System; +using System.ComponentModel; + +namespace MaestroShared.Targets { + public interface ITargetProcessor : INotifyPropertyChanged { + DateTime Started { get; set; } + DateTime Finished { get; set; } + string Input { get; set; } + string Output { get; set; } + string Status { get; set; } + string Message { get; set; } + string ID { get; set; } + int Progress { get; set; } + string KillDate { get; set; } + string Label { get; set; } + string KillDatePath { get; set; } + bool Execute(); + } +} \ No newline at end of file diff --git a/client/MaestroShared/Targets/TargetProcessor.cs b/client/MaestroShared/Targets/TargetProcessor.cs new file mode 100644 index 00000000..3ada7fa9 --- /dev/null +++ b/client/MaestroShared/Targets/TargetProcessor.cs @@ -0,0 +1,196 @@ +using MaestroShared.Commons; +using System; +using System.ComponentModel; +using System.Runtime.CompilerServices; +using System.Windows.Forms; + +namespace MaestroShared.Targets { + public abstract class TargetProcessor : ITargetProcessor { + private string status; + private string message; + private string id; + private DateTime started; + private DateTime finished; + private string input; + private string output; + private string inputName; + private string outputName; + private int progress; + private string killDate; + private string label; + private string killDatePath; + protected Control parent; + + public TargetProcessor(Control parent) { + this.parent = parent; + } + + public event PropertyChangedEventHandler PropertyChanged; + + protected void NotifyPropertyChanged([CallerMemberName] String propertyName = "") { + parent?.SafeCall(() => { + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); + }); + } + + public abstract bool Execute(); + + protected virtual void ExecuteCompleted() { + } + + public string Status { + get { + return status; + } + set { + if (status != value) { + status = value; + NotifyPropertyChanged(); + } + } + } + + public DateTime Started { + get { + return started; + } + set { + if (started != value) { + started = value; + NotifyPropertyChanged(); + } + } + } + + public DateTime Finished { + get { + return finished; + } + set { + if (finished != value) { + finished = value; + NotifyPropertyChanged(); + } + } + } + + public string Input { + get { + return input; + } + set { + if (input != value) { + input = value; + NotifyPropertyChanged(); + } + } + } + + public string Output { + get { + return output; + } + set { + if (output != value) { + output = value; + NotifyPropertyChanged(); + } + } + } + + public string InputName { + get { + return inputName; + } + set { + if (inputName != value) { + inputName = value; + NotifyPropertyChanged(); + } + } + } + + public string OutputName { + get { + return outputName; + } + set { + if (outputName != value) { + outputName = value; + NotifyPropertyChanged(); + } + } + } + + public string Message { + get { + return message; + } + set { + if (message != value) { + message = value; + NotifyPropertyChanged(); + } + } + } + + public string ID { + get { + return id; + } + set { + if (id != value) { + id = value; + NotifyPropertyChanged(); + } + } + } + + public int Progress { + get { + return progress; + } + set { + if (progress != value) { + progress = value; + NotifyPropertyChanged(); + } + } + } + + public string KillDate { + get { + return killDate; + } + set { + if (killDate != value) { + killDate = value; + NotifyPropertyChanged(); + } + } + } + + + public string Label { + get { return label; } + set { + //label != value biztos jó stringeknél? + if (label != value) { + label = value; + NotifyPropertyChanged(); + } + } + } + + public string KillDatePath { + get { return killDatePath; } + set { + //label != value biztos jó stringeknél? + if (killDatePath != value) { + killDatePath = value; + NotifyPropertyChanged(); + } + } + } + } +} \ No newline at end of file diff --git a/client/MaestroShared/Targets/TargetProcessorParameter.cs b/client/MaestroShared/Targets/TargetProcessorParameter.cs new file mode 100644 index 00000000..d7860313 --- /dev/null +++ b/client/MaestroShared/Targets/TargetProcessorParameter.cs @@ -0,0 +1,23 @@ +using System.Collections.Generic; +using TrafficClient; +using MediaCubeClient; +using MaestroShared.Configuration; +using MaestroShared.Metadata; + +namespace MaestroShared.Target { + public class TargetProcessorParameter { + public Source SourceConfig { get; set; } + public Configuration.Target TargetConfig { get; set; } + public string InputFileName { get; set; } + public string ID { get; set; } + public string MetadataText { get; set; } + public List Segments { get; set; } + public List MovieSegments { get; set; } + public MediaCubeApi MediaCubeApi { get; set; } + public ArchiveMetadata ArchiveMetadata { get; set; } + public TrafficAPI TrafficApi { get; set; } + public int VariantID { get; set; } + public MetadataType MetadataKind { get; set; } + public string UserName { get; set; } + } +} diff --git a/client/MaestroShared/Targets/UNCTargetProcessor.cs b/client/MaestroShared/Targets/UNCTargetProcessor.cs new file mode 100644 index 00000000..30a21dc0 --- /dev/null +++ b/client/MaestroShared/Targets/UNCTargetProcessor.cs @@ -0,0 +1,357 @@ +using NLog; +using System; +using System.IO; +using System.Windows.Forms; +using TrafficClient; +using Model; +using System.Text; +using System.Globalization; +using System.Text.RegularExpressions; +using MaestroShared.Configuration; +using MaestroShared.Target; +using MaestroShared.Metadata; +using MaestroShared.Commons; + +namespace MaestroShared.Targets { + + public class UNCTargetProcessor : TargetProcessor { + private readonly Logger logger = LogManager.GetCurrentClassLogger(); + private const string SUCCESS = "Successfully completed."; + private const string PROCESSING = "Processing {0}"; + private const string PROCESSING_COMPLETED = "Finished processing {0}"; + private const string FILENAME = "{0}{1}"; + private const string VERSIONED_FILENAME = "{0}-{1}{2}"; + private const string ALREADY_EXISTS = "File {0} already exists, trying {1}"; + private const string STATUS_FOLDER = ".STATUS"; + private const string KILLDATE_FILE = "{0}.{1}.killdate"; + private const string METADATA_FILE = "{0}.json"; + private const string DEFAULT_EXTENSION = ".MXF"; + private const string NORMALIZE_TEXT_PATTERN = "[^0-9A-Za-z-._]"; + protected const string UNDERSCORE = "_"; + protected const string HYPHEN = "-"; + private const string DATE_FORMAT = "yyyy.MM.dd"; + private const string PROGRAMME = "PROGRAMME"; + private const string COMMERCIAL = "COMMERCIAL"; + private const string JUNCTION = "JUNCTION"; + private const string XML_EXT = ".xml"; + private const string PATTERN_TARGETNAME = "%TARGETNAME%"; + protected const string PATTERN_TEXT = "%TEXT%"; + protected const string SLASH = "/"; + private const string INPROGRESS = "Folyamatban"; + private const string ERROR = "Hiba"; + private const string DOT = "."; + private const string HYPHENSTAR = "-*"; + private const string DATE_FORMAT_NODOTS = "yyyyMMdd"; + private const string READY = "Kész"; + private const string HYPHEN_SPACES = " - "; + private const string PATTERN_ID = "%ID%"; + private const string PATTERN_IDROOT = "%IDROOT%"; + private const string PATTERN_SOURCENAME = "%SOURCENAME%"; + private const string PATTERN_TIMESTAMP = "%TIMESTAMP%"; + private const string DATETIME_FORMAT = "yyyyMMddhhmmss"; + protected FileInfo inputFile; + protected string workingDir; + protected TargetProcessorParameter parameters; + + public WorkflowAction workFlowAction { get; set; } + + public UNCTargetProcessor(Control parent, TargetProcessorParameter parameters) + : base(parent) { + this.parameters = parameters; + InputName = parameters.InputFileName; + Input = Path.Combine(parameters.SourceConfig.Local.Address.LocalPath, parameters.InputFileName); + inputFile = new FileInfo(Input); + ID = parameters.ID; + workFlowAction = new WorkflowAction() { + houseId = ID, + tag = parameters.TargetConfig.Tag, + touched = DateTime.Now, + userName = parameters.UserName + }; + Label = parameters.TargetConfig.Label; + } + + protected virtual void BeforeExecute() { + Started = DateTime.Now; + workFlowAction.started = Started; + } + + public override bool Execute() { + logger.Info(PROCESSING, InputName); + bool result = false; + try { + BeforeExecute(); + workingDir = DetermineWorkingDirectory(parameters.TargetConfig.Remote); + EnsureDirectoryExistence(workingDir); + OutputName = CreateOutputFileName(); + OutputName = OutputName.ToUpper(); + Output = "/".Equals(workingDir) ? OutputName : Path.Combine(workingDir, OutputName); + Output = Output.Replace(@"\", "/"); + workFlowAction.source = Input; + workFlowAction.destination = Output; + Status = INPROGRESS; + //DateTime started = DateTime.Now; + string currentFile = GetOutputFilePath(workingDir, OutputName); + if (FileExists(currentFile) && parameters.TargetConfig.DisableFileVersioning) + DeleteFile(currentFile); + UploadFile(); + //logger.Info("Spend (s):" + (DateTime.Now - started).TotalSeconds); + ExecuteCompleted(); + } + catch (Exception e) { + Status = ERROR; + Message = e.Message; + workFlowAction.description = Message; + logger.Error(e); + if (parameters.TargetConfig.SendEmailOnError && !String.IsNullOrEmpty(parameters.TargetConfig.ErrorEmailRecipient) && !String.IsNullOrEmpty(parameters.TargetConfig.ErrorEmailPattern)) + SendEmail(parameters.TargetConfig.ErrorEmailRecipient, parameters.TargetConfig.ErrorEmailPattern); + } + finally { + AfterExecute(); + } + logger.Info(PROCESSING_COMPLETED, InputName); + return result; + } + + protected virtual void DeleteFile(string currentFile) { + File.Delete(currentFile); + } + + private string GetOutputName() { + if (String.IsNullOrEmpty(OutputName)) + return null; + string result = OutputName; + if (result.Contains(DOT)) + result = result.Substring(0, result.LastIndexOf(DOT)); + return result; + } + + protected override void ExecuteCompleted() { + base.ExecuteCompleted(); + workFlowAction.description = SUCCESS; + workFlowAction.successful = true; + if (parameters.TargetConfig.NexioServer) + UploadNexioMetadata(); + else { + if (parameters.TargetConfig.KillDateDays > 0) + UploadKillDateFile(); + } + + if (parameters.TargetConfig.SaveArchiveMetadata && parameters.ArchiveMetadata != null) + CreateArchiveMetadata(); + if (parameters.TargetConfig.SaveMorpheusMetadata && parameters.ArchiveMetadata != null && parameters.MovieSegments != null && parameters.MovieSegments.Count > 0) + UploadMorpheusMetadata(); + if (parameters.TargetConfig.SaveSegments && parameters.Segments != null) + parameters.TrafficApi.UpdateTrafficInformation(parameters.VariantID, true, (TrafficMetadataType)parameters.MetadataKind, parameters.Segments); + + if (parameters.TargetConfig.SendEmailOnSuccess && !String.IsNullOrEmpty(parameters.TargetConfig.SuccessEmailRecipient) && !String.IsNullOrEmpty(parameters.TargetConfig.SuccessEmailPattern)) + SendEmail(parameters.TargetConfig.SuccessEmailRecipient, parameters.TargetConfig.SuccessEmailPattern); + Status = READY; + Message = SUCCESS; + } + + private void UploadNexioMetadata() { + String xml = null; + string name = GetOutputName(); + string description = parameters.ArchiveMetadata?.mediaTitle; + if (parameters.TargetConfig.KillDateDays > 0) { + DateTime date = GetKillDate(); + KillDate = date.ToString(DATE_FORMAT); + xml = NexioXML.ToXML(name, date, description, parameters.TargetConfig.Agency); + } else + xml = NexioXML.ToXML(name, null, description, parameters.TargetConfig.Agency); + byte[] content = Encoding.Unicode.GetBytes(xml); + UploadContent(name + XML_EXT, content); + } + + private void UploadMorpheusMetadata() { + string name = GetOutputName(); + string title = parameters.ArchiveMetadata?.itemTitle; + if (!title.Equals(parameters.ArchiveMetadata?.mediaTitle)) + title += HYPHEN_SPACES + parameters.ArchiveMetadata?.mediaTitle; + string type = null; + switch (parameters.MetadataKind) { + case MetadataType.TrafficMaterial: + type = PROGRAMME; + break; + case MetadataType.TrafficPromo: + type = COMMERCIAL; + break; + case MetadataType.TrafficAD: + type = JUNCTION; + break; + } + byte[] content = MorpheusXML.ToXML(title, name, parameters.TargetConfig.DeviceIDMorpheus, type, parameters.MovieSegments); + EnsureDirectoryExistence(parameters.TargetConfig.PathMorpheusMetadata); + UploadContent(name + XML_EXT, content); + } + + private void SendEmail(string to, string messagePattern) { + try { + string message = messagePattern.Replace(PATTERN_TARGETNAME, OutputName); + parameters.MediaCubeApi.Notify(to, message); + } + catch (Exception e) { + MessageBox.Show(parent, e.Message); + } + } + + protected virtual void AfterExecute() { + Finished = DateTime.Now; + workFlowAction.finished = Finished; + SendWorkFlowAction(); + Progress = 0; + } + + protected virtual bool FileExists(string path) { + return File.Exists(path); + } + + private void SendWorkFlowAction() { + try { + parameters.MediaCubeApi.Create(workFlowAction); + } + catch (Exception e) { + MessageBox.Show(parent, e.Message); + } + } + + protected virtual string DetermineWorkingDirectory(Connection connection) { + string result = null; + if (!String.IsNullOrEmpty(parameters.TargetConfig.SubFolderFormat)) { + string name = GetDynamicName(parameters.TargetConfig.SubFolderFormat); + if (parameters.TargetConfig.SubFolderFormat.Contains(PATTERN_TEXT)) { + string pattern = name.Split(HYPHEN[0])[0] + HYPHENSTAR; + string[] dirs = Directory.GetDirectories(connection.Address.LocalPath, pattern); + if (dirs.Length > 0) + name = dirs[0]; + } + result = Path.Combine(connection.Address.LocalPath, name); + } else + result = connection.Address.LocalPath; + return result; + } + + private DateTime GetKillDate() { + DateTime result = DateTime.Now; + result = result.AddDays(parameters.TargetConfig.KillDateDays); + return result; + } + + private void UploadKillDateFile() { + Uri address = parameters.TargetConfig.Remote.Address; + string statusWorkDir = Path.Combine(workingDir, STATUS_FOLDER); + EnsureDirectoryExistence(statusWorkDir); + DateTime date = GetKillDate(); + string fileName = String.Format(KILLDATE_FILE, OutputName, date.ToString(DATE_FORMAT_NODOTS)); + //logger.Debug("Creating KILLDATE status file {0}", fileName); + KillDatePath = GetOutputFilePath(statusWorkDir, fileName); + UploadContent(KillDatePath, new byte[] { }); + KillDate = date.ToString(DATE_FORMAT); + } + + private void CreateArchiveMetadata() { + Uri address = parameters.TargetConfig.Remote.Address; + string statusWorkDir = Path.Combine(workingDir, STATUS_FOLDER); + EnsureDirectoryExistence(statusWorkDir); + string fileName = String.Format(METADATA_FILE, OutputName); + //logger.Debug("Creating METADATA file {0}", fileName); + byte[] content = Encoding.UTF8.GetBytes(parameters.ArchiveMetadata.ToString()); + string ouputPath = GetOutputFilePath(statusWorkDir, fileName); + UploadContent(ouputPath, content); + } + + private void CreateTrafficMetadata() { + Uri address = parameters.TargetConfig.Remote.Address; + string statusWorkDir = Path.Combine(workingDir, STATUS_FOLDER); + EnsureDirectoryExistence(statusWorkDir); + string fileName = String.Format(METADATA_FILE, OutputName); + //logger.Debug("Creating METADATA file {0}", fileName); + byte[] content = Encoding.UTF8.GetBytes(parameters.ArchiveMetadata.ToString()); + string ouputPath = GetOutputFilePath(statusWorkDir, fileName); + UploadContent(ouputPath, content); + } + + protected void CopyStream(Stream istream, long ilength, Stream ostream) { + byte[] buffer = new byte[32768]; + int read, overall = 0; + while ((read = istream.Read(buffer, 0, buffer.Length)) > 0) { + ostream.Write(buffer, 0, read); + ostream.Flush(); + overall += read; + Progress = (int)((double)overall / ilength * 100); + } + } + + protected virtual void UploadContent(string outputPath, byte[] content) { + File.WriteAllBytes(outputPath, content); + } + + private CopyProgressResult CopyProgressHandler(long total, long transferred, long streamSize, long StreamByteTrans, uint dwStreamNumber, CopyProgressCallbackReason reason, IntPtr hSourceFile, IntPtr hDestinationFile, IntPtr lpData) { + if (transferred > 0) + Progress = (int)((double)transferred * 100 / total); + return CopyProgressResult.PROGRESS_CONTINUE; + } + + protected virtual void UploadFile() { + int pbCancel = 0; + Win32File.CopyFileEx(Input, Output, new CopyProgressRoutine(this.CopyProgressHandler), IntPtr.Zero, ref pbCancel, CopyFileFlags.COPY_FILE_RESTARTABLE); + } + + protected virtual string GetOutputFilePath(string path, string fileName) { + return "/".Equals(workingDir) ? fileName : Path.Combine(path, fileName); + } + + public static String RemoveDiacritics(String s) { + String normalizedString = s.Normalize(NormalizationForm.FormD); + StringBuilder stringBuilder = new StringBuilder(); + + for (int i = 0; i < normalizedString.Length; i++) { + Char c = normalizedString[i]; + if (CharUnicodeInfo.GetUnicodeCategory(c) != UnicodeCategory.NonSpacingMark) + stringBuilder.Append(c); + } + + return stringBuilder.ToString(); + } + + protected string GetDynamicName(string text) { + string idRoot = ID.Contains(UNDERSCORE) ? ID.Split(UNDERSCORE[0])[0] : ID; + string result = text + .Replace(PATTERN_ID, ID) + .Replace(PATTERN_IDROOT, idRoot) + .Replace(PATTERN_TEXT, HYPHEN + RemoveDiacritics(parameters.MetadataText)) + .Replace(PATTERN_SOURCENAME, Path.GetFileNameWithoutExtension(InputName)) + .Replace(PATTERN_TIMESTAMP, DateTime.Now.ToString(DATETIME_FORMAT, CultureInfo.InvariantCulture)); + // replace hungarian and special characters + result = Regex.Replace(result, NORMALIZE_TEXT_PATTERN, UNDERSCORE); + if (result.Length > 100) + result = result.Substring(0, 100); + return result; + } + + protected virtual string CreateOutputFileName() { + string nameWithoutExtension = GetDynamicName(parameters.TargetConfig.OutputFormat); + string extension = InputName.Contains(DOT) ? InputName.Substring(InputName.LastIndexOf(DOT)) : DEFAULT_EXTENSION; + extension = extension.ToUpper(); + string result = String.Format(FILENAME, nameWithoutExtension, extension); + if (!parameters.TargetConfig.DisableFileVersioning) { + int version = 1; + while (FileExists(GetOutputFilePath(workingDir, result))) { + string versioned = String.Format(VERSIONED_FILENAME, nameWithoutExtension, version, extension); + logger.Debug(ALREADY_EXISTS, result, versioned); + result = versioned; + version++; + } + } + return result; + } + + protected virtual void EnsureDirectoryExistence(string path) { + if (!Directory.Exists(path)) + Directory.CreateDirectory(path); + } + + + } +} diff --git a/client/MaestroShared/packages.config b/client/MaestroShared/packages.config new file mode 100644 index 00000000..19cd1669 --- /dev/null +++ b/client/MaestroShared/packages.config @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/client/MediaCube.sln b/client/MediaCube.sln index 573ed156..f3793813 100644 --- a/client/MediaCube.sln +++ b/client/MediaCube.sln @@ -20,6 +20,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PasswordEncrypter", "Passwo EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MXFFileParser", "MXFFileParser\MXFFileParser.csproj", "{BF494EE9-1E70-44E8-8942-DD726510A766}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MaestroShared", "MaestroShared\MaestroShared.csproj", "{D4417174-F21E-4CE2-AE5C-8EB30C9A9625}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -138,12 +140,24 @@ Global {BF494EE9-1E70-44E8-8942-DD726510A766}.Release|x64.Build.0 = Release|x64 {BF494EE9-1E70-44E8-8942-DD726510A766}.Release|x86.ActiveCfg = Release|Any CPU {BF494EE9-1E70-44E8-8942-DD726510A766}.Release|x86.Build.0 = Release|Any CPU + {D4417174-F21E-4CE2-AE5C-8EB30C9A9625}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D4417174-F21E-4CE2-AE5C-8EB30C9A9625}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D4417174-F21E-4CE2-AE5C-8EB30C9A9625}.Debug|x64.ActiveCfg = Debug|Any CPU + {D4417174-F21E-4CE2-AE5C-8EB30C9A9625}.Debug|x64.Build.0 = Debug|Any CPU + {D4417174-F21E-4CE2-AE5C-8EB30C9A9625}.Debug|x86.ActiveCfg = Debug|Any CPU + {D4417174-F21E-4CE2-AE5C-8EB30C9A9625}.Debug|x86.Build.0 = Debug|Any CPU + {D4417174-F21E-4CE2-AE5C-8EB30C9A9625}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D4417174-F21E-4CE2-AE5C-8EB30C9A9625}.Release|Any CPU.Build.0 = Release|Any CPU + {D4417174-F21E-4CE2-AE5C-8EB30C9A9625}.Release|x64.ActiveCfg = Release|Any CPU + {D4417174-F21E-4CE2-AE5C-8EB30C9A9625}.Release|x64.Build.0 = Release|Any CPU + {D4417174-F21E-4CE2-AE5C-8EB30C9A9625}.Release|x86.ActiveCfg = Release|Any CPU + {D4417174-F21E-4CE2-AE5C-8EB30C9A9625}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection GlobalSection(TeamFoundationVersionControl) = preSolution - SccNumberOfProjects = 10 + SccNumberOfProjects = 11 SccEnterpriseProvider = {4CA58AB2-18FA-4F8D-95D4-32DDF27D184C} SccTeamFoundationServer = https://tfs.userrendszerhaz.hu/tfs/defaultcollection SccLocalPath0 = . @@ -174,5 +188,8 @@ Global SccProjectUniqueName9 = MXFFileParser\\MXFFileParser.csproj SccProjectName9 = MXFFileParser SccLocalPath9 = MXFFileParser + SccProjectUniqueName10 = MaestroShared\\MaestroShared.csproj + SccProjectName10 = MaestroShared + SccLocalPath10 = MaestroShared EndGlobalSection EndGlobal diff --git a/client/MediaCubeClient/Model/Model.cs b/client/MediaCubeClient/Model/Model.cs index 281e5642..629e452e 100644 --- a/client/MediaCubeClient/Model/Model.cs +++ b/client/MediaCubeClient/Model/Model.cs @@ -7,11 +7,12 @@ namespace Model { public DateTime started; public DateTime finished; public bool successful; - public String houseId; - public String description; - public String source; - public String destination; - public String tag; + public string houseId; + public string description; + public string source; + public string destination; + public string tag; + public string userName; public long size; } diff --git a/server/user.jobengine.osgi.db/build-remote-sqlj.bat b/server/user.jobengine.osgi.db/build-remote-sqlj.bat index e14046f3..b8bb4798 100644 --- a/server/user.jobengine.osgi.db/build-remote-sqlj.bat +++ b/server/user.jobengine.osgi.db/build-remote-sqlj.bat @@ -1,7 +1,10 @@ @ECHO OFF - ECHO *** Begin SQL compile on server %DB_REMOTE_HOST% *** + ECHO *** Begin SQL compile *** - CALL settings.bat + ::Remote:: + SET REMOTE_LOCATION=/tmp/mediaarch + SET REMOTE_SERVER_HOSTKEY=ssh-ed25519 256 ea:ab:67:70:79:63:2f:6a:34:81:48:e2:b9:dd:ca:d4 + SET REMOTE_SERVER_ADDRESS=scp://db2admin:password@10.10.1.27 CALL :deploy_source if %ERRORLEVEL% neq 0 exit /b %ERRORLEVEL% diff --git a/server/user.jobengine.osgi.db/database/structure.sql b/server/user.jobengine.osgi.db/database/structure.sql index 5a42ca02..16fbb01a 100644 --- a/server/user.jobengine.osgi.db/database/structure.sql +++ b/server/user.jobengine.osgi.db/database/structure.sql @@ -1,3 +1,5 @@ +ALTER TABLE WORKFLOWACTION ADD COLUMN USERNAME VARCHAR(50) NOT NULL DEFAULT '' + DROP INDEX IDX_ITEM_DESCRIPTION ALTER TABLE ITEM ALTER COLUMN TITLE SET DATA TYPE VARCHAR(1000) ALTER TABLE ITEM ALTER COLUMN DESCRIPTION SET DATA TYPE VARCHAR(32000) diff --git a/server/user.jobengine.osgi.db/settings.bat b/server/user.jobengine.osgi.db/settings.bat deleted file mode 100644 index d2fc7342..00000000 --- a/server/user.jobengine.osgi.db/settings.bat +++ /dev/null @@ -1,19 +0,0 @@ -::Database:: - -SET DB_INSTANCE=DB2 -SET DB_HOST=localhost -SET DB_PORT=50000 -SET DB_NAME=JE -SET DB_URL=jdbc:db2://%DB_HOST%:%DB_PORT%/%DB_NAME%:retrieveMessagesFromServerOnGetMessage=true; -SET DB_SCHEMA=DB2ADMIN -SET DB_USER=db2admin -SET DB_PWD=salabakter -SET DB_CMD_OPTIONS=-td@ -f -SET DB2CLP=DB20FADE - -::Remote:: -SET DB_REMOTE_HOST=10.228.198.1 -SET REMOTE_LOCATION=/tmp/mediaarch -SET REMOTE_SERVER_HOSTKEY=ssh-ed25519 256 86:5b:9b:bc:df:7b:df:90:c6:bf:60:69:d2:c9:61:62 -SET REMOTE_SERVER_ADDRESS=scp://db2admin:password@%DB_REMOTE_HOST% - diff --git a/server/user.jobengine.osgi.db/sql/2-CreateStructure.db2 b/server/user.jobengine.osgi.db/sql/2-CreateStructure.db2 index de77e03b..32c9ca3c 100644 --- a/server/user.jobengine.osgi.db/sql/2-CreateStructure.db2 +++ b/server/user.jobengine.osgi.db/sql/2-CreateStructure.db2 @@ -377,6 +377,7 @@ CREATE TABLE WORKFLOWACTION SOURCE VARCHAR(255) NOT NULL, DESTINATION VARCHAR(255) NOT NULL, TAG VARCHAR(40) NOT NULL, + USERNAME VARCHAR(50) NOT NULL, SIZE BIGINT NOT NULL, CONSTRAINT CHK_WORKFLOWACTION_SUCCESSFUL CHECK (SUCCESSFUL in ('Y', 'N')) )@ diff --git a/server/user.jobengine.osgi.db/src/user/jobengine/db/WorkflowAction.java b/server/user.jobengine.osgi.db/src/user/jobengine/db/WorkflowAction.java index 0edde20d..8d89a664 100644 --- a/server/user.jobengine.osgi.db/src/user/jobengine/db/WorkflowAction.java +++ b/server/user.jobengine.osgi.db/src/user/jobengine/db/WorkflowAction.java @@ -14,86 +14,95 @@ public class WorkflowAction extends JSONBase implements Serializable { private String source; private String destination; private String tag; + private String userName; private long size; - public Timestamp getTouched() { - return touched; - } - - public void setTouched(Timestamp touched) { - this.touched = touched; - } - - public Timestamp getStarted() { - return started; + public String getDescription() { + return description; } - public void setStarted(Timestamp started) { - this.started = started; + public String getDestination() { + return destination; } public Timestamp getFinished() { return finished; } - public void setFinished(Timestamp finished) { - this.finished = finished; - } - public String getHouseId() { return houseId; } - public void setHouseId(String houseId) { - this.houseId = houseId; + public long getSize() { + return size; } - public String getDescription() { - return description; + public String getSource() { + return source; } - public void setDescription(String description) { - this.description = description; + public Timestamp getStarted() { + return started; } - public String getSource() { - return source; + public String getTag() { + return tag; } - public void setSource(String source) { - this.source = source; + public Timestamp getTouched() { + return touched; } - public String getDestination() { - return destination; + public String getUserName() { + return userName; + } + + public boolean isSuccessful() { + return successful; + } + + public void setDescription(String description) { + this.description = description; } public void setDestination(String destination) { this.destination = destination; } - public String getTag() { - return tag; + public void setFinished(Timestamp finished) { + this.finished = finished; } - public void setTag(String tag) { - this.tag = tag; + public void setHouseId(String houseId) { + this.houseId = houseId; } - public boolean isSuccessful() { - return successful; + public void setSize(long size) { + this.size = size; + } + + public void setSource(String source) { + this.source = source; + } + + public void setStarted(Timestamp started) { + this.started = started; } public void setSuccessful(boolean successful) { this.successful = successful; } - public long getSize() { - return size; + public void setTag(String tag) { + this.tag = tag; } - public void setSize(long size) { - this.size = size; + public void setTouched(Timestamp touched) { + this.touched = touched; + } + + public void setUserName(String userName) { + this.userName = userName; } } \ No newline at end of file diff --git a/server/user.jobengine.osgi.db/src/user/jobengine/db/WorkflowActionDAO.sqlj b/server/user.jobengine.osgi.db/src/user/jobengine/db/WorkflowActionDAO.sqlj index d5350677..79e7c588 100644 --- a/server/user.jobengine.osgi.db/src/user/jobengine/db/WorkflowActionDAO.sqlj +++ b/server/user.jobengine.osgi.db/src/user/jobengine/db/WorkflowActionDAO.sqlj @@ -8,7 +8,7 @@ import java.util.List; import java.util.ArrayList; -#sql iterator WorkflowActionIter(long id, Timestamp touched, Timestamp started, Timestamp finished, String successful, String houseId, String description, String source, String destination, String tag, long size); +#sql iterator WorkflowActionIter(long id, Timestamp touched, Timestamp started, Timestamp finished, String successful, String houseId, String description, String source, String destination, String tag, String userName, long size); @SuppressWarnings("unused") class WorkflowActionDAO extends EntityBaseDAO { @@ -33,6 +33,7 @@ class WorkflowActionDAO extends EntityBaseDAO { entity.setSource(iterator.source()); entity.setDestination(iterator.destination()); entity.setTag(iterator.tag()); + entity.setUserName(iterator.userName()); entity.setSize(iterator.size()); if (result == null) @@ -46,20 +47,20 @@ class WorkflowActionDAO extends EntityBaseDAO { @Override protected ResultSetIterImpl selectByKey(DefaultContext context, long id) throws SQLException{ WorkflowActionIter iter = null; - #sql [context] iter = { SELECT ID, TOUCHED, STARTED, FINISHED, SUCCESSFUL, HOUSEID, DESCRIPTION, SOURCE, DESTINATION, TAG, SIZE FROM WORKFLOWACTION WHERE ID = :id }; + #sql [context] iter = { SELECT ID, TOUCHED, STARTED, FINISHED, SUCCESSFUL, HOUSEID, DESCRIPTION, SOURCE, DESTINATION, TAG, USERNAME, SIZE FROM WORKFLOWACTION WHERE ID = :id }; return iter; } @Override protected ResultSetIterImpl selectAll(DefaultContext context) throws SQLException{ WorkflowActionIter iter = null; - #sql [context] iter = { SELECT ID, TOUCHED, STARTED, FINISHED, SUCCESSFUL, HOUSEID, DESCRIPTION, SOURCE, DESTINATION, TAG, SIZE FROM WORKFLOWACTION }; + #sql [context] iter = { SELECT ID, TOUCHED, STARTED, FINISHED, SUCCESSFUL, HOUSEID, DESCRIPTION, SOURCE, DESTINATION, TAG, USERNAME, SIZE FROM WORKFLOWACTION }; return iter; } private ResultSetIterImpl selectByFinished(DefaultContext context, Timestamp begin, Timestamp end) throws SQLException{ WorkflowActionIter iter = null; - #sql [context] iter = { SELECT ID, TOUCHED, STARTED, FINISHED, SUCCESSFUL, HOUSEID, DESCRIPTION, SOURCE, DESTINATION, TAG, SIZE FROM WORKFLOWACTION WHERE FINISHED BETWEEN :begin AND :end ORDER BY HOUSEID }; + #sql [context] iter = { SELECT ID, TOUCHED, STARTED, FINISHED, SUCCESSFUL, HOUSEID, DESCRIPTION, SOURCE, DESTINATION, TAG, USERNAME, SIZE FROM WORKFLOWACTION WHERE FINISHED BETWEEN :begin AND :end ORDER BY HOUSEID }; return iter; } @@ -87,9 +88,10 @@ class WorkflowActionDAO extends EntityBaseDAO { String source = obj.getSource(); String destination = obj.getDestination(); String tag = obj.getTag(); + String userName = obj.getUserName(); long size = obj.getSize(); - #sql [context] { UPDATE WORKFLOWACTION SET TOUCHED = :touched, STARTED = :started, FINISHED = :finished, SUCCESSFUL = :successful, HOUSEID = :houseId, DESCRIPTION = :description, SOURCE = :source, DESTINATION = :destination, TAG = :tag, SIZE = :size WHERE ID = :id }; + #sql [context] { UPDATE WORKFLOWACTION SET TOUCHED = :touched, STARTED = :started, FINISHED = :finished, SUCCESSFUL = :successful, HOUSEID = :houseId, DESCRIPTION = :description, SOURCE = :source, DESTINATION = :destination, TAG = :tag, USERNAME = :userName, SIZE = :size WHERE ID = :id }; } @Override @@ -106,9 +108,10 @@ class WorkflowActionDAO extends EntityBaseDAO { String source = obj.getSource(); String destination = obj.getDestination(); String tag = obj.getTag(); + String userName = obj.getUserName(); long size = obj.getSize(); - #sql [context] { INSERT INTO WORKFLOWACTION (TOUCHED, STARTED, FINISHED, SUCCESSFUL, HOUSEID, DESCRIPTION, SOURCE, DESTINATION, TAG, SIZE) VALUES (:touched, :started, :finished, :successful, :houseId, :description, :source, :destination, :tag, :size) }; + #sql [context] { INSERT INTO WORKFLOWACTION (TOUCHED, STARTED, FINISHED, SUCCESSFUL, HOUSEID, DESCRIPTION, SOURCE, DESTINATION, TAG, USERNAME, SIZE) VALUES (:touched, :started, :finished, :successful, :houseId, :description, :source, :destination, :tag, :userName, :size) }; } public List getWorkflowActions(Timestamp begin, Timestamp end) { -- 2.54.0