From 4fbfdbaf2c5f9d8a5d07ee7ba91a7e46b9c9e033 Mon Sep 17 00:00:00 2001 From: rene Date: Wed, 28 Dec 2022 16:36:59 +0100 Subject: [PATCH] =?UTF-8?q?Unit=20Tests=20erstellt=20Informationen=20ausge?= =?UTF-8?q?lagert=20Kleines=20Spy/Test=20Programm=20erstellt=20Mehr=20Exce?= =?UTF-8?q?ptions/InvalidUpdateFileRequestException.cs=20Launcher=20Host?= =?UTF-8?q?=20in=20Download=20Server=20ge=C3=A4ndert=20Download=20Server?= =?UTF-8?q?=20macht=20zus=C3=A4tzlich=20Abfrage=20an=20den=20Hauptserver?= =?UTF-8?q?=20Download=20geht=20jetzt=20st=C3=BCckweise=20von=20statten?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 8 +- BeWo/BeWoApp.xaml.cs | 86 +--- BeWo/Loader.cs | 31 +- BeWo/MainWindow.xaml.cs | 3 +- BeWoLauncher/App.config | 2 +- BeWoLauncher/BeWoLauncher.csproj | 10 +- BeWoLauncher/BeWoLauncher_TemporaryKey.pfx | Bin 1668 -> 0 bytes BeWoLauncher/LauncherApp.xaml.cs | 6 +- BeWoLauncher/Logic/Behavior/LaunchBehavior.cs | 5 +- .../Logic/Behavior/ViewSwitchBehavior.cs | 26 +- .../Logic/Controller/DownloadController.cs | 8 +- .../Logic/Controller/ProcessController.cs | 36 +- .../Multitenancy/MultitenancyInterceptor.cs | 2 +- .../LauncherSecurityHeaderInterceptor.cs | 2 +- .../Logic/ServiceProxy/LauncherGenerated.cs | 240 ++++++----- .../ServiceProxy/LauncherServiceFacade.cs | 32 +- .../Logic/Utils/Download/DownloadManager.cs | 234 ++++++---- BeWoLauncher/Logic/Utils/LauncherPaths.cs | 35 +- BeWoLauncher/Logic/ViewBuilder.cs | 22 +- .../ServiceProxy/LauncherGenerated.cs | 403 ++++++++++++++++++ .../View/Components/MessageDialog.xaml.cs | 2 +- .../Components/PasswortAenderungsView.xaml.cs | 6 +- .../View/Frames/GenericProgressFrame.xaml.cs | 75 ---- BeWoLauncher/View/Frames/InfoFrame.xaml | 7 +- BeWoLauncher/View/Frames/InfoFrame.xaml.cs | 4 +- .../View/Frames/InstallInfoFrame.xaml | 6 - .../View/Frames/InstallInfoFrame.xaml.cs | 12 +- .../View/Frames/InstallProgressInfoFrame.cs | 183 -------- ...cProgressFrame.xaml => ProgressFrame.xaml} | 4 +- .../View/Frames/ProgressFrame.xaml.cs | 237 ++++++++++ .../View/Frames/UninstallProgressInfoFrame.cs | 69 --- BeWoLauncher/View/Frames/UpdateInfoFrame.xaml | 8 - .../View/Frames/UpdateInfoFrame.xaml.cs | 18 +- .../View/Frames/UpdateProgressInfoFrame.cs | 183 -------- BeWoLauncher/View/LoginView.xaml.cs | 105 +++-- BeWoOhneReports.sln | 33 +- BeWoTest/App.config | 6 + BeWoTest/App.xaml | 9 + BeWoTest/App.xaml.cs | 22 + BeWoTest/BeWoTest.csproj | 103 +++++ BeWoTest/MainWindow.xaml | 16 + BeWoTest/MainWindow.xaml.cs | 33 ++ BeWoTest/Properties/AssemblyInfo.cs | 55 +++ BeWoTest/Properties/Resources.Designer.cs | 71 +++ BeWoTest/Properties/Resources.resx | 117 +++++ BeWoTest/Properties/Settings.Designer.cs | 30 ++ BeWoTest/Properties/Settings.settings | 7 + .../DownloadBeWoService.svc | 0 .../DownloadServer.csproj | 13 +- .../DownloadServer.csproj.user | 3 +- .../DownloadServerServiceReferences.bat | 1 + .../Multitenancy/Symbol Edit.png | Bin .../Multitenancy/debug.config | 0 .../Multitenancy/debugMsSQL.config | 0 .../Multitenancy/debugMySQL.config | 0 .../Multitenancy/demo.config | 0 .../Properties/AssemblyInfo.cs | 0 .../Web.Debug.config | 0 .../Web.Release.config | 0 {LauncherHost => DownloadServer}/Web.config | 18 +- .../packages.config | 0 .../EnumTranslationService.svc | 0 Host/Host.csproj | 5 +- Host/Host.csproj.user | 3 +- {LauncherHost => Host}/LauncherService.svc | 0 Host/Web.config | 6 + .../DMultitenancyEndpointBehavior.cs | 28 ++ Service/Multitenancy/DMultitenancyHeader.cs | 39 ++ .../Multitenancy/DMultitenancyInterceptor.cs | 21 + Service/Service.csproj | 9 +- .../ServiceContracts/IDownloadBeWoService.cs | 12 +- .../DownloadBeWoServiceImp.cs | 91 ++-- .../LauncherServiceImp.cs | 4 +- .../ServiceImplementations/UserServiceImp.cs | 2 - Service/ServiceProxy/ServiceFacade.cs | 116 +++++ Service/ServiceProxy/ServiceGenerated.cs | 276 ++++++++++++ Service/ServiceReferences.bat | 1 + Service/ServiceUtils/Paths/ServerFilePaths.cs | 4 +- Service/ServiceUtils/Update/DownloadLogger.cs | 23 - .../Update/DownloadPlanerResponseBuilder.cs | 146 ------- .../Update/UpdateFileResponseBuilder.cs | 104 +++++ .../Update/UpdatePlanResponseBuilder.cs | 166 ++++++++ Service/SvcUtil.exe | Bin 0 -> 184144 bytes .../DataContract/DownloadPlanerResponseDC.cs | 49 --- SharedLauncher/DataContract/LoginDC.cs | 34 ++ .../DataContract/PlanerFileInfoDC.cs | 26 -- SharedLauncher/DataContract/UpdateFileDC.cs | 50 +++ .../DataContract/UpdateFileRequest.cs | 32 ++ .../DataContract/UpdateFileResponse.cs | 24 ++ ...PlanerPackageInfoDC.cs => UpdatePlanDC.cs} | 6 +- ...lanerRequestDC.cs => UpdatePlanRequest.cs} | 11 +- ...esponseInfoDC.cs => UpdatePlanResponse.cs} | 27 +- .../InvalidUpdateFileRequestException.cs | 23 + .../InvalidUpdatePlanRequestException.cs | 23 + .../DownloadPlanerResponseExtension.cs | 27 -- SharedLauncher/Extensions/PathExtensions.cs | 1 + .../Extensions/PlanerFileExtension.cs | 78 ++-- .../Extensions/PlanerPackageExtension.cs | 65 +-- .../Extensions/UpdateResponseExtension.cs | 32 ++ .../Information/BeWoPathFileConfig.cs | 4 +- SharedLauncher/Information/Connection.cs | 112 +++++ .../Information/ConnectionInformation.cs | 246 ----------- SharedLauncher/Information/DownloadLogger.cs | 59 +++ SharedLauncher/Information/Login.cs | 45 ++ SharedLauncher/Information/Session.cs | 30 ++ .../Information/SessionInformation.cs | 146 +++++++ SharedLauncher/LauncherEnums.cs | 51 +-- SharedLauncher/Logic/FileController.cs | 262 ++++-------- SharedLauncher/SharedLauncher.csproj | 24 +- SharedLauncher/Update/ApplyFileEventArgs.cs | 8 +- .../Update/DownloadProgressEventArgs.cs | 11 +- SharedLauncher/Update/PlanerFileInfo.cs | 45 -- SharedLauncher/Update/PlanerPackageInfo.cs | 30 -- UnitTests/SharedLauncherTests.cs | 33 ++ UnitTests/UnitTests.csproj | 19 + 115 files changed, 3364 insertions(+), 1972 deletions(-) delete mode 100644 BeWoLauncher/BeWoLauncher_TemporaryKey.pfx create mode 100644 BeWoLauncher/ServiceProxy/LauncherGenerated.cs delete mode 100644 BeWoLauncher/View/Frames/GenericProgressFrame.xaml.cs delete mode 100644 BeWoLauncher/View/Frames/InstallProgressInfoFrame.cs rename BeWoLauncher/View/Frames/{GenericProgressFrame.xaml => ProgressFrame.xaml} (91%) create mode 100644 BeWoLauncher/View/Frames/ProgressFrame.xaml.cs delete mode 100644 BeWoLauncher/View/Frames/UninstallProgressInfoFrame.cs delete mode 100644 BeWoLauncher/View/Frames/UpdateProgressInfoFrame.cs create mode 100644 BeWoTest/App.config create mode 100644 BeWoTest/App.xaml create mode 100644 BeWoTest/App.xaml.cs create mode 100644 BeWoTest/BeWoTest.csproj create mode 100644 BeWoTest/MainWindow.xaml create mode 100644 BeWoTest/MainWindow.xaml.cs create mode 100644 BeWoTest/Properties/AssemblyInfo.cs create mode 100644 BeWoTest/Properties/Resources.Designer.cs create mode 100644 BeWoTest/Properties/Resources.resx create mode 100644 BeWoTest/Properties/Settings.Designer.cs create mode 100644 BeWoTest/Properties/Settings.settings rename {LauncherHost => DownloadServer}/DownloadBeWoService.svc (100%) rename LauncherHost/LauncherHost.csproj => DownloadServer/DownloadServer.csproj (95%) rename LauncherHost/LauncherHost.csproj.user => DownloadServer/DownloadServer.csproj.user (96%) create mode 100644 DownloadServer/DownloadServerServiceReferences.bat rename {LauncherHost => DownloadServer}/Multitenancy/Symbol Edit.png (100%) rename {LauncherHost => DownloadServer}/Multitenancy/debug.config (100%) rename {LauncherHost => DownloadServer}/Multitenancy/debugMsSQL.config (100%) rename {LauncherHost => DownloadServer}/Multitenancy/debugMySQL.config (100%) rename {LauncherHost => DownloadServer}/Multitenancy/demo.config (100%) rename {LauncherHost => DownloadServer}/Properties/AssemblyInfo.cs (100%) rename {LauncherHost => DownloadServer}/Web.Debug.config (100%) rename {LauncherHost => DownloadServer}/Web.Release.config (100%) rename {LauncherHost => DownloadServer}/Web.config (87%) rename {LauncherHost => DownloadServer}/packages.config (100%) rename {LauncherHost => Host}/EnumTranslationService.svc (100%) rename {LauncherHost => Host}/LauncherService.svc (100%) create mode 100644 Service/Multitenancy/DMultitenancyEndpointBehavior.cs create mode 100644 Service/Multitenancy/DMultitenancyHeader.cs create mode 100644 Service/Multitenancy/DMultitenancyInterceptor.cs create mode 100644 Service/ServiceProxy/ServiceFacade.cs create mode 100644 Service/ServiceProxy/ServiceGenerated.cs create mode 100644 Service/ServiceReferences.bat delete mode 100644 Service/ServiceUtils/Update/DownloadLogger.cs delete mode 100644 Service/ServiceUtils/Update/DownloadPlanerResponseBuilder.cs create mode 100644 Service/ServiceUtils/Update/UpdateFileResponseBuilder.cs create mode 100644 Service/ServiceUtils/Update/UpdatePlanResponseBuilder.cs create mode 100644 Service/SvcUtil.exe delete mode 100644 SharedLauncher/DataContract/DownloadPlanerResponseDC.cs create mode 100644 SharedLauncher/DataContract/LoginDC.cs delete mode 100644 SharedLauncher/DataContract/PlanerFileInfoDC.cs create mode 100644 SharedLauncher/DataContract/UpdateFileDC.cs create mode 100644 SharedLauncher/DataContract/UpdateFileRequest.cs create mode 100644 SharedLauncher/DataContract/UpdateFileResponse.cs rename SharedLauncher/DataContract/{PlanerPackageInfoDC.cs => UpdatePlanDC.cs} (83%) rename SharedLauncher/DataContract/{DownloadPlanerRequestDC.cs => UpdatePlanRequest.cs} (79%) rename SharedLauncher/DataContract/{DownloadPlanerResponseInfoDC.cs => UpdatePlanResponse.cs} (58%) create mode 100644 SharedLauncher/Exceptions/InvalidUpdateFileRequestException.cs create mode 100644 SharedLauncher/Exceptions/InvalidUpdatePlanRequestException.cs delete mode 100644 SharedLauncher/Extensions/DownloadPlanerResponseExtension.cs create mode 100644 SharedLauncher/Extensions/UpdateResponseExtension.cs create mode 100644 SharedLauncher/Information/Connection.cs delete mode 100644 SharedLauncher/Information/ConnectionInformation.cs create mode 100644 SharedLauncher/Information/DownloadLogger.cs create mode 100644 SharedLauncher/Information/Login.cs create mode 100644 SharedLauncher/Information/Session.cs create mode 100644 SharedLauncher/Information/SessionInformation.cs delete mode 100644 SharedLauncher/Update/PlanerFileInfo.cs delete mode 100644 SharedLauncher/Update/PlanerPackageInfo.cs create mode 100644 UnitTests/SharedLauncherTests.cs create mode 100644 UnitTests/UnitTests.csproj diff --git a/.gitignore b/.gitignore index 02cfcaa3e..dc85c3122 100644 --- a/.gitignore +++ b/.gitignore @@ -570,4 +570,10 @@ obj /SharedLauncher/bin /SharedLauncher/obj /BeWoLauncher/bin -/BeWoLauncher/obj \ No newline at end of file +/BeWoLauncher/obj +/UnitTests/bin +/UnitTests/obj +/DownloadServer/bin +/DownloadServer/obj +/BeWoTest/bin +/BeWoTest/obj diff --git a/BeWo/BeWoApp.xaml.cs b/BeWo/BeWoApp.xaml.cs index b66a7545a..2ff6ce89b 100644 --- a/BeWo/BeWoApp.xaml.cs +++ b/BeWo/BeWoApp.xaml.cs @@ -10,6 +10,7 @@ using BS.Shared.Core; using BS.Shared.DataContracts; using BS.Shared.DataContracts.Compact; using BS.Shared.Extensions; +using BS.SharedLauncher.Information; using ChatController.HauptKlassen; using DevExpress.Xpf.Core; using DevExpress.Xpf.Grid; @@ -537,39 +538,7 @@ namespace BeWo { get { - String url = ServerAddress?.ToLower(); - -#if DEBUG - //url = String.Format("http://localhost:3777/Host"); - //return new Uri("https://app4.bewoplaner.de/service"); - //url = String.Format("app1.bewoplaner.de/service"); -#endif - - if (url.IndexOf("localhost") < 0) - { - int i; - - - if (Int32.TryParse(url, out i)) - url = "app" + url; - - if (url.IndexOf('.') < 0) - { - url += ".bewoplaner.de"; - } - - //if (url.IndexOf("/service45") < 0) - //{ - // url += "/service45"; - //} - if (url.IndexOf("/service") < 0) - { - url += "/service"; - } - - return new Uri(String.Format("https://{0}", url)); - } - return new Uri(url); + return new Uri(SessionInformation.Connection.CoreServerAddressExact); } } @@ -764,52 +733,11 @@ namespace BeWo FrameworkElement.LanguageProperty.OverrideMetadata(typeof(FrameworkElement), new FrameworkPropertyMetadata(XmlLanguage.GetLanguage(CultureInfo.CurrentCulture.IetfLanguageTag))); var args = e.Args; - - //args = new string[] { "tedemo?undemo?pwdemo?ip?sn1?cs" }; - try + + if (args.Length > 0) { - if (args.Length > 0) - { - using (PipeStream pipeClient = new AnonymousPipeClientStream(PipeDirection.In, args[0])) - { - using (StreamReader sr = new StreamReader(pipeClient)) - { - string temp; - List result = new List(); - var signal = new string[] { "C-137", "C-131"}; - - // Warte auf Start - do - { - temp = sr.ReadLine(); - } - while (!temp.StartsWith(signal[0])); - - result.Add(sr.ReadLine()); - result.Add(sr.ReadLine()); - result.Add(sr.ReadLine()); - result.Add(sr.ReadLine()); - result.Add(sr.ReadLine()); - result.Add(sr.ReadLine()); - result.Add(sr.ReadLine()); - - do - { - temp = sr.ReadLine(); - } - while (!temp.StartsWith(signal[1])); - - Loader.Load(result.ToArray()); - - //if (System.Windows.Forms.MessageBox.Show(temp, "(OK to copy)", System.Windows.Forms.MessageBoxButtons.OKCancel) == System.Windows.Forms.DialogResult.OK) - //{ Clipboard.SetText(temp); } - } - } - } - } - catch (Exception ex) - { - MessageBox.Show(ex.ToString()); + SessionInformation.LoadPipe(args[0]); + Loader.Load(); } } @@ -1109,7 +1037,7 @@ namespace BeWo tenant = "5473568546"; #endif - var login = new Login(tenant, serverUrl => + var login = new ChatController.HauptKlassen.Login(tenant, serverUrl => { if (!string.IsNullOrWhiteSpace(serverUrl)) { diff --git a/BeWo/Loader.cs b/BeWo/Loader.cs index 91b77e4c9..f7a707c69 100644 --- a/BeWo/Loader.cs +++ b/BeWo/Loader.cs @@ -2,9 +2,9 @@ using BS.SharedLauncher.Information; using System; using System.Collections.Generic; +using System.IO; +using System.IO.Pipes; using System.Linq; -using System.Text; -using System.Threading.Tasks; using System.Windows; namespace BeWo @@ -17,30 +17,21 @@ namespace BeWo { Loaded = false; } - - public static void Load(string username, string password, string servername, string tenant, string coreserveraddress, string version) + + public static void Load() { - BeWoApp.UserName = username; - BeWoApp.UserPassword = password; - BeWoApp.ServerName = servername; - BeWoApp.Tenant = tenant; - BeWoApp.ServerAddress = coreserveraddress; - BeWoApp.ShortVersion = version; - BeWoApp.Version = "Version " + version; - - // var t = MessageBox.Show(BeWoApp.ServerAddress); - // var t1 = MessageBox.Show(BeWoApp.SiteOfOrigin.ToString()); + BeWoApp.UserName = SessionInformation.Login.Username; + BeWoApp.UserPassword = SessionInformation.Login.Password; + BeWoApp.ServerName = SessionInformation.Connection.Servername; + BeWoApp.Tenant = SessionInformation.Login.Tenant; + BeWoApp.ServerAddress = SessionInformation.Connection.CoreServerAddress; + BeWoApp.ShortVersion = SessionInformation.Session.Version; + BeWoApp.Version = "Version " + SessionInformation.Session.Version; BeWoApp.LoggedOnUser = ServiceFacade.DoUserServiceSync(s => s.LoadUserByNameAndPassword(BeWoApp.UserName, BeWoApp.UserPassword)); BeWoApp.Mandator = ServiceFacade.DoOperationsServiceSync(s => s.GetMandator()); Loaded = true; } - - public static void Load(Connection connection) - => Load(connection.Username, connection.Password, connection.Servername, connection.Tenant, connection.CoreServerAddress, connection.Version); - - public static void Load(string[] rawInput) - => Load(Connection.Parse(rawInput)); } } diff --git a/BeWo/MainWindow.xaml.cs b/BeWo/MainWindow.xaml.cs index dad6041ef..83ca3a7ba 100644 --- a/BeWo/MainWindow.xaml.cs +++ b/BeWo/MainWindow.xaml.cs @@ -25,7 +25,8 @@ namespace BeWo if (Loader.Loaded) ShowNewWay(); else - ShowOldWay(false); + // ShowOldWay(false); + throw new Exception("Loader failed"); } private void ShowNewWay() diff --git a/BeWoLauncher/App.config b/BeWoLauncher/App.config index bbc6e0aa7..ddbd19381 100644 --- a/BeWoLauncher/App.config +++ b/BeWoLauncher/App.config @@ -13,7 +13,7 @@ - + diff --git a/BeWoLauncher/BeWoLauncher.csproj b/BeWoLauncher/BeWoLauncher.csproj index fbfaf7511..ae35b12a9 100644 --- a/BeWoLauncher/BeWoLauncher.csproj +++ b/BeWoLauncher/BeWoLauncher.csproj @@ -145,11 +145,8 @@ LoadingFrame.xaml - - - - - GenericProgressFrame.xaml + + ProgressFrame.xaml FrameView.xaml @@ -217,7 +214,7 @@ Designer MSBuild:Compile - + MSBuild:Compile Designer @@ -311,7 +308,6 @@ ResXFileCodeGenerator Resources.Designer.cs - SettingsSingleFileGenerator diff --git a/BeWoLauncher/BeWoLauncher_TemporaryKey.pfx b/BeWoLauncher/BeWoLauncher_TemporaryKey.pfx deleted file mode 100644 index 5a575a88ede38f104534b6abdaddd52e456cdf7d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1668 zcmZXTdpOi-6vyA+Z^m!jTZSTx5hj;L<2or}Fhv@T87mYMxfUbrRx>V5BSS7l%O=x` z@F-i;#jbKK>yi|srZh+^&1&hQM76ToUp?*av(G;7bKY~#=X=ikynmcS5h4N@!cc^W z3!-8r@)o_*fN)TS5FulQh$V{6DMC!ceI}LGk<$%YK zn_KQ9O_PUtUcD!?#e1UG(8muq$mXg$`penNkG>)vn{d*|%~-Vi=&@N2FRra5KJjpE zU%lP(ili>v0pGcx6vMnWtDkxNid}x$aFJ=#R|c~_KTC236nSbv@>G9Tgi`rpNLqTz z0ZtD=Yw(BKLc~1Tb(vL(a0bTr7<5D|`8Y179a>dgz&%p7(%swdoQlP&P!b6R0Q|=DIew(`N@Hr4Yajlc1TW;dqSm%lJ`4-r>C-^=W zU;Sj9Eaw+>GhNIWC26y9crQp66umgOWk7xU03ltQ(NEK@EFW4lVxFNHEWNKc@VH<` zf8aUc{X=$_?_)S@l+;zfdOpHLcT!2&X8kSmZdd)dZGAr63=63m*}{Z5ro51GBJ@q$ z(#(U7H72nm9Af-|`l{lURBx+_gq$SkUhAV(mI1E#)<hhHI$Em&EnkE?q+N9W)`okoP!Ps?% z!yIqhgLf$Sf5u!z*A~HIApihn+rLo9){n3mqyjJWYycj>0Z`E61jv8}?0_e5Mk5DQ zvHi@P0riXO1l9n1w1S3u50rVL84ayTr-ULZ)(C`!gj6lamPzmf3=ju)f@F{gQc#Nq z-vA(%Q_fYpB~~i!!7SWzged( zKPz70%-JroE!Fukq|~E#iSA}5KCG#9Y<_Yl*(-r7Z58A0ckb%A?^2^{^uh6Trz%F8 zl6K+d3^gpnx_WhIaJEC=ZK^ah<^8F$;tQOare-yI_;=T>UPjDRiNZy{n`D*Y=dR#F z>0e=dSROt%_gKc}s>&T!ESU-g^F{TNlkT@^66`{ zT_q=5gu|61Hck=#1<`Iht`h>!D*G)D4mQ3=h}GwR=vTT{h}Rn)OE7-jC{x=_*I7pM zyz}S{65X>@ir;nY;^@(Z5XbZ6F+MX(*DRR9oVK4B=k4JWRlD2{c+8i11Z>+%YReJ$ zsPh@vNShTfHAuZS+KrAjqP*u@uvzO)$cz4Fp@ueY!UbhSy# zsVUX8-Bh+KGdPI;}kn?!&RM<`xm-jpDQ#;n%RJKYpC`Y2R0$er_^wRHc{K$Hg zX5V&p+;qF4f~#lM&X#zd6A&-N9XG0{D+Z;Sc^jJ*hE~y-)xYhp@wWRGs=2xHQFAk8 z9mSY}LzJvFG4OJ%&P~?c#UTeXQw@It-gBS8_w2&y-B=xej^@12_fxrTIZw2lR}9;{ LI>mDRG+=)L#&D{e diff --git a/BeWoLauncher/LauncherApp.xaml.cs b/BeWoLauncher/LauncherApp.xaml.cs index 034822460..37515ed1d 100644 --- a/BeWoLauncher/LauncherApp.xaml.cs +++ b/BeWoLauncher/LauncherApp.xaml.cs @@ -48,11 +48,7 @@ namespace BeWoLauncher base.OnStartup(e); - ProcessController.CheckForOtherInstance(); - - // Update Server Adresses - ConnectionInformation.LauncherServerAddress = ConnectionInformation.LauncherServerAddressOrigin.ToString(); - LauncherServiceFacade.UpdateServerAddresses(ConnectionInformation.LauncherServerAddress); + ProcessController.StartLauncher(); Dispatcher.UnhandledException += (s, ex) => diff --git a/BeWoLauncher/Logic/Behavior/LaunchBehavior.cs b/BeWoLauncher/Logic/Behavior/LaunchBehavior.cs index e4849e8c3..63d4eea1c 100644 --- a/BeWoLauncher/Logic/Behavior/LaunchBehavior.cs +++ b/BeWoLauncher/Logic/Behavior/LaunchBehavior.cs @@ -1,6 +1,7 @@ using BeWoLauncher.Components; using BeWoLauncher.Logic.Controller; using BeWoLauncher.Logic.Utils; +using BS.SharedLauncher.Extensions; using BS.SharedLauncher.Information; using System; using System.Threading.Tasks; @@ -52,9 +53,9 @@ namespace BeWoLauncher.Logic.Behavior try { DownloadController.Start(); - DownloadController.Manager.StartDownloadInfo(); + DownloadController.Manager.GetUpdatePlan(); - if (DownloadController.Manager.ResponseInfo.HasSomethingToDo) + if (DownloadController.Manager.UpdatePlanResponse.HasToDo()) { ViewBehavior.ShowInfo(); } diff --git a/BeWoLauncher/Logic/Behavior/ViewSwitchBehavior.cs b/BeWoLauncher/Logic/Behavior/ViewSwitchBehavior.cs index cf589467b..4904ee431 100644 --- a/BeWoLauncher/Logic/Behavior/ViewSwitchBehavior.cs +++ b/BeWoLauncher/Logic/Behavior/ViewSwitchBehavior.cs @@ -2,6 +2,7 @@ using BeWoLauncher.Logic.Utils; using BeWoLauncher.View; using BeWoLauncher.View.Frames; +using BS.SharedLauncher.Enums; using System; using System.IO; using System.Threading.Tasks; @@ -15,6 +16,7 @@ namespace BeWoLauncher.Logic.Behavior { private UserControl _currentView; private FrameBase _currentFrame; + private LauncherMode _currentLauncherMode; private UserControl CurrentView { @@ -32,7 +34,8 @@ namespace BeWoLauncher.Logic.Behavior } private FrameBase CurrentFrame { - get => _currentFrame; set + get => _currentFrame; + set { _currentFrame = value; @@ -131,11 +134,18 @@ namespace BeWoLauncher.Logic.Behavior LauncherAppdataConfig.SetFirstInstallationSuccess(true); ShowFrame(FrameType.LoadingScreen); } - public void InstallationFailed(Exception exception) + public void InstallFailed(object sender, EventArgs e) { - Error = exception; ShowFrame(FrameType.InstallFailed); } + public void UpdateFailed(object sender, EventArgs e) + { + ShowFrame(FrameType.UpdateFailed); + } + public void UninstallFailed(object sender, EventArgs e) + { + ShowFrame(FrameType.UninstallFailed); + } public void UpdateStarting(object sender, EventArgs e) { @@ -145,11 +155,6 @@ namespace BeWoLauncher.Logic.Behavior { ShowFrame(FrameType.LoadingScreen); } - public void UpdateFailed(Exception exception) - { - Error = exception; - ShowFrame(FrameType.UpdateFailed); - } public void UninstallStarting(object sender, EventArgs e) { @@ -159,10 +164,5 @@ namespace BeWoLauncher.Logic.Behavior { ShowFrame(FrameType.UninstallSuccessful); } - public void UninstallFailed(Exception exception) - { - Error = exception; - ShowFrame(FrameType.UninstallFailed); - } } } diff --git a/BeWoLauncher/Logic/Controller/DownloadController.cs b/BeWoLauncher/Logic/Controller/DownloadController.cs index 139b0fa85..6ff041aeb 100644 --- a/BeWoLauncher/Logic/Controller/DownloadController.cs +++ b/BeWoLauncher/Logic/Controller/DownloadController.cs @@ -1,4 +1,6 @@ -using BeWoLauncher.Logic.Utils.Download; +using BeWoLauncher.Logic.Utils; +using BeWoLauncher.Logic.Utils.Download; +using BS.SharedLauncher.Information; using BS.SharedLauncher.Utils; using System.IO; @@ -9,11 +11,13 @@ namespace BeWoLauncher.Logic.Controller public static DownloadManager Manager { get; set; } public static long FreeSpace { get; set; } - public static long NeededSpace => Manager.ResponseInfo.DownloadSize; + public static long NeededSpace => Manager.UpdatePlanResponse.DownloadSize; public static void Start() { Manager = new DownloadManager(); + + DownloadLogger.Init(LauncherPaths.GetLoggerPath()); } public static string UpdateDiskSpace(string path) diff --git a/BeWoLauncher/Logic/Controller/ProcessController.cs b/BeWoLauncher/Logic/Controller/ProcessController.cs index cd8081027..9fed8fdd4 100644 --- a/BeWoLauncher/Logic/Controller/ProcessController.cs +++ b/BeWoLauncher/Logic/Controller/ProcessController.cs @@ -1,4 +1,5 @@ using BeWoLauncher.Logic.Utils; +using BeWoLauncher.ServiceProxy; using BS.SharedLauncher.Information; using System; using System.Diagnostics; @@ -49,6 +50,17 @@ namespace BeWoLauncher.Logic.Controller } } + internal static void StartLauncher() + { + CheckForOtherInstance(); + + // Update Server Adresses + //ConnectionInformation.DownloadServerAddress = ConnectionInformation.DownloadServerAddressExact.ToString(); + //ConnectionInformation.CoreServerAddress = ConnectionInformation.CoreServerAddress.ToString(); + + LauncherServiceFacade.UpdateServerAddresses(SessionInformation.Connection.DownloadServerAddressExact, SessionInformation.Connection.CoreServerAddressExact); + } + internal static void StartLauncherShutdown() { Current.Shutdown(); @@ -72,6 +84,7 @@ namespace BeWoLauncher.Logic.Controller PlanerProcess.OutputDataReceived += MessageFromPlanerClient; PlanerProcess.Start(); + DownloadLogger.Post2($"Launcher Start: {PlanerProcess.StartInfo.FileName}"); PlanerProcess.BeginOutputReadLine(); @@ -81,19 +94,17 @@ namespace BeWoLauncher.Logic.Controller { using (StreamWriter sw = new StreamWriter(pipeServer)) { + var signal = new string[] { "C-137", "C-131" }; + sw.AutoFlush = true; - - sw.WriteLine("C-137"); - pipeServer.WaitForPipeDrain(); - foreach (var info in ConnectionInformation.Connection.ToArray()) - { - sw.WriteLine(info); - pipeServer.WaitForPipeDrain(); - } + SendInfo(sw, signal[0], pipeServer); - sw.WriteLine("C-131"); - pipeServer.WaitForPipeDrain(); + SessionInformation.Connection.ToList().ForEach(info => SendInfo(sw, info, pipeServer)); + SessionInformation.Login.ToList().ForEach(info => SendInfo(sw, info, pipeServer)); + SessionInformation.Session.ToList().ForEach(info => SendInfo(sw, info, pipeServer)); + + SendInfo(sw, signal[1], pipeServer); } } catch (IOException ex) @@ -102,6 +113,11 @@ namespace BeWoLauncher.Logic.Controller } } } + internal static void SendInfo(StreamWriter sw, string info, AnonymousPipeServerStream pipe) + { + sw.WriteLine(info); + pipe.WaitForPipeDrain(); + } internal static void KillPlanerProcess() { foreach (var process in Process.GetProcesses()) diff --git a/BeWoLauncher/Logic/Multitenancy/MultitenancyInterceptor.cs b/BeWoLauncher/Logic/Multitenancy/MultitenancyInterceptor.cs index 075b61c14..cc05087b0 100644 --- a/BeWoLauncher/Logic/Multitenancy/MultitenancyInterceptor.cs +++ b/BeWoLauncher/Logic/Multitenancy/MultitenancyInterceptor.cs @@ -14,7 +14,7 @@ namespace BeWoLauncher.Multitenancy public object BeforeSendRequest(ref Message request, IClientChannel channel) { - request.Headers.Add(new MultitenancyHeader { Tenant = ConnectionInformation.Tenant }); + request.Headers.Add(new MultitenancyHeader { Tenant = SessionInformation.Login.Tenant }); return null; } } diff --git a/BeWoLauncher/Logic/Security/LauncherSecurityHeaderInterceptor.cs b/BeWoLauncher/Logic/Security/LauncherSecurityHeaderInterceptor.cs index 9629a7419..8c0e49527 100644 --- a/BeWoLauncher/Logic/Security/LauncherSecurityHeaderInterceptor.cs +++ b/BeWoLauncher/Logic/Security/LauncherSecurityHeaderInterceptor.cs @@ -15,7 +15,7 @@ namespace BeWoLauncher.Security public object BeforeSendRequest(ref Message request, IClientChannel channel) { - request.Headers.Add(new LauncherSecurityHeader { Username = ConnectionInformation.Username, Password = ConnectionInformation.Password }); + request.Headers.Add(new LauncherSecurityHeader { Username = SessionInformation.Login.Username, Password = SessionInformation.Login.Password }); return null; } } diff --git a/BeWoLauncher/Logic/ServiceProxy/LauncherGenerated.cs b/BeWoLauncher/Logic/ServiceProxy/LauncherGenerated.cs index d7c9e0f13..0b2a8cd65 100644 --- a/BeWoLauncher/Logic/ServiceProxy/LauncherGenerated.cs +++ b/BeWoLauncher/Logic/ServiceProxy/LauncherGenerated.cs @@ -11,26 +11,26 @@ namespace BeWoLauncher.ServiceProxy { using System.Runtime.Serialization; - - + + [System.Diagnostics.DebuggerStepThroughAttribute()] [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Runtime.Serialization", "4.0.0.0")] - [System.Runtime.Serialization.DataContractAttribute(Name="BeWoFault", Namespace="http://schemas.datacontract.org/2004/07/BeWo.Service.ServiceContracts")] + [System.Runtime.Serialization.DataContractAttribute(Name = "BeWoFault", Namespace = "http://schemas.datacontract.org/2004/07/BeWo.Service.ServiceContracts")] public partial class BeWoFault : object, System.Runtime.Serialization.IExtensibleDataObject, System.ComponentModel.INotifyPropertyChanged { - + private System.Runtime.Serialization.ExtensionDataObject extensionDataField; - + private BeWoLauncher.ServiceProxy.BeWoFaultType FaultTypeField; - + private string InnerExceptionMessageField; - + private string InnerExceptionStackTraceField; - + private string MessageField; - + private string StackTraceField; - + public System.Runtime.Serialization.ExtensionDataObject ExtensionData { get @@ -42,7 +42,7 @@ namespace BeWoLauncher.ServiceProxy this.extensionDataField = value; } } - + [System.Runtime.Serialization.DataMemberAttribute()] public BeWoLauncher.ServiceProxy.BeWoFaultType FaultType { @@ -59,7 +59,7 @@ namespace BeWoLauncher.ServiceProxy } } } - + [System.Runtime.Serialization.DataMemberAttribute()] public string InnerExceptionMessage { @@ -76,7 +76,7 @@ namespace BeWoLauncher.ServiceProxy } } } - + [System.Runtime.Serialization.DataMemberAttribute()] public string InnerExceptionStackTrace { @@ -93,7 +93,7 @@ namespace BeWoLauncher.ServiceProxy } } } - + [System.Runtime.Serialization.DataMemberAttribute()] public string Message { @@ -110,7 +110,7 @@ namespace BeWoLauncher.ServiceProxy } } } - + [System.Runtime.Serialization.DataMemberAttribute()] public string StackTrace { @@ -127,9 +127,9 @@ namespace BeWoLauncher.ServiceProxy } } } - + public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged; - + protected void RaisePropertyChanged(string propertyName) { System.ComponentModel.PropertyChangedEventHandler propertyChanged = this.PropertyChanged; @@ -139,247 +139,265 @@ namespace BeWoLauncher.ServiceProxy } } } - + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Runtime.Serialization", "4.0.0.0")] - [System.Runtime.Serialization.DataContractAttribute(Name="BeWoFaultType", Namespace="http://schemas.datacontract.org/2004/07/BeWo.Service.ServiceContracts")] + [System.Runtime.Serialization.DataContractAttribute(Name = "BeWoFaultType", Namespace = "http://schemas.datacontract.org/2004/07/BeWo.Service.ServiceContracts")] public enum BeWoFaultType : int { - + [System.Runtime.Serialization.EnumMemberAttribute()] Unknown = 0, - + [System.Runtime.Serialization.EnumMemberAttribute()] Concurrency = 1, - + [System.Runtime.Serialization.EnumMemberAttribute()] DeleteNotPossible = 2, - + [System.Runtime.Serialization.EnumMemberAttribute()] LoginNameTaken = 3, - + [System.Runtime.Serialization.EnumMemberAttribute()] CustomWithoutDetails = 4, } - + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")] - [System.ServiceModel.ServiceContractAttribute(ConfigurationName="BeWoLauncher.ServiceProxy.ILauncherService")] + [System.ServiceModel.ServiceContractAttribute(ConfigurationName = "BeWoLauncher.ServiceProxy.ILauncherService")] public interface ILauncherService { - - [System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/ILauncherService/IsUserValid", ReplyAction="http://tempuri.org/ILauncherService/IsUserValidResponse")] - [System.ServiceModel.FaultContractAttribute(typeof(BeWoLauncher.ServiceProxy.BeWoFault), Action="http://tempuri.org/ILauncherService/IsUserValidBeWoFaultFault", Name="BeWoFault", Namespace="http://schemas.datacontract.org/2004/07/BeWo.Service.ServiceContracts")] + + [System.ServiceModel.OperationContractAttribute(Action = "http://tempuri.org/ILauncherService/IsUserValid", ReplyAction = "http://tempuri.org/ILauncherService/IsUserValidResponse")] + [System.ServiceModel.FaultContractAttribute(typeof(BeWoLauncher.ServiceProxy.BeWoFault), Action = "http://tempuri.org/ILauncherService/IsUserValidBeWoFaultFault", Name = "BeWoFault", Namespace = "http://schemas.datacontract.org/2004/07/BeWo.Service.ServiceContracts")] BS.SharedLauncher.Enums.UserValidationResult IsUserValid(string pUserName, string pPassword, string pPIN, string clientId, bool checkTenant); - - [System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/ILauncherService/ResetTenant", ReplyAction="http://tempuri.org/ILauncherService/ResetTenantResponse")] - [System.ServiceModel.FaultContractAttribute(typeof(BeWoLauncher.ServiceProxy.BeWoFault), Action="http://tempuri.org/ILauncherService/ResetTenantBeWoFaultFault", Name="BeWoFault", Namespace="http://schemas.datacontract.org/2004/07/BeWo.Service.ServiceContracts")] + + [System.ServiceModel.OperationContractAttribute(Action = "http://tempuri.org/ILauncherService/ResetTenant", ReplyAction = "http://tempuri.org/ILauncherService/ResetTenantResponse")] + [System.ServiceModel.FaultContractAttribute(typeof(BeWoLauncher.ServiceProxy.BeWoFault), Action = "http://tempuri.org/ILauncherService/ResetTenantBeWoFaultFault", Name = "BeWoFault", Namespace = "http://schemas.datacontract.org/2004/07/BeWo.Service.ServiceContracts")] void ResetTenant(string tenant); - - [System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/ILauncherService/ResetAllTenant", ReplyAction="http://tempuri.org/ILauncherService/ResetAllTenantResponse")] - [System.ServiceModel.FaultContractAttribute(typeof(BeWoLauncher.ServiceProxy.BeWoFault), Action="http://tempuri.org/ILauncherService/ResetAllTenantBeWoFaultFault", Name="BeWoFault", Namespace="http://schemas.datacontract.org/2004/07/BeWo.Service.ServiceContracts")] + + [System.ServiceModel.OperationContractAttribute(Action = "http://tempuri.org/ILauncherService/ResetAllTenant", ReplyAction = "http://tempuri.org/ILauncherService/ResetAllTenantResponse")] + [System.ServiceModel.FaultContractAttribute(typeof(BeWoLauncher.ServiceProxy.BeWoFault), Action = "http://tempuri.org/ILauncherService/ResetAllTenantBeWoFaultFault", Name = "BeWoFault", Namespace = "http://schemas.datacontract.org/2004/07/BeWo.Service.ServiceContracts")] void ResetAllTenant(); - - [System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/ILauncherService/GetEmailForUserName", ReplyAction="http://tempuri.org/ILauncherService/GetEmailForUserNameResponse")] - [System.ServiceModel.FaultContractAttribute(typeof(BeWoLauncher.ServiceProxy.BeWoFault), Action="http://tempuri.org/ILauncherService/GetEmailForUserNameBeWoFaultFault", Name="BeWoFault", Namespace="http://schemas.datacontract.org/2004/07/BeWo.Service.ServiceContracts")] + + [System.ServiceModel.OperationContractAttribute(Action = "http://tempuri.org/ILauncherService/GetEmailForUserName", ReplyAction = "http://tempuri.org/ILauncherService/GetEmailForUserNameResponse")] + [System.ServiceModel.FaultContractAttribute(typeof(BeWoLauncher.ServiceProxy.BeWoFault), Action = "http://tempuri.org/ILauncherService/GetEmailForUserNameBeWoFaultFault", Name = "BeWoFault", Namespace = "http://schemas.datacontract.org/2004/07/BeWo.Service.ServiceContracts")] bool GetEmailForUserName(out string email, string pUserName, System.Uri serverName); - - [System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/ILauncherService/CheckPassword", ReplyAction="http://tempuri.org/ILauncherService/CheckPasswordResponse")] - [System.ServiceModel.FaultContractAttribute(typeof(BeWoLauncher.ServiceProxy.BeWoFault), Action="http://tempuri.org/ILauncherService/CheckPasswordBeWoFaultFault", Name="BeWoFault", Namespace="http://schemas.datacontract.org/2004/07/BeWo.Service.ServiceContracts")] + + [System.ServiceModel.OperationContractAttribute(Action = "http://tempuri.org/ILauncherService/CheckPassword", ReplyAction = "http://tempuri.org/ILauncherService/CheckPasswordResponse")] + [System.ServiceModel.FaultContractAttribute(typeof(BeWoLauncher.ServiceProxy.BeWoFault), Action = "http://tempuri.org/ILauncherService/CheckPasswordBeWoFaultFault", Name = "BeWoFault", Namespace = "http://schemas.datacontract.org/2004/07/BeWo.Service.ServiceContracts")] BS.SharedLauncher.Enums.PasswordValidationResult CheckPassword(long userOid, string pOldPassword, string pNewPassword); - - [System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/ILauncherService/CheckPassword2", ReplyAction="http://tempuri.org/ILauncherService/CheckPassword2Response")] - [System.ServiceModel.FaultContractAttribute(typeof(BeWoLauncher.ServiceProxy.BeWoFault), Action="http://tempuri.org/ILauncherService/CheckPassword2BeWoFaultFault", Name="BeWoFault", Namespace="http://schemas.datacontract.org/2004/07/BeWo.Service.ServiceContracts")] + + [System.ServiceModel.OperationContractAttribute(Action = "http://tempuri.org/ILauncherService/CheckPassword2", ReplyAction = "http://tempuri.org/ILauncherService/CheckPassword2Response")] + [System.ServiceModel.FaultContractAttribute(typeof(BeWoLauncher.ServiceProxy.BeWoFault), Action = "http://tempuri.org/ILauncherService/CheckPassword2BeWoFaultFault", Name = "BeWoFault", Namespace = "http://schemas.datacontract.org/2004/07/BeWo.Service.ServiceContracts")] BS.SharedLauncher.Enums.PasswordValidationResult CheckPassword2(string username, string pOldPassword, string pNewPassword); - - [System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/ILauncherService/ChangePassword", ReplyAction="http://tempuri.org/ILauncherService/ChangePasswordResponse")] - [System.ServiceModel.FaultContractAttribute(typeof(BeWoLauncher.ServiceProxy.BeWoFault), Action="http://tempuri.org/ILauncherService/ChangePasswordBeWoFaultFault", Name="BeWoFault", Namespace="http://schemas.datacontract.org/2004/07/BeWo.Service.ServiceContracts")] + + [System.ServiceModel.OperationContractAttribute(Action = "http://tempuri.org/ILauncherService/ChangePassword", ReplyAction = "http://tempuri.org/ILauncherService/ChangePasswordResponse")] + [System.ServiceModel.FaultContractAttribute(typeof(BeWoLauncher.ServiceProxy.BeWoFault), Action = "http://tempuri.org/ILauncherService/ChangePasswordBeWoFaultFault", Name = "BeWoFault", Namespace = "http://schemas.datacontract.org/2004/07/BeWo.Service.ServiceContracts")] long ChangePassword(string pUserName, string pOldPassword, string pNewPassword); - - [System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/ILauncherService/ResetPasswordInfo", ReplyAction="http://tempuri.org/ILauncherService/ResetPasswordInfoResponse")] - [System.ServiceModel.FaultContractAttribute(typeof(BeWoLauncher.ServiceProxy.BeWoFault), Action="http://tempuri.org/ILauncherService/ResetPasswordInfoBeWoFaultFault", Name="BeWoFault", Namespace="http://schemas.datacontract.org/2004/07/BeWo.Service.ServiceContracts")] + + [System.ServiceModel.OperationContractAttribute(Action = "http://tempuri.org/ILauncherService/ResetPasswordInfo", ReplyAction = "http://tempuri.org/ILauncherService/ResetPasswordInfoResponse")] + [System.ServiceModel.FaultContractAttribute(typeof(BeWoLauncher.ServiceProxy.BeWoFault), Action = "http://tempuri.org/ILauncherService/ResetPasswordInfoBeWoFaultFault", Name = "BeWoFault", Namespace = "http://schemas.datacontract.org/2004/07/BeWo.Service.ServiceContracts")] void ResetPasswordInfo(string pUserName, string pPassword); } - + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")] public interface ILauncherServiceChannel : BeWoLauncher.ServiceProxy.ILauncherService, System.ServiceModel.IClientChannel { } - + [System.Diagnostics.DebuggerStepThroughAttribute()] [System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")] public partial class LauncherServiceClient : System.ServiceModel.ClientBase, BeWoLauncher.ServiceProxy.ILauncherService { - + public LauncherServiceClient() { } - - public LauncherServiceClient(string endpointConfigurationName) : + + public LauncherServiceClient(string endpointConfigurationName) : base(endpointConfigurationName) { } - - public LauncherServiceClient(string endpointConfigurationName, string remoteAddress) : + + public LauncherServiceClient(string endpointConfigurationName, string remoteAddress) : base(endpointConfigurationName, remoteAddress) { } - - public LauncherServiceClient(string endpointConfigurationName, System.ServiceModel.EndpointAddress remoteAddress) : + + public LauncherServiceClient(string endpointConfigurationName, System.ServiceModel.EndpointAddress remoteAddress) : base(endpointConfigurationName, remoteAddress) { } - - public LauncherServiceClient(System.ServiceModel.Channels.Binding binding, System.ServiceModel.EndpointAddress remoteAddress) : + + public LauncherServiceClient(System.ServiceModel.Channels.Binding binding, System.ServiceModel.EndpointAddress remoteAddress) : base(binding, remoteAddress) { } - + public BS.SharedLauncher.Enums.UserValidationResult IsUserValid(string pUserName, string pPassword, string pPIN, string clientId, bool checkTenant) { return base.Channel.IsUserValid(pUserName, pPassword, pPIN, clientId, checkTenant); } - + public void ResetTenant(string tenant) { base.Channel.ResetTenant(tenant); } - + public void ResetAllTenant() { base.Channel.ResetAllTenant(); } - + public bool GetEmailForUserName(out string email, string pUserName, System.Uri serverName) { return base.Channel.GetEmailForUserName(out email, pUserName, serverName); } - + public BS.SharedLauncher.Enums.PasswordValidationResult CheckPassword(long userOid, string pOldPassword, string pNewPassword) { return base.Channel.CheckPassword(userOid, pOldPassword, pNewPassword); } - + public BS.SharedLauncher.Enums.PasswordValidationResult CheckPassword2(string username, string pOldPassword, string pNewPassword) { return base.Channel.CheckPassword2(username, pOldPassword, pNewPassword); } - + public long ChangePassword(string pUserName, string pOldPassword, string pNewPassword) { return base.Channel.ChangePassword(pUserName, pOldPassword, pNewPassword); } - + public void ResetPasswordInfo(string pUserName, string pPassword) { base.Channel.ResetPasswordInfo(pUserName, pPassword); } } - + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")] - [System.ServiceModel.ServiceContractAttribute(ConfigurationName="BeWoLauncher.ServiceProxy.IEnumTranslationService")] + [System.ServiceModel.ServiceContractAttribute(ConfigurationName = "BeWoLauncher.ServiceProxy.IEnumTranslationService")] public interface IEnumTranslationService { - - [System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/IEnumTranslationService/GetTranslation", ReplyAction="http://tempuri.org/IEnumTranslationService/GetTranslationResponse")] - [System.ServiceModel.FaultContractAttribute(typeof(BeWoLauncher.ServiceProxy.BeWoFault), Action="http://tempuri.org/IEnumTranslationService/GetTranslationBeWoFaultFault", Name="BeWoFault", Namespace="http://schemas.datacontract.org/2004/07/BeWo.Service.ServiceContracts")] + + [System.ServiceModel.OperationContractAttribute(Action = "http://tempuri.org/IEnumTranslationService/GetTranslation", ReplyAction = "http://tempuri.org/IEnumTranslationService/GetTranslationResponse")] + [System.ServiceModel.FaultContractAttribute(typeof(BeWoLauncher.ServiceProxy.BeWoFault), Action = "http://tempuri.org/IEnumTranslationService/GetTranslationBeWoFaultFault", Name = "BeWoFault", Namespace = "http://schemas.datacontract.org/2004/07/BeWo.Service.ServiceContracts")] string GetTranslation(string e, short value); } - + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")] public interface IEnumTranslationServiceChannel : BeWoLauncher.ServiceProxy.IEnumTranslationService, System.ServiceModel.IClientChannel { } - + [System.Diagnostics.DebuggerStepThroughAttribute()] [System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")] public partial class EnumTranslationServiceClient : System.ServiceModel.ClientBase, BeWoLauncher.ServiceProxy.IEnumTranslationService { - + public EnumTranslationServiceClient() { } - - public EnumTranslationServiceClient(string endpointConfigurationName) : + + public EnumTranslationServiceClient(string endpointConfigurationName) : base(endpointConfigurationName) { } - - public EnumTranslationServiceClient(string endpointConfigurationName, string remoteAddress) : + + public EnumTranslationServiceClient(string endpointConfigurationName, string remoteAddress) : base(endpointConfigurationName, remoteAddress) { } - - public EnumTranslationServiceClient(string endpointConfigurationName, System.ServiceModel.EndpointAddress remoteAddress) : + + public EnumTranslationServiceClient(string endpointConfigurationName, System.ServiceModel.EndpointAddress remoteAddress) : base(endpointConfigurationName, remoteAddress) { } - - public EnumTranslationServiceClient(System.ServiceModel.Channels.Binding binding, System.ServiceModel.EndpointAddress remoteAddress) : + + public EnumTranslationServiceClient(System.ServiceModel.Channels.Binding binding, System.ServiceModel.EndpointAddress remoteAddress) : base(binding, remoteAddress) { } - + public string GetTranslation(string e, short value) { return base.Channel.GetTranslation(e, value); } } - + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")] - [System.ServiceModel.ServiceContractAttribute(ConfigurationName="BeWoLauncher.ServiceProxy.IDownloadBeWoService")] + [System.ServiceModel.ServiceContractAttribute(ConfigurationName = "BeWoLauncher.ServiceProxy.IDownloadBeWoService")] public interface IDownloadBeWoService { - - [System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/IDownloadBeWoService/Download2", ReplyAction="http://tempuri.org/IDownloadBeWoService/Download2Response")] - [System.ServiceModel.FaultContractAttribute(typeof(BeWoLauncher.ServiceProxy.BeWoFault), Action="http://tempuri.org/IDownloadBeWoService/Download2BeWoFaultFault", Name="BeWoFault", Namespace="http://schemas.datacontract.org/2004/07/BeWo.Service.ServiceContracts")] - BS.SharedLauncher.DataContract.DownloadPlanerResponseDC Download2(BS.SharedLauncher.DataContract.DownloadPlanerRequestDC request); - - [System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/IDownloadBeWoService/DownloadInfo", ReplyAction="http://tempuri.org/IDownloadBeWoService/DownloadInfoResponse")] - [System.ServiceModel.FaultContractAttribute(typeof(BeWoLauncher.ServiceProxy.BeWoFault), Action="http://tempuri.org/IDownloadBeWoService/DownloadInfoBeWoFaultFault", Name="BeWoFault", Namespace="http://schemas.datacontract.org/2004/07/BeWo.Service.ServiceContracts")] - BS.SharedLauncher.DataContract.DownloadPlanerResponseInfoDC DownloadInfo(BS.SharedLauncher.DataContract.DownloadPlanerRequestDC request); + + [System.ServiceModel.OperationContractAttribute(Action = "http://tempuri.org/IDownloadBeWoService/Download2", ReplyAction = "http://tempuri.org/IDownloadBeWoService/Download2Response")] + [System.ServiceModel.FaultContractAttribute(typeof(BeWoLauncher.ServiceProxy.BeWoFault), Action = "http://tempuri.org/IDownloadBeWoService/Download2BeWoFaultFault", Name = "BeWoFault", Namespace = "http://schemas.datacontract.org/2004/07/BeWo.Service.ServiceContracts")] + BS.SharedLauncher.DataContract.UpdateFileResponse Download2(BS.SharedLauncher.DataContract.UpdatePlanRequest request); + + [System.ServiceModel.OperationContractAttribute(Action = "http://tempuri.org/IDownloadBeWoService/DownloadInfo", ReplyAction = "http://tempuri.org/IDownloadBeWoService/DownloadInfoResponse")] + [System.ServiceModel.FaultContractAttribute(typeof(BeWoLauncher.ServiceProxy.BeWoFault), Action = "http://tempuri.org/IDownloadBeWoService/DownloadInfoBeWoFaultFault", Name = "BeWoFault", Namespace = "http://schemas.datacontract.org/2004/07/BeWo.Service.ServiceContracts")] + BS.SharedLauncher.DataContract.UpdatePlanResponse DownloadInfo(BS.SharedLauncher.DataContract.UpdatePlanRequest request); + + [System.ServiceModel.OperationContractAttribute(Action = "http://tempuri.org/IDownloadBeWoService/GetUpdatePlan", ReplyAction = "http://tempuri.org/IDownloadBeWoService/GetUpdatePlanResponse")] + [System.ServiceModel.FaultContractAttribute(typeof(BeWoLauncher.ServiceProxy.BeWoFault), Action = "http://tempuri.org/IDownloadBeWoService/GetUpdatePlanBeWoFaultFault", Name = "BeWoFault", Namespace = "http://schemas.datacontract.org/2004/07/BeWo.Service.ServiceContracts")] + BS.SharedLauncher.DataContract.UpdatePlanResponse GetUpdatePlan(BS.SharedLauncher.DataContract.UpdatePlanRequest request); + + [System.ServiceModel.OperationContractAttribute(Action = "http://tempuri.org/IDownloadBeWoService/GetUpdateFile", ReplyAction = "http://tempuri.org/IDownloadBeWoService/GetUpdateFileResponse")] + [System.ServiceModel.FaultContractAttribute(typeof(BeWoLauncher.ServiceProxy.BeWoFault), Action = "http://tempuri.org/IDownloadBeWoService/GetUpdateFileBeWoFaultFault", Name = "BeWoFault", Namespace = "http://schemas.datacontract.org/2004/07/BeWo.Service.ServiceContracts")] + BS.SharedLauncher.DataContract.UpdateFileResponse GetUpdateFile(BS.SharedLauncher.DataContract.UpdateFileRequest request); } - + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")] public interface IDownloadBeWoServiceChannel : BeWoLauncher.ServiceProxy.IDownloadBeWoService, System.ServiceModel.IClientChannel { } - + [System.Diagnostics.DebuggerStepThroughAttribute()] [System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")] public partial class DownloadBeWoServiceClient : System.ServiceModel.ClientBase, BeWoLauncher.ServiceProxy.IDownloadBeWoService { - + public DownloadBeWoServiceClient() { } - - public DownloadBeWoServiceClient(string endpointConfigurationName) : + + public DownloadBeWoServiceClient(string endpointConfigurationName) : base(endpointConfigurationName) { } - - public DownloadBeWoServiceClient(string endpointConfigurationName, string remoteAddress) : + + public DownloadBeWoServiceClient(string endpointConfigurationName, string remoteAddress) : base(endpointConfigurationName, remoteAddress) { } - - public DownloadBeWoServiceClient(string endpointConfigurationName, System.ServiceModel.EndpointAddress remoteAddress) : + + public DownloadBeWoServiceClient(string endpointConfigurationName, System.ServiceModel.EndpointAddress remoteAddress) : base(endpointConfigurationName, remoteAddress) { } - - public DownloadBeWoServiceClient(System.ServiceModel.Channels.Binding binding, System.ServiceModel.EndpointAddress remoteAddress) : + + public DownloadBeWoServiceClient(System.ServiceModel.Channels.Binding binding, System.ServiceModel.EndpointAddress remoteAddress) : base(binding, remoteAddress) { } - - public BS.SharedLauncher.DataContract.DownloadPlanerResponseDC Download2(BS.SharedLauncher.DataContract.DownloadPlanerRequestDC request) + + public BS.SharedLauncher.DataContract.UpdateFileResponse Download2(BS.SharedLauncher.DataContract.UpdatePlanRequest request) { return base.Channel.Download2(request); } - - public BS.SharedLauncher.DataContract.DownloadPlanerResponseInfoDC DownloadInfo(BS.SharedLauncher.DataContract.DownloadPlanerRequestDC request) + + public BS.SharedLauncher.DataContract.UpdatePlanResponse DownloadInfo(BS.SharedLauncher.DataContract.UpdatePlanRequest request) { return base.Channel.DownloadInfo(request); } + + public BS.SharedLauncher.DataContract.UpdatePlanResponse GetUpdatePlan(BS.SharedLauncher.DataContract.UpdatePlanRequest request) + { + return base.Channel.GetUpdatePlan(request); + } + + public BS.SharedLauncher.DataContract.UpdateFileResponse GetUpdateFile(BS.SharedLauncher.DataContract.UpdateFileRequest request) + { + return base.Channel.GetUpdateFile(request); + } } } diff --git a/BeWoLauncher/Logic/ServiceProxy/LauncherServiceFacade.cs b/BeWoLauncher/Logic/ServiceProxy/LauncherServiceFacade.cs index 4ed1571ab..12ad742b8 100644 --- a/BeWoLauncher/Logic/ServiceProxy/LauncherServiceFacade.cs +++ b/BeWoLauncher/Logic/ServiceProxy/LauncherServiceFacade.cs @@ -1,15 +1,10 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.ServiceModel; -using System.Text; -using System.Threading; -using System.Threading.Tasks; -using System.Windows; - -using BeWoLauncher.Multitenancy; +using BeWoLauncher.Multitenancy; using BeWoLauncher.Security; -using BS.SharedLauncher.Information; +using System; +using System.Collections.Generic; +using System.ServiceModel; +using System.Threading; +using System.Windows; namespace BeWoLauncher.ServiceProxy { @@ -20,18 +15,21 @@ namespace BeWoLauncher.ServiceProxy private static Dictionary _EndpointAddresses; private static readonly Dictionary _ProxyCache; - private static int _RunningAsyncs; - - public static void UpdateServerAddresses(string siteOfOrigin) + private static readonly int _RunningAsyncs; + + public static void UpdateServerAddresses(string launcher, string main) { - var serverName = siteOfOrigin; + var serverName = launcher; + var serverName2 = main; if (serverName.Substring(serverName.Length - 1, 1) != "/") serverName += "/"; + if (serverName2.Substring(serverName2.Length - 1, 1) != "/") + serverName2 += "/"; _EndpointAddresses = new Dictionary { - { typeof(ILauncherService), new EndpointAddress(serverName + "LauncherService.svc") }, - { typeof(IEnumTranslationService), new EndpointAddress(serverName + "EnumTranslationService.svc") }, + { typeof(ILauncherService), new EndpointAddress(serverName2 + "LauncherService.svc") }, + { typeof(IEnumTranslationService), new EndpointAddress(serverName2 + "EnumTranslationService.svc") }, { typeof(IDownloadBeWoService), new EndpointAddress(serverName + "DownloadBeWoService.svc") } }; } diff --git a/BeWoLauncher/Logic/Utils/Download/DownloadManager.cs b/BeWoLauncher/Logic/Utils/Download/DownloadManager.cs index 553ef6e12..af73ba4b8 100644 --- a/BeWoLauncher/Logic/Utils/Download/DownloadManager.cs +++ b/BeWoLauncher/Logic/Utils/Download/DownloadManager.cs @@ -10,6 +10,7 @@ using BS.SharedLauncher.Update; using BS.SharedLauncher.Utils; using System; using System.Collections.Generic; +using System.ComponentModel; using System.IO; using System.IO.Compression; using System.Linq; @@ -23,144 +24,189 @@ namespace BeWoLauncher.Logic.Utils.Download { public class DownloadManager { - public DownloadPlanerRequestDC Request { get; set; } - public DownloadPlanerResponseInfoDC ResponseInfo { get; set; } - public DownloadPlanerResponseDC Response { get; set; } + public UpdatePlanRequest UpdatePlanRequest { get; set; } + public UpdatePlanResponse UpdatePlanResponse { get; set; } + public string RootFolder => LauncherPaths.GetRootPath(); public string DownloadFolder => LauncherPaths.GetDownloadPath(); public string ApplyFolder => LauncherPaths.GetApplyPath(); + public bool SkipLock { get; set; } + public Action Feedback { get; set; } + + public int FilesToDownloadCount => UpdatePlanResponse.FilesToRequest?.Count ?? 0; + public int FilesToApplyCount => FilesToDownloadCount + (UpdatePlanResponse.FilesToApply?.Count ?? 0); + public int FilesToDeleteInApplyCount => UpdatePlanResponse.FilesToDeleteInApply?.Count ?? 0; + public int FilesToProcessTotal => FilesToDownloadCount + FilesToApplyCount + FilesToDeleteInApplyCount; + public DownloadManager() { - Request = null; - ResponseInfo = null; - Response = null; + } - public void StartDownloadInfo() + public void GetUpdatePlan() { - CreateDownloadRequest(); + CreateUpdatePlanRequest(); - GetDownloadResponseInfo(); + GetUpdatePlanResponse(); - ConnectionInformation.Version = ResponseInfo.Version; + SessionInformation.Session.Version = UpdatePlanResponse.CurrentPackage.Version; } - public void StartDownload(bool skipLock, Action download) - { - GetDownloadResponse(); - if (!Response.HasToDo()) + public void StartProcess(BackgroundWorker worker) + { + var report = new Action((progress, waitms) => { - // Macht das Sinn? - // Ne, wahrsch. Fehler - throw new NotImplementedException("#45419873274"); + worker.ReportProgress((int)progress); + Thread.Sleep(waitms); + }); + + report(LauncherProgress.ProgressStart, 1000); - return; + if (FilesToDownloadCount > 0) + { + report(LauncherProgress.DownloadStart, 500); + + Download(); + + report(LauncherProgress.DownloadFinish, 1000); } - if (Response.HasToDoNewZip()) + if (FilesToApplyCount > 0) { - DownloadFolder.CreateFolder(); + report(LauncherProgress.ApplyStart, 500); - DownloadFolder.Lock(skipLock); + Apply(); - LauncherPaths.CurrentDownloadZipLocation = FileController.GetNewZipPath(LauncherPaths.GetDownloadPath()); - - //FileController.SaveDZipStream(LauncherPaths.CurrentDownloadZipLocation, Response.NewZipStream, Response.NewZipData.LongLength, download); - FileController.SaveDZip(LauncherPaths.CurrentDownloadZipLocation, Response.NewZipData); - FileController.SaveInfo(LauncherPaths.CurrentDownloadZipLocation, Response.NewZipInfo); - FileController.SaveInfo(LauncherPaths.GetRootPath().Combine("latest"), Response.LatestApplicationInfo); - - Response.NewZipData = null; - - DownloadFolder.Unlock(); + report(LauncherProgress.ApplyFinished, 1000); } + + if (FilesToDeleteInApplyCount > 0) + { + report(LauncherProgress.DeleteStart, 500); + + Delete(); + + report(LauncherProgress.DeleteFinished, 1000); + } + + report(LauncherProgress.CleanupStart, 500); + + Cleanup(); + + report(LauncherProgress.CleanupFinished, 1000); + + // report(LauncherProgress.ProgressEnd, 500); } - public void StartApply(bool skiplock, Action apply) + + public void Download() + { + DownloadFolder.CreateFolder(); + + DownloadFolder.Lock(SkipLock); + + DownloadFolder.SaveCurrentInfo("current"); + + UpdateFileRequest req = new UpdateFileRequest(UpdatePlanResponse.CurrentPackage.Version); + foreach (var file2request in UpdatePlanResponse.FilesToRequest) + { + req.UpdateFile = file2request; + + var res = AskForFile(req); + + var download_path = DownloadFolder.Combine(file2request.RelativePath); + + Path.GetDirectoryName(download_path).CreateFolder(); + download_path.SaveFile(res.FileData); + + var size = NonspecificTools.SizeSuffix((ulong)res.FileData.Length); + + Feedback((int)LauncherProgress.DownloadUpdate, new DownloadProgressEventArgs(size, file2request)); + } + + DownloadFolder.Unlock(); + } + public void Apply() { ApplyFolder.CreateFolder(); - ApplyFolder.Lock(skiplock); + ApplyFolder.Lock(SkipLock); - if (Response.HasToDoDownload2Keep()) - { - FileController.ApplyDZip(Response.DownloadFilesToKeep, ApplyFolder, apply); - } + if (UpdatePlanResponse.FilesToApply is object) + UpdatePlanResponse.FilesToApply.ForEach(ApplyFile); + + if (UpdatePlanResponse.FilesToRequest is object) + UpdatePlanResponse.FilesToRequest.ForEach(ApplyFile); - if (Response.HasToDoNewZip()) + ApplyFolder.SaveCurrentInfo("current"); + } + public void ApplyFile(UpdateFileDC file2apply) + { + var apply_path = ApplyFolder.Combine(file2apply.RelativePath); + var download_path = DownloadFolder.Combine(file2apply.RelativePath); + + Path.GetDirectoryName(apply_path).CreateFolder(); + download_path.CopyFileTo(apply_path); + + Feedback((int)LauncherProgress.ApplyUpdate, new ApplyFileEventArgs(file2apply.RelativePath)); + } + public void Delete() + { + foreach (var file2delete in UpdatePlanResponse.FilesToDeleteInApply) { - FileController.ApplyDZip(LauncherPaths.CurrentDownloadZipLocation, ApplyFolder, apply); + var delete_path = ApplyFolder.Combine(file2delete.RelativePath); + + delete_path.DeleteFile(); + + Feedback((int)LauncherProgress.DeleteUpdate, file2delete.RelativePath); } } - public void StartCleanup(Action feedback) + public void Cleanup() { - if (Response.HasToRemoveFiles) - { - StartRemoveFiles(feedback, Response.LatestApplicationInfo); - } + ApplyFolder.DeleteEmptyDirectories(); DownloadFolder.ClearFolder(); ApplyFolder.Unlock(); - - Thread.Sleep(1000); } - public void StartUninstall(Action feedback) + + private void CreateUpdatePlanRequest() { - var t = new PlanerPackageInfoDC() + UpdatePlanRequest = new UpdatePlanRequest(); + + if (UpdatePlanRequest.PlanerRootFolderExists = LauncherPaths.ActualPlanerLocation.Exists()) { - Files = new List() - }; + if (UpdatePlanRequest.DownloadFolderExists = DownloadFolder.Exists()) + if (!(UpdatePlanRequest.DownloadFolderIsEmpty = DownloadFolder.IsFolderEmpty())) + UpdatePlanRequest.DownloadedFiles = FileController.GetDownloadedFiles(DownloadFolder); - StartRemoveFiles(feedback, t); - } - - private void StartRemoveFiles(Action feedback, PlanerPackageInfoDC newPackage) - { - feedback((int)LauncherProgress.DeleteStart, null); - - Thread.Sleep(500); - - FileController.RemoveUnsuedFiles(newPackage, ApplyFolder, feedback); - } - - private void CreateDownloadRequest() - { - Request = new DownloadPlanerRequestDC(); - - if (Request.PlanerRootFolderExists = LauncherPaths.ActualPlanerLocation.Exists()) - { - if (Request.DownloadFolderExists = DownloadFolder.Exists()) - if (!(Request.DownloadFolderIsEmpty = DownloadFolder.IsFolderEmpty())) - Request.DownloadedPackages = FileController.LoadInfos(DownloadFolder); - - if (Request.ApplyFolderExists = ApplyFolder.Exists()) - if (!(Request.ApplyFolderIsEmpty = ApplyFolder.IsFolderEmpty())) - { - var files = FileController.GetPlanerFiles(ApplyFolder); - - if (files is object) - files.ForEach(file => file.LoadHash()); - - FileController.TryGetPackageInfo(ApplyFolder, out var package); - - if (package == null) - package = new PlanerPackageInfoDC(); - - package.Files = files.ToPlanerFileInfoDCList(); - - Request.ApplyPackage = package; - } + if (UpdatePlanRequest.ApplyFolderExists = ApplyFolder.Exists()) + if (!(UpdatePlanRequest.ApplyFolderIsEmpty = ApplyFolder.IsFolderEmpty())) + UpdatePlanRequest.ApplyPackage = FileController.GetApplyPackage(ApplyFolder); } + + UpdatePlanRequest.Login = new LoginDC() + { + Username = SessionInformation.Login.Username, + Password = SessionInformation.Login.Password, + CoreServerAddress = SessionInformation.Connection.CoreServerAddress, + Pin = SessionInformation.Login.Pin, + ClientID = SessionInformation.Login.ClientId, + CheckTenant = true, + TempUsername = SessionInformation.Login.TempUsername, + }; } - private void GetDownloadResponse() + + private UpdateFileResponse AskForFile(UpdateFileRequest request) { - Response = LauncherServiceFacade.DoDownloadBeWoServiceSync(x => x.Download2(Request)); + return LauncherServiceFacade.DoDownloadBeWoServiceSyncWithException(x => x.GetUpdateFile(request)); } - private void GetDownloadResponseInfo() + + private void GetUpdatePlanResponse() { - var t = ConnectionInformation.Tenant; - ResponseInfo = LauncherServiceFacade.DoDownloadBeWoServiceSyncWithException(x => x.DownloadInfo(Request)); + UpdatePlanResponse = LauncherServiceFacade.DoDownloadBeWoServiceSyncWithException(x => x.GetUpdatePlan(UpdatePlanRequest)); + + // UpdatePlanResponse.FilesToApply.AddRange(UpdatePlanResponse.FilesToRequest); } } } diff --git a/BeWoLauncher/Logic/Utils/LauncherPaths.cs b/BeWoLauncher/Logic/Utils/LauncherPaths.cs index 29f13a7ee..ac145715e 100644 --- a/BeWoLauncher/Logic/Utils/LauncherPaths.cs +++ b/BeWoLauncher/Logic/Utils/LauncherPaths.cs @@ -1,5 +1,7 @@ -using BS.SharedLauncher.Extensions; +using BeWoLauncher.Logic.Controller; +using BS.SharedLauncher.Extensions; using BS.SharedLauncher.Information; +using BS.SharedLauncher.Logic; using System; using System.Collections.Generic; using System.IO; @@ -19,8 +21,6 @@ namespace BeWoLauncher.Logic.Utils public static string LoginSelectionPlanerLocation { get; set; } public static string ActualPlanerLocation { get; set; } - public static string CurrentDownloadZipLocation { get; set; } - /// /// Holt den Install Ort aus den Properties Settings. /// Sollte dieser nicht verfügbar sein, wird als default - "CurrentBaseDir"/BeWoPlaner - verwendet @@ -81,6 +81,10 @@ namespace BeWoLauncher.Logic.Utils { return ActualPlanerLocation; } + public static string GetLoggerPath() + { + return Path.Combine(new string[] { GetRootPath(), "log" }); + } public static string GetDownloadPath() { return Path.Combine(new string[] { GetRootPath(), "download" }); @@ -94,13 +98,30 @@ namespace BeWoLauncher.Logic.Utils { return Path.Combine(GetApplyPath(), GetPlanerExeName()); } - public static string GetApplyPackagePath() + + public static void SaveCurrentInfo(this string path, string file) { - return Path.Combine(GetApplyPath(), BeWoPathFileConfig.LatestBeWoInfo); + FileController.SaveInfo(path.Combine(file), DownloadController.Manager.UpdatePlanResponse.CurrentPackage); } - public static string GetDownloadPackagePath() + + public static void SaveFile(this string path, byte[] data) { - return Path.Combine(GetDownloadPath(), BeWoPathFileConfig.LatestBeWoInfo); + FileController.SaveFile(path, data); + } + + public static void CopyFileTo(this string source, string destination) + { + FileController.CopyFile(source, destination); + } + + public static void DeleteFile(this string file) + { + FileController.DeleteFile(file); + } + + public static void DeleteEmptyDirectories(this string dir) + { + FileController.DeleteEmptyDirectories(dir); } } } \ No newline at end of file diff --git a/BeWoLauncher/Logic/ViewBuilder.cs b/BeWoLauncher/Logic/ViewBuilder.cs index 018f0a772..b9c41357a 100644 --- a/BeWoLauncher/Logic/ViewBuilder.cs +++ b/BeWoLauncher/Logic/ViewBuilder.cs @@ -2,6 +2,7 @@ using BeWoLauncher.Logic.Controller; using BeWoLauncher.View; using BeWoLauncher.View.Frames; +using BS.SharedLauncher.Enums; using System; using System.Threading.Tasks; using System.Windows.Controls; @@ -120,11 +121,12 @@ namespace BeWoLauncher.Logic private FrameBase getUninstallProgressFrame() { - var uninstallProgress = new UninstallProgressInfoFrame(); + var progress = new ProgressFrame(LauncherMode.Update); - uninstallProgress.UninstallSuccessful += ViewBehavior.UninstallSuccess; + progress.Successful += ViewBehavior.UninstallSuccess; + progress.Exception += ViewBehavior.UninstallFailed; - return uninstallProgress; + return progress; } private FrameBase getUninstallInfoFrame() @@ -151,11 +153,12 @@ namespace BeWoLauncher.Logic private FrameBase getUpdateProgressFrame() { - var updateProgress = new UpdateProgressInfoFrame(); + var progress = new ProgressFrame(LauncherMode.Update); - updateProgress.UpdateSuccessful += ViewBehavior.UpdateSuccess; + progress.Successful += ViewBehavior.UpdateSuccess; + progress.Exception += ViewBehavior.UpdateFailed; - return updateProgress; + return progress; } private FrameBase getUpdateInfoFrame() @@ -194,11 +197,12 @@ namespace BeWoLauncher.Logic private FrameBase getInstallProgressFrame() { - var installprogress = new InstallProgressInfoFrame(); + var progress = new ProgressFrame(LauncherMode.Install); - installprogress.InstallSuccessful += ViewBehavior.InstallSuccesss; + progress.Successful += ViewBehavior.InstallSuccesss; + progress.Exception += ViewBehavior.InstallFailed; - return installprogress; + return progress; } private FrameBase getInstallInfoFrame() diff --git a/BeWoLauncher/ServiceProxy/LauncherGenerated.cs b/BeWoLauncher/ServiceProxy/LauncherGenerated.cs new file mode 100644 index 000000000..f096a7629 --- /dev/null +++ b/BeWoLauncher/ServiceProxy/LauncherGenerated.cs @@ -0,0 +1,403 @@ +//------------------------------------------------------------------------------ +// +// Dieser Code wurde von einem Tool generiert. +// Laufzeitversion:4.0.30319.42000 +// +// Änderungen an dieser Datei können falsches Verhalten verursachen und gehen verloren, wenn +// der Code erneut generiert wird. +// +//------------------------------------------------------------------------------ + +namespace BeWoLauncher.ServiceProxy +{ + using System.Runtime.Serialization; + + + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Runtime.Serialization", "4.0.0.0")] + [System.Runtime.Serialization.DataContractAttribute(Name="BeWoFault", Namespace="http://schemas.datacontract.org/2004/07/BeWo.Service.ServiceContracts")] + public partial class BeWoFault : object, System.Runtime.Serialization.IExtensibleDataObject, System.ComponentModel.INotifyPropertyChanged + { + + private System.Runtime.Serialization.ExtensionDataObject extensionDataField; + + private BeWoLauncher.ServiceProxy.BeWoFaultType FaultTypeField; + + private string InnerExceptionMessageField; + + private string InnerExceptionStackTraceField; + + private string MessageField; + + private string StackTraceField; + + public System.Runtime.Serialization.ExtensionDataObject ExtensionData + { + get + { + return this.extensionDataField; + } + set + { + this.extensionDataField = value; + } + } + + [System.Runtime.Serialization.DataMemberAttribute()] + public BeWoLauncher.ServiceProxy.BeWoFaultType FaultType + { + get + { + return this.FaultTypeField; + } + set + { + if ((this.FaultTypeField.Equals(value) != true)) + { + this.FaultTypeField = value; + this.RaisePropertyChanged("FaultType"); + } + } + } + + [System.Runtime.Serialization.DataMemberAttribute()] + public string InnerExceptionMessage + { + get + { + return this.InnerExceptionMessageField; + } + set + { + if ((object.ReferenceEquals(this.InnerExceptionMessageField, value) != true)) + { + this.InnerExceptionMessageField = value; + this.RaisePropertyChanged("InnerExceptionMessage"); + } + } + } + + [System.Runtime.Serialization.DataMemberAttribute()] + public string InnerExceptionStackTrace + { + get + { + return this.InnerExceptionStackTraceField; + } + set + { + if ((object.ReferenceEquals(this.InnerExceptionStackTraceField, value) != true)) + { + this.InnerExceptionStackTraceField = value; + this.RaisePropertyChanged("InnerExceptionStackTrace"); + } + } + } + + [System.Runtime.Serialization.DataMemberAttribute()] + public string Message + { + get + { + return this.MessageField; + } + set + { + if ((object.ReferenceEquals(this.MessageField, value) != true)) + { + this.MessageField = value; + this.RaisePropertyChanged("Message"); + } + } + } + + [System.Runtime.Serialization.DataMemberAttribute()] + public string StackTrace + { + get + { + return this.StackTraceField; + } + set + { + if ((object.ReferenceEquals(this.StackTraceField, value) != true)) + { + this.StackTraceField = value; + this.RaisePropertyChanged("StackTrace"); + } + } + } + + public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged; + + protected void RaisePropertyChanged(string propertyName) + { + System.ComponentModel.PropertyChangedEventHandler propertyChanged = this.PropertyChanged; + if ((propertyChanged != null)) + { + propertyChanged(this, new System.ComponentModel.PropertyChangedEventArgs(propertyName)); + } + } + } + + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Runtime.Serialization", "4.0.0.0")] + [System.Runtime.Serialization.DataContractAttribute(Name="BeWoFaultType", Namespace="http://schemas.datacontract.org/2004/07/BeWo.Service.ServiceContracts")] + public enum BeWoFaultType : int + { + + [System.Runtime.Serialization.EnumMemberAttribute()] + Unknown = 0, + + [System.Runtime.Serialization.EnumMemberAttribute()] + Concurrency = 1, + + [System.Runtime.Serialization.EnumMemberAttribute()] + DeleteNotPossible = 2, + + [System.Runtime.Serialization.EnumMemberAttribute()] + LoginNameTaken = 3, + + [System.Runtime.Serialization.EnumMemberAttribute()] + CustomWithoutDetails = 4, + } + + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")] + [System.ServiceModel.ServiceContractAttribute(ConfigurationName="BeWoLauncher.ServiceProxy.ILauncherService")] + public interface ILauncherService + { + + [System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/ILauncherService/IsUserValid", ReplyAction="http://tempuri.org/ILauncherService/IsUserValidResponse")] + [System.ServiceModel.FaultContractAttribute(typeof(BeWoLauncher.ServiceProxy.BeWoFault), Action="http://tempuri.org/ILauncherService/IsUserValidBeWoFaultFault", Name="BeWoFault", Namespace="http://schemas.datacontract.org/2004/07/BeWo.Service.ServiceContracts")] + BS.SharedLauncher.Enums.UserValidationResult IsUserValid(string pUserName, string pPassword, string pPIN, string clientId, bool checkTenant); + + [System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/ILauncherService/ResetTenant", ReplyAction="http://tempuri.org/ILauncherService/ResetTenantResponse")] + [System.ServiceModel.FaultContractAttribute(typeof(BeWoLauncher.ServiceProxy.BeWoFault), Action="http://tempuri.org/ILauncherService/ResetTenantBeWoFaultFault", Name="BeWoFault", Namespace="http://schemas.datacontract.org/2004/07/BeWo.Service.ServiceContracts")] + void ResetTenant(string tenant); + + [System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/ILauncherService/ResetAllTenant", ReplyAction="http://tempuri.org/ILauncherService/ResetAllTenantResponse")] + [System.ServiceModel.FaultContractAttribute(typeof(BeWoLauncher.ServiceProxy.BeWoFault), Action="http://tempuri.org/ILauncherService/ResetAllTenantBeWoFaultFault", Name="BeWoFault", Namespace="http://schemas.datacontract.org/2004/07/BeWo.Service.ServiceContracts")] + void ResetAllTenant(); + + [System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/ILauncherService/GetEmailForUserName", ReplyAction="http://tempuri.org/ILauncherService/GetEmailForUserNameResponse")] + [System.ServiceModel.FaultContractAttribute(typeof(BeWoLauncher.ServiceProxy.BeWoFault), Action="http://tempuri.org/ILauncherService/GetEmailForUserNameBeWoFaultFault", Name="BeWoFault", Namespace="http://schemas.datacontract.org/2004/07/BeWo.Service.ServiceContracts")] + bool GetEmailForUserName(out string email, string pUserName, System.Uri serverName); + + [System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/ILauncherService/CheckPassword", ReplyAction="http://tempuri.org/ILauncherService/CheckPasswordResponse")] + [System.ServiceModel.FaultContractAttribute(typeof(BeWoLauncher.ServiceProxy.BeWoFault), Action="http://tempuri.org/ILauncherService/CheckPasswordBeWoFaultFault", Name="BeWoFault", Namespace="http://schemas.datacontract.org/2004/07/BeWo.Service.ServiceContracts")] + BS.SharedLauncher.Enums.PasswordValidationResult CheckPassword(long userOid, string pOldPassword, string pNewPassword); + + [System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/ILauncherService/CheckPassword2", ReplyAction="http://tempuri.org/ILauncherService/CheckPassword2Response")] + [System.ServiceModel.FaultContractAttribute(typeof(BeWoLauncher.ServiceProxy.BeWoFault), Action="http://tempuri.org/ILauncherService/CheckPassword2BeWoFaultFault", Name="BeWoFault", Namespace="http://schemas.datacontract.org/2004/07/BeWo.Service.ServiceContracts")] + BS.SharedLauncher.Enums.PasswordValidationResult CheckPassword2(string username, string pOldPassword, string pNewPassword); + + [System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/ILauncherService/ChangePassword", ReplyAction="http://tempuri.org/ILauncherService/ChangePasswordResponse")] + [System.ServiceModel.FaultContractAttribute(typeof(BeWoLauncher.ServiceProxy.BeWoFault), Action="http://tempuri.org/ILauncherService/ChangePasswordBeWoFaultFault", Name="BeWoFault", Namespace="http://schemas.datacontract.org/2004/07/BeWo.Service.ServiceContracts")] + long ChangePassword(string pUserName, string pOldPassword, string pNewPassword); + + [System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/ILauncherService/ResetPasswordInfo", ReplyAction="http://tempuri.org/ILauncherService/ResetPasswordInfoResponse")] + [System.ServiceModel.FaultContractAttribute(typeof(BeWoLauncher.ServiceProxy.BeWoFault), Action="http://tempuri.org/ILauncherService/ResetPasswordInfoBeWoFaultFault", Name="BeWoFault", Namespace="http://schemas.datacontract.org/2004/07/BeWo.Service.ServiceContracts")] + void ResetPasswordInfo(string pUserName, string pPassword); + } + + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")] + public interface ILauncherServiceChannel : BeWoLauncher.ServiceProxy.ILauncherService, System.ServiceModel.IClientChannel + { + } + + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")] + public partial class LauncherServiceClient : System.ServiceModel.ClientBase, BeWoLauncher.ServiceProxy.ILauncherService + { + + public LauncherServiceClient() + { + } + + public LauncherServiceClient(string endpointConfigurationName) : + base(endpointConfigurationName) + { + } + + public LauncherServiceClient(string endpointConfigurationName, string remoteAddress) : + base(endpointConfigurationName, remoteAddress) + { + } + + public LauncherServiceClient(string endpointConfigurationName, System.ServiceModel.EndpointAddress remoteAddress) : + base(endpointConfigurationName, remoteAddress) + { + } + + public LauncherServiceClient(System.ServiceModel.Channels.Binding binding, System.ServiceModel.EndpointAddress remoteAddress) : + base(binding, remoteAddress) + { + } + + public BS.SharedLauncher.Enums.UserValidationResult IsUserValid(string pUserName, string pPassword, string pPIN, string clientId, bool checkTenant) + { + return base.Channel.IsUserValid(pUserName, pPassword, pPIN, clientId, checkTenant); + } + + public void ResetTenant(string tenant) + { + base.Channel.ResetTenant(tenant); + } + + public void ResetAllTenant() + { + base.Channel.ResetAllTenant(); + } + + public bool GetEmailForUserName(out string email, string pUserName, System.Uri serverName) + { + return base.Channel.GetEmailForUserName(out email, pUserName, serverName); + } + + public BS.SharedLauncher.Enums.PasswordValidationResult CheckPassword(long userOid, string pOldPassword, string pNewPassword) + { + return base.Channel.CheckPassword(userOid, pOldPassword, pNewPassword); + } + + public BS.SharedLauncher.Enums.PasswordValidationResult CheckPassword2(string username, string pOldPassword, string pNewPassword) + { + return base.Channel.CheckPassword2(username, pOldPassword, pNewPassword); + } + + public long ChangePassword(string pUserName, string pOldPassword, string pNewPassword) + { + return base.Channel.ChangePassword(pUserName, pOldPassword, pNewPassword); + } + + public void ResetPasswordInfo(string pUserName, string pPassword) + { + base.Channel.ResetPasswordInfo(pUserName, pPassword); + } + } + + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")] + [System.ServiceModel.ServiceContractAttribute(ConfigurationName="BeWoLauncher.ServiceProxy.IEnumTranslationService")] + public interface IEnumTranslationService + { + + [System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/IEnumTranslationService/GetTranslation", ReplyAction="http://tempuri.org/IEnumTranslationService/GetTranslationResponse")] + [System.ServiceModel.FaultContractAttribute(typeof(BeWoLauncher.ServiceProxy.BeWoFault), Action="http://tempuri.org/IEnumTranslationService/GetTranslationBeWoFaultFault", Name="BeWoFault", Namespace="http://schemas.datacontract.org/2004/07/BeWo.Service.ServiceContracts")] + string GetTranslation(string e, short value); + } + + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")] + public interface IEnumTranslationServiceChannel : BeWoLauncher.ServiceProxy.IEnumTranslationService, System.ServiceModel.IClientChannel + { + } + + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")] + public partial class EnumTranslationServiceClient : System.ServiceModel.ClientBase, BeWoLauncher.ServiceProxy.IEnumTranslationService + { + + public EnumTranslationServiceClient() + { + } + + public EnumTranslationServiceClient(string endpointConfigurationName) : + base(endpointConfigurationName) + { + } + + public EnumTranslationServiceClient(string endpointConfigurationName, string remoteAddress) : + base(endpointConfigurationName, remoteAddress) + { + } + + public EnumTranslationServiceClient(string endpointConfigurationName, System.ServiceModel.EndpointAddress remoteAddress) : + base(endpointConfigurationName, remoteAddress) + { + } + + public EnumTranslationServiceClient(System.ServiceModel.Channels.Binding binding, System.ServiceModel.EndpointAddress remoteAddress) : + base(binding, remoteAddress) + { + } + + public string GetTranslation(string e, short value) + { + return base.Channel.GetTranslation(e, value); + } + } + + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")] + [System.ServiceModel.ServiceContractAttribute(ConfigurationName="BeWoLauncher.ServiceProxy.IDownloadBeWoService")] + public interface IDownloadBeWoService + { + + [System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/IDownloadBeWoService/Download2", ReplyAction="http://tempuri.org/IDownloadBeWoService/Download2Response")] + [System.ServiceModel.FaultContractAttribute(typeof(BeWoLauncher.ServiceProxy.BeWoFault), Action="http://tempuri.org/IDownloadBeWoService/Download2BeWoFaultFault", Name="BeWoFault", Namespace="http://schemas.datacontract.org/2004/07/BeWo.Service.ServiceContracts")] + BS.SharedLauncher.DataContract.UpdateFileResponse Download2(BS.SharedLauncher.DataContract.UpdateRequest request); + + [System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/IDownloadBeWoService/DownloadInfo", ReplyAction="http://tempuri.org/IDownloadBeWoService/DownloadInfoResponse")] + [System.ServiceModel.FaultContractAttribute(typeof(BeWoLauncher.ServiceProxy.BeWoFault), Action="http://tempuri.org/IDownloadBeWoService/DownloadInfoBeWoFaultFault", Name="BeWoFault", Namespace="http://schemas.datacontract.org/2004/07/BeWo.Service.ServiceContracts")] + BS.SharedLauncher.DataContract.UpdateResponse DownloadInfo(BS.SharedLauncher.DataContract.UpdateRequest request); + + [System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/IDownloadBeWoService/GetUpdatePlan", ReplyAction="http://tempuri.org/IDownloadBeWoService/GetUpdatePlanResponse")] + [System.ServiceModel.FaultContractAttribute(typeof(BeWoLauncher.ServiceProxy.BeWoFault), Action="http://tempuri.org/IDownloadBeWoService/GetUpdatePlanBeWoFaultFault", Name="BeWoFault", Namespace="http://schemas.datacontract.org/2004/07/BeWo.Service.ServiceContracts")] + BS.SharedLauncher.DataContract.UpdateResponse GetUpdatePlan(BS.SharedLauncher.DataContract.UpdateRequest request); + + [System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/IDownloadBeWoService/GetUpdateFile", ReplyAction="http://tempuri.org/IDownloadBeWoService/GetUpdateFileResponse")] + [System.ServiceModel.FaultContractAttribute(typeof(BeWoLauncher.ServiceProxy.BeWoFault), Action="http://tempuri.org/IDownloadBeWoService/GetUpdateFileBeWoFaultFault", Name="BeWoFault", Namespace="http://schemas.datacontract.org/2004/07/BeWo.Service.ServiceContracts")] + BS.SharedLauncher.DataContract.UpdateFileResponse GetUpdateFile(BS.SharedLauncher.DataContract.UpdateFileRequest request); + } + + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")] + public interface IDownloadBeWoServiceChannel : BeWoLauncher.ServiceProxy.IDownloadBeWoService, System.ServiceModel.IClientChannel + { + } + + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")] + public partial class DownloadBeWoServiceClient : System.ServiceModel.ClientBase, BeWoLauncher.ServiceProxy.IDownloadBeWoService + { + + public DownloadBeWoServiceClient() + { + } + + public DownloadBeWoServiceClient(string endpointConfigurationName) : + base(endpointConfigurationName) + { + } + + public DownloadBeWoServiceClient(string endpointConfigurationName, string remoteAddress) : + base(endpointConfigurationName, remoteAddress) + { + } + + public DownloadBeWoServiceClient(string endpointConfigurationName, System.ServiceModel.EndpointAddress remoteAddress) : + base(endpointConfigurationName, remoteAddress) + { + } + + public DownloadBeWoServiceClient(System.ServiceModel.Channels.Binding binding, System.ServiceModel.EndpointAddress remoteAddress) : + base(binding, remoteAddress) + { + } + + public BS.SharedLauncher.DataContract.UpdateFileResponse Download2(BS.SharedLauncher.DataContract.UpdateRequest request) + { + return base.Channel.Download2(request); + } + + public BS.SharedLauncher.DataContract.UpdateResponse DownloadInfo(BS.SharedLauncher.DataContract.UpdateRequest request) + { + return base.Channel.DownloadInfo(request); + } + + public BS.SharedLauncher.DataContract.UpdateResponse GetUpdatePlan(BS.SharedLauncher.DataContract.UpdateRequest request) + { + return base.Channel.GetUpdatePlan(request); + } + + public BS.SharedLauncher.DataContract.UpdateFileResponse GetUpdateFile(BS.SharedLauncher.DataContract.UpdateFileRequest request) + { + return base.Channel.GetUpdateFile(request); + } + } +} diff --git a/BeWoLauncher/View/Components/MessageDialog.xaml.cs b/BeWoLauncher/View/Components/MessageDialog.xaml.cs index 7188a8ddb..2fcce003c 100644 --- a/BeWoLauncher/View/Components/MessageDialog.xaml.cs +++ b/BeWoLauncher/View/Components/MessageDialog.xaml.cs @@ -105,7 +105,7 @@ namespace BeWoLauncher.Components private void OkayButton_OnClick(object sender, RoutedEventArgs e) { - LauncherServiceFacade.DoLauncherServiceAsync(u => u.IsUserValid(ConnectionInformation.Username, PasswordBox.Password, null, null, false), result => + LauncherServiceFacade.DoLauncherServiceAsync(u => u.IsUserValid(SessionInformation.Login.Username, PasswordBox.Password, null, null, false), result => { if(result == UserValidationResult.UserValid) { diff --git a/BeWoLauncher/View/Components/PasswortAenderungsView.xaml.cs b/BeWoLauncher/View/Components/PasswortAenderungsView.xaml.cs index 395ace7ba..f158e3b5e 100644 --- a/BeWoLauncher/View/Components/PasswortAenderungsView.xaml.cs +++ b/BeWoLauncher/View/Components/PasswortAenderungsView.xaml.cs @@ -70,7 +70,7 @@ namespace BeWoLauncher.Components var lOld = AltesPwBox.Password; var lNew = NeuesPwBox.Password; - LauncherServiceFacade.DoLauncherServiceAsync(x => x.CheckPassword2(ConnectionInformation.Username, lOld, lNew), + LauncherServiceFacade.DoLauncherServiceAsync(x => x.CheckPassword2(SessionInformation.Login.Username, lOld, lNew), result => CheckPasswordResult(result, lOld, lNew), true); } @@ -78,9 +78,9 @@ namespace BeWoLauncher.Components { if (result == PasswordValidationResult.Succesful) { - LauncherServiceFacade.DoLauncherServiceSync(x => x.ChangePassword(ConnectionInformation.Username, oldPassword, newPassword)); + LauncherServiceFacade.DoLauncherServiceSync(x => x.ChangePassword(SessionInformation.Login.Username, oldPassword, newPassword)); - ConnectionInformation.Password = newPassword; + SessionInformation.Login.Password = newPassword; Dispatcher.BeginInvoke(DispatcherPriority.Normal, (Action)PopUp.Close); } diff --git a/BeWoLauncher/View/Frames/GenericProgressFrame.xaml.cs b/BeWoLauncher/View/Frames/GenericProgressFrame.xaml.cs deleted file mode 100644 index b2fc0f763..000000000 --- a/BeWoLauncher/View/Frames/GenericProgressFrame.xaml.cs +++ /dev/null @@ -1,75 +0,0 @@ -using System; -using System.ComponentModel; -using System.Windows; -using System.Windows.Controls; -using System.Windows.Media.Animation; - -namespace BeWoLauncher.View.Frames -{ - /// - /// Interaktionslogik für UpdateView.xaml - /// - public abstract partial class GenericProgressInfo : FrameBase - { - private static TimeSpan duration = TimeSpan.FromSeconds(1); - - public readonly BackgroundWorker Worker = new BackgroundWorker(); - - private int lastStep = -1; - - public GenericProgressInfo() - { - InitializeComponent(); - - proBar1.IsIndeterminate = false; - proBar1.Minimum = 0; - proBar1.Maximum = 100; - - proBar2.IsIndeterminate = false; - proBar2.Minimum = 0; - - Loaded += (s, e) => Start(); - } - - public string Message - { - get { return lblMessage.Content as string; } - set { lblMessage.Content = value; } - } - public string SubMessage - { - get { return lblSubmessage.Content as string; } - set { lblSubmessage.Content = value; } - } - - public abstract void Start(); - - public void Bar1Activate() => proBar1.IsIndeterminate = false; - public void Bar1Deactivate() => proBar1.IsIndeterminate = true; - public void Bar1SetLimit(int max) => proBar1.Maximum = max; - public void Bar1MakeStep() => proBar1.Value++; - public void Bar1Hide() => proBar1.Visibility = Visibility.Collapsed; - public void Bar1Show() => proBar1.Visibility = Visibility.Visible; - - public void Bar2Activate() => proBar2.IsIndeterminate = false; - public void Bar2Deactivate() => proBar2.IsIndeterminate = true; - public void Bar2SetLimit(int max) => proBar2.Maximum = max; - public void Bar2MakeStep(int step) - { - if (step > lastStep) - { - lastStep = step; - proBar2.Value++; - } - } - public void Bar2Fill() => proBar2.Value = proBar2.Maximum; - public void Bar2Hide() => proBar2.Visibility = Visibility.Collapsed; - public void Bar2Show() => proBar2.Visibility = Visibility.Visible; - - public void Bar2SetPercent(double percentage) - { - DoubleAnimation animation = new DoubleAnimation(percentage, duration); - proBar2.BeginAnimation(ProgressBar.ValueProperty, animation); - } - } -} diff --git a/BeWoLauncher/View/Frames/InfoFrame.xaml b/BeWoLauncher/View/Frames/InfoFrame.xaml index e46e1c8d1..e82888b24 100644 --- a/BeWoLauncher/View/Frames/InfoFrame.xaml +++ b/BeWoLauncher/View/Frames/InfoFrame.xaml @@ -9,12 +9,15 @@ - - + + + Hier könnte ihre Fehlermeldung stehen! + + diff --git a/BeWoLauncher/View/Frames/InfoFrame.xaml.cs b/BeWoLauncher/View/Frames/InfoFrame.xaml.cs index a23a79ae0..37ddb3978 100644 --- a/BeWoLauncher/View/Frames/InfoFrame.xaml.cs +++ b/BeWoLauncher/View/Frames/InfoFrame.xaml.cs @@ -35,8 +35,8 @@ namespace BeWoLauncher.View.Frames public string Text { - get => txtField.Content as string; - set => txtField.Content = value; + get => txtField2.Text; + set => txtField2.Text = value; } public void CollapseCopyButton() => btnCopy.Visibility = Visibility.Collapsed; diff --git a/BeWoLauncher/View/Frames/InstallInfoFrame.xaml b/BeWoLauncher/View/Frames/InstallInfoFrame.xaml index ecc9f136d..dba8bed7e 100644 --- a/BeWoLauncher/View/Frames/InstallInfoFrame.xaml +++ b/BeWoLauncher/View/Frames/InstallInfoFrame.xaml @@ -45,12 +45,6 @@ - - - - - - diff --git a/BeWoLauncher/View/Frames/InstallInfoFrame.xaml.cs b/BeWoLauncher/View/Frames/InstallInfoFrame.xaml.cs index d3d7ca4db..c23e2c852 100644 --- a/BeWoLauncher/View/Frames/InstallInfoFrame.xaml.cs +++ b/BeWoLauncher/View/Frames/InstallInfoFrame.xaml.cs @@ -23,20 +23,12 @@ namespace BeWoLauncher.View.Frames InstallLocation = LauncherPaths.GetInstallLocationFromSettingOrDefault(); - var size = NonspecificTools.SizeSuffix((ulong)DownloadController.Manager.ResponseInfo.DownloadSize).Split(' '); + var size = NonspecificTools.SizeSuffix((ulong)DownloadController.Manager.UpdatePlanResponse.DownloadSize).Split(' '); lblErforderlich.Content = size[0]; lblErforderlichSize.Content = size[1]; - lblcountnew.Content = $"{DownloadController.Manager.ResponseInfo.NewFileCount}"; - lblcountalready.Content = $"{DownloadController.Manager.ResponseInfo.FileCount - DownloadController.Manager.ResponseInfo.NewFileCount}"; - - lblversion.Content = DownloadController.Manager.ResponseInfo.Version; - - lblcountalready.Visibility = Visibility.Hidden; - lblcountalreadytxt.Visibility = Visibility.Hidden; - lblcountnew.Visibility = Visibility.Hidden; - lblcountnewtxt.Visibility = Visibility.Hidden; + lblversion.Content = DownloadController.Manager.UpdatePlanResponse.CurrentPackage.Version; } public string InstallLocation diff --git a/BeWoLauncher/View/Frames/InstallProgressInfoFrame.cs b/BeWoLauncher/View/Frames/InstallProgressInfoFrame.cs deleted file mode 100644 index 639c8bfcc..000000000 --- a/BeWoLauncher/View/Frames/InstallProgressInfoFrame.cs +++ /dev/null @@ -1,183 +0,0 @@ -using BeWoLauncher.Logic.Controller; -using BeWoLauncher.Logic.Utils.Download; -using BS.SharedLauncher.Enums; -using BS.SharedLauncher.Update; -using System; -using System.ComponentModel; -using System.Configuration; -using System.Threading; - -namespace BeWoLauncher.View.Frames -{ - public class InstallProgressInfoFrame : GenericProgressInfo - { - public event EventHandler InstallSuccessful; - - public DownloadManager Manager => DownloadController.Manager; - - public InstallProgressInfoFrame() : base() - { - Bar1SetLimit(Manager.ResponseInfo.FileCount); - Bar1Hide(); - - Bar2SetLimit(100); - } - - public override void Start() - { - var skipLock = bool.TryParse(ConfigurationManager.AppSettings.Get("SkipLock"), out bool c) && c; - - Worker.DoWork += worker_DoWork; - Worker.ProgressChanged += worker_ProgressChanged; - Worker.RunWorkerCompleted += worker_completed; - - Worker.WorkerReportsProgress = true; - - Worker.RunWorkerAsync(skipLock); - } - - void worker_DoWork(object sender, DoWorkEventArgs e) - { - bool skipLock = (bool)e.Argument; - - BackgroundWorker worker = sender as BackgroundWorker; - - // UI: 0 - worker.ReportProgress((int)LauncherProgress.ProgressStart); - - // Wait - Thread.Sleep(1000); - - // UI: 1 - worker.ReportProgress((int)LauncherProgress.DownloadStart); - - // Wait - Thread.Sleep(500); - - // Process: 2 - DownloadController.Manager.StartDownload(skipLock, worker.ReportProgress); - - // UI: 3 - worker.ReportProgress((int)LauncherProgress.DownloadFinish); - - // Wait - Thread.Sleep(1000); - - // UI: 4 - worker.ReportProgress((int)LauncherProgress.ApplyStart); - - // Wait - Thread.Sleep(500); - - // Process: 5 - DownloadController.Manager.StartApply(skipLock, worker.ReportProgress); - - // UI: 6 - worker.ReportProgress((int)LauncherProgress.ApplyFinished); - - // Wait - Thread.Sleep(1000); - - // Process: 7, Wait, 8 - DownloadController.Manager.StartCleanup(worker.ReportProgress); - - // UI: 9 - worker.ReportProgress((int)LauncherProgress.DeleteFinished); - - // Wait - Thread.Sleep(500); - - // UI: 10 - worker.ReportProgress((int)LauncherProgress.ProgressEnd); - } - - private void worker_completed(object sender, RunWorkerCompletedEventArgs e) - { - if (e.Error != null) - { - ViewController.ViewBehavior.InstallationFailed(e.Error); - } - else - { - InstallSuccessful.Invoke(this, new EventArgs()); - } - } - - private void worker_ProgressChanged(object sender, ProgressChangedEventArgs e) - { - var progress = (LauncherProgress)e.ProgressPercentage; - var obj = e.UserState; - - switch (progress) - { - case LauncherProgress.ProgressStart: - Message = "Installation wird vorbereitet..."; - SubMessage = "Lade benötigte Pakete herunter..."; - break; - - case LauncherProgress.DownloadStart: - Message = "Download startet..."; - SubMessage = ""; - Bar1Show(); - Bar1Deactivate(); - Bar2SetPercent(10); - break; - - case LauncherProgress.DownloadUpdate: - throw new NotImplementedException("#fd42398"); - var args = obj as DownloadProgressEventArgs; - SubMessage = $"{args.Progress.ToString("0.##")}% fertig"; - break; - - case LauncherProgress.DownloadFinish: - Message = "Download abgeschlossen!"; - SubMessage = ""; - Bar2SetPercent(40); - break; - - case LauncherProgress.ApplyStart: - Message = "Füge Pakete hinzu..."; - SubMessage = ""; - Bar1Activate(); - break; - - case LauncherProgress.ApplyUpdate: - var args2 = obj as ApplyFileEventArgs; - SubMessage = $"{args2.Name} wurde erfolgreich von \n{args2.AbsolutePath} hinzugefügt!"; - Bar1MakeStep(); - break; - - case LauncherProgress.ApplyFinished: - Message = "Hinzufügen abgeschlossen!"; - SubMessage = ""; - Bar2SetPercent(80); - Bar1Deactivate(); - break; - - case LauncherProgress.DeleteStart: - Message = "Ungebrauchte Datei(en) gefunden."; - SubMessage = ""; - break; - case LauncherProgress.DeleteUpdate: - var args3 = obj as string; - SubMessage = $"{args3} wurde entfernt!"; - break; - - case LauncherProgress.DeleteFinished: - Message = "Säuberung abgeschlossen!"; - SubMessage = ""; - Bar2SetPercent(95); - Bar1Deactivate(); - break; - - case LauncherProgress.ProgressEnd: - Message = "Installation abgeschlossen!"; - SubMessage = ""; - Bar2Fill(); - break; - default: - break; - } - } - } -} diff --git a/BeWoLauncher/View/Frames/GenericProgressFrame.xaml b/BeWoLauncher/View/Frames/ProgressFrame.xaml similarity index 91% rename from BeWoLauncher/View/Frames/GenericProgressFrame.xaml rename to BeWoLauncher/View/Frames/ProgressFrame.xaml index ed7c96d63..c1c426bdc 100644 --- a/BeWoLauncher/View/Frames/GenericProgressFrame.xaml +++ b/BeWoLauncher/View/Frames/ProgressFrame.xaml @@ -1,5 +1,5 @@  - + diff --git a/BeWoLauncher/View/Frames/ProgressFrame.xaml.cs b/BeWoLauncher/View/Frames/ProgressFrame.xaml.cs new file mode 100644 index 000000000..ac1a86671 --- /dev/null +++ b/BeWoLauncher/View/Frames/ProgressFrame.xaml.cs @@ -0,0 +1,237 @@ +using BeWoLauncher.Logic.Controller; +using BS.SharedLauncher.Enums; +using BS.SharedLauncher.Update; +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Configuration; +using System.Threading; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Media.Animation; + +namespace BeWoLauncher.View.Frames +{ + /// + /// Interaktionslogik für UpdateView.xaml + /// + public partial class ProgressFrame : FrameBase + { + private static TimeSpan duration = TimeSpan.FromSeconds(1); + + private int lastStep = -1; + + private string[][] keywords = new string[][] + { + new string[]{"Installation", "Ungebrauchte Datei(en) gefunden." }, + new string[]{"Update", "Ungebrauchte Datei(en) gefunden."}, + new string[]{"Deinstallation", "Deinstallation startet..."}, + }; + private int keyword_mode; + + public readonly BackgroundWorker Worker = new BackgroundWorker(); + public event EventHandler Successful; + public event EventHandler Exception; + + public LauncherMode LauncherMode { get; set; } + + public ProgressFrame(LauncherMode mode) + { + InitializeComponent(); + + proBar1.IsIndeterminate = false; + proBar1.Minimum = 0; + proBar1.Maximum = 100; + + proBar2.IsIndeterminate = false; + proBar2.Minimum = 0; + proBar2.Maximum = DownloadController.Manager.FilesToProcessTotal; + + LauncherMode = mode; + + keyword_mode = (int)mode; + + Loaded += (s, e) => Start(); + } + + private string getKeyword(int pos) => keywords[keyword_mode][pos]; + + public string Message + { + get { return lblMessage.Content as string; } + set { lblMessage.Content = value; } + } + public string SubMessage + { + get { return lblSubmessage.Content as string; } + set { lblSubmessage.Content = value; } + } + + public void Start() + { + var skipLock = bool.TryParse(ConfigurationManager.AppSettings.Get("SkipLock"), out bool c) && c; + + Worker.DoWork += worker_DoWork; + Worker.ProgressChanged += worker_ProgressChanged; + Worker.RunWorkerCompleted += worker_completed; + + Worker.WorkerReportsProgress = true; + + Worker.RunWorkerAsync(skipLock); + } + + void worker_DoWork(object sender, DoWorkEventArgs e) + { + var skipLock = (bool)e.Argument; + var worker = sender as BackgroundWorker; + + DownloadController.Manager.SkipLock = skipLock; + DownloadController.Manager.Feedback = worker.ReportProgress; + + DownloadController.Manager.StartProcess(worker); + } + + private void worker_completed(object sender, RunWorkerCompletedEventArgs e) + { + if (e.Error != null) + { + ViewController.Error = e.Error; + + Exception.Invoke(this, new EventArgs()); + } + else + { + Successful.Invoke(this, new EventArgs()); + } + } + + private void worker_ProgressChanged(object sender, ProgressChangedEventArgs e) + { + var progress = (LauncherProgress)e.ProgressPercentage; + var obj = e.UserState; + + switch (progress) + { + case LauncherProgress.ProgressStart: + Message = $"{getKeyword(0)} wird vorbereitet..."; + SubMessage = ""; + Bar2Activate(); + break; + + case LauncherProgress.DownloadStart: + Message = "Download startet..."; + SubMessage = ""; + Bar1Show(); + Bar1Activate(); + Bar1Reset(); + Bar1SetLimit(DownloadController.Manager.FilesToDownloadCount); + break; + + case LauncherProgress.DownloadUpdate: + var args = obj as DownloadProgressEventArgs; + Message = "Download wird ausgeführt..."; + SubMessage = $"{args.File.RelativePath} ({args.Size})\n wurde heruntergeladen..."; + Bar1MakeStep(); + Bar2MakeStep(); + break; + + case LauncherProgress.DownloadFinish: + Message = "Download abgeschlossen!"; + SubMessage = ""; + Bar1Hide(); + break; + + case LauncherProgress.ApplyStart: + Message = "Füge Pakete hinzu..."; + SubMessage = ""; + Bar1Show(); + Bar1Activate(); + Bar1Reset(); + Bar1SetLimit(DownloadController.Manager.FilesToApplyCount); + break; + + case LauncherProgress.ApplyUpdate: + var args2 = obj as ApplyFileEventArgs; + SubMessage = $"{args2.RelativePath}\n wurde installiert..."; + Bar1MakeStep(); + Bar2MakeStep(); + break; + + case LauncherProgress.ApplyFinished: + Message = "Hinzufügen abgeschlossen!"; + SubMessage = ""; + Bar1Hide(); + break; + + case LauncherProgress.DeleteStart: + Message = getKeyword(1); + SubMessage = ""; + Bar1Show(); + Bar1Activate(); + Bar1Reset(); + Bar1SetLimit(DownloadController.Manager.FilesToDeleteInApplyCount); + break; + case LauncherProgress.DeleteUpdate: + var args3 = obj as string; + SubMessage = $"{args3}\n wurde entfernt!"; + Bar1MakeStep(); + Bar2MakeStep(); + break; + + case LauncherProgress.DeleteFinished: + Message = "Säuberung abgeschlossen!"; + SubMessage = ""; + Bar1Hide(); + break; + + case LauncherProgress.CleanupStart: + Message = "Räume hier noch eben auf..."; + SubMessage = ""; + Bar1Show(); + Bar1Deactivate(); + break; + + case LauncherProgress.CleanupUpdate: + break; + + case LauncherProgress.CleanupFinished: + Message = "Blitze blank..."; + SubMessage = ""; + break; + + case LauncherProgress.ProgressEnd: + Message = $"{getKeyword(0)} abgeschlossen!"; + SubMessage = ""; + Bar2Fill(); + break; + default: + break; + } + } + + #region a + public void Bar1Activate() => proBar1.IsIndeterminate = false; + public void Bar1Deactivate() => proBar1.IsIndeterminate = true; + public void Bar1SetLimit(int max) => proBar1.Maximum = max; + public void Bar1Reset() => proBar1.Value = 0; + public void Bar1MakeStep() => proBar1.Value++; + public void Bar1Hide() => proBar1.Visibility = Visibility.Hidden; + public void Bar1Show() => proBar1.Visibility = Visibility.Visible; + + public void Bar2Activate() => proBar2.IsIndeterminate = false; + public void Bar2Deactivate() => proBar2.IsIndeterminate = true; + public void Bar2SetLimit(int max) => proBar2.Maximum = max; + public void Bar2MakeStep() => proBar2.Value++; + public void Bar2MakeStep(int val) => proBar2.Value += val; + public void Bar2Fill() => proBar2.Value = proBar2.Maximum; + public void Bar2Hide() => proBar2.Visibility = Visibility.Hidden; + public void Bar2Show() => proBar2.Visibility = Visibility.Visible; + + public void Bar2SetPercent(double percentage) + { + DoubleAnimation animation = new DoubleAnimation(percentage, duration); + proBar2.BeginAnimation(ProgressBar.ValueProperty, animation); + } + #endregion + } +} diff --git a/BeWoLauncher/View/Frames/UninstallProgressInfoFrame.cs b/BeWoLauncher/View/Frames/UninstallProgressInfoFrame.cs deleted file mode 100644 index fac42c630..000000000 --- a/BeWoLauncher/View/Frames/UninstallProgressInfoFrame.cs +++ /dev/null @@ -1,69 +0,0 @@ -using BeWoLauncher.Logic.Controller; -using BS.SharedLauncher.Update; -using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Linq; -using System.Text; -using System.Threading; -using System.Threading.Tasks; - -namespace BeWoLauncher.View.Frames -{ - public class UninstallProgressInfoFrame : GenericProgressInfo - { - public event EventHandler UninstallSuccessful; - - public UninstallProgressInfoFrame() - { - Bar1Deactivate(); - Bar2Hide(); - } - - public override void Start() - { - Worker.DoWork += worker_DoWork; - Worker.ProgressChanged += worker_ProgressChanged; - Worker.RunWorkerCompleted += worker_completed; - - Worker.WorkerReportsProgress = true; - - Worker.RunWorkerAsync(); - } - - void worker_DoWork(object sender, DoWorkEventArgs e) - { - BackgroundWorker worker = sender as BackgroundWorker; - - DownloadController.Manager.StartUninstall(worker.ReportProgress); - } - - private void worker_completed(object sender, RunWorkerCompletedEventArgs e) - { - if (e.Error != null) - { - ViewController.ViewBehavior.UninstallFailed(e.Error); - } - else - { - UninstallSuccessful.Invoke(this, new EventArgs()); - } - } - - private void worker_ProgressChanged(object sender, ProgressChangedEventArgs e) - { - if (e.ProgressPercentage == 3) - { - Bar1Deactivate(); - - Message = "Alte Dateien werden entfernt."; - SubMessage = ""; - } - else if (e.ProgressPercentage == 4) - { - var args = e.UserState as string; - SubMessage = $"{args} wurde entfernt!"; - } - } - } -} diff --git a/BeWoLauncher/View/Frames/UpdateInfoFrame.xaml b/BeWoLauncher/View/Frames/UpdateInfoFrame.xaml index 55a6e1565..95a2b0c54 100644 --- a/BeWoLauncher/View/Frames/UpdateInfoFrame.xaml +++ b/BeWoLauncher/View/Frames/UpdateInfoFrame.xaml @@ -47,14 +47,6 @@ - - - - - - - - diff --git a/BeWoLauncher/View/Frames/UpdateInfoFrame.xaml.cs b/BeWoLauncher/View/Frames/UpdateInfoFrame.xaml.cs index 1910c2d6d..fc2cb2cd9 100644 --- a/BeWoLauncher/View/Frames/UpdateInfoFrame.xaml.cs +++ b/BeWoLauncher/View/Frames/UpdateInfoFrame.xaml.cs @@ -33,7 +33,7 @@ namespace BeWoLauncher.View.Frames LauncherPaths.ActualPlanerLocation = LauncherPaths.GetInstallLocationFromSetting(); - var size = NonspecificTools.SizeSuffix((ulong)DownloadController.Manager.ResponseInfo.DownloadSize).Split(' '); + var size = NonspecificTools.SizeSuffix((ulong)DownloadController.Manager.UpdatePlanResponse.DownloadSize).Split(' '); lblErforderlich.Content = size[0]; lblErforderlichSize.Content = size[1]; @@ -50,22 +50,8 @@ namespace BeWoLauncher.View.Frames lblVerfuegbar.Content = size2[0] ?? "error#87"; lblVerfuegbarSize.Content = string.Empty; } - - var total = DownloadController.Manager.ResponseInfo.FileCount; - var download = DownloadController.Manager.ResponseInfo.NewFileCount; - var already = total - download; - - lblcountnew.Content = $"{download}"; - lblcountalready.Content = $"{already}"; - lblversion.Content = DownloadController.Manager.ResponseInfo.Version; - - lblcountalready.Visibility = Visibility.Hidden; - lblcountalreadytxt.Visibility = Visibility.Hidden; - lblcountnew.Visibility = Visibility.Hidden; - lblcountnewtxt.Visibility = Visibility.Hidden; - - lblfound.Visibility = already == 0 ? Visibility.Hidden : Visibility.Visible; + lblversion.Content = DownloadController.Manager.UpdatePlanResponse.CurrentPackage.Version; } private void Button_Click(object sender, RoutedEventArgs e) diff --git a/BeWoLauncher/View/Frames/UpdateProgressInfoFrame.cs b/BeWoLauncher/View/Frames/UpdateProgressInfoFrame.cs deleted file mode 100644 index 4a9004803..000000000 --- a/BeWoLauncher/View/Frames/UpdateProgressInfoFrame.cs +++ /dev/null @@ -1,183 +0,0 @@ -using BeWoLauncher.Logic.Controller; -using BeWoLauncher.Logic.Utils.Download; -using BS.SharedLauncher.Enums; -using BS.SharedLauncher.Update; -using System; -using System.ComponentModel; -using System.Configuration; -using System.Threading; - -namespace BeWoLauncher.View.Frames -{ - public class UpdateProgressInfoFrame : GenericProgressInfo - { - public event EventHandler UpdateSuccessful; - - public DownloadManager Manager => DownloadController.Manager; - - public UpdateProgressInfoFrame() - { - Bar1SetLimit(Manager.ResponseInfo.FileCount); - Bar1Hide(); - - Bar2SetLimit(100); - } - - public override void Start() - { - var skipLock = bool.TryParse(ConfigurationManager.AppSettings.Get("SkipLock"), out bool c) && c; - - Worker.DoWork += worker_DoWork; - Worker.ProgressChanged += worker_ProgressChanged; - Worker.RunWorkerCompleted += worker_completed; - - Worker.WorkerReportsProgress = true; - - Worker.RunWorkerAsync(skipLock); - } - - void worker_DoWork(object sender, DoWorkEventArgs e) - { - bool skipLock = (bool)e.Argument; - - BackgroundWorker worker = sender as BackgroundWorker; - - // UI: 0 - worker.ReportProgress((int)LauncherProgress.ProgressStart); - - // Wait - Thread.Sleep(1000); - - // UI: 1 - worker.ReportProgress((int)LauncherProgress.DownloadStart); - - // Wait - Thread.Sleep(500); - - // Process: 2 - DownloadController.Manager.StartDownload(skipLock, worker.ReportProgress); - - // UI: 3 - worker.ReportProgress((int)LauncherProgress.DownloadFinish); - - // Wait - Thread.Sleep(1000); - - // UI: 4 - worker.ReportProgress((int)LauncherProgress.ApplyStart); - - // Wait - Thread.Sleep(500); - - // Process: 5 - DownloadController.Manager.StartApply(skipLock, worker.ReportProgress); - - // UI: 6 - worker.ReportProgress((int)LauncherProgress.ApplyFinished); - - // Wait - Thread.Sleep(1000); - - // Process: 7, Wait, 8 - DownloadController.Manager.StartCleanup(worker.ReportProgress); - - // UI: 9 - worker.ReportProgress((int)LauncherProgress.DeleteFinished); - - // Wait - Thread.Sleep(500); - - // UI: 10 - worker.ReportProgress((int)LauncherProgress.ProgressEnd); - } - - private void worker_completed(object sender, RunWorkerCompletedEventArgs e) - { - if (e.Error != null) - { - ViewController.ViewBehavior.UpdateFailed(e.Error); - } - else - { - UpdateSuccessful.Invoke(this, new EventArgs()); - } - } - - private void worker_ProgressChanged(object sender, ProgressChangedEventArgs e) - { - var progress = (LauncherProgress)e.ProgressPercentage; - var obj = e.UserState; - - switch (progress) - { - case LauncherProgress.ProgressStart: - Message = "Update wird vorbereitet..."; - SubMessage = "Lade benötigte Pakete herunter..."; - break; - - case LauncherProgress.DownloadStart: - Message = "Download startet..."; - SubMessage = ""; - Bar1Show(); - Bar1Deactivate(); - Bar2SetPercent(5); - break; - - case LauncherProgress.DownloadUpdate: - throw new NotImplementedException("#fd42398"); - var args = obj as DownloadProgressEventArgs; - SubMessage = $"{args.Progress.ToString("0.##")}% fertig"; - break; - - case LauncherProgress.DownloadFinish: - Message = "Download abgeschlossen!"; - SubMessage = ""; - Bar2SetPercent(40); - break; - - case LauncherProgress.ApplyStart: - Message = "Füge Pakete hinzu..."; - SubMessage = ""; - Bar1Activate(); - break; - - case LauncherProgress.ApplyUpdate: - var args2 = obj as ApplyFileEventArgs; - SubMessage = $"{args2.Name} wurde erfolgreich von \n{args2.AbsolutePath} hinzugefügt!"; - Bar1MakeStep(); - break; - - case LauncherProgress.ApplyFinished: - Message = "Hinzufügen abgeschlossen!"; - SubMessage = ""; - Bar2SetPercent(80); - Bar1Deactivate(); - break; - - case LauncherProgress.DeleteStart: - Message = "Ungebrauchte Datei(en) gefunden."; - SubMessage = ""; - break; - case LauncherProgress.DeleteUpdate: - var args3 = obj as string; - SubMessage = $"{args3} wurde entfernt!"; - break; - - case LauncherProgress.DeleteFinished: - Message = "Säuberung abgeschlossen!"; - SubMessage = ""; - Bar2SetPercent(95); - Bar1Deactivate(); - break; - - case LauncherProgress.ProgressEnd: - Message = "Installation abgeschlossen!"; - SubMessage = ""; - Bar2Fill(); - break; - default: - break; - } - } - } -} diff --git a/BeWoLauncher/View/LoginView.xaml.cs b/BeWoLauncher/View/LoginView.xaml.cs index 6bb6cd0df..cf5fe7352 100644 --- a/BeWoLauncher/View/LoginView.xaml.cs +++ b/BeWoLauncher/View/LoginView.xaml.cs @@ -12,7 +12,6 @@ using System.Collections.Generic; using System.Collections.ObjectModel; using System.Collections.Specialized; using System.ComponentModel; -using System.Deployment.Application; using System.IO; using System.Linq; using System.Net; @@ -61,7 +60,7 @@ namespace BeWoLauncher.View private string GETSERVER_URL = "https://support.bewoplaner.de/api/getserver.php?k={0}&t=1"; private string GETSTATUSMESSAGE_URL = "https://support.bewoplaner.de/api/getstate.php?k={0}&t=1&v={1}"; private string GETNETMESSAGE_URL = "https://support.bewoplaner.de/api/getxmlstate.php?k={0}&t=1"; - + public LoginView() { InitializeComponent(); @@ -113,19 +112,19 @@ namespace BeWoLauncher.View private void button_login_Click(object sender, RoutedEventArgs e) { - if (!String.IsNullOrEmpty(ConnectionInformation.ProxyName)) + if (!String.IsNullOrEmpty(SessionInformation.Connection.ProxyName)) { var webProxy = WebProxy.GetDefaultProxy(); webProxy.UseDefaultCredentials = true; - System.Net.WebRequest.DefaultWebProxy = new WebProxy(ConnectionInformation.ProxyName, true); + System.Net.WebRequest.DefaultWebProxy = new WebProxy(SessionInformation.Connection.ProxyName, true); - if (String.IsNullOrEmpty(ConnectionInformation.ProxyUsername)) + if (String.IsNullOrEmpty(SessionInformation.Connection.ProxyUsername)) { WebRequest.DefaultWebProxy.Credentials = CredentialCache.DefaultNetworkCredentials; } else { - WebRequest.DefaultWebProxy.Credentials = new NetworkCredential(ConnectionInformation.ProxyUsername, ConnectionInformation.ProxyPassword); + WebRequest.DefaultWebProxy.Credentials = new NetworkCredential(SessionInformation.Connection.ProxyUsername, SessionInformation.Connection.ProxyPassword); } } @@ -168,18 +167,17 @@ namespace BeWoLauncher.View ViewController.StartWaiting(); - string lUserName = TextBox_Username.Text; - string lPassword = PasswordBox_Password.Password; - string lPIN = PINTextBox.Text; - string lTenant = ConnectionInformation.Tenant; + SessionInformation.Login.Username = TextBox_Username.Text; + SessionInformation.Login.Password = PasswordBox_Password.Password; + SessionInformation.Login.Pin = PINTextBox.Text; - if (!String.IsNullOrEmpty(lPIN)) + if (!String.IsNullOrEmpty(SessionInformation.Login.Pin)) { - lPIN += "_" + System.Environment.MachineName; + SessionInformation.Login.Pin += "_" + System.Environment.MachineName; } - Action action = Login; - action.BeginInvoke(lUserName, lPassword, lTenant, lPIN, cb => { }, null); + Action action = Login; + action.BeginInvoke(cb => { }, null); } } private void Hyperlink_OnRequestNavigate(object sender, RequestNavigateEventArgs e) @@ -358,12 +356,12 @@ namespace BeWoLauncher.View string v1, v2; paramDic.TryGetValue("k", out v1); paramDic.TryGetValue("s", out v2); - ConnectionInformation.Tenant = v1; - ConnectionInformation.ServerName = v2; + SessionInformation.Login.Tenant = v1; + SessionInformation.Connection.Servername = v2; if (ProfileList.Count > 0) - ProfileList.Insert(0, new ConnectionProfile(v1, v2, ConnectionInformation.Tenant)); + ProfileList.Insert(0, new ConnectionProfile(v1, v2, SessionInformation.Login.Tenant)); else - ProfileList.Add(new ConnectionProfile(v1, v2, ConnectionInformation.Tenant)); + ProfileList.Add(new ConnectionProfile(v1, v2, SessionInformation.Login.Tenant)); SaveProfileListToFile(); #else if (ApplicationDeployment.IsNetworkDeployed && ApplicationDeployment.CurrentDeployment.ActivationUri != null) @@ -460,19 +458,19 @@ namespace BeWoLauncher.View ChangeServerAndTenant(profileSelectionComboBox.SelectedItem as ConnectionProfile); - if (!String.IsNullOrEmpty(ConnectionInformation.ProxyName)) + if (!String.IsNullOrEmpty(SessionInformation.Connection.ProxyName)) { var webProxy = WebProxy.GetDefaultProxy(); webProxy.UseDefaultCredentials = true; - System.Net.WebRequest.DefaultWebProxy = new WebProxy(ConnectionInformation.ProxyName, true); + System.Net.WebRequest.DefaultWebProxy = new WebProxy(SessionInformation.Connection.ProxyName, true); - if (String.IsNullOrEmpty(ConnectionInformation.ProxyUsername)) + if (String.IsNullOrEmpty(SessionInformation.Connection.ProxyUsername)) { WebRequest.DefaultWebProxy.Credentials = CredentialCache.DefaultNetworkCredentials; } else { - WebRequest.DefaultWebProxy.Credentials = new NetworkCredential(ConnectionInformation.ProxyUsername, ConnectionInformation.ProxyPassword); + WebRequest.DefaultWebProxy.Credentials = new NetworkCredential(SessionInformation.Connection.ProxyUsername, SessionInformation.Connection.ProxyPassword); } } } @@ -629,14 +627,14 @@ namespace BeWoLauncher.View { Uri path = new Uri(adminUrl); - ConnectionInformation.IpAddress = Encoding.UTF8.GetString(wc.DownloadData(path)); + SessionInformation.Connection.IpAddress = Encoding.UTF8.GetString(wc.DownloadData(path)); } } } catch (Exception) { - ConnectionInformation.IpAddress = String.Empty; + SessionInformation.Connection.IpAddress = String.Empty; } } private string GetAdminUrl() @@ -706,11 +704,11 @@ namespace BeWoLauncher.View file.Close(); - ConnectionInformation.ProxyName = datai[0]; - ConnectionInformation.ProxyUsername = datai[1]; - ConnectionInformation.ProxyPassword = datai[2]; + SessionInformation.Connection.ProxyName = datai[0]; + SessionInformation.Connection.ProxyUsername = datai[1]; + SessionInformation.Connection.ProxyPassword = datai[2]; - proxyTextBox.Text = ConnectionInformation.ProxyName; + proxyTextBox.Text = SessionInformation.Connection.ProxyName; } catch (IOException) @@ -847,11 +845,16 @@ namespace BeWoLauncher.View SaveProfileListToFile(); } - ConnectionInformation.Tenant = profile.Tenant; - ConnectionInformation.ServerName = GetNumericServerName(profile.Server); - ConnectionInformation.LauncherServerAddress = profile.Server; + SessionInformation.Login.Tenant = profile.Tenant; + SessionInformation.Connection.Servername = GetNumericServerName(profile.Server); + SessionInformation.Connection.CoreServerAddress = profile.Server; + SessionInformation.Connection.DownloadServerAddress = profile.Server; #if DEBUG + + SessionInformation.Connection.DownloadServerAddress = SessionInformation.GetDebugConnection(1); + SessionInformation.Connection.CoreServerAddress = SessionInformation.GetDebugConnection(2); + //CB ZUM TESTEN //ConnectionInformation.Tenant = "9876543210"; //ConnectionInformation.ServerName = "4"; @@ -1010,20 +1013,20 @@ namespace BeWoLauncher.View return true; #endif } - private void Login(String lUserName, String lPassword, String lTenant, String lPIN) + private void Login() { try { //1. Versuch - UserValidationResult result = TryLogin(lUserName, lPassword, lPIN); + UserValidationResult result = TryLogin(); //2. Versuch if (result == UserValidationResult.UnknownError) { - LauncherServiceFacade.DoLauncherServiceAsync(op => op.ResetTenant(lTenant), + LauncherServiceFacade.DoLauncherServiceAsync(op => op.ResetTenant(SessionInformation.Login.Tenant), delegate { - result = TryLogin(lUserName, lPassword, lPIN); + result = TryLogin(); if (result == UserValidationResult.UnknownError) { @@ -1031,7 +1034,7 @@ namespace BeWoLauncher.View LauncherServiceFacade.DoLauncherServiceAsync(op => op.ResetAllTenant(), delegate { - result = TryLogin(lUserName, lPassword, lPIN); + result = TryLogin(); if (result == UserValidationResult.UnknownError) { @@ -1059,14 +1062,14 @@ namespace BeWoLauncher.View this.Dispatcher.BeginInvoke(DispatcherPriority.Normal, (Action)delegate { ViewController.EndWaiting(); - MessageBox.Show("Die Kundennummer '" + lTenant + "' ist ungültig.", "Fehler bei der Anmeldung", MessageBoxButton.OK, MessageBoxImage.Exclamation); + MessageBox.Show("Die Kundennummer '" + SessionInformation.Login.Tenant + "' ist ungültig.", "Fehler bei der Anmeldung", MessageBoxButton.OK, MessageBoxImage.Exclamation); }); } - String pin = lPIN; + String pin = SessionInformation.Login.Pin; - if (!String.IsNullOrEmpty(lPIN) && lPIN.IndexOf('_') >= 0) + if (!String.IsNullOrEmpty(SessionInformation.Login.Pin) && SessionInformation.Login.Pin.IndexOf('_') >= 0) { - pin = lPIN.Substring(0, lPIN.IndexOf('_')); + pin = SessionInformation.Login.Pin.Substring(0, SessionInformation.Login.Pin.IndexOf('_')); } if (result == UserValidationResult.IncorrectPin) @@ -1115,13 +1118,12 @@ namespace BeWoLauncher.View LauncherApp.ShowError(ex); //MessageBox.Show(ex.Message); } } - private UserValidationResult TryLogin(string lUserName, string lPassword, string lPIN = "") + private UserValidationResult TryLogin() { UserValidationResult? result = null; - if (!string.IsNullOrEmpty(lUserName) && !string.IsNullOrEmpty(lPassword)) + if (!string.IsNullOrEmpty(SessionInformation.Login.Username) && !string.IsNullOrEmpty(SessionInformation.Login.Password)) { - String tempUsername = lUserName; String version = "unbekannt"; String clr = "unbekannt"; var bewoVersion = LauncherApp.Version; @@ -1145,14 +1147,17 @@ namespace BeWoLauncher.View } - tempUsername = String.Format("{0}//Version={1};CLRVersion={2};BeWoVersion={3};IsNet45OrNewer={4}", lUserName, version, clr, bewoVersion, isNet45OrNewer); + SessionInformation.Login.TempUsername = + $"{SessionInformation.Login.Username}" + + $"//Version={version};CLRVersion={clr};BeWoVersion={bewoVersion};IsNet45OrNewer={isNet45OrNewer}"; try { LauncherServiceFacade.DoLauncherServiceAsync(s => { try { - var t = s.IsUserValid(tempUsername, lPassword, lPIN, "BeWoClient", true); + SessionInformation.Login.ClientId = "BeWoClient"; + var t = s.IsUserValid(SessionInformation.Login.TempUsername, SessionInformation.Login.Password, SessionInformation.Login.Pin, SessionInformation.Login.ClientId, true); return t; } catch (Exception e) @@ -1163,7 +1168,7 @@ namespace BeWoLauncher.View r => { result = r; - Dispatcher.BeginInvoke(DispatcherPriority.Normal, (Action)delegate { LoginResult(r, lUserName, lPassword, lPIN); }); + Dispatcher.BeginInvoke(DispatcherPriority.Normal, (Action)delegate { LoginResult(r); }); }, true); } catch (Exception e) @@ -1184,13 +1189,10 @@ namespace BeWoLauncher.View return result.Value; } - private void LoginResult(UserValidationResult result, String lUserName, String lPassword, String lPIN = "") + private void LoginResult(UserValidationResult result) { if (result == UserValidationResult.UserValid) { - ConnectionInformation.Username = lUserName; - ConnectionInformation.Password = lPassword; - LoginSuccessful.Invoke(this, new EventArgs()); } else if (result == UserValidationResult.PasswordExpired) @@ -1205,9 +1207,6 @@ namespace BeWoLauncher.View if (!window.Abbruch) { - ConnectionInformation.Username = lUserName; - ConnectionInformation.Password = lPassword; - LoginSuccessful.Invoke(this, new EventArgs()); } }); diff --git a/BeWoOhneReports.sln b/BeWoOhneReports.sln index 6df300f17..b029612d0 100644 --- a/BeWoOhneReports.sln +++ b/BeWoOhneReports.sln @@ -31,10 +31,16 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ChatController", "..\Chat\C EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BeWoLauncher", "BeWoLauncher\BeWoLauncher.csproj", "{E3BA193A-A64F-4CE6-91BE-F54E551797BE}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LauncherHost", "LauncherHost\LauncherHost.csproj", "{18019E8C-C6DA-4B1B-9C2B-908BC14911AB}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DownloadServer", "DownloadServer\DownloadServer.csproj", "{18019E8C-C6DA-4B1B-9C2B-908BC14911AB}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SharedLauncher", "SharedLauncher\SharedLauncher.csproj", "{EFE05C79-E0DD-4311-8B90-A8DA7EBDF36F}" EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Test", "Test", "{CA77E4CE-37D5-489D-9009-ACC75DFC421E}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BeWoTest", "BeWoTest\BeWoTest.csproj", "{767ACFAF-D6ED-4DFD-AC49-0990F23B2239}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UnitTests", "UnitTests\UnitTests.csproj", "{825B9513-40EF-48C1-A354-9D4503A3FA74}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|.NET = Debug|.NET @@ -173,6 +179,30 @@ Global {EFE05C79-E0DD-4311-8B90-A8DA7EBDF36F}.Release|Any CPU.Build.0 = Release|Any CPU {EFE05C79-E0DD-4311-8B90-A8DA7EBDF36F}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU {EFE05C79-E0DD-4311-8B90-A8DA7EBDF36F}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {767ACFAF-D6ED-4DFD-AC49-0990F23B2239}.Debug|.NET.ActiveCfg = Debug|Any CPU + {767ACFAF-D6ED-4DFD-AC49-0990F23B2239}.Debug|.NET.Build.0 = Debug|Any CPU + {767ACFAF-D6ED-4DFD-AC49-0990F23B2239}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {767ACFAF-D6ED-4DFD-AC49-0990F23B2239}.Debug|Any CPU.Build.0 = Debug|Any CPU + {767ACFAF-D6ED-4DFD-AC49-0990F23B2239}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {767ACFAF-D6ED-4DFD-AC49-0990F23B2239}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {767ACFAF-D6ED-4DFD-AC49-0990F23B2239}.Release|.NET.ActiveCfg = Release|Any CPU + {767ACFAF-D6ED-4DFD-AC49-0990F23B2239}.Release|.NET.Build.0 = Release|Any CPU + {767ACFAF-D6ED-4DFD-AC49-0990F23B2239}.Release|Any CPU.ActiveCfg = Release|Any CPU + {767ACFAF-D6ED-4DFD-AC49-0990F23B2239}.Release|Any CPU.Build.0 = Release|Any CPU + {767ACFAF-D6ED-4DFD-AC49-0990F23B2239}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {767ACFAF-D6ED-4DFD-AC49-0990F23B2239}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {825B9513-40EF-48C1-A354-9D4503A3FA74}.Debug|.NET.ActiveCfg = Debug|Any CPU + {825B9513-40EF-48C1-A354-9D4503A3FA74}.Debug|.NET.Build.0 = Debug|Any CPU + {825B9513-40EF-48C1-A354-9D4503A3FA74}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {825B9513-40EF-48C1-A354-9D4503A3FA74}.Debug|Any CPU.Build.0 = Debug|Any CPU + {825B9513-40EF-48C1-A354-9D4503A3FA74}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {825B9513-40EF-48C1-A354-9D4503A3FA74}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {825B9513-40EF-48C1-A354-9D4503A3FA74}.Release|.NET.ActiveCfg = Release|Any CPU + {825B9513-40EF-48C1-A354-9D4503A3FA74}.Release|.NET.Build.0 = Release|Any CPU + {825B9513-40EF-48C1-A354-9D4503A3FA74}.Release|Any CPU.ActiveCfg = Release|Any CPU + {825B9513-40EF-48C1-A354-9D4503A3FA74}.Release|Any CPU.Build.0 = Release|Any CPU + {825B9513-40EF-48C1-A354-9D4503A3FA74}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {825B9513-40EF-48C1-A354-9D4503A3FA74}.Release|Mixed Platforms.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -188,6 +218,7 @@ Global {8A83C4DC-A0B1-4A51-AE1D-366D7A05B298} = {E7543C39-A44C-40C9-82C9-E7FAA2D9A852} {E3BA193A-A64F-4CE6-91BE-F54E551797BE} = {E7543C39-A44C-40C9-82C9-E7FAA2D9A852} {18019E8C-C6DA-4B1B-9C2B-908BC14911AB} = {FEB0336B-F053-40B6-92DD-7DE56AB9408A} + {767ACFAF-D6ED-4DFD-AC49-0990F23B2239} = {CA77E4CE-37D5-489D-9009-ACC75DFC421E} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {5352BE53-F2FD-442F-85A8-4157599AA153} diff --git a/BeWoTest/App.config b/BeWoTest/App.config new file mode 100644 index 000000000..8e1564635 --- /dev/null +++ b/BeWoTest/App.config @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/BeWoTest/App.xaml b/BeWoTest/App.xaml new file mode 100644 index 000000000..18bc591a4 --- /dev/null +++ b/BeWoTest/App.xaml @@ -0,0 +1,9 @@ + + + + + diff --git a/BeWoTest/App.xaml.cs b/BeWoTest/App.xaml.cs new file mode 100644 index 000000000..36acbfa16 --- /dev/null +++ b/BeWoTest/App.xaml.cs @@ -0,0 +1,22 @@ +using BS.SharedLauncher.Information; +using System; +using System.Collections.Generic; +using System.Configuration; +using System.Data; +using System.Linq; +using System.Threading.Tasks; +using System.Windows; + +namespace BeWoTest +{ + /// + /// Interaktionslogik für "App.xaml" + /// + public partial class App : Application + { + protected override void OnStartup(StartupEventArgs e) + { + SessionInformation.LoadPipe(e.Args[0]); + } + } +} diff --git a/BeWoTest/BeWoTest.csproj b/BeWoTest/BeWoTest.csproj new file mode 100644 index 000000000..468cac3c2 --- /dev/null +++ b/BeWoTest/BeWoTest.csproj @@ -0,0 +1,103 @@ + + + + + Debug + AnyCPU + {767ACFAF-D6ED-4DFD-AC49-0990F23B2239} + WinExe + BeWoTest + BeWoPlaner + v4.5 + 512 + {60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + 4 + true + + + AnyCPU + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + AnyCPU + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + + + + + + + + + 4.0 + + + + + + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + App.xaml + Code + + + MainWindow.xaml + Code + + + + + Code + + + True + True + Resources.resx + + + True + Settings.settings + True + + + ResXFileCodeGenerator + Resources.Designer.cs + + + SettingsSingleFileGenerator + Settings.Designer.cs + + + + + + + + {EFE05C79-E0DD-4311-8B90-A8DA7EBDF36F} + SharedLauncher + + + + \ No newline at end of file diff --git a/BeWoTest/MainWindow.xaml b/BeWoTest/MainWindow.xaml new file mode 100644 index 000000000..b1179c36c --- /dev/null +++ b/BeWoTest/MainWindow.xaml @@ -0,0 +1,16 @@ + + + + + adafsafdssssssssssssssssssssssssssssssssgfddddddddddddddddddddddfkjaghuiareghuirgheaurighbireuahgiuaerhgiuaerghhergaihhgaressssssssssssasdf + + + + diff --git a/BeWoTest/MainWindow.xaml.cs b/BeWoTest/MainWindow.xaml.cs new file mode 100644 index 000000000..6f1bac2ee --- /dev/null +++ b/BeWoTest/MainWindow.xaml.cs @@ -0,0 +1,33 @@ +using BS.SharedLauncher.Information; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using System.Windows.Navigation; +using System.Windows.Shapes; + +namespace BeWoTest +{ + /// + /// Interaktionslogik für MainWindow.xaml + /// + public partial class MainWindow : Window + { + public MainWindow() + { + InitializeComponent(); + + testtxt.Text = SessionInformation.ToString(); + + Console.WriteLine("GUI geladen"); + } + } +} diff --git a/BeWoTest/Properties/AssemblyInfo.cs b/BeWoTest/Properties/AssemblyInfo.cs new file mode 100644 index 000000000..165eca48e --- /dev/null +++ b/BeWoTest/Properties/AssemblyInfo.cs @@ -0,0 +1,55 @@ +using System.Reflection; +using System.Resources; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Windows; + +// Allgemeine Informationen über eine Assembly werden über die folgenden +// Attribute gesteuert. Ändern Sie diese Attributwerte, um die Informationen zu ändern, +// die einer Assembly zugeordnet sind. +[assembly: AssemblyTitle("BeWoTest")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("BeWoTest")] +[assembly: AssemblyCopyright("Copyright © 2022")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Durch Festlegen von ComVisible auf FALSE werden die Typen in dieser Assembly +// für COM-Komponenten unsichtbar. Wenn Sie auf einen Typ in dieser Assembly von +// COM aus zugreifen müssen, sollten Sie das ComVisible-Attribut für diesen Typ auf "True" festlegen. +[assembly: ComVisible(false)] + +//Um mit dem Erstellen lokalisierbarer Anwendungen zu beginnen, legen Sie +//ImCodeVerwendeteKultur in der .csproj-Datei +//in einer fest. Wenn Sie in den Quelldateien beispielsweise Deutsch +//(Deutschland) verwenden, legen Sie auf \"de-DE\" fest. Heben Sie dann die Auskommentierung +//des nachstehenden NeutralResourceLanguage-Attributs auf. Aktualisieren Sie "en-US" in der nachstehenden Zeile, +//sodass es mit der UICulture-Einstellung in der Projektdatei übereinstimmt. + +//[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)] + + +[assembly: ThemeInfo( + ResourceDictionaryLocation.None, //Speicherort der designspezifischen Ressourcenwörterbücher + //(wird verwendet, wenn eine Ressource auf der Seite nicht gefunden wird, + // oder in den Anwendungsressourcen-Wörterbüchern nicht gefunden werden kann.) + ResourceDictionaryLocation.SourceAssembly //Speicherort des generischen Ressourcenwörterbuchs + //(wird verwendet, wenn eine Ressource auf der Seite nicht gefunden wird, + // designspezifischen Ressourcenwörterbuch nicht gefunden werden kann.) +)] + + +// Versionsinformationen für eine Assembly bestehen aus den folgenden vier Werten: +// +// Hauptversion +// Nebenversion +// Buildnummer +// Revision +// +// Sie können alle Werte angeben oder Standardwerte für die Build- und Revisionsnummern verwenden, +// übernehmen, indem Sie "*" eingeben: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/BeWoTest/Properties/Resources.Designer.cs b/BeWoTest/Properties/Resources.Designer.cs new file mode 100644 index 000000000..f152c10f2 --- /dev/null +++ b/BeWoTest/Properties/Resources.Designer.cs @@ -0,0 +1,71 @@ +//------------------------------------------------------------------------------ +// +// Dieser Code wurde von einem Tool generiert. +// Laufzeitversion: 4.0.30319.42000 +// +// Änderungen an dieser Datei können fehlerhaftes Verhalten verursachen und gehen verloren, wenn +// der Code neu generiert wird. +// +//------------------------------------------------------------------------------ + +namespace BeWoTest.Properties +{ + + + /// + /// Eine stark typisierte Ressourcenklasse zum Suchen von lokalisierten Zeichenfolgen usw. + /// + // Diese Klasse wurde von der StronglyTypedResourceBuilder-Klasse + // über ein Tool wie ResGen oder Visual Studio automatisch generiert. + // Um einen Member hinzuzufügen oder zu entfernen, bearbeiten Sie die .ResX-Datei und führen dann ResGen + // mit der Option /str erneut aus, oder erstellen Sie Ihr VS-Projekt neu. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Resources + { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Resources() + { + } + + /// + /// Gibt die zwischengespeicherte ResourceManager-Instanz zurück, die von dieser Klasse verwendet wird. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager + { + get + { + if ((resourceMan == null)) + { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("BeWoTest.Properties.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Überschreibt die CurrentUICulture-Eigenschaft des aktuellen Threads für alle + /// Ressourcenlookups, die diese stark typisierte Ressourcenklasse verwenden. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture + { + get + { + return resourceCulture; + } + set + { + resourceCulture = value; + } + } + } +} diff --git a/BeWoTest/Properties/Resources.resx b/BeWoTest/Properties/Resources.resx new file mode 100644 index 000000000..af7dbebba --- /dev/null +++ b/BeWoTest/Properties/Resources.resx @@ -0,0 +1,117 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/BeWoTest/Properties/Settings.Designer.cs b/BeWoTest/Properties/Settings.Designer.cs new file mode 100644 index 000000000..bb4981e3c --- /dev/null +++ b/BeWoTest/Properties/Settings.Designer.cs @@ -0,0 +1,30 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace BeWoTest.Properties +{ + + + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")] + internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase + { + + private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); + + public static Settings Default + { + get + { + return defaultInstance; + } + } + } +} diff --git a/BeWoTest/Properties/Settings.settings b/BeWoTest/Properties/Settings.settings new file mode 100644 index 000000000..033d7a5e9 --- /dev/null +++ b/BeWoTest/Properties/Settings.settings @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/LauncherHost/DownloadBeWoService.svc b/DownloadServer/DownloadBeWoService.svc similarity index 100% rename from LauncherHost/DownloadBeWoService.svc rename to DownloadServer/DownloadBeWoService.svc diff --git a/LauncherHost/LauncherHost.csproj b/DownloadServer/DownloadServer.csproj similarity index 95% rename from LauncherHost/LauncherHost.csproj rename to DownloadServer/DownloadServer.csproj index 2c079e930..a40ffbf81 100644 --- a/LauncherHost/LauncherHost.csproj +++ b/DownloadServer/DownloadServer.csproj @@ -12,12 +12,13 @@ {349c5851-65df-11da-9384-00065b846f21};{fae04ec0-301f-11d3-bf4b-00c04f79efbc} Library Properties - LauncherHost - LauncherHost + DownloadServer + DownloadServer v4.7.2 true - + + @@ -78,9 +79,7 @@ - - Designer @@ -108,6 +107,10 @@ {094331c3-ecee-4c89-bbfd-4c9ded89f0ef} Service + + {efe05c79-e0dd-4311-8b90-a8da7ebdf36f} + SharedLauncher + diff --git a/LauncherHost/LauncherHost.csproj.user b/DownloadServer/DownloadServer.csproj.user similarity index 96% rename from LauncherHost/LauncherHost.csproj.user rename to DownloadServer/DownloadServer.csproj.user index f95380675..eac4167e7 100644 --- a/LauncherHost/LauncherHost.csproj.user +++ b/DownloadServer/DownloadServer.csproj.user @@ -3,7 +3,8 @@ true - + + diff --git a/DownloadServer/DownloadServerServiceReferences.bat b/DownloadServer/DownloadServerServiceReferences.bat new file mode 100644 index 000000000..2d8fa49ad --- /dev/null +++ b/DownloadServer/DownloadServerServiceReferences.bat @@ -0,0 +1 @@ +svcutil.exe /noConfig /edb /n:*,DownloadServer.ServiceProxy /out:ServiceProxy\DownloadGenerated.cs /ct:System.Collections.Generic.List`1 /r:..\SharedLauncher\bin\Debug\BS.SharedLauncher.dll http://localhost:3777/Host/LauncherService.svc?wsdl \ No newline at end of file diff --git a/LauncherHost/Multitenancy/Symbol Edit.png b/DownloadServer/Multitenancy/Symbol Edit.png similarity index 100% rename from LauncherHost/Multitenancy/Symbol Edit.png rename to DownloadServer/Multitenancy/Symbol Edit.png diff --git a/LauncherHost/Multitenancy/debug.config b/DownloadServer/Multitenancy/debug.config similarity index 100% rename from LauncherHost/Multitenancy/debug.config rename to DownloadServer/Multitenancy/debug.config diff --git a/LauncherHost/Multitenancy/debugMsSQL.config b/DownloadServer/Multitenancy/debugMsSQL.config similarity index 100% rename from LauncherHost/Multitenancy/debugMsSQL.config rename to DownloadServer/Multitenancy/debugMsSQL.config diff --git a/LauncherHost/Multitenancy/debugMySQL.config b/DownloadServer/Multitenancy/debugMySQL.config similarity index 100% rename from LauncherHost/Multitenancy/debugMySQL.config rename to DownloadServer/Multitenancy/debugMySQL.config diff --git a/LauncherHost/Multitenancy/demo.config b/DownloadServer/Multitenancy/demo.config similarity index 100% rename from LauncherHost/Multitenancy/demo.config rename to DownloadServer/Multitenancy/demo.config diff --git a/LauncherHost/Properties/AssemblyInfo.cs b/DownloadServer/Properties/AssemblyInfo.cs similarity index 100% rename from LauncherHost/Properties/AssemblyInfo.cs rename to DownloadServer/Properties/AssemblyInfo.cs diff --git a/LauncherHost/Web.Debug.config b/DownloadServer/Web.Debug.config similarity index 100% rename from LauncherHost/Web.Debug.config rename to DownloadServer/Web.Debug.config diff --git a/LauncherHost/Web.Release.config b/DownloadServer/Web.Release.config similarity index 100% rename from LauncherHost/Web.Release.config rename to DownloadServer/Web.Release.config diff --git a/LauncherHost/Web.config b/DownloadServer/Web.config similarity index 87% rename from LauncherHost/Web.config rename to DownloadServer/Web.config index 96e9fb899..c49cca32b 100644 --- a/LauncherHost/Web.config +++ b/DownloadServer/Web.config @@ -44,17 +44,24 @@ + + + + + + + @@ -74,6 +81,9 @@ + + + @@ -86,14 +96,6 @@ - - - - - - diff --git a/LauncherHost/packages.config b/DownloadServer/packages.config similarity index 100% rename from LauncherHost/packages.config rename to DownloadServer/packages.config diff --git a/LauncherHost/EnumTranslationService.svc b/Host/EnumTranslationService.svc similarity index 100% rename from LauncherHost/EnumTranslationService.svc rename to Host/EnumTranslationService.svc diff --git a/Host/Host.csproj b/Host/Host.csproj index 6cc7736e6..8833d7521 100644 --- a/Host/Host.csproj +++ b/Host/Host.csproj @@ -21,7 +21,8 @@ true - + + @@ -196,6 +197,8 @@ + + diff --git a/Host/Host.csproj.user b/Host/Host.csproj.user index 7eda74d9d..d4f1ce7a0 100644 --- a/Host/Host.csproj.user +++ b/Host/Host.csproj.user @@ -5,7 +5,8 @@ true Debug|Any CPU - + + diff --git a/LauncherHost/LauncherService.svc b/Host/LauncherService.svc similarity index 100% rename from LauncherHost/LauncherService.svc rename to Host/LauncherService.svc diff --git a/Host/Web.config b/Host/Web.config index 45b154b59..0ec77dd6d 100644 --- a/Host/Web.config +++ b/Host/Web.config @@ -156,6 +156,12 @@ + + + + + + diff --git a/Service/Multitenancy/DMultitenancyEndpointBehavior.cs b/Service/Multitenancy/DMultitenancyEndpointBehavior.cs new file mode 100644 index 000000000..5def827ca --- /dev/null +++ b/Service/Multitenancy/DMultitenancyEndpointBehavior.cs @@ -0,0 +1,28 @@ +using System; +using System.ServiceModel.Channels; +using System.ServiceModel.Description; +using System.ServiceModel.Dispatcher; + +namespace BeWo.Service.Multitenancy +{ + public class DMultitenancyEndpointBehavior : IEndpointBehavior + { + public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters) + { + } + + public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime) + { + clientRuntime.MessageInspectors.Add(new DMultitenancyInterceptor()); + } + + public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher) + { + throw new NotImplementedException("This is a client behavior only"); + } + + public void Validate(ServiceEndpoint endpoint) + { + } + } +} \ No newline at end of file diff --git a/Service/Multitenancy/DMultitenancyHeader.cs b/Service/Multitenancy/DMultitenancyHeader.cs new file mode 100644 index 000000000..6186a9160 --- /dev/null +++ b/Service/Multitenancy/DMultitenancyHeader.cs @@ -0,0 +1,39 @@ +using System.ServiceModel.Channels; +using System.Xml; + +namespace BeWo.Service.Multitenancy +{ + public class DMultitenancyHeader : MessageHeader + { + public override bool MustUnderstand + { + get + { + return false; + } + } + + public override string Name + { + get + { + return "Multitenancy"; + } + } + + public override string Namespace + { + get + { + return "http://beyondsoft.de/Multitenancy.xsd"; + } + } + + public string Tenant { get; set; } + + protected override void OnWriteHeaderContents(XmlDictionaryWriter writer, MessageVersion messageVersion) + { + writer.WriteElementString("Tenant", this.Tenant); + } + } +} \ No newline at end of file diff --git a/Service/Multitenancy/DMultitenancyInterceptor.cs b/Service/Multitenancy/DMultitenancyInterceptor.cs new file mode 100644 index 000000000..766a6d193 --- /dev/null +++ b/Service/Multitenancy/DMultitenancyInterceptor.cs @@ -0,0 +1,21 @@ +using BS.SharedLauncher; +using BS.SharedLauncher.Information; +using System.ServiceModel; +using System.ServiceModel.Channels; +using System.ServiceModel.Dispatcher; + +namespace BeWo.Service.Multitenancy +{ + public class DMultitenancyInterceptor : IClientMessageInspector + { + public void AfterReceiveReply(ref Message reply, object correlationState) + { + } + + public object BeforeSendRequest(ref Message request, IClientChannel channel) + { + request.Headers.Add(new DMultitenancyHeader { Tenant = SessionInformation.Login.Tenant }); + return null; + } + } +} \ No newline at end of file diff --git a/Service/Service.csproj b/Service/Service.csproj index 4e92203d5..234e2a7a3 100644 --- a/Service/Service.csproj +++ b/Service/Service.csproj @@ -393,9 +393,12 @@ + + + @@ -476,10 +479,12 @@ + + - - + + diff --git a/Service/ServiceContracts/IDownloadBeWoService.cs b/Service/ServiceContracts/IDownloadBeWoService.cs index ecfd9daf9..e9afdcc51 100644 --- a/Service/ServiceContracts/IDownloadBeWoService.cs +++ b/Service/ServiceContracts/IDownloadBeWoService.cs @@ -12,10 +12,18 @@ namespace BeWo.Service.ServiceContracts { [FaultContract(typeof(BeWoFault))] [OperationContract] - DownloadPlanerResponseDC Download2(DownloadPlanerRequestDC request); + UpdateFileResponse Download2(UpdatePlanRequest request); [FaultContract(typeof(BeWoFault))] [OperationContract] - DownloadPlanerResponseInfoDC DownloadInfo(DownloadPlanerRequestDC request); + UpdatePlanResponse DownloadInfo(UpdatePlanRequest request); + + [FaultContract(typeof(BeWoFault))] + [OperationContract] + UpdatePlanResponse GetUpdatePlan(UpdatePlanRequest request); + + [FaultContract(typeof(BeWoFault))] + [OperationContract] + UpdateFileResponse GetUpdateFile(UpdateFileRequest request); } } \ No newline at end of file diff --git a/Service/ServiceImplementations/DownloadBeWoServiceImp.cs b/Service/ServiceImplementations/DownloadBeWoServiceImp.cs index e98f37bdc..25e41b202 100644 --- a/Service/ServiceImplementations/DownloadBeWoServiceImp.cs +++ b/Service/ServiceImplementations/DownloadBeWoServiceImp.cs @@ -8,12 +8,14 @@ using System.ServiceModel; using System.Xml; using BeWo.Data; using BeWo.Service.ServiceContracts; +using BeWo.Service.ServiceProxy; using BeWo.Service.ServiceUtils.Paths; using BeWo.Service.ServiceUtils.Update; using BS.SharedLauncher.DataContract; using BS.SharedLauncher.Enums; using BS.SharedLauncher.Exceptions; using BS.SharedLauncher.Extensions; +using BS.SharedLauncher.Information; using BS.SharedLauncher.Logic; using BS.SharedLauncher.Update; @@ -24,23 +26,29 @@ namespace BeWo.Service.ServiceImplementations { public string Tenant => MultitenancyOperationContextExt.Current.Tenant; - public DownloadPlanerResponseDC Download2(DownloadPlanerRequestDC request) + public UpdateFileResponse Download2(UpdatePlanRequest request) + { + return null; + } + public UpdatePlanResponse DownloadInfo(UpdatePlanRequest request) + { + return null; + } + + + public UpdatePlanResponse GetUpdatePlan(UpdatePlanRequest request) { try { - DownloadPlanerResponseBuilder builder = new DownloadPlanerResponseBuilder(request); + if (!isUpdatePlanRequestValid(request)) + throw new InvalidUpdatePlanRequestException(); - builder.Calculate(Tenant); + if (!VerifyLogin(request)) + throw new InvalidUpdatePlanRequestException("Login konnte nicht aufm Download Server verifiziert werden."); - if (!request.ApplyFolderIsEmpty) - if (request.ApplyPackage is object) - builder.Substract(request.ApplyPackage.ToPlanerPackageInfo()); + var response = UpdatePlanResponseBuilder.GetUpdatePlanResponse(request, Tenant); - if (!request.DownloadFolderIsEmpty) - if (request.DownloadedPackages is object) - builder.AnalyseDownload(request.DownloadedPackages.ToDictionary(pair => pair.Key, pair => pair.Value.ToPlanerPackageInfo())); - - return builder.CreateResponse(request); + return response; } catch (UpdateException update) { @@ -48,35 +56,20 @@ namespace BeWo.Service.ServiceImplementations } catch (Exception ex) { - throw new UpdateException("Update - Download - Exception", ex); + throw new UpdateException("Update - GetUpdatePlan - Exception", ex); } } - public DownloadPlanerResponseInfoDC DownloadInfo(DownloadPlanerRequestDC request) + public UpdateFileResponse GetUpdateFile(UpdateFileRequest request) { try { - var responseInfo = new DownloadPlanerResponseInfoDC(); + if (!isUpdateFileRequestValid(request)) + throw new InvalidUpdateFileRequestException(); + + var response = UpdateFileResponseBuilder.GetUpdateFileResponse(request, Tenant); - var response = Download2(request); - - responseInfo.DownloadSize = response.NewZipData?.LongLength ?? 0; - responseInfo.FileCount = 0; - - if (response.DownloadFilesToKeep is object) - responseInfo.FileCount += response.DownloadFilesToKeep.Sum(kv => kv.Value.Count); - - if (response.NewZipInfo is object) - { - responseInfo.FileCount += response.NewZipInfo.Files.Count; - responseInfo.NewFileCount = response.NewZipInfo.Files.Count; - } - - responseInfo.HasSomethingToDo = response.HasToDo(); - - responseInfo.Version = response.LatestApplicationInfo.Version; - - return responseInfo; + return response; } catch (UpdateException update) { @@ -84,8 +77,38 @@ namespace BeWo.Service.ServiceImplementations } catch (Exception ex) { - throw new UpdateException("Update - DownloadInfo - Exception", ex); + throw new UpdateException("Update - GetUpdateFile - Exception", ex); } } + + private bool VerifyLogin(UpdatePlanRequest request) + { + SessionInformation.Login.Username = request.Login.Username; + SessionInformation.Login.Password = request.Login.Password; + SessionInformation.Login.Tenant = Tenant; + + ServiceFacade.UpdateServerAddresses(request.Login.CoreServerAddress); + + var result = ServiceFacade.DoLauncherServiceSync(x => x.IsUserValid(request.Login.TempUsername, request.Login.Password, request.Login.Pin, request.Login.ClientID, true)); + + if (result == UserValidationResult.UserValid) + return true; + + return false; + } + + private bool isUpdatePlanRequestValid(UpdatePlanRequest request) + { + return true; + } + + private bool isUpdateFileRequestValid(UpdateFileRequest request) + { + // Check for Login + // Check for Correct Version + // Check for File Permissions + + return true; + } } } \ No newline at end of file diff --git a/Service/ServiceImplementations/LauncherServiceImp.cs b/Service/ServiceImplementations/LauncherServiceImp.cs index d0f26a114..924f23c94 100644 --- a/Service/ServiceImplementations/LauncherServiceImp.cs +++ b/Service/ServiceImplementations/LauncherServiceImp.cs @@ -139,7 +139,7 @@ namespace BeWo.Service.ServiceImplementations { try { - var user = DAOFactory.UserDAO.FindUserByLoginName(ConnectionInformation.Username); + var user = DAOFactory.UserDAO.FindUserByLoginName(SessionInformation.Login.Username); var version = (new UserServiceImp()).ChangePassword(pUserName, user.Version.Value, pOldPassword, pNewPassword); @@ -156,7 +156,7 @@ namespace BeWo.Service.ServiceImplementations { try { - var user = DAOFactory.UserDAO.FindUserByLoginName(ConnectionInformation.Username); + var user = DAOFactory.UserDAO.FindUserByLoginName(SessionInformation.Login.Username); user.ResetPasswordInfos.ForEach(f => f.HasToChangePW = false); diff --git a/Service/ServiceImplementations/UserServiceImp.cs b/Service/ServiceImplementations/UserServiceImp.cs index adfab87f2..a3a1c6e5f 100644 --- a/Service/ServiceImplementations/UserServiceImp.cs +++ b/Service/ServiceImplementations/UserServiceImp.cs @@ -47,8 +47,6 @@ namespace BeWo.Service.ServiceImplementations { allowChange = true; } - - } if (allowChange) diff --git a/Service/ServiceProxy/ServiceFacade.cs b/Service/ServiceProxy/ServiceFacade.cs new file mode 100644 index 000000000..de6c79c76 --- /dev/null +++ b/Service/ServiceProxy/ServiceFacade.cs @@ -0,0 +1,116 @@ +using BeWo.Service.Multitenancy; +using System; +using System.Collections.Generic; +using System.Linq; +using System.ServiceModel; +using System.Text; +using System.Threading.Tasks; + +namespace BeWo.Service.ServiceProxy +{ + public class ServiceFacade + { + public static object _Lock = string.Empty; + + private static Dictionary _EndpointAddresses; + private static readonly Dictionary _ProxyCache; + + private static int _RunningAsyncs; + + public static void UpdateServerAddresses(string main) + { + var serverName2 = main; + if (serverName2.Substring(serverName2.Length - 1, 1) != "/") + serverName2 += "/"; + + _EndpointAddresses = new Dictionary + { + { typeof(ILauncherService), new EndpointAddress(serverName2 + "LauncherService.svc") } + }; + } + + static ServiceFacade() + { + _ProxyCache = new Dictionary(); + } + + public static void DoLauncherServiceSync(Action pAction) + { + try + { + pAction.Invoke(GetInstance()); + } + catch (Exception e) + { + // if (HandleServiceProxyException(e)) + // throw e; + throw e; + } + } + public static T DoLauncherServiceSync(Func pFunc) + { + try + { + return pFunc.Invoke(GetInstance()); + } + catch (Exception e) + { + throw e; + } + return default(T); + } + + private static TInterface GetInstance() + where TClient : ClientBase, TInterface, new() + where TInterface : class + { + TClient lClient = null; + if (_ProxyCache.ContainsKey(typeof(TClient))) + { + lClient = (TClient)_ProxyCache[typeof(TClient)]; + + if (lClient.State == CommunicationState.Closing || lClient.State == CommunicationState.Closed || lClient.State == CommunicationState.Faulted) + { + if (lClient.State == CommunicationState.Faulted) + { + lClient.Abort(); + } + + lClient = null; + _ProxyCache.Remove(typeof(TClient)); + } + } + + if (lClient != null) + {// EndpointAddresses aktualisieren + if (!lClient.Endpoint.Address.Equals(_EndpointAddresses[typeof(TInterface)])) + { + if (lClient.State == CommunicationState.Opened) + lClient.Close(); + + if (_ProxyCache.ContainsKey(typeof(TClient))) + _ProxyCache.Remove(typeof(TClient)); + lClient = null; + } + } + + if (lClient == null) + { + lClient = new TClient(); + + if (!_ProxyCache.ContainsKey(lClient.GetType())) + { + _ProxyCache.Add(typeof(TClient), lClient); + } + + + // lClient.Endpoint.Behaviors.Add(new DownloadSecurityHeaderEndpointBehavior()); + lClient.Endpoint.Behaviors.Add(new DMultitenancyEndpointBehavior()); + + lClient.Endpoint.Address = _EndpointAddresses[typeof(TInterface)]; + } + + return lClient; + } + } +} diff --git a/Service/ServiceProxy/ServiceGenerated.cs b/Service/ServiceProxy/ServiceGenerated.cs new file mode 100644 index 000000000..4ac27d37c --- /dev/null +++ b/Service/ServiceProxy/ServiceGenerated.cs @@ -0,0 +1,276 @@ +//------------------------------------------------------------------------------ +// +// Dieser Code wurde von einem Tool generiert. +// Laufzeitversion:4.0.30319.42000 +// +// Änderungen an dieser Datei können falsches Verhalten verursachen und gehen verloren, wenn +// der Code erneut generiert wird. +// +//------------------------------------------------------------------------------ + +namespace BeWo.Service.ServiceProxy +{ + using System.Runtime.Serialization; + + + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Runtime.Serialization", "4.0.0.0")] + [System.Runtime.Serialization.DataContractAttribute(Name="BeWoFault", Namespace="http://schemas.datacontract.org/2004/07/BeWo.Service.ServiceContracts")] + public partial class BeWoFault : object, System.Runtime.Serialization.IExtensibleDataObject, System.ComponentModel.INotifyPropertyChanged + { + + private System.Runtime.Serialization.ExtensionDataObject extensionDataField; + + private BeWo.Service.ServiceProxy.BeWoFaultType FaultTypeField; + + private string InnerExceptionMessageField; + + private string InnerExceptionStackTraceField; + + private string MessageField; + + private string StackTraceField; + + public System.Runtime.Serialization.ExtensionDataObject ExtensionData + { + get + { + return this.extensionDataField; + } + set + { + this.extensionDataField = value; + } + } + + [System.Runtime.Serialization.DataMemberAttribute()] + public BeWo.Service.ServiceProxy.BeWoFaultType FaultType + { + get + { + return this.FaultTypeField; + } + set + { + if ((this.FaultTypeField.Equals(value) != true)) + { + this.FaultTypeField = value; + this.RaisePropertyChanged("FaultType"); + } + } + } + + [System.Runtime.Serialization.DataMemberAttribute()] + public string InnerExceptionMessage + { + get + { + return this.InnerExceptionMessageField; + } + set + { + if ((object.ReferenceEquals(this.InnerExceptionMessageField, value) != true)) + { + this.InnerExceptionMessageField = value; + this.RaisePropertyChanged("InnerExceptionMessage"); + } + } + } + + [System.Runtime.Serialization.DataMemberAttribute()] + public string InnerExceptionStackTrace + { + get + { + return this.InnerExceptionStackTraceField; + } + set + { + if ((object.ReferenceEquals(this.InnerExceptionStackTraceField, value) != true)) + { + this.InnerExceptionStackTraceField = value; + this.RaisePropertyChanged("InnerExceptionStackTrace"); + } + } + } + + [System.Runtime.Serialization.DataMemberAttribute()] + public string Message + { + get + { + return this.MessageField; + } + set + { + if ((object.ReferenceEquals(this.MessageField, value) != true)) + { + this.MessageField = value; + this.RaisePropertyChanged("Message"); + } + } + } + + [System.Runtime.Serialization.DataMemberAttribute()] + public string StackTrace + { + get + { + return this.StackTraceField; + } + set + { + if ((object.ReferenceEquals(this.StackTraceField, value) != true)) + { + this.StackTraceField = value; + this.RaisePropertyChanged("StackTrace"); + } + } + } + + public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged; + + protected void RaisePropertyChanged(string propertyName) + { + System.ComponentModel.PropertyChangedEventHandler propertyChanged = this.PropertyChanged; + if ((propertyChanged != null)) + { + propertyChanged(this, new System.ComponentModel.PropertyChangedEventArgs(propertyName)); + } + } + } + + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Runtime.Serialization", "4.0.0.0")] + [System.Runtime.Serialization.DataContractAttribute(Name="BeWoFaultType", Namespace="http://schemas.datacontract.org/2004/07/BeWo.Service.ServiceContracts")] + public enum BeWoFaultType : int + { + + [System.Runtime.Serialization.EnumMemberAttribute()] + Unknown = 0, + + [System.Runtime.Serialization.EnumMemberAttribute()] + Concurrency = 1, + + [System.Runtime.Serialization.EnumMemberAttribute()] + DeleteNotPossible = 2, + + [System.Runtime.Serialization.EnumMemberAttribute()] + LoginNameTaken = 3, + + [System.Runtime.Serialization.EnumMemberAttribute()] + CustomWithoutDetails = 4, + } + + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")] + [System.ServiceModel.ServiceContractAttribute(ConfigurationName="BeWo.Service.ServiceProxy.ILauncherService")] + public interface ILauncherService + { + + [System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/ILauncherService/IsUserValid", ReplyAction="http://tempuri.org/ILauncherService/IsUserValidResponse")] + [System.ServiceModel.FaultContractAttribute(typeof(BeWo.Service.ServiceProxy.BeWoFault), Action="http://tempuri.org/ILauncherService/IsUserValidBeWoFaultFault", Name="BeWoFault", Namespace="http://schemas.datacontract.org/2004/07/BeWo.Service.ServiceContracts")] + BS.SharedLauncher.Enums.UserValidationResult IsUserValid(string pUserName, string pPassword, string pPIN, string clientId, bool checkTenant); + + [System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/ILauncherService/ResetTenant", ReplyAction="http://tempuri.org/ILauncherService/ResetTenantResponse")] + [System.ServiceModel.FaultContractAttribute(typeof(BeWo.Service.ServiceProxy.BeWoFault), Action="http://tempuri.org/ILauncherService/ResetTenantBeWoFaultFault", Name="BeWoFault", Namespace="http://schemas.datacontract.org/2004/07/BeWo.Service.ServiceContracts")] + void ResetTenant(string tenant); + + [System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/ILauncherService/ResetAllTenant", ReplyAction="http://tempuri.org/ILauncherService/ResetAllTenantResponse")] + [System.ServiceModel.FaultContractAttribute(typeof(BeWo.Service.ServiceProxy.BeWoFault), Action="http://tempuri.org/ILauncherService/ResetAllTenantBeWoFaultFault", Name="BeWoFault", Namespace="http://schemas.datacontract.org/2004/07/BeWo.Service.ServiceContracts")] + void ResetAllTenant(); + + [System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/ILauncherService/GetEmailForUserName", ReplyAction="http://tempuri.org/ILauncherService/GetEmailForUserNameResponse")] + [System.ServiceModel.FaultContractAttribute(typeof(BeWo.Service.ServiceProxy.BeWoFault), Action="http://tempuri.org/ILauncherService/GetEmailForUserNameBeWoFaultFault", Name="BeWoFault", Namespace="http://schemas.datacontract.org/2004/07/BeWo.Service.ServiceContracts")] + bool GetEmailForUserName(out string email, string pUserName, System.Uri serverName); + + [System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/ILauncherService/CheckPassword", ReplyAction="http://tempuri.org/ILauncherService/CheckPasswordResponse")] + [System.ServiceModel.FaultContractAttribute(typeof(BeWo.Service.ServiceProxy.BeWoFault), Action="http://tempuri.org/ILauncherService/CheckPasswordBeWoFaultFault", Name="BeWoFault", Namespace="http://schemas.datacontract.org/2004/07/BeWo.Service.ServiceContracts")] + BS.SharedLauncher.Enums.PasswordValidationResult CheckPassword(long userOid, string pOldPassword, string pNewPassword); + + [System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/ILauncherService/CheckPassword2", ReplyAction="http://tempuri.org/ILauncherService/CheckPassword2Response")] + [System.ServiceModel.FaultContractAttribute(typeof(BeWo.Service.ServiceProxy.BeWoFault), Action="http://tempuri.org/ILauncherService/CheckPassword2BeWoFaultFault", Name="BeWoFault", Namespace="http://schemas.datacontract.org/2004/07/BeWo.Service.ServiceContracts")] + BS.SharedLauncher.Enums.PasswordValidationResult CheckPassword2(string username, string pOldPassword, string pNewPassword); + + [System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/ILauncherService/ChangePassword", ReplyAction="http://tempuri.org/ILauncherService/ChangePasswordResponse")] + [System.ServiceModel.FaultContractAttribute(typeof(BeWo.Service.ServiceProxy.BeWoFault), Action="http://tempuri.org/ILauncherService/ChangePasswordBeWoFaultFault", Name="BeWoFault", Namespace="http://schemas.datacontract.org/2004/07/BeWo.Service.ServiceContracts")] + long ChangePassword(string pUserName, string pOldPassword, string pNewPassword); + + [System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/ILauncherService/ResetPasswordInfo", ReplyAction="http://tempuri.org/ILauncherService/ResetPasswordInfoResponse")] + [System.ServiceModel.FaultContractAttribute(typeof(BeWo.Service.ServiceProxy.BeWoFault), Action="http://tempuri.org/ILauncherService/ResetPasswordInfoBeWoFaultFault", Name="BeWoFault", Namespace="http://schemas.datacontract.org/2004/07/BeWo.Service.ServiceContracts")] + void ResetPasswordInfo(string pUserName, string pPassword); + } + + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")] + public interface ILauncherServiceChannel : BeWo.Service.ServiceProxy.ILauncherService, System.ServiceModel.IClientChannel + { + } + + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")] + public partial class LauncherServiceClient : System.ServiceModel.ClientBase, BeWo.Service.ServiceProxy.ILauncherService + { + + public LauncherServiceClient() + { + } + + public LauncherServiceClient(string endpointConfigurationName) : + base(endpointConfigurationName) + { + } + + public LauncherServiceClient(string endpointConfigurationName, string remoteAddress) : + base(endpointConfigurationName, remoteAddress) + { + } + + public LauncherServiceClient(string endpointConfigurationName, System.ServiceModel.EndpointAddress remoteAddress) : + base(endpointConfigurationName, remoteAddress) + { + } + + public LauncherServiceClient(System.ServiceModel.Channels.Binding binding, System.ServiceModel.EndpointAddress remoteAddress) : + base(binding, remoteAddress) + { + } + + public BS.SharedLauncher.Enums.UserValidationResult IsUserValid(string pUserName, string pPassword, string pPIN, string clientId, bool checkTenant) + { + return base.Channel.IsUserValid(pUserName, pPassword, pPIN, clientId, checkTenant); + } + + public void ResetTenant(string tenant) + { + base.Channel.ResetTenant(tenant); + } + + public void ResetAllTenant() + { + base.Channel.ResetAllTenant(); + } + + public bool GetEmailForUserName(out string email, string pUserName, System.Uri serverName) + { + return base.Channel.GetEmailForUserName(out email, pUserName, serverName); + } + + public BS.SharedLauncher.Enums.PasswordValidationResult CheckPassword(long userOid, string pOldPassword, string pNewPassword) + { + return base.Channel.CheckPassword(userOid, pOldPassword, pNewPassword); + } + + public BS.SharedLauncher.Enums.PasswordValidationResult CheckPassword2(string username, string pOldPassword, string pNewPassword) + { + return base.Channel.CheckPassword2(username, pOldPassword, pNewPassword); + } + + public long ChangePassword(string pUserName, string pOldPassword, string pNewPassword) + { + return base.Channel.ChangePassword(pUserName, pOldPassword, pNewPassword); + } + + public void ResetPasswordInfo(string pUserName, string pPassword) + { + base.Channel.ResetPasswordInfo(pUserName, pPassword); + } + } +} diff --git a/Service/ServiceReferences.bat b/Service/ServiceReferences.bat new file mode 100644 index 000000000..19f6e697a --- /dev/null +++ b/Service/ServiceReferences.bat @@ -0,0 +1 @@ +svcutil.exe /noConfig /edb /n:*,BeWo.Service.ServiceProxy /out:ServiceProxy\ServiceGenerated.cs /ct:System.Collections.Generic.List`1 /r:..\SharedLauncher\bin\Debug\BS.SharedLauncher.dll http://localhost:3777/Host/LauncherService.svc?wsdl \ No newline at end of file diff --git a/Service/ServiceUtils/Paths/ServerFilePaths.cs b/Service/ServiceUtils/Paths/ServerFilePaths.cs index eff05b45a..eeafffc6b 100644 --- a/Service/ServiceUtils/Paths/ServerFilePaths.cs +++ b/Service/ServiceUtils/Paths/ServerFilePaths.cs @@ -40,8 +40,8 @@ namespace BeWo.Service.ServiceUtils.Paths } - public static string GetSpecialTenantFolderPath() => Path.Combine(DownloadFolderPath, "overridetenant"); - public static string GetOverrideTenantFolderPath(string tenant) => Path.Combine(GetSpecialTenantFolderPath(), tenant); + public static string GetOverrideTenantFolderPath() => Path.Combine(DownloadFolderPath, "overridetenant"); + public static string GetOverrideTenantFolderPath(string tenant) => Path.Combine(GetOverrideTenantFolderPath(), tenant); public static string GetVersionFolderPath() => Path.Combine(DownloadFolderPath, "version"); public static string GetVersionFolderPath(string version) => Path.Combine(GetVersionFolderPath(), version); diff --git a/Service/ServiceUtils/Update/DownloadLogger.cs b/Service/ServiceUtils/Update/DownloadLogger.cs deleted file mode 100644 index 8a3e24b7f..000000000 --- a/Service/ServiceUtils/Update/DownloadLogger.cs +++ /dev/null @@ -1,23 +0,0 @@ -using BeWo.Data; -using BeWo.Service.ServiceUtils.Paths; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace BeWo.Service.ServiceUtils.Update -{ - public static class DownloadLogger - { - //public static string Tenant => MultitenancyOperationContextExt.Current.Tenant; - //public static string Folder => ServerFilePaths.GetLogFolderPath(Tenant); - - //static DownloadLogger() - //{ - // _Started = true; - //} - - //public static string - } -} diff --git a/Service/ServiceUtils/Update/DownloadPlanerResponseBuilder.cs b/Service/ServiceUtils/Update/DownloadPlanerResponseBuilder.cs deleted file mode 100644 index 88af9e978..000000000 --- a/Service/ServiceUtils/Update/DownloadPlanerResponseBuilder.cs +++ /dev/null @@ -1,146 +0,0 @@ -using BeWo.Service.ServiceUtils.Paths; -using BS.SharedLauncher.DataContract; -using BS.SharedLauncher.Exceptions; -using BS.SharedLauncher.Extensions; -using BS.SharedLauncher.Logic; -using BS.SharedLauncher.Update; -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace BeWo.Service.ServiceUtils.Update -{ - public class DownloadPlanerResponseBuilder - { - private PlanerPackageInfo currentUpdatePackageInfo; - private PlanerPackageInfo latestUpdatePackageInfo; - private Dictionary> downloadFilesToKeep; - - public DownloadPlanerResponseBuilder(DownloadPlanerRequestDC req) - { - currentUpdatePackageInfo = null; - latestUpdatePackageInfo = null; - downloadFilesToKeep = null; - } - - public PlanerPackageInfo CurrentUpdatePackageInfo => currentUpdatePackageInfo; - public PlanerPackageInfo FullUpdatePackageInfo => latestUpdatePackageInfo; - - public void Calculate(string tenant) - { - PlanerPackageInfo root = new PlanerPackageInfo(); - UpdateConfigReader reader = new UpdateConfigReader(ServerFilePaths.GetVersionConfigFilePath(), tenant); - - root.DefaultVersion = reader.GetDefaultVersion(); - root.TenantVersion = reader.GetSpecificVersion(); - - string version = root.Version; - - // Setze Basis - root.InitFiles(getVersionDefaultFiles(version)); - - // Überschreibe mit Version-Tenant Daten - root.OverrideFiles(getVersionTenantFiles(version, tenant)); - - // Überschreibe mit Special-Tenant Daten - root.OverrideFiles(getSpecialTenantFiles(tenant)); - - // Lade Hash Werte - root.LoadHash(); - - latestUpdatePackageInfo = root; - currentUpdatePackageInfo = root.Copy(); - } - public void Substract(PlanerPackageInfo applyPackage) - { - currentUpdatePackageInfo.SubstractFiles(applyPackage.Files); - } - public void AnalyseDownload(Dictionary zip2info) - { - downloadFilesToKeep = new Dictionary>(); - - foreach (var z2i in zip2info) - { - bool found = false; - - for (int i = currentUpdatePackageInfo.Files.Count - 1; i >= 0; i--) - //foreach (var file in currentUpdatePackageInfo.Files) - { - var file = currentUpdatePackageInfo.Files[i]; - - if (z2i.Value.ContainsPlanerFile(file.RelativePath, file.Checksum)) - { - if (!found) - { - found = true; - downloadFilesToKeep.Add(z2i.Key, new List()); - } - - downloadFilesToKeep[z2i.Key].Add(file.RelativePath); - - currentUpdatePackageInfo.RemoveFileAt(i); - } - } - } - } - public void Compress() - { - if (downloadFilesToKeep != null && !downloadFilesToKeep.Any()) - downloadFilesToKeep = null; - - if (currentUpdatePackageInfo != null && !currentUpdatePackageInfo.AnyFile()) - currentUpdatePackageInfo = null; - } - - public DownloadPlanerResponseDC CreateResponse(DownloadPlanerRequestDC request) - { - var res = new DownloadPlanerResponseDC(); - - Compress(); - - res.LatestApplicationInfo = latestUpdatePackageInfo.ToPlanerPackageInfoDC(); - - if (downloadFilesToKeep is object) - { - res.DownloadFilesToKeep = downloadFilesToKeep; - } - - if (currentUpdatePackageInfo is object) - { - res.NewZipData = ZipArchiveBuilder.CreateZipArray(currentUpdatePackageInfo.Files, - (file) => file.AbsolutePath, (file) => file.RelativePath); - res.NewZipInfo = currentUpdatePackageInfo.ToPlanerPackageInfoDC(); - //res.NewZipStream = ZipArchiveBuilder.CreateZipStream(currentUpdatePackageInfo.Files, - // (file) => file.AbsolutePath, (file) => file.RelativePath); - //res.NewZipStreamLength = res.NewZipStream.Length; - } - - res.HasToRemoveFiles = request.ApplyPackage?.Files?.Any(x => !res.LatestApplicationInfo.Files.Any(y => x.EqualsFile(y))) ?? false; - - - - return res; - } - - private List getVersionDefaultFiles(string version) => getPlanerFiles(ServerFilePaths.GetVersionDefaultFolderPath(version), false); - private List getVersionTenantFiles(string version, string tenant) => getPlanerFiles(ServerFilePaths.GetVersionTenantFolderPath(version, tenant), true); - private List getSpecialTenantFiles(string tenant) => getPlanerFiles(ServerFilePaths.GetOverrideTenantFolderPath(tenant), true); - - private List getPlanerFiles(string path, bool ignore) - { - if (!Directory.Exists(path)) { - if (ignore) - return new List(); - else - throw new ServerConfigException($"{path} konnte nicht gefunden werden"); - } - var res = FileController.GetPlanerFiles(path); - - //res.ForEach(x => x.Source = source); - return res; - } - } -} diff --git a/Service/ServiceUtils/Update/UpdateFileResponseBuilder.cs b/Service/ServiceUtils/Update/UpdateFileResponseBuilder.cs new file mode 100644 index 000000000..680e3bc07 --- /dev/null +++ b/Service/ServiceUtils/Update/UpdateFileResponseBuilder.cs @@ -0,0 +1,104 @@ +using BeWo.Service.ServiceUtils.Paths; +using BS.SharedLauncher.DataContract; +using BS.SharedLauncher.Exceptions; +using BS.SharedLauncher.Extensions; +using BS.SharedLauncher.Logic; +using BS.SharedLauncher.Update; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace BeWo.Service.ServiceUtils.Update +{ + public static class UpdateFileResponseBuilder + { + private static string _Version; + private static string _Tenant; + + private static UpdateFileRequest _Request; + private static UpdateFileResponse _Response; + + public static UpdateFileResponse GetUpdateFileResponse(UpdateFileRequest request, string tenant) + { + _Response = new UpdateFileResponse(); + _Tenant = tenant; + _Request = request; + _Version = request.Version; + + calculate(); + + return _Response; + } + + private static void calculate() + { + var path = Path.Combine(getSourceFolderPath(), _Request.UpdateFile.RelativePath); + + _Response.FileData = File.ReadAllBytes(path); + } + + private static string getSourceFolderPath() + { + switch (_Request.UpdateFile.Source) + { + case BS.SharedLauncher.Enums.UpdateFileSource.Invalid: + throw new UpdateException("Invalid UpdateFileSource"); + + case BS.SharedLauncher.Enums.UpdateFileSource.VersionDefault: + return ServerFilePaths.GetVersionDefaultFolderPath(_Version); + + case BS.SharedLauncher.Enums.UpdateFileSource.VersionTenant: + return ServerFilePaths.GetVersionTenantFolderPath(_Version, _Tenant); + + case BS.SharedLauncher.Enums.UpdateFileSource.VersionUser: + break; + + case BS.SharedLauncher.Enums.UpdateFileSource.OverrideTenant: + return ServerFilePaths.GetOverrideTenantFolderPath(_Tenant); + + case BS.SharedLauncher.Enums.UpdateFileSource.OverrideUser: + break; + default: + break; + } + + // User bekommt eigene Daten Feature + throw new NotImplementedException("#479839129"); + } + + //public static UpdateResponse GetUpdatePlanResponse(UpdateRequest request, string tenant) + //{ + // var reader = new UpdateConfigReader(ServerFilePaths.GetVersionConfigFilePath(), tenant); + + // _Tenant = tenant; + // _Request = request; + // _Response = new UpdateResponse + // { + // CurrentPackage = new PlanerPackageInfoDC + // { + // DefaultVersion = reader.GetDefaultVersion(), + // TenantVersion = reader.GetSpecificVersion() + // } + // }; + + // _Version = _Response.CurrentPackage.Version; + + // // Lädt komplettes Paket ohne Hash + // CalcFullPackage(); + + // // Lade Hash Werte + // _Response.CurrentPackage.LoadHash(); + + // CalcFilesToRequest(); + + // CalcFilesToDeleteInApply(); + + // CalcFilesToIgnoreInDownload(); + + // return _Response; + //} + } +} diff --git a/Service/ServiceUtils/Update/UpdatePlanResponseBuilder.cs b/Service/ServiceUtils/Update/UpdatePlanResponseBuilder.cs new file mode 100644 index 000000000..4abd1edd6 --- /dev/null +++ b/Service/ServiceUtils/Update/UpdatePlanResponseBuilder.cs @@ -0,0 +1,166 @@ +using BeWo.Service.ServiceUtils.Paths; +using BS.SharedLauncher.DataContract; +using BS.SharedLauncher.Enums; +using BS.SharedLauncher.Exceptions; +using BS.SharedLauncher.Extensions; +using BS.SharedLauncher.Information; +using BS.SharedLauncher.Logic; +using BS.SharedLauncher.Update; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace BeWo.Service.ServiceUtils.Update +{ + public static class UpdatePlanResponseBuilder + { + private static UpdatePlanRequest _Request; + private static UpdatePlanResponse _Response; + + private static string _Version; + private static string _Tenant; + + public static UpdatePlanResponse GetUpdatePlanResponse(UpdatePlanRequest request, string tenant) + { + var reader = new UpdateConfigReader(ServerFilePaths.GetVersionConfigFilePath(), tenant); + + _Tenant = tenant; + _Request = request; + _Response = new UpdatePlanResponse + { + CurrentPackage = new UpdatePlanDC + { + DefaultVersion = reader.GetDefaultVersion(), + TenantVersion = reader.GetSpecificVersion() + } + }; + + _Version = _Response.CurrentPackage.Version; + + // Lädt komplettes Paket ohne Hash + CalcFullPackage(); + + // Lade Hash Werte + _Response.CurrentPackage.LoadHash(); + + CalcFilesToRequest(); + + if (!_Request.ApplyFolderIsEmpty) + CalcFilesToDeleteInApply(); + + if (!_Request.DownloadFolderIsEmpty) + CalcFilesToApplyInDownload(); + + CalcDownloadSize(); + + return _Response; + } + + private static void CalcFullPackage() + { + // Setze Basis + _Response.CurrentPackage.InitFiles(getVersionDefaultFiles(_Version)); + + // Überschreibe mit Version-Tenant Daten + _Response.CurrentPackage.OverrideOrAddFiles(getVersionTenantFiles(_Version, _Tenant)); + + // Überschreibe mit Special-Tenant Daten + _Response.CurrentPackage.OverrideOrAddFiles(getSpecialTenantFiles(_Tenant)); + } + + private static void CalcFilesToRequest() + { + foreach (var file in _Response.CurrentPackage.Files) + { + // Bereits installiert + if (_Request.ApplyPackage?.ContainsPlanerFileWithHash(file) ?? false) + continue; + + // Bereits heruntergeladen + if (_Request.DownloadedFiles?.ContainsPlanerFileWithHash(file) ?? false) + continue; + + if (_Response.FilesToRequest is null) + _Response.FilesToRequest = new List(); + + _Response.FilesToRequest.Add(file); + } + } + + private static void CalcFilesToDeleteInApply() + { + foreach (var file in _Request.ApplyPackage.Files) + { + // Datei wird gebraucht + if (_Response.CurrentPackage.ContainsPlanerFile(file)) + continue; + + if (_Response.FilesToDeleteInApply is null) + _Response.FilesToDeleteInApply = new List(); + + _Response.FilesToDeleteInApply.Add(file); + } + } + + private static void CalcFilesToApplyInDownload() + { + foreach (var file in _Request.DownloadedFiles) + { + // Datei wird gebraucht + if (!_Response.CurrentPackage.ContainsPlanerFile(file)) + continue; + + if (_Response.FilesToApply is null) + _Response.FilesToApply = new List(); + + _Response.FilesToApply.Add(file); + } + } + + private static void CalcDownloadSize() + { + if (_Response.FilesToRequest is null || !_Response.FilesToRequest.Any()) + return; + + long count = 0; + foreach (var file in _Response.FilesToRequest) + { + var fi = new FileInfo(file.AbsolutePath); + + count += fi.Length; + } + + _Response.DownloadSize = count; + } + + private static List getVersionDefaultFiles(string version) => getPlanerFiles(ServerFilePaths.GetVersionDefaultFolderPath(version), UpdateFileSource.VersionDefault, false); + private static List getVersionTenantFiles(string version, string tenant) => getPlanerFiles(ServerFilePaths.GetVersionTenantFolderPath(version, tenant), UpdateFileSource.VersionTenant, true); + private static List getSpecialTenantFiles(string tenant) => getPlanerFiles(ServerFilePaths.GetOverrideTenantFolderPath(tenant), UpdateFileSource.OverrideTenant, true); + + private static List getPlanerFiles(string path, UpdateFileSource source, bool ignoreOnError) + { + if (!Directory.Exists(path)) { + if (ignoreOnError) + return new List(); + else + throw new ServerConfigException($"{path} konnte nicht gefunden werden"); + } + var res = FileController.GetPlanerFiles(path, true, ignorePlanerFile); + + res.ForEach(x => x.Source = source); + + return res; + } + + private static bool ignorePlanerFile(UpdateFileDC update) + { + if (update.GetExtensionType() == ".xml") + return true; + + return false; + } + } +} diff --git a/Service/SvcUtil.exe b/Service/SvcUtil.exe new file mode 100644 index 0000000000000000000000000000000000000000..c81ea03b12c61df6be2a970810d1557b52185799 GIT binary patch literal 184144 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 literal 0 HcmV?d00001 diff --git a/SharedLauncher/DataContract/DownloadPlanerResponseDC.cs b/SharedLauncher/DataContract/DownloadPlanerResponseDC.cs deleted file mode 100644 index c88ac36a6..000000000 --- a/SharedLauncher/DataContract/DownloadPlanerResponseDC.cs +++ /dev/null @@ -1,49 +0,0 @@ -using BS.SharedLauncher.Update; -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Runtime.Serialization; -using System.Text; -using System.Threading.Tasks; -using System.Xml.Serialization; - -namespace BS.SharedLauncher.DataContract -{ - [DataContract] - public class DownloadPlanerResponseDC - { - public DownloadPlanerResponseDC() - { - DownloadFilesToKeep = null; - HasToRemoveFiles = false; - } - - [DataMember] - public bool HasToRemoveFiles { get; set; } - - [DataMember] - public byte[] NewZipData { get; set; } - - [DataMember] - public Stream NewZipStream { get; set; } - - [DataMember] - public long NewZipStreamLength { get; set; } - - /// - /// Nur neue Dateien - /// - [DataMember] - public PlanerPackageInfoDC NewZipInfo { get; set; } - - /// - /// Alle Dateien aus der letzten Version - /// - [DataMember] - public PlanerPackageInfoDC LatestApplicationInfo { get; set; } - - [DataMember] - public Dictionary> DownloadFilesToKeep { get; set; } - } -} diff --git a/SharedLauncher/DataContract/LoginDC.cs b/SharedLauncher/DataContract/LoginDC.cs new file mode 100644 index 000000000..369f5d68f --- /dev/null +++ b/SharedLauncher/DataContract/LoginDC.cs @@ -0,0 +1,34 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.Serialization; +using System.Text; +using System.Threading.Tasks; + +namespace BS.SharedLauncher.DataContract +{ + [DataContract] + public class LoginDC + { + [DataMember] + public string Username { get; set; } + + [DataMember] + public string TempUsername { get; set; } + + [DataMember] + public string Password { get; set; } + + [DataMember] + public string CoreServerAddress { get; set; } + + [DataMember] + public string Pin { get; set; } + + [DataMember] + public string ClientID { get; set; } + + [DataMember] + public bool CheckTenant { get; set; } + } +} diff --git a/SharedLauncher/DataContract/PlanerFileInfoDC.cs b/SharedLauncher/DataContract/PlanerFileInfoDC.cs deleted file mode 100644 index 1b09625d0..000000000 --- a/SharedLauncher/DataContract/PlanerFileInfoDC.cs +++ /dev/null @@ -1,26 +0,0 @@ -using BS.SharedLauncher.Enums; -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Linq; -using System.Runtime.Serialization; -using System.Text; -using System.Threading.Tasks; -using System.Xml.Serialization; - -namespace BS.SharedLauncher.DataContract -{ - [DebuggerDisplay("{RelativePath} ({Checksum})")] - [DataContract, Serializable()] - public class PlanerFileInfoDC - { - [DataMember, XmlAttribute] - public string Name { get; set; } - - [DataMember, XmlAttribute] - public string RelativePath { get; set; } - - [DataMember, XmlAttribute] - public string Checksum { get; set; } - } -} diff --git a/SharedLauncher/DataContract/UpdateFileDC.cs b/SharedLauncher/DataContract/UpdateFileDC.cs new file mode 100644 index 000000000..9a7a3a0d0 --- /dev/null +++ b/SharedLauncher/DataContract/UpdateFileDC.cs @@ -0,0 +1,50 @@ +using BS.SharedLauncher.Enums; +using BS.SharedLauncher.Utils; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Runtime.Serialization; +using System.Text; +using System.Threading.Tasks; +using System.Xml.Serialization; + +namespace BS.SharedLauncher.DataContract +{ + [DebuggerDisplay("{RelativePath} ({Checksum})")] + [DataContract, Serializable()] + public class UpdateFileDC + { + public UpdateFileDC() + { + + } + + public UpdateFileDC(FileInfo fileInfo, string relativeTo) : base() + { + Name = fileInfo.Name; + AbsolutePath = fileInfo.FullName; + RelativePath = PathUtils.MakeRelativePath(relativeTo, fileInfo.FullName); + Size = fileInfo.Length; + } + + [DataMember, XmlAttribute] + public string Name { get; set; } + + [XmlIgnore] + public string AbsolutePath { get; set; } + + [DataMember, XmlAttribute] + public string RelativePath { get; set; } + + [DataMember, XmlAttribute] + public UpdateFileSource Source { get; set; } + + [DataMember, XmlAttribute] + public string Checksum { get; set; } + + [DataMember, XmlAttribute] + public long Size { get; set; } + } +} diff --git a/SharedLauncher/DataContract/UpdateFileRequest.cs b/SharedLauncher/DataContract/UpdateFileRequest.cs new file mode 100644 index 000000000..de926eb3d --- /dev/null +++ b/SharedLauncher/DataContract/UpdateFileRequest.cs @@ -0,0 +1,32 @@ +using BS.SharedLauncher.Update; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Runtime.Serialization; +using System.Text; +using System.Threading.Tasks; +using System.Xml.Serialization; + +namespace BS.SharedLauncher.DataContract +{ + [DataContract] + public class UpdateFileRequest + { + public UpdateFileRequest() + { + + } + + public UpdateFileRequest(string version) : base() + { + Version = version; + } + + [DataMember] + public string Version { get; set; } + + [DataMember] + public UpdateFileDC UpdateFile { get; set; } + } +} diff --git a/SharedLauncher/DataContract/UpdateFileResponse.cs b/SharedLauncher/DataContract/UpdateFileResponse.cs new file mode 100644 index 000000000..0525f4ba9 --- /dev/null +++ b/SharedLauncher/DataContract/UpdateFileResponse.cs @@ -0,0 +1,24 @@ +using BS.SharedLauncher.Update; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Runtime.Serialization; +using System.Text; +using System.Threading.Tasks; +using System.Xml.Serialization; + +namespace BS.SharedLauncher.DataContract +{ + [DataContract] + public class UpdateFileResponse + { + public UpdateFileResponse() + { + + } + + [DataMember] + public byte[] FileData { get; set; } + } +} diff --git a/SharedLauncher/DataContract/PlanerPackageInfoDC.cs b/SharedLauncher/DataContract/UpdatePlanDC.cs similarity index 83% rename from SharedLauncher/DataContract/PlanerPackageInfoDC.cs rename to SharedLauncher/DataContract/UpdatePlanDC.cs index 8213d5031..7b121a5df 100644 --- a/SharedLauncher/DataContract/PlanerPackageInfoDC.cs +++ b/SharedLauncher/DataContract/UpdatePlanDC.cs @@ -9,10 +9,10 @@ using System.Xml.Serialization; namespace BS.SharedLauncher.DataContract { [DataContract, XmlRoot("Package"), Serializable()] - public class PlanerPackageInfoDC + public class UpdatePlanDC { - [DataMember] - public List Files { get; set; } + [DataMember, XmlIgnore] + public List Files { get; set; } [DataMember] public DateTime Created { get; set; } diff --git a/SharedLauncher/DataContract/DownloadPlanerRequestDC.cs b/SharedLauncher/DataContract/UpdatePlanRequest.cs similarity index 79% rename from SharedLauncher/DataContract/DownloadPlanerRequestDC.cs rename to SharedLauncher/DataContract/UpdatePlanRequest.cs index 224300699..9da9b5d55 100644 --- a/SharedLauncher/DataContract/DownloadPlanerRequestDC.cs +++ b/SharedLauncher/DataContract/UpdatePlanRequest.cs @@ -10,9 +10,9 @@ namespace BS.SharedLauncher.DataContract { //[DebuggerDisplay("{InternalName} ({FileVersion})")] [DataContract] - public class DownloadPlanerRequestDC + public class UpdatePlanRequest { - public DownloadPlanerRequestDC() + public UpdatePlanRequest() { PlanerRootFolderExists = false; DownloadFolderExists = false; @@ -37,9 +37,12 @@ namespace BS.SharedLauncher.DataContract public bool ApplyFolderIsEmpty { get; set; } [DataMember] - public Dictionary DownloadedPackages { get; set; } + public List DownloadedFiles { get; set; } [DataMember] - public PlanerPackageInfoDC ApplyPackage { get; set; } + public UpdatePlanDC ApplyPackage { get; set; } + + [DataMember] + public LoginDC Login { get; set; } } } diff --git a/SharedLauncher/DataContract/DownloadPlanerResponseInfoDC.cs b/SharedLauncher/DataContract/UpdatePlanResponse.cs similarity index 58% rename from SharedLauncher/DataContract/DownloadPlanerResponseInfoDC.cs rename to SharedLauncher/DataContract/UpdatePlanResponse.cs index a047c3680..0273dfe4c 100644 --- a/SharedLauncher/DataContract/DownloadPlanerResponseInfoDC.cs +++ b/SharedLauncher/DataContract/UpdatePlanResponse.cs @@ -10,29 +10,26 @@ using System.Xml.Serialization; namespace BS.SharedLauncher.DataContract { [DataContract] - public class DownloadPlanerResponseInfoDC + public class UpdatePlanResponse { - public DownloadPlanerResponseInfoDC() + public UpdatePlanResponse() { } [DataMember] - public string Version { get; set; } + public UpdatePlanDC CurrentPackage { get; set; } + [DataMember] + public List FilesToRequest { get; set; } + + [DataMember] + public List FilesToApply { get; set; } + + [DataMember] + public List FilesToDeleteInApply { get; set; } + [DataMember] public long DownloadSize { get; set; } - - [DataMember] - public long TotalSize { get; set; } - - [DataMember] - public int FileCount { get; set; } - - [DataMember] - public int NewFileCount { get; set; } - - [DataMember] - public bool HasSomethingToDo { get; set; } } } diff --git a/SharedLauncher/Exceptions/InvalidUpdateFileRequestException.cs b/SharedLauncher/Exceptions/InvalidUpdateFileRequestException.cs new file mode 100644 index 000000000..cdf6425f9 --- /dev/null +++ b/SharedLauncher/Exceptions/InvalidUpdateFileRequestException.cs @@ -0,0 +1,23 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace BS.SharedLauncher.Exceptions +{ + public class InvalidUpdateFileRequestException : UpdateException + { + public InvalidUpdateFileRequestException() + { + } + + public InvalidUpdateFileRequestException(string message) : base(message) + { + } + + public InvalidUpdateFileRequestException(string message, Exception innerException) : base(message, innerException) + { + } + } +} diff --git a/SharedLauncher/Exceptions/InvalidUpdatePlanRequestException.cs b/SharedLauncher/Exceptions/InvalidUpdatePlanRequestException.cs new file mode 100644 index 000000000..e565b85ab --- /dev/null +++ b/SharedLauncher/Exceptions/InvalidUpdatePlanRequestException.cs @@ -0,0 +1,23 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace BS.SharedLauncher.Exceptions +{ + public class InvalidUpdatePlanRequestException : UpdateException + { + public InvalidUpdatePlanRequestException() + { + } + + public InvalidUpdatePlanRequestException(string message) : base(message) + { + } + + public InvalidUpdatePlanRequestException(string message, Exception innerException) : base(message, innerException) + { + } + } +} diff --git a/SharedLauncher/Extensions/DownloadPlanerResponseExtension.cs b/SharedLauncher/Extensions/DownloadPlanerResponseExtension.cs deleted file mode 100644 index 313cf4e0c..000000000 --- a/SharedLauncher/Extensions/DownloadPlanerResponseExtension.cs +++ /dev/null @@ -1,27 +0,0 @@ -using BS.SharedLauncher.DataContract; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace BS.SharedLauncher.Extensions -{ - public static class DownloadPlanerResponseExtension - { - public static bool HasToDo(this DownloadPlanerResponseDC response) - { - return response.HasToDoDownload2Keep() || response.HasToDoNewZip() || response.HasToRemoveFiles; - } - - public static bool HasToDoDownload2Keep(this DownloadPlanerResponseDC response) - { - return response.DownloadFilesToKeep is object; - } - - public static bool HasToDoNewZip(this DownloadPlanerResponseDC response) - { - return response.NewZipInfo is object; - } - } -} diff --git a/SharedLauncher/Extensions/PathExtensions.cs b/SharedLauncher/Extensions/PathExtensions.cs index 140a5cde7..144ead075 100644 --- a/SharedLauncher/Extensions/PathExtensions.cs +++ b/SharedLauncher/Extensions/PathExtensions.cs @@ -5,6 +5,7 @@ using System.Linq; using System.Text; using System.Threading.Tasks; using BS.SharedLauncher.Information; +using BS.SharedLauncher.Logic; namespace BS.SharedLauncher.Extensions { diff --git a/SharedLauncher/Extensions/PlanerFileExtension.cs b/SharedLauncher/Extensions/PlanerFileExtension.cs index 97cdb0a4b..18570f9af 100644 --- a/SharedLauncher/Extensions/PlanerFileExtension.cs +++ b/SharedLauncher/Extensions/PlanerFileExtension.cs @@ -13,22 +13,16 @@ namespace BS.SharedLauncher.Extensions { public static class PlanerFileExtension { - public static List ToPlanerFileInfoDCList(this List planerFileInfos) => planerFileInfos.Select(x => new PlanerFileInfoDC() + public static bool ContainsPlanerFile(this List files, UpdateFileDC file2) { - Checksum = x.Checksum, - Name = x.Name, - RelativePath = x.RelativePath - }).ToList(); - public static List ToPlanerFileInfoList(this List planerFileInfos) => planerFileInfos.Select(x => new PlanerFileInfo() + return files.FirstOrDefault(file => file.RelativePath == file2.RelativePath) is object; + } + public static bool ContainsPlanerFileWithHash(this List files, UpdateFileDC file2) { - Checksum = x.Checksum, - Name = x.Name, - RelativePath = x.RelativePath - }).ToList(); - - public static void LoadHash(this PlanerFileInfo planerFileInfo) + return files.FirstOrDefault(file => file.RelativePath == file2.RelativePath && file.Checksum == file2.Checksum) is object; + } + public static void LoadHash(this UpdateFileDC planerFileInfo) { - //FileData = File.ReadAllBytes(AbsolutePath); using (var md5 = MD5.Create()) { using (var stream = File.OpenRead(planerFileInfo.AbsolutePath)) @@ -38,44 +32,52 @@ namespace BS.SharedLauncher.Extensions } } - public static void Copy(this PlanerFileInfo info) => new PlanerFileInfo() + public static void Copy(this UpdateFileDC info) => new UpdateFileDC() { Name = info.Name, AbsolutePath = info.AbsolutePath, Checksum = info.Checksum, RelativePath = info.RelativePath }; + public static bool EqualsFile(this UpdateFileDC file, UpdateFileDC file2) + { + return (file.Checksum == file2.Checksum) && + (file.RelativePath == file2.RelativePath) && + (file.Name == file2.Name); + } + public static string GetExtensionType(this UpdateFileDC file) + { + return Path.GetExtension(file.AbsolutePath); + } + public static bool IsLockFile(this UpdateFileDC file) + { + return file.Name == BeWoPathFileConfig.LockFileName; + } + public static bool IsPackageInfo(this UpdateFileDC file) + { + return file.GetExtensionType() == BeWoPathFileConfig.DotBeWoInfo; + } + public static bool IgnoreFile(this UpdateFileDC file) + { + // Lock File Ignorieren + if (file.IsLockFile()) + return true; - public static bool EqualsFile(this PlanerFileInfo file, PlanerFileInfo file2) - { - return (file.Checksum == file2.Checksum) && - (file.RelativePath == file2.RelativePath) && - (file.Name == file2.Name); - } - public static bool EqualsFile(this PlanerFileInfoDC file, PlanerFileInfoDC file2) - { - return (file.Checksum == file2.Checksum) && - (file.RelativePath == file2.RelativePath) && - (file.Name == file2.Name); - } - public static bool EqualsFile(this PlanerFileInfo file, PlanerFileInfoDC file2) - { - return (file.Checksum == file2.Checksum) && - (file.RelativePath == file2.RelativePath) && - (file.Name == file2.Name); - } - public static bool EqualsFile(this PlanerFileInfoDC file, PlanerFileInfo file2) - { - return (file.Checksum == file2.Checksum) && - (file.RelativePath == file2.RelativePath) && - (file.Name == file2.Name); + // Package Info Ignorieren + if (file.IsPackageInfo()) + return true; + + return false; } - public static bool IgnoreToRemove(this PlanerFileInfo file) + public static bool IgnoreToRemove(this UpdateFileDC file) { if (file.Name == BeWoPathFileConfig.LockFileName) return true; + if (file.GetExtensionType() == BeWoPathFileConfig.DotBeWoInfo) + return true; + return false; } } diff --git a/SharedLauncher/Extensions/PlanerPackageExtension.cs b/SharedLauncher/Extensions/PlanerPackageExtension.cs index 54fa46eb3..8d4667501 100644 --- a/SharedLauncher/Extensions/PlanerPackageExtension.cs +++ b/SharedLauncher/Extensions/PlanerPackageExtension.cs @@ -10,26 +10,15 @@ namespace BS.SharedLauncher.Extensions { public static class PlanerPackageExtension { - public static PlanerPackageInfoDC ToPlanerPackageInfoDC(this PlanerPackageInfo planerFileInfo) => new PlanerPackageInfoDC() + public static bool ContainsPlanerFile(this UpdatePlanDC planerPackageInfo, UpdateFileDC file2) { - Created = planerFileInfo.Created, - DefaultVersion = planerFileInfo.DefaultVersion, - Files = planerFileInfo.Files.ToPlanerFileInfoDCList(), - TenantVersion = planerFileInfo.TenantVersion - }; - public static PlanerPackageInfo ToPlanerPackageInfo(this PlanerPackageInfoDC planerFileInfo) => new PlanerPackageInfo() - { - Created = planerFileInfo.Created, - DefaultVersion = planerFileInfo.DefaultVersion, - Files = planerFileInfo.Files.ToPlanerFileInfoList(), - TenantVersion = planerFileInfo.TenantVersion - }; - - public static bool ContainsPlanerFile(this PlanerPackageInfo planerPackageInfo, string rel, string checksum) - { - return planerPackageInfo.Files.FirstOrDefault(file => file.RelativePath == rel && file.Checksum == checksum) is object; + return planerPackageInfo.Files.FirstOrDefault(file => file.RelativePath == file2.RelativePath) is object; } - public static bool AnyFile(this PlanerPackageInfo planerPackageInfo) + public static bool ContainsPlanerFileWithHash(this UpdatePlanDC planerPackageInfo, UpdateFileDC file2) + { + return planerPackageInfo.Files.FirstOrDefault(file => file.RelativePath == file2.RelativePath && file.Checksum == file2.Checksum) is object; + } + public static bool AnyFile(this UpdatePlanDC planerPackageInfo) { if (planerPackageInfo.Files is null) return false; @@ -37,25 +26,25 @@ namespace BS.SharedLauncher.Extensions return planerPackageInfo.Files.Any(); } - public static PlanerFileInfo FindPlanerFile(this PlanerPackageInfo planerFileInfo, string relative) + public static UpdateFileDC FindPlanerFile(this UpdatePlanDC planerFileInfo, string relative) { return planerFileInfo.Files.Find(x => x.RelativePath == relative); } - public static PlanerFileInfo FirstOrDefaultPlanerFile(this PlanerPackageInfo planerFileInfo, string relative) + public static UpdateFileDC FirstOrDefaultPlanerFile(this UpdatePlanDC planerFileInfo, string relative) { return planerFileInfo.Files.FirstOrDefault(x => x.RelativePath == relative); } - public static PlanerFileInfo FirstOrDefaultPlanerFile(this PlanerPackageInfo planerFileInfo, PlanerFileInfo file) + public static UpdateFileDC FirstOrDefaultPlanerFile(this UpdatePlanDC planerFileInfo, UpdateFileDC file) { return planerFileInfo.Files.FirstOrDefault(x => x.EqualsFile(file)); } - public static void InitFiles(this PlanerPackageInfo planerFileInfo, List files) + public static void InitFiles(this UpdatePlanDC planerFileInfo, List files) { - planerFileInfo.Files = new List(); + planerFileInfo.Files = new List(); planerFileInfo.Files.AddRange(files); } - private static void OverrideFile(this PlanerPackageInfo planerFileInfo, PlanerFileInfo newFile) + private static void OverrideOrAddFile(this UpdatePlanDC planerFileInfo, UpdateFileDC newFile) { var oldFile = planerFileInfo.FirstOrDefaultPlanerFile(newFile.RelativePath); @@ -65,44 +54,32 @@ namespace BS.SharedLauncher.Extensions planerFileInfo.Files.Add(newFile); //oldFile.Source = newFile.Source; } - public static void OverrideFiles(this PlanerPackageInfo planerFileInfo, List files) + public static void OverrideOrAddFiles(this UpdatePlanDC planerFileInfo, List files) { - files.ForEach(x => planerFileInfo.OverrideFile(x)); + files.ForEach(x => planerFileInfo.OverrideOrAddFile(x)); } - public static void TryRemoveFile(this PlanerPackageInfo planerFileInfo, PlanerFileInfo file) + public static void TryRemoveFile(this UpdatePlanDC planerFileInfo, UpdateFileDC file) { var minuend = planerFileInfo.FirstOrDefaultPlanerFile(file); - if (minuend is PlanerFileInfo) + if (minuend is UpdateFileDC) { planerFileInfo.RemoveFile(minuend); } } - public static void RemoveFile(this PlanerPackageInfo planerFileInfo, PlanerFileInfo file) + public static void RemoveFile(this UpdatePlanDC planerFileInfo, UpdateFileDC file) { planerFileInfo.Files.Remove(file); } - public static void RemoveFileAt(this PlanerPackageInfo planerFileInfo, int index) + public static void RemoveFileAt(this UpdatePlanDC planerFileInfo, int index) { planerFileInfo.Files.RemoveAt(index); } - public static void SubstractFiles(this PlanerPackageInfo planerPackageInfo, List files) + public static void SubstractFiles(this UpdatePlanDC planerPackageInfo, List files) { files.ForEach(f => planerPackageInfo.TryRemoveFile(f)); } - public static void LoadHash(this PlanerPackageInfo planer) => planer.Files.ForEach(file => file.LoadHash()); - public static PlanerPackageInfo Copy(this PlanerPackageInfo pp) => new PlanerPackageInfo() - { - Created = pp.Created, - DefaultVersion = pp.DefaultVersion, - TenantVersion = pp.TenantVersion, - Files = pp.Files.Select(file => file.Copy()).ToList() - }; - - public static void Apply(this PlanerPackageInfo planer) - { - - } + public static void LoadHash(this UpdatePlanDC planer) => planer.Files.ForEach(file => file.LoadHash()); } } diff --git a/SharedLauncher/Extensions/UpdateResponseExtension.cs b/SharedLauncher/Extensions/UpdateResponseExtension.cs new file mode 100644 index 000000000..c7468079d --- /dev/null +++ b/SharedLauncher/Extensions/UpdateResponseExtension.cs @@ -0,0 +1,32 @@ +using BS.SharedLauncher.DataContract; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace BS.SharedLauncher.Extensions +{ + public static class UpdateResponseExtension + { + public static bool HasToDo(this UpdatePlanResponse response) + { + return response.HasToRequestFiles() || response.HasToApplyFiles() || response.HasToDeleteFilesInApply(); + } + + public static bool HasToRequestFiles(this UpdatePlanResponse response) + { + return response.FilesToRequest is object; + } + + public static bool HasToApplyFiles(this UpdatePlanResponse response) + { + return response.FilesToApply is object; + } + + public static bool HasToDeleteFilesInApply(this UpdatePlanResponse response) + { + return response.FilesToDeleteInApply is object; + } + } +} diff --git a/SharedLauncher/Information/BeWoPathFileConfig.cs b/SharedLauncher/Information/BeWoPathFileConfig.cs index 73ecce5c0..53c72f856 100644 --- a/SharedLauncher/Information/BeWoPathFileConfig.cs +++ b/SharedLauncher/Information/BeWoPathFileConfig.cs @@ -11,14 +11,12 @@ namespace BS.SharedLauncher.Information public static class BeWoPathFileConfig { private static readonly string lockFileName = "_lock"; - private static readonly string zipName = "bewo{0}.zip"; - private static readonly string dotbewoinfo = ".bewoinfo"; + private static readonly string dotbewoinfo = ".bewoplan"; private static readonly string latestFileName = "latest"; private static readonly string subdir = "BeWoPlaner"; private static readonly string testForPermission = "bewo.permission.test"; public static string LockFileName => lockFileName; - public static string ZipFormatName => zipName; public static string DotBeWoInfo => dotbewoinfo; public static string LatestBeWoInfo => latestFileName + DotBeWoInfo; public static string SubDirectory => subdir; diff --git a/SharedLauncher/Information/Connection.cs b/SharedLauncher/Information/Connection.cs new file mode 100644 index 000000000..0b0df6f92 --- /dev/null +++ b/SharedLauncher/Information/Connection.cs @@ -0,0 +1,112 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace BS.SharedLauncher.Information +{ + public class Connection + { + private const char trennzeichen = '\t'; + + public string ProxyName { get; set; } + public string ProxyPassword { get; set; } + public string ProxyUsername { get; set; } + + public string IpAddress { get; set; } + public string DownloadServerAddress { get; set; } + public string Servername { get; set; } + + public string CoreServerAddress { get; set; } + public string ChatServerAddress { get; set; } + + public int Length => ToList().Count; + + public static Connection Parse(List data) + { + var connection = new Connection(); + var c = 0; + + connection.ProxyName = data[c++]; + connection.ProxyPassword = data[c++]; + connection.ProxyUsername = data[c++]; + + connection.IpAddress = data[c++]; + connection.DownloadServerAddress = data[c++]; + connection.Servername = data[c++]; + + connection.CoreServerAddress = data[c++]; + connection.ChatServerAddress = data[c++]; + + return connection; + } + + public List ToList() + { + return new List { ProxyName, ProxyPassword, ProxyUsername, + IpAddress, DownloadServerAddress, Servername, + CoreServerAddress, ChatServerAddress}; + } + + public string DownloadServerAddressExact + { + get + { + String url = DownloadServerAddress?.ToLower(); + + // Localhost + if (url.IndexOf("localhost") >= 0) + return new Uri(url).ToString(); + + // Just Number + if (int.TryParse(url, out int i)) + url = "app" + url; + + // Kein Https + if (url.IndexOf("https://") < 0) + url = "https://" + url; + + // Kein Punkt + if (url.IndexOf('.') < 0) + url += ".bewoplaner.de"; + + // Kein Slash + if (url.IndexOf("/download") < 0) + url += "/download"; + + return new Uri(url).ToString(); + } + } + + public string CoreServerAddressExact + { + get + { + String url = CoreServerAddress?.ToLower(); + + // Localhost + if (url.IndexOf("localhost") >= 0) + return new Uri(url).ToString(); + + // Just Number + if (int.TryParse(url, out int i)) + url = "app" + url; + + // Kein Https + if (url.IndexOf("https://") < 0) + url = "https://" + url; + + // Kein Punkt + if (url.IndexOf('.') < 0) + url += ".bewoplaner.de"; + + // Kein Slash + if (url.IndexOf("/service") < 0) + url += "/service"; + + return new Uri(url).ToString(); + } + } + } +} diff --git a/SharedLauncher/Information/ConnectionInformation.cs b/SharedLauncher/Information/ConnectionInformation.cs deleted file mode 100644 index 309ad7fb6..000000000 --- a/SharedLauncher/Information/ConnectionInformation.cs +++ /dev/null @@ -1,246 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace BS.SharedLauncher.Information -{ - public class Connection - { - private const char trennzeichen = '\t'; - - public string Tenant { get; set; } - public string Username { get; set; } - public string Password { get; set; } - - public string ProxyName { get; set; } - public string ProxyPassword { get; set; } - public string ProxyUsername { get; set; } - - public string IpAddress{ get; set; } - public string LauncherServerAddress { get; set; } - public string Servername { get; set; } - public string CoreServerAddress { get; set; } - public string ChatServerAddress { get; set; } - public string Version { get; set; } - - public static Connection Parse(string[] data) - { - var connection = new Connection(); - - connection.Tenant = data[0]; - connection.Username = data[1]; - connection.Password = data[2]; - connection.IpAddress = data[3]; - connection.CoreServerAddress = data[4]; - connection.ChatServerAddress = data[5]; - connection.Version = data[6]; - - return connection; - } - - public string[] ToArray() - { - return new string[] { "demo", "demo", "demo", IpAddress, ConnectionInformation.CoreServerAddressOrigin.ToString(), ChatServerAddress, Version }; - } - - //public static bool TryParse(string input, out Connection connection) - //{ - // connection = new Connection(); - - // try - // { - // connection = Parse(input); - - // return true; - // } - // catch (Exception) - // { - // return false; - // } - //} - - //public static bool TryParse(string input, out Connection connection) - //{ - // connection = new Connection(); - - // try - // { - // connection = Parse(input); - - // return true; - // } - // catch (Exception) - // { - // return false; - // } - //} - - public override string ToString() - { - return - $"te{Tenant}{trennzeichen}un{Username}{trennzeichen}pw{Password}{trennzeichen}ip{IpAddress}{trennzeichen}sn{Servername}{trennzeichen}cs{ChatServerAddress}{trennzeichen}vr{Version}"; - } - } - - public static class ConnectionInformation - { - private static Connection connection; - - public static Connection Connection - { - get - { - if (connection is null) - connection = new Connection(); - - return connection; - } - } - public static string ProxyName - { - get { return Connection.ProxyName; } - set { Connection.ProxyName = value; } - } - - public static string ProxyPassword - { - get { return Connection.ProxyPassword; } - set { Connection.ProxyPassword = value; } - } - - public static string ProxyUsername - { - get { return Connection.ProxyUsername; } - set { Connection.ProxyUsername = value; } - } - - public static string ChatServerAddress - { - get { return Connection.ChatServerAddress; } - set { Connection.ChatServerAddress = value; } - } - - public static string CoreServerAddress - { - get { return Connection.CoreServerAddress; } - set { Connection.CoreServerAddress = value; } - } - - public static string IpAddress - { - get { return Connection.IpAddress; } - set { Connection.IpAddress = value; } - } - - public static string Password - { - get { return Connection.Password; } - set { Connection.Password = value; } - } - - public static string ServerName - { - get { return Connection.Servername; } - set { Connection.Servername = value; } - } - - public static string Tenant - { - get { return Connection.Tenant; } - set { Connection.Tenant = value; } - } - - public static string Username - { - get { return Connection.Username; } - set { Connection.Username = value; } - } - - public static string Version - { - get { return Connection.Version; } - set { Connection.Version = value; } - } - - public static string LauncherServerAddress - { - get { return Connection.LauncherServerAddress; } - set - { - Connection.LauncherServerAddress = value; - //LauncherServiceFacade.UpdateServerAddresses(LauncherServerAddressOrigin.ToString()); - } - } - - public static Uri LauncherServerAddressOrigin - { - get - { - String url = Connection.LauncherServerAddress?.ToLower(); - -#if DEBUG - //url = String.Format("http://localhost:3778"); - return new Uri("https://app5.bewoplaner.de/launcher"); - //url = String.Format("app1.bewoplaner.de/service"); -#endif - - if (url.IndexOf("localhost") < 0) - { - if (int.TryParse(url, out int i)) - url = "app" + url; - - if (url.IndexOf('.') < 0) - { - url += ".bewoplaner.de"; - } - - if (url.IndexOf("/service") < 0) - { - url += "/service"; - } - - return new Uri(string.Format("https://{0}", url)); - } - return new Uri(url); - } - } - - public static Uri CoreServerAddressOrigin - { - get - { - String url = Connection.CoreServerAddress?.ToLower(); -#if DEBUG - url = String.Format("http://localhost:3777/Host"); - //return new Uri("https://app4.bewoplaner.de/servicesbd"); - //url = String.Format("app1.bewoplaner.de/service"); -#endif - - if (url.IndexOf("localhost") < 0) - { - if (Int32.TryParse(url, out int i)) - url = "app" + url; - - if (url.IndexOf('.') < 0) - { - url += ".bewoplaner.de"; - } - - //if (url.IndexOf("/service45") < 0) - //{ - // url += "/service45"; - //} - if (url.IndexOf("/servicesbd") < 0) - { - url += "/servicesbd"; - } - - return new Uri(string.Format("https://{0}", url)); - } - return new Uri(url); - } - } - } -} diff --git a/SharedLauncher/Information/DownloadLogger.cs b/SharedLauncher/Information/DownloadLogger.cs new file mode 100644 index 000000000..446df1ab5 --- /dev/null +++ b/SharedLauncher/Information/DownloadLogger.cs @@ -0,0 +1,59 @@ +using BS.SharedLauncher.Extensions; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace BS.SharedLauncher.Information +{ + public static class DownloadLogger + { + private static bool _started; + + private static string _LogFileName; + private static string _LogFilePath; + private static string _folder; + + public static string LogFilePath => _LogFilePath; + + static DownloadLogger() + { + _started = false; + } + + public static void Init(string folder) + { + _LogFileName = DateTime.Now.ToString("yyyy-MM-dd") + ".txt"; + _LogFilePath = folder.Combine(_LogFileName); + + folder.CreateFolder(); + + _started = true; + + Post3(); + Post2("Starting Download Logger..."); + Post3(); + } + + public static void Post(string message) + { + if (!_started) + return; + + var log = $"[{DateTime.Now.ToString("HH:mm:ss")}]: {message}\n"; + File.AppendAllText(_LogFilePath, log); + } + + public static void Post2(string message) + { + Post("--->>> " + message); + } + + public static void Post3() + { + Post("-----------------------------------"); + } + } +} diff --git a/SharedLauncher/Information/Login.cs b/SharedLauncher/Information/Login.cs new file mode 100644 index 000000000..1b9d4d39a --- /dev/null +++ b/SharedLauncher/Information/Login.cs @@ -0,0 +1,45 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace BS.SharedLauncher.Information +{ + public class Login + { + public string Tenant { get; set; } + public string Username { get; set; } + public string TempUsername { get; set; } + public string Password { get; set; } + + public string CoreServerAddress { get; set; } + public string Pin { get; set; } + public string ClientId { get; set; } + + public int Length => ToList().Count; + + public static Login Parse(List data) + { + var login = new Login(); + var c = 0; + + login.Tenant = data[c++]; + login.Username = data[c++]; + login.TempUsername = data[c++]; + login.Password = data[c++]; + + login.CoreServerAddress = data[c++]; + login.Pin = data[c++]; + login.ClientId = data[c++]; + + return login; + } + + public List ToList() + { + return new List { Tenant, Username, TempUsername, Password, + CoreServerAddress, Pin, ClientId}; + } + } +} diff --git a/SharedLauncher/Information/Session.cs b/SharedLauncher/Information/Session.cs new file mode 100644 index 000000000..57ececd79 --- /dev/null +++ b/SharedLauncher/Information/Session.cs @@ -0,0 +1,30 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace BS.SharedLauncher.Information +{ + public class Session + { + public string Version { get; set; } + + public int Length => ToList().Count; + + public static Session Parse(List data) + { + var session = new Session(); + var c = 0; + + session.Version = data[c++]; + + return session; + } + + public List ToList() + { + return new List { Version }; + } + } +} diff --git a/SharedLauncher/Information/SessionInformation.cs b/SharedLauncher/Information/SessionInformation.cs new file mode 100644 index 000000000..ee4f38250 --- /dev/null +++ b/SharedLauncher/Information/SessionInformation.cs @@ -0,0 +1,146 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.IO.Pipes; +using System.Linq; + +namespace BS.SharedLauncher.Information +{ + public static class SessionInformation + { + private static Connection connection; + private static Login login; + private static Session session; + + public static string GetDebugConnection(int i) + { + if (i == 1) + { + // Download Server + + return "http://localhost:3778"; + //return "https://localhost:44367/"; + //return "https://app5.bewoplaner.de"; + } + if (i == 2) + { + // Core Server + + return "http://localhost:3777/Host/"; + //return "https://localhost:44308/Host/"; + //return "https://app5.bewoplaner.de"; + } + throw new Exception(); + } + + public static Connection Connection + { + get + { + if (connection is null) + { + connection = new Connection(); + Loaded = true; + } + + return connection; + } + } + public static Session Session + { + get + { + if (session is null) + { + session = new Session(); + Loaded = true; + } + + return session; + } + } + public static Login Login + { + get + { + if (login is null) + { + login = new Login(); + Loaded = true; + } + + return login; + } + } + + public static bool Loaded { get; set; } + + static SessionInformation() + { + Loaded = false; + } + + public static void Load(List connection, List login, List session) + { + Init( + BS.SharedLauncher.Information.Connection.Parse(connection), + BS.SharedLauncher.Information.Login.Parse(login), + BS.SharedLauncher.Information.Session.Parse(session)); + } + public static void Init(Connection pconnection, Login plogin, Session psession) + { + //if (Loaded) + // throw new Exception(SessionInformation.ToString()); + + connection = pconnection; + login = plogin; + session = psession; + + Loaded = true; + } + + public static void LoadPipe(string pipe) + { + try + { + using (PipeStream pipeClient = new AnonymousPipeClientStream(PipeDirection.In, pipe)) + { + using (StreamReader sr = new StreamReader(pipeClient)) + { + string temp; + List result = new List(); + var signal = new string[] { "C-137", "C-131" }; + + // Warte auf Start + do + { + temp = sr.ReadLine(); + } + while (!temp.StartsWith(signal[0])); + + var connection = (from x in Enumerable.Range(0, Connection.Length) select sr.ReadLine()).ToList(); + var login = (from x in Enumerable.Range(0, Login.Length) select sr.ReadLine()).ToList(); + var session = (from x in Enumerable.Range(0, Session.Length) select sr.ReadLine()).ToList(); + + do + { + temp = sr.ReadLine(); + } + while (!temp.StartsWith(signal[1])); + + Load(connection, login, session); + } + } + } + catch (Exception ex) + { + throw ex; + } + } + + public static string ToString() + { + return $"c:{string.Join(",", connection.ToList())} l:{string.Join(",", login.ToList())} s:{string.Join(",", session.ToList())}"; + } + } +} diff --git a/SharedLauncher/LauncherEnums.cs b/SharedLauncher/LauncherEnums.cs index 1a0e2c40b..ceba34d1f 100644 --- a/SharedLauncher/LauncherEnums.cs +++ b/SharedLauncher/LauncherEnums.cs @@ -51,39 +51,26 @@ namespace BS.SharedLauncher.Enums DeleteStart = 7, DeleteUpdate = 8, DeleteFinished = 9, - ProgressEnd = 10, + CleanupStart = 10, + CleanupUpdate = 11, + CleanupFinished = 12, + ProgressEnd = 13, } - //public enum PlanerUpdateSource - //{ - // Invalid = 0, - // Version = 1, - // VersionTenant = 2, - // OverrideTenant = 3 + public enum LauncherMode + { + Install = 0, + Update = 1, + Uninstall = 2 + } - // ///// - // ///// Aus der neusten Version / Default Case - // ///// - // //NewestVersion = 1, - - // ///// - // ///// Durch spezieller Version in version.config - // ///// - // //SpecialVersion = 2, - - // ///// - // ///// Aus der neusten Version aus dem Version-Kunden-Ordner - // ///// - // //NewestVersionTenant = 3, - - // ///// - // ///// Aus der speziellen Version aus dem Version-Kunden-Ordner - // ///// - // //SpecialVersionTenant = 4, - - // ///// - // ///// Aus dem Kunden-Ordner - // ///// - // //SpecialTenant = 5 - //} + public enum UpdateFileSource + { + Invalid = 0, + VersionDefault = 1, + VersionTenant = 2, + VersionUser = 3, + OverrideTenant = 4, + OverrideUser = 5 + } } diff --git a/SharedLauncher/Logic/FileController.cs b/SharedLauncher/Logic/FileController.cs index 8adedd92d..3f7a8a5bf 100644 --- a/SharedLauncher/Logic/FileController.cs +++ b/SharedLauncher/Logic/FileController.cs @@ -16,196 +16,77 @@ namespace BS.SharedLauncher.Logic { public static class FileController { - private static string ZipFormatName => BeWoPathFileConfig.ZipFormatName; private static string DotBeWoInfo => BeWoPathFileConfig.DotBeWoInfo; - - public static string GetDZipPath(string root, int number) => Path.Combine(root, string.Format(ZipFormatName, getFileNumberCountString(number))); - public static string GetDZipInfoPath(string root, int number) => GetDZipPath(root, number) + DotBeWoInfo; - public static void ApplyDZip(Dictionary> zip2keepfiles, string destinationfolder, Action apply) + public static List GetDownloadedFiles(string downloadFolder) { - foreach (var pair in zip2keepfiles) - { - ApplyDZip(pair.Key, destinationfolder, pair.Value.Contains, apply); - } + return GetPlanerFiles(downloadFolder, true, null); } - public static void ApplyDZip(string zipfilepath, string destinationfolder, Action apply) - => ApplyDZip(zipfilepath, destinationfolder, (s) => true, apply); - private static void ApplyDZip(string zipfilepath, string destinationfolder, Func isValidFunc, Action apply) + public static UpdatePlanDC GetApplyPackage(string applyFolder) { - using (ZipArchive archive = ZipFile.OpenRead(zipfilepath)) - { - foreach (ZipArchiveEntry entry in archive.Entries) - { - if (isValidFunc(entry.FullName)) - { - var path = destinationfolder.Combine(entry.FullName); - Directory.CreateDirectory(Path.GetDirectoryName(path)); - entry.ExtractToFile(path, true); - apply((int)LauncherProgress.ApplyUpdate, new ApplyFileEventArgs(entry.FullName, path)); - Thread.Sleep(100); - } - } - } + TryGetPackageInfo(applyFolder, out var package); + + if (package == null) + package = new UpdatePlanDC(); + + package.Files = GetPlanerFiles(applyFolder, true, null); + + return package; } - - public static void RemoveUnsuedFiles(PlanerPackageInfoDC latestApplicationInfo, string applyFolder, Action status) - { - foreach (var file in GetPlanerFiles(applyFolder)) - { - file.LoadHash(); - if (latestApplicationInfo.Files.Any(late => late.EqualsFile(file))) - continue; - - if (file.IgnoreToRemove()) - continue; - - File.Delete(file.AbsolutePath); - status((int)LauncherProgress.DeleteUpdate, file); - } - } - - public static List GetValidDZipPaths(string path) - { - var res = new List(); - - var dir = new DirectoryInfo(path); - var files = dir.GetFiles("*.zip"); - - foreach (var file in files) - { - if (file.FullName.IsDZipValid()) - res.Add(file.FullName); - } - - return res; - } - public static string GetNewZipPath(string root) - { - int i = 0; - string temp = string.Empty; - - do - { - temp = GetDZipPath(root, i++); - - } while (temp.IsDZipValidAndDeleteIfNot()); - - return temp; - } - - public static void SaveDZipStream(string path, Stream filebytestream, long length, Action download) - { - long startlength = 0; - FileInfo finfo = new FileInfo(path); - if (finfo.Exists) - startlength = finfo.Length; // If File exists, - // we need to send the Start length to the server - - using (FileStream writeStream = - new System.IO.FileStream(path, FileMode.OpenOrCreate, FileAccess.Write)) - { - int chunkSize = 2048; - byte[] buffer = new byte[chunkSize]; - - do - { - int bytesRead = filebytestream.Read(buffer, 0, chunkSize); - if (bytesRead == 0) break; - - writeStream.Write(buffer, 0, bytesRead); - - download(11, new DownloadProgressEventArgs(writeStream.Position * 100 / length)); - } - while (true); - - writeStream.Close(); - } - filebytestream.Dispose(); - } - public static void SaveDZip(string path, byte[] data) - { - File.WriteAllBytes(path, data); - } - public static void SaveInfo(string path, T t) - where T : class - { - File.WriteAllText(path.WithInfoExtension(), XmlConverter.Serialize(t)); - } - public static void DeleteInfo(string path) - { - File.Delete(path.WithInfoExtension()); - } - public static PlanerPackageInfoDC LoadInfo(string filepath) + public static UpdatePlanDC LoadPackageInfo(string filepath) { filepath = filepath.WithInfoExtension(); var xml = File.ReadAllText(filepath); - var obj = XmlConverter.Deserialize(xml); + var obj = XmlConverter.Deserialize(xml); return obj; } - - public static bool TryGetPackageInfo(string filepath, out PlanerPackageInfoDC planerPackageInfoDC) + public static bool TryGetPackageInfo(string filepath, out UpdatePlanDC planerPackageInfoDC) { planerPackageInfoDC = null; try { - planerPackageInfoDC = LoadInfo(filepath); + planerPackageInfoDC = LoadPackageInfo(filepath); } catch (Exception) { return false; } + return true; } - public static Dictionary LoadInfos(string rootfolder) + + #region file + public static void SaveFile(string path, byte[] data) { - var allDZips = GetValidDZipPaths(rootfolder); - - if (allDZips is null || !allDZips.Any()) - return null; - - return allDZips.ToDictionary(dzip => dzip, dzip => LoadInfo(dzip)); - - // Detailed Debug Section - //var res = new Dictionary(); - - //foreach (var dzip in allDZips) - //{ - // res.Add(dzip, GetPackageInfo(dzip)); - //} - - //return res; + File.WriteAllBytes(path, data); + DownloadLogger.Post($"Save File: {path}"); } - public static List GetPlanerFiles(string path) + public static void CopyFile(string source, string destination) { - var res = new List(); - - // Sollte der Path ohne / enden, wird der unterordner mit angegeben - // Deshalb manuell hinzufügen, falls nicht vorhanden - - if (!path.EndsWith(Path.DirectorySeparatorChar.ToString())) - path += Path.DirectorySeparatorChar; - - getPlanerFilesRecursive(new DirectoryInfo(path), path, ref res); - return res; + File.Copy(source, destination, true); + DownloadLogger.Post($"Copy File: {source} -> {destination}"); } - - public static bool IsDZipValidAndDeleteIfNot(this string path) + public static void DeleteFile(string source) { - if (path.IsDZipValid()) - return true; - - new FileInfo(path).Delete(); - new FileInfo(path + BeWoPathFileConfig.DotBeWoInfo).Delete(); - - return false; + File.Delete(source); + DownloadLogger.Post($"Delete File: {source}"); } - public static bool IsDZipValid(this string path) + #endregion + + #region info + public static void SaveInfo(string path, T t) + where T : class { - return path.Exists() && (path + BeWoPathFileConfig.DotBeWoInfo).Exists(); + File.WriteAllText(path.WithInfoExtension(), XmlConverter.Serialize(t)); + DownloadLogger.Post($"Info Save: {path}"); + } + public static void DeleteInfo(string path) + { + File.Delete(path.WithInfoExtension()); + DownloadLogger.Post($"Info delete: {path}"); } public static string WithInfoExtension(this string path) { @@ -214,28 +95,69 @@ namespace BS.SharedLauncher.Logic return path + DotBeWoInfo; } + #endregion - private static void getPlanerFilesRecursive(DirectoryInfo directoryInfo, string relativeTo, ref List files) + public static void DeleteEmptyDirectories(string path) + { + // Witzige Sache: Generiert mit chat.openai.com/chat + // Recursive function to delete empty directories + // Get all subdirectories in the specified path + string[] subdirectories = Directory.GetDirectories(path); + + // Loop through each subdirectory + foreach (string subdirectory in subdirectories) + { + // Call the recursive function to delete empty directories in the subdirectory + DeleteEmptyDirectories(subdirectory); + + // Check if the subdirectory is empty + if (IsDirectoryEmpty(subdirectory)) + { + // If the subdirectory is empty, delete it + Directory.Delete(subdirectory); + DownloadLogger.Post($"Deleted empty directory: {subdirectory}"); + } + } + } + + public static List GetPlanerFiles(string path, bool hash, Func skipFile) + { + var files = new List(); + + // Sollte der Path ohne / enden, wird der unterordner mit angegeben + // Deshalb manuell hinzufügen, falls nicht vorhanden + + if (!path.EndsWith(Path.DirectorySeparatorChar.ToString())) + path += Path.DirectorySeparatorChar; + + GetPlanerFilesRecursive(new DirectoryInfo(path), path, ref files, hash, skipFile); + + return files; + } + public static void GetPlanerFilesRecursive(DirectoryInfo directoryInfo, string relativeTo, ref List files, bool load_hash, Func skipFile) { foreach (var item in directoryInfo.GetDirectories()) { - getPlanerFilesRecursive(item, relativeTo, ref files); + GetPlanerFilesRecursive(item, relativeTo, ref files, load_hash, skipFile); } foreach (var item in directoryInfo.GetFiles()) { - var file = new PlanerFileInfo(item, relativeTo); + var file = new UpdateFileDC(item, relativeTo); + if (file.IgnoreFile()) + continue; + + if (skipFile is object && skipFile(file)) + continue; + + if (load_hash) + file.LoadHash(); + files.Add(file); } } - private static string getFileNumberCountString(int i) - { - if (i == 0) - return string.Empty; - return $"({i})"; - } - + public static bool IsDirectoryWritable(string dirPath, bool throwIfFails = false) { try @@ -260,5 +182,9 @@ namespace BS.SharedLauncher.Logic return false; } } + private static bool IsDirectoryEmpty(string path) + { + return !Directory.EnumerateFileSystemEntries(path).Any(); + } } } diff --git a/SharedLauncher/SharedLauncher.csproj b/SharedLauncher/SharedLauncher.csproj index 32749c241..0f93921e5 100644 --- a/SharedLauncher/SharedLauncher.csproj +++ b/SharedLauncher/SharedLauncher.csproj @@ -49,27 +49,33 @@ - - - - - + + + + + + + + + - + + + + + - + - - diff --git a/SharedLauncher/Update/ApplyFileEventArgs.cs b/SharedLauncher/Update/ApplyFileEventArgs.cs index 86d454cf4..4653e30be 100644 --- a/SharedLauncher/Update/ApplyFileEventArgs.cs +++ b/SharedLauncher/Update/ApplyFileEventArgs.cs @@ -8,13 +8,11 @@ namespace BS.SharedLauncher.Update { public class ApplyFileEventArgs : EventArgs { - public string Name { get; set; } - public string AbsolutePath { get; set; } + public string RelativePath { get; set; } - public ApplyFileEventArgs(string name, string path) + public ApplyFileEventArgs(string name) { - Name = name; - AbsolutePath = path; + RelativePath = name; } } } diff --git a/SharedLauncher/Update/DownloadProgressEventArgs.cs b/SharedLauncher/Update/DownloadProgressEventArgs.cs index 6157994ae..a56124a96 100644 --- a/SharedLauncher/Update/DownloadProgressEventArgs.cs +++ b/SharedLauncher/Update/DownloadProgressEventArgs.cs @@ -1,4 +1,5 @@ -using System; +using BS.SharedLauncher.DataContract; +using System; using System.Collections.Generic; using System.Linq; using System.Text; @@ -8,11 +9,13 @@ namespace BS.SharedLauncher.Update { public class DownloadProgressEventArgs : EventArgs { - public double Progress { get; set; } + public string Size { get; set; } + public UpdateFileDC File { get; set; } - public DownloadProgressEventArgs(double progress) + public DownloadProgressEventArgs(string size, UpdateFileDC file) { - Progress = progress; + Size = size; + File = file; } } } diff --git a/SharedLauncher/Update/PlanerFileInfo.cs b/SharedLauncher/Update/PlanerFileInfo.cs deleted file mode 100644 index 15d57d53d..000000000 --- a/SharedLauncher/Update/PlanerFileInfo.cs +++ /dev/null @@ -1,45 +0,0 @@ -using BS.SharedLauncher.Utils; -using BS.SharedLauncher.Enums; -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Security.Cryptography; -using BS.SharedLauncher.Update; -using System.Diagnostics; - -namespace BS.SharedLauncher.Update -{ - [DebuggerDisplay("{AbsolutePath}")] - public class PlanerFileInfo - { - public string Name { get; set; } - public string AbsolutePath { get; set; } - public string RelativePath { get; set; } - public string Checksum { get; set; } - - public PlanerFileInfo() - { - } - - public PlanerFileInfo(FileInfo fileInfo, string relativeTo) : this() - { - Name = fileInfo.Name; - AbsolutePath = fileInfo.FullName; - RelativePath = PathUtils.MakeRelativePath(relativeTo, fileInfo.FullName); - } - - public PlanerFileInfo Copy() - { - return new PlanerFileInfo() - { - Name = Name, - AbsolutePath = AbsolutePath, - RelativePath = RelativePath, - Checksum = Checksum - }; - } - } -} diff --git a/SharedLauncher/Update/PlanerPackageInfo.cs b/SharedLauncher/Update/PlanerPackageInfo.cs deleted file mode 100644 index 64a3ec8ad..000000000 --- a/SharedLauncher/Update/PlanerPackageInfo.cs +++ /dev/null @@ -1,30 +0,0 @@ -using BS.SharedLauncher.Enums; -using System; -using System.Collections.Generic; -using System.IO; -using System.IO.Compression; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Xml; -using System.Xml.Linq; -using System.Xml.Serialization; - -namespace BS.SharedLauncher.Update -{ - public class PlanerPackageInfo - { - public List Files { get; set; } - public DateTime Created { get; set; } - public string DefaultVersion { get; set; } - public string TenantVersion { get; set; } - - public PlanerPackageInfo() - { - DefaultVersion = null; - TenantVersion = null; - } - - public string Version => TenantVersion ?? DefaultVersion; - } -} diff --git a/UnitTests/SharedLauncherTests.cs b/UnitTests/SharedLauncherTests.cs new file mode 100644 index 000000000..d7c39fe2e --- /dev/null +++ b/UnitTests/SharedLauncherTests.cs @@ -0,0 +1,33 @@ +using BS.SharedLauncher.Information; +using Microsoft.VisualStudio.TestTools.UnitTesting; + +namespace UnitTests +{ + [TestClass] + public class SharedLauncherTests + { + [TestMethod] + public void TestLoginLength() + { + var login = new Login(); + + Assert.AreEqual(login.Length, 7); + } + + [TestMethod] + public void TestConnectionLength() + { + var conn = new Connection(); + + Assert.AreEqual(conn.Length, 8); + } + + [TestMethod] + public void TestSessionLength() + { + var session = new Session(); + + Assert.AreEqual(session.Length, 1); + } + } +} diff --git a/UnitTests/UnitTests.csproj b/UnitTests/UnitTests.csproj new file mode 100644 index 000000000..aa0327a5d --- /dev/null +++ b/UnitTests/UnitTests.csproj @@ -0,0 +1,19 @@ + + + + netcoreapp2.1 + + false + + + + + + + + + + + + +