/// <summary> /// Gets a new web proxy orchestrator /// </summary> public WebRemoteOrchestrator(string serviceUri, IConverter customConverter = null, HttpClient client = null, SyncPolicy syncPolicy = null, int maxDownladingDegreeOfParallelism = 4) : base(null, new SyncOptions()) { this.httpRequestHandler = new HttpRequestHandler(this); // if no HttpClient provisionned, create a new one if (client == null) { var handler = new HttpClientHandler(); // Activated by default if (handler.SupportsAutomaticDecompression) { handler.AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate; } this.HttpClient = new HttpClient(handler); } else { this.HttpClient = client; } this.SyncPolicy = this.EnsurePolicy(syncPolicy); this.Converter = customConverter; this.MaxDownladingDegreeOfParallelism = maxDownladingDegreeOfParallelism <= 0 ? -1 : maxDownladingDegreeOfParallelism; this.ServiceUri = serviceUri; this.SerializerFactory = SerializersCollection.JsonSerializerFactory; }
/// <summary> /// Create a new MySql Server database /// </summary> private static async Task CreateMariaDBDatabaseAsync(string dbName, bool recreateDb = true) { var onRetry = new Func <Exception, int, TimeSpan, object, Task>((ex, cpt, ts, arg) => { Console.WriteLine($"Creating MariaDB database failed when connecting to information_schema ({ex.Message}). Wating {ts.Milliseconds}. Try number {cpt}"); return(Task.CompletedTask); }); SyncPolicy policy = SyncPolicy.WaitAndRetry(3, TimeSpan.FromMilliseconds(500), null, onRetry); await policy.ExecuteAsync(async() => { using var sysConnection = new MySqlConnection(Setup.GetMariaDBDatabaseConnectionString("information_schema")); sysConnection.Open(); if (recreateDb) { using var cmdDrop = new MySqlCommand($"Drop schema if exists {dbName};", sysConnection); await cmdDrop.ExecuteNonQueryAsync(); } using (var cmdDb = new MySqlCommand($"create schema {dbName};", sysConnection)) cmdDb.ExecuteNonQuery(); sysConnection.Close(); }); }
/// <summary> /// Ensure we have policy. Create a new one, if not provided /// </summary> private SyncPolicy EnsurePolicy(SyncPolicy policy) { if (policy != default) { return(policy); } // Defining my retry policy policy = SyncPolicy.WaitAndRetry(2, (retryNumber) => { return(TimeSpan.FromMilliseconds(500 * retryNumber)); }, (ex, arg) => { var webEx = ex as SyncException; // handle session lost return(webEx == null || webEx.TypeName != nameof(HttpSessionLostException)); }, async(ex, cpt, ts, arg) => { await this.InterceptAsync(new HttpSyncPolicyArgs(10, cpt, ts), default).ConfigureAwait(false); }); return(policy); }
/// <summary> /// Gets a new web proxy orchestrator /// </summary> public WebClientOrchestrator(string serviceUri, ISerializerFactory serializerFactory = null, IConverter customConverter = null, HttpClient client = null, SyncPolicy syncPolicy = null) : base(new FancyCoreProvider(), new SyncOptions(), new SyncSetup()) { this.httpRequestHandler = new HttpRequestHandler(this); // if no HttpClient provisionned, create a new one if (client == null) { var handler = new HttpClientHandler(); // Activated by default if (handler.SupportsAutomaticDecompression) { handler.AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate; } this.HttpClient = new HttpClient(handler); } else { this.HttpClient = client; } this.SyncPolicy = this.EnsurePolicy(syncPolicy); this.Converter = customConverter; this.SerializerFactory = serializerFactory ?? SerializersCollection.JsonSerializer; this.ServiceUri = serviceUri; }
/// <summary> /// Create a new Sql Server database /// </summary> public static async Task CreateSqlServerDatabaseAsync(string dbName, bool recreateDb = true) { var onRetry = new Func <Exception, int, TimeSpan, object, Task>((ex, cpt, ts, arg) => { Console.WriteLine($"Creating SQL Server database failed when connecting to master ({ex.Message}). Wating {ts.Milliseconds}. Try number {cpt}"); return(Task.CompletedTask); }); SyncPolicy policy = SyncPolicy.WaitAndRetry(3, TimeSpan.FromMilliseconds(500), null, onRetry); await policy.ExecuteAsync(async() => { using var masterConnection = new SqlConnection(Setup.GetSqlDatabaseConnectionString("master")); masterConnection.Open(); using (var cmdDb = new SqlCommand(GetSqlCreationScript(dbName, recreateDb), masterConnection)) await cmdDb.ExecuteNonQueryAsync(); masterConnection.Close(); }); }
/// <summary> /// Gets whether the manager can and should sync. /// May return false because sync process is already running or because the last /// synchronization attempt was too soon. /// </summary> public bool CheckSyncConditions(SyncPolicy policy) { #if DEBUG if (policy != SyncPolicy.Forced) { Log.Debug("Unforced sync aborted in debug configuration"); return(false); } #endif if (Settings.OfflineMode) { Log.Debug("Can't sync: synchronization disabled in offline mode"); return(false); } if (IsSyncing) { Log.Debug("Can't sync: SyncManager already syncing"); return(false); } return(CheckPlatformSyncConditions()); }
/// <summary> /// Inner worker synchronizer. /// Will never throw for normal sync operations, even in case of failure. /// </summary> /// <exception cref="TaskCanceledException">Thrown when sync canceled.</exception> private async Task <SyncResult> SynchronizeInner(CancellationToken token, SyncPolicy policy) { token.ThrowIfCancellationRequested(); IList <DatabaseQueries.TrackAndCount> tracks = await Task.Run(() => { using (var db = DatabaseUtility.OpenConnection()) { return((from t in db.GetAllPendingTracks() let trackFilepath = FileNaming.GetDataTrackFilepath(t.TrackId) where File.Exists(trackFilepath) select t).ToList()); } }); if (tracks.Count == 0) { Log.Debug("No files to synchronize"); return(new SyncResult(0, 0)); } token.ThrowIfCancellationRequested(); Log.Debug("{0} tracks queued to synchronize", tracks.Count); Log.Event("Sync.start", new Dictionary <string, string>() { { "policy", policy.ToString() } }); if (policy == SyncPolicy.ForceLast && tracks.Count > 1) { Log.Debug("Constraining upload to most recent file as per policy"); tracks = new DatabaseQueries.TrackAndCount[] { tracks.First() }; } int countUploadedPoints = 0; int countUploadedChunks = 0; foreach (var track in tracks) { token.ThrowIfCancellationRequested(); int pendingPoints = track.DataCount - track.UploadedCount; Log.Debug("Uploading {0}/{1} points from track {2}", pendingPoints, track.DataCount, track.TrackId); try { var reader = new DataReader(track.TrackId); if (!await reader.Skip(track.UploadedCount)) { Log.Error(null, "Cannot advance {0} rows in file for track {1}", track.UploadedCount, track.TrackId); continue; } int currentChunk = 0; while (pendingPoints > 0) { int chunkPoints = Math.Min(ChunkSize, pendingPoints); Log.Debug("Processing chunk {0} with {1} points", currentChunk + 1, chunkPoints); var package = new List <DataPiece>(chunkPoints); for (int p = 0; p < chunkPoints; ++p) { if (!await reader.Advance()) { throw new Exception(string.Format("Cannot read line for {0}th point", p + 1)); } package.Add(new DataPiece { TrackId = track.TrackId, StartTimestamp = new DateTime(reader.Current.StartTicks), EndTimestamp = new DateTime(reader.Current.EndTicks), Ppe = reader.Current.Ppe, PpeX = reader.Current.PpeX, PpeY = reader.Current.PpeY, PpeZ = reader.Current.PpeZ, Latitude = reader.Current.Latitude, Longitude = reader.Current.Longitude, Bearing = reader.Current.Bearing, Accuracy = reader.Current.Accuracy, Vehicle = track.VehicleType, Anchorage = track.AnchorageType, NumberOfPeople = track.NumberOfPeople }); } var secret = Crypto.GenerateSecret(); var secretHash = secret.ToSha512Hash(); var uploadQuery = new UploadDataQuery { Package = package, SecretHash = secretHash }; var response = await uploadQuery.Execute(token); Log.Debug("Points uploaded successfully, chunk {0} for track ID {1}", currentChunk + 1, track.TrackId); //Store record of uploaded chunk using (var db = DatabaseUtility.OpenConnection()) { var record = new TrackUploadRecord { TrackId = track.TrackId, UploadedId = response.UploadedTrackId, Secret = secret, UploadedOn = DateTime.UtcNow, Count = chunkPoints }; db.Insert(record); } pendingPoints -= chunkPoints; currentChunk++; countUploadedPoints += chunkPoints; countUploadedChunks++; } } catch (IOException exIo) { Log.Error(exIo, "File for track {0} not found", track.TrackId); } catch (Exception ex) { Log.Error(ex, "Failed while processing track {0}", track.TrackId); } } return(new SyncResult(countUploadedPoints, countUploadedChunks)); }
/// <summary> /// Runs the synchronization attempt. /// Does not raise exceptions. /// </summary> public async Task <SyncResult> Synchronize(CancellationToken token, SyncPolicy policy = SyncPolicy.Default) { if (DateTime.UtcNow < NextUploadOpportunity && policy == SyncPolicy.Default) { Log.Debug("Can't sync: sync attempt too early, next upload scheduled after {0}", NextUploadOpportunity); return(new SyncResult(new InvalidOperationException("Sync attempt too early"))); } Settings.LastUploadAttempt = DateTime.UtcNow; if (!CheckSyncConditions(policy)) { return(new SyncResult(error: new InvalidOperationException("Sync conditions not met"))); } Log.Debug("Sync attempt started (policy {0})", policy); IsSyncing = true; StatusChanged.Raise(this); try { var ret = await SynchronizeInner(token, policy); Log.Debug("Sync process terminated normally"); Log.Event("Sync.terminate", new Dictionary <string, string>() { { "policy", policy.ToString() } }); if (ret.HasFailed) { UserLog.Add(UserLog.Icon.Error, LogStrings.FileUploadFailure, ret.Error.Message); SyncError.Raise(this, new SyncErrorEventArgs(ret.Error)); } else { if (ret.ChunksUploaded == 1) { UserLog.Add(LogStrings.FileUploadSummarySingular); } else { UserLog.Add(LogStrings.FileUploadSummaryPlural, ret.ChunksUploaded); } } return(ret); } catch (TaskCanceledException) { Log.Debug("Sync process was canceled"); return(new SyncResult(0, 0)); } catch (Exception ex) { Log.Error(ex, "Sync process failed with unforeseen error"); UserLog.Add(UserLog.Icon.Error, LogStrings.FileUploadFailure, ex.Message); return(new SyncResult(error: ex)); } finally { IsSyncing = false; StatusChanged.Raise(this); } }
static int Main() { FoxEventLog.Shutup = true; string dir = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); if (dir.EndsWith("\\") == false) { dir += "\\"; } ProgramAgent.Init(); if (ProgramAgent.LoadDLL() == false) { return(1); } if (SystemInfos.CollectSystemInfo() != 0) { return(1); } if (ApplicationCertificate.LoadCertificate() == false) { FoxEventLog.WriteEventLog("Cannot load certificate", System.Diagnostics.EventLogEntryType.Error); return(1); } if (FilesystemData.LoadCertificates() == false) { return(1); } if (FilesystemData.LoadPolicies() == false) { return(1); } FilesystemData.LoadLocalPackageData(); FilesystemData.LoadLocalPackages(); FilesystemData.LoadUserPackageData(); FilesystemData.LoadEventLogList(); FoxEventLog.Shutup = false; if (SyncPolicy.ApplyPolicy(SyncPolicy.ApplyPolicyFunction.Uninstall) == false) { return(5); } ServiceController svc = new ServiceController("FoxSDCA"); try { svc.Stop(); } catch { } int i = 0; do { i++; if (i > 120 * 4) { break; } svc.Refresh(); Thread.Sleep(1000); } while (svc.Status != ServiceControllerStatus.Stopped); #region Kill Processes foreach (Process proc in Process.GetProcesses()) { try { if (proc.MainModule.FileName.ToLower() == dir.ToLower() + "foxsdc_agent_ui.exe") { proc.Kill(); } } catch { } } foreach (Process proc in Process.GetProcesses()) { try { if (proc.MainModule.FileName.ToLower() == dir.ToLower() + "foxsdc_applyusersettings.exe") { proc.Kill(); } } catch { } } foreach (Process proc in Process.GetProcesses()) { try { if (proc.MainModule.FileName.ToLower() == dir.ToLower() + "foxsdc_agent.exe") { proc.Kill(); } } catch { } } #endregion try { RegistryKey reg = Registry.LocalMachine.OpenSubKey("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run", true); reg.DeleteValue("FoxSDCAgent", false); reg.DeleteValue("FoxSDCAgentApply", false); reg.Close(); } catch { } try { Process.Start(Environment.ExpandEnvironmentVariables("%systemroot%\\system32\\msiexec.exe"), "/x {A6F066EE-E795-4C65-8FE4-2D93AB52BC36} /passive"); } catch { } return(0); }
static int Main(string[] args) { foreach (string arg in args) { if (arg.ToLower() == "-nopackages") { NoPackages = true; } } FoxEventLog.Shutup = true; ProgramAgent.Init(); if (ProgramAgent.LoadDLL() == false) { return(1); } FoxEventLog.Shutup = false; #if !DEBUG List <string> Additionals = new List <string>(); Additionals.Add(Assembly.GetExecutingAssembly().Location); if (ProgramAgent.TestIntegrity(Additionals) == false) { FoxEventLog.WriteEventLog("Apply User settings: Integrity failed!", EventLogEntryType.Error, true); return(1); } #endif FoxEventLog.Shutup = true; if (SystemInfos.CollectSystemInfo() != 0) { return(1); } if (ApplicationCertificate.LoadCertificate() == false) { FoxEventLog.Shutup = false; FoxEventLog.WriteEventLog("Apply User settings: Cannot load certificate", System.Diagnostics.EventLogEntryType.Error); return(1); } FoxEventLog.Shutup = false; if (FilesystemData.LoadCertificates(true) == false) { return(1); } if (FilesystemData.LoadPolicies() == false) { return(1); } FilesystemData.LoadLocalPackageData(); FilesystemData.LoadLocalPackages(); FilesystemData.LoadUserPackageData(); FilesystemData.LoadEventLogList(); SyncPolicy.ApplyPolicy(SyncPolicy.ApplyPolicyFunction.ApplyUser); if (NoPackages == true) { return(0); } string PackagesFolder = SystemInfos.ProgramData + "Packages\\"; if (Directory.Exists(PackagesFolder) == false) { return(2); } foreach (PackagesToInstall pkg in FilesystemData.LocalPackages) { LocalPackageData lpkg = FilesystemData.FindLocalPackageFromListLatest(pkg.PackageID); if (lpkg == null) { continue; } if (pkg.Version != lpkg.Version) { continue; } PackageInstaller inst = new PackageInstaller(); string metafile = PackagesFolder + pkg.MetaFilename; if (File.Exists(metafile) == false) { continue; } string Error; PKGRecieptData Reciept; PKGStatus res; if (inst.InstallPackage(metafile, PackageCertificate.ActivePackageCerts, PackageInstaller.InstallMode.ApplyUserSettingsTest, true, out Error, out res, out Reciept) == false) { FoxEventLog.WriteEventLog("Apply User settings: The Metapackage " + pkg.MetaFilename + " cannot be tested: " + Error, System.Diagnostics.EventLogEntryType.Error); continue; } FoxEventLog.VerboseWriteEventLog("Apply User settings: Applying user settings for " + pkg.MetaFilename, EventLogEntryType.Information); if (inst.ApplyUserSettings(metafile, PackageCertificate.ActivePackageCerts, out Error, out res) == false) { FoxEventLog.WriteEventLog("Apply User settings: The Metapackage " + pkg.MetaFilename + " cannot be used to apply user settings: " + Error, System.Diagnostics.EventLogEntryType.Error); continue; } } if (RegistryData.Verbose == 1) { FoxEventLog.VerboseWriteEventLog("Apply User settings: ApplyUserSettings success for " + Environment.UserDomainName + "\\" + Environment.UserName, EventLogEntryType.Information); } return(0); }