public static void Main(string[] Arguments) { try { Run(Arguments); } catch (Exception exception) { ThreadsafeConsole.WriteLine(exception.GetSummary(true, true), ConsoleColor.Red); } }
private static async Task DecryptAsync(string InputPath) { // Get password from user. // TODO: Hide and confirm password. ThreadsafeConsole.Write("Enter password: "******"Output filename is {outputFilename}."); // Generate key from password (provided by user) and salt (stored in encrypted file). using (var keyDerivation = KeyDerivation.Create(encryptedFileHeader.KeyDerivationAlgorithm, password, encryptedFileHeader.Salt, encryptedFileHeader.KeyDerivationIterations)) { var key = keyDerivation.GetBytes(encryptedFileHeader.KeyLength); ThreadsafeConsole.WriteLine($"Encryption key (derived from password and salt) is {Convert.ToBase64String(key)}."); ThreadsafeConsole.WriteLine($"Cipher initialization vector is {Convert.ToBase64String(encryptedFileHeader.InitializationVector)}."); // Create cipher from key (see above) plus algorithm name and initialization vector (stored in unencrypted header at beginning of encrypted file). // Create decrypting input stream. using (var cipher = Cipher.Create(encryptedFileHeader.CipherAlgorithm)) using (var decryptor = cipher.CreateDecryptor(key, encryptedFileHeader.InitializationVector)) await using (var cryptoStream = new CryptoStream(inputFileStream, decryptor, CryptoStreamMode.Read)) await using (var outputFileStream = File.Open(outputFilename, FileMode.CreateNew, FileAccess.Write, FileShare.None)) { // To limit memory usage, repeatedly read a small block from input stream and write it to the decrypted output stream. var buffer = new byte[cipher.BlockSize]; int bytesRead; while ((bytesRead = await cryptoStream.ReadAsync(buffer, 0, buffer.Length)) > 0) { await outputFileStream.WriteAsync(buffer, 0, bytesRead); } } } } var encryptionDuration = _stopwatch.Elapsed - encryptionStart; ThreadsafeConsole.WriteLine($"Wrote decrypted file to {outputFilename}."); ThreadsafeConsole.WriteLine($"Decryption took {encryptionDuration.TotalSeconds.ToString(_elapsedSecondsFormat)} seconds."); }
public static async Task Main(string[] Arguments) { try { await Run(Arguments); ThreadsafeConsole.WriteLine(null); } catch (Exception exception) { ThreadsafeConsole.WriteLine(exception.GetSummary(true, true), ConsoleColor.Red); } }
// ReSharper disable once SuggestBaseTypeForParameter private static async Task TestReadPerformance(Client NaClient, Region AsRegion) { // Test client performance. Console.WriteLine("Testing performance of North American client."); Console.WriteLine(); Console.Write("Writing sentinel value... "); TimeSpan begin = _stopwatch.Elapsed; await NaClient.WriteValueAsync(_sentinelKey, "Yada, yada, yada"); TimeSpan end = _stopwatch.Elapsed; TimeSpan clientWriteDuration = end - begin; Console.WriteLine("done."); Console.WriteLine($"Wrote sentinel value in {clientWriteDuration.TotalSeconds.ToString(_timeSpanFormat)} seconds."); Console.WriteLine(); Console.Write("Reading sentinel value... "); begin = _stopwatch.Elapsed; string sentinelValue = await NaClient.ReadValueAsync(_sentinelKey); end = _stopwatch.Elapsed; TimeSpan clientReadDuration = end - begin; Console.WriteLine("done."); Console.WriteLine($"Sentinel value = {sentinelValue}."); Console.WriteLine($"Read sentinel value in {clientReadDuration.TotalSeconds.ToString(_timeSpanFormat)} seconds."); Console.WriteLine(); // Compare client read performance to reading from a high-latency connection. Console.WriteLine("Testing performance of connection between Asian node and North American node."); Console.Write("Reading sentinel value... "); begin = _stopwatch.Elapsed; Connection asToNaConnection = AsRegion.Nodes[0].Connections[RegionName.NorthAmerica][0]; sentinelValue = await asToNaConnection.GetValueAsync(_sentinelKey); end = _stopwatch.Elapsed; TimeSpan highLatencyDuration = end - begin; Console.WriteLine("done."); Console.WriteLine($"Sentinel value = {sentinelValue}."); Console.WriteLine($"Read sentinel value in {highLatencyDuration.TotalSeconds.ToString(_timeSpanFormat)} seconds."); Console.WriteLine(); Console.Write("Test result: "); if (clientReadDuration < highLatencyDuration) { ThreadsafeConsole.WriteLine("success.", ConsoleColor.Green); } else { ThreadsafeConsole.WriteLine("failure.", ConsoleColor.Red); } }
public static async Task Main(string[] Arguments) { try { Console.WriteLine(); if (Arguments?.Length != 1) { throw new ArgumentException("Test name not specified."); } await Run(Arguments); } catch (Exception exception) { ThreadsafeConsole.WriteLine(exception.GetSummary(true, true), ConsoleColor.Red); } finally { Console.WriteLine(); } }
public static void Main(string[] Arguments) { try { Console.WriteLine(); if ((Arguments == null) || (Arguments.Length == 0)) { throw new ArgumentException($"{nameof(Arguments)} must specify an integer version.", nameof(Arguments)); } Run(Arguments); } catch (Exception exception) { ThreadsafeConsole.WriteLine(exception.GetSummary(true, true), ConsoleColor.Red); } finally { Console.WriteLine(); } }
private static void PrintSalaries(ITeam Team) { // Sort by salary descending. var teamMembers = Team.GetAllTeamMembers().ToList(); ThreadsafeConsole.WriteLine($"Team Salary Cap = {LeagueRegulations.TeamSalaryCap:C0}."); ThreadsafeConsole.WriteLine(); teamMembers.Sort((TeamMember1, TeamMember2) => TeamMember2.Salary.CompareTo(TeamMember1.Salary)); const string columnSpacer = " "; ThreadsafeConsole.WriteLine($"{"Team Member", -_namePadding}{columnSpacer}{"Salary", _salaryPadding}"); ThreadsafeConsole.WriteLine(new string('=', _namePadding + _salaryPadding + columnSpacer.Length)); foreach (var teamMember in teamMembers) { ThreadsafeConsole.WriteLine($"{teamMember.Name, -_namePadding}{teamMember.Salary, _namePadding:C0}"); } var totalSalaries = teamMembers.Sum(TeamMember => TeamMember.Salary); ThreadsafeConsole.WriteLine(new string('=', _namePadding + _salaryPadding + columnSpacer.Length)); ThreadsafeConsole.WriteLine($"{"Total", -_namePadding}{totalSalaries, _namePadding:C0}"); }
private static void TestSalaryUpdate_23_7() { IBaseballRepo repo = new BaseballRepo(); var cubs1984Team = repo.CreateTeam(); PopulateCubs1984Team(repo, cubs1984Team); PrintSalaries(cubs1984Team); ThreadsafeConsole.WriteLine(); ThreadsafeConsole.WriteLine(); const decimal sandbergIncrease = 7_000_000m; const decimal davisIncrease = 2_000_000m; // ReSharper disable PossibleNullReferenceException cubs1984Team.Players.First(Player => Player.JerseyNumber == 23).Salary += sandbergIncrease; cubs1984Team.Players.First(Player => Player.JerseyNumber == 07).Salary += davisIncrease; ThreadsafeConsole.WriteLine($"Increase Sandberg's salary by {sandbergIncrease:C0}"); ThreadsafeConsole.WriteLine($"Increase Davis' salary by {davisIncrease:C0}"); ThreadsafeConsole.WriteLine(); ThreadsafeConsole.WriteLine(); // ReSharper restore PossibleNullReferenceException PrintSalaries(cubs1984Team); }
private static async Task RunAsync(IReadOnlyList <string> Arguments) { _stopwatch = Stopwatch.StartNew(); var encryptedFileHeader = ParseCommandLine(Arguments); ThreadsafeConsole.WriteLine(); // ReSharper disable once SwitchStatementHandlesSomeKnownEnumValuesWithDefault switch (encryptedFileHeader.Operation) { case Operation.Encrypt: await EncryptAsync(encryptedFileHeader); break; case Operation.Decrypt: await DecryptAsync(encryptedFileHeader.Filename); break; default: throw new ArgumentException($"{encryptedFileHeader.Operation} operation not supported."); } }
// ReSharper disable once SuggestBaseTypeForParameter private static async Task TestEventualConsistency(Client NaClient, Region NaRegion, List <NodeBase> GlobalNodes) { Console.WriteLine("Testing eventual consistency of global nodes."); Console.WriteLine(); Console.Write("Writing sentinel value... "); TimeSpan begin = _stopwatch.Elapsed; await NaClient.WriteValueAsync(_sentinelKey, "Before"); TimeSpan end = _stopwatch.Elapsed; TimeSpan clientWriteDuration = end - begin; Console.WriteLine("done."); Console.WriteLine($"Wrote sentinel value in {clientWriteDuration.TotalSeconds.ToString(_timeSpanFormat)} seconds."); Console.WriteLine(); // Wait for writes to complete globally. Console.Write("Waiting for write to complete globally... "); await Task.Delay(TimeSpan.FromSeconds(1)); Console.WriteLine("done."); Console.WriteLine(); Console.Write("Reading sentinel value... "); begin = _stopwatch.Elapsed; string sentinelValue = await NaClient.ReadValueAsync(_sentinelKey); end = _stopwatch.Elapsed; TimeSpan clientReadDuration = end - begin; Console.WriteLine("done."); Console.WriteLine($"Sentinel value = {sentinelValue}."); Console.WriteLine($"Read sentinel value in {clientReadDuration.TotalSeconds.ToString(_timeSpanFormat)} seconds."); Console.WriteLine(); // Take two regional nodes offline. Console.Write("Taking two (of five) nodes offline... "); NaRegion.Nodes[2].Online = false; NaRegion.Nodes[3].Online = false; Console.WriteLine("done."); Console.WriteLine(); Console.Write("Updating sentinel value... "); begin = _stopwatch.Elapsed; await NaClient.WriteValueAsync(_sentinelKey, "After"); end = _stopwatch.Elapsed; clientWriteDuration = end - begin; Console.WriteLine("done."); Console.WriteLine($"Wrote sentinel value in {clientWriteDuration.TotalSeconds.ToString(_timeSpanFormat)} seconds."); Console.WriteLine(); // Wait for writes to complete globally. Console.Write("Waiting for write to complete globally... "); await Task.Delay(TimeSpan.FromSeconds(1)); Console.WriteLine("done."); Console.WriteLine(); // Examine value of sentinel key in global nodes while two regional nodes are offline. foreach (NodeBase node in GlobalNodes) { Console.WriteLine($"{node.Name} node's {_sentinelKey} = {node.GetValue(_sentinelKey)}."); } Console.WriteLine(); // Bring two offline nodes back online. NaRegion.Nodes[2].Online = true; NaRegion.Nodes[3].Online = true; Console.Write("Triggering read repairs by reading sentinel value again... "); begin = _stopwatch.Elapsed; sentinelValue = await NaClient.ReadValueAsync(_sentinelKey); end = _stopwatch.Elapsed; clientReadDuration = end - begin; Console.WriteLine("done."); Console.WriteLine("Read is done. However, read repairs are in progress."); Console.WriteLine($"Sentinel value = {sentinelValue}."); Console.WriteLine($"Read sentinel value in {clientReadDuration.TotalSeconds.ToString(_timeSpanFormat)} seconds."); Console.WriteLine(); // Examine value of sentinel key in global nodes. All nodes are back online and read repairs are in progress. HashSet <string> nodeValues = new HashSet <string>(); foreach (NodeBase node in GlobalNodes) { string value = node.GetValue(_sentinelKey); if (!nodeValues.Contains(value)) { nodeValues.Add(value); } Console.WriteLine($"{node.Name} node's {_sentinelKey} = {value}."); } Console.WriteLine(); bool consistentDuringReadRepairs = nodeValues.Count == 1; // Wait for read repairs to complete. Console.Write("Waiting for read repairs to complete... "); await Task.Delay(TimeSpan.FromSeconds(1)); Console.WriteLine("done."); Console.WriteLine(); // Examine value of sentinel key in global nodes. All nodes are back online and read repairs are complete. nodeValues.Clear(); foreach (NodeBase node in GlobalNodes) { string value = node.GetValue(_sentinelKey); if (!nodeValues.Contains(value)) { nodeValues.Add(value); } Console.WriteLine($"{node.Name} node's {_sentinelKey} = {value}."); } Console.WriteLine(); bool consistentAfterReadRepairs = nodeValues.Count == 1; bool success = !consistentDuringReadRepairs && consistentAfterReadRepairs; Console.Write("Test result: "); if (success) { ThreadsafeConsole.WriteLine("success.", ConsoleColor.Green); } else { ThreadsafeConsole.WriteLine("failure.", ConsoleColor.Red); } }
// ReSharper disable once SuggestBaseTypeForParameter private static async Task TestFaultTolerance(Client NaClient, Region NaRegion) { Console.WriteLine("Testing fault tolerance of North American nodes."); Console.WriteLine(); Console.Write("Writing sentinel value... "); TimeSpan begin = _stopwatch.Elapsed; await NaClient.WriteValueAsync(_sentinelKey, "Yada, yada, yada"); TimeSpan end = _stopwatch.Elapsed; TimeSpan clientWriteDuration = end - begin; Console.WriteLine("done."); Console.WriteLine($"Wrote sentinel value in {clientWriteDuration.TotalSeconds.ToString(_timeSpanFormat)} seconds."); Console.WriteLine(); Console.Write("Reading sentinel value... "); begin = _stopwatch.Elapsed; string sentinelValue = await NaClient.ReadValueAsync(_sentinelKey); end = _stopwatch.Elapsed; TimeSpan clientReadDuration = end - begin; Console.WriteLine("done."); Console.WriteLine($"Sentinel value = {sentinelValue}."); Console.WriteLine($"Read sentinel value in {clientReadDuration.TotalSeconds.ToString(_timeSpanFormat)} seconds."); Console.WriteLine(); // Take two nodes offline. Expect no service interruption. Console.Write("Taking two (of five) nodes offline... "); NaRegion.Nodes[2].Online = false; NaRegion.Nodes[3].Online = false; Console.WriteLine("done."); Console.Write("Reading sentinel value... "); begin = _stopwatch.Elapsed; sentinelValue = await NaClient.ReadValueAsync(_sentinelKey); end = _stopwatch.Elapsed; clientReadDuration = end - begin; Console.WriteLine("done."); Console.WriteLine($"Sentinel value = {sentinelValue}."); Console.WriteLine($"Read sentinel value in {clientReadDuration.TotalSeconds.ToString(_timeSpanFormat)} seconds."); Console.WriteLine(); // Take a third node offline. Expect service interruption. Console.Write("Taking a third (of five) node offline... "); NaRegion.Nodes[4].Online = false; Console.WriteLine("done."); Console.Write("Reading sentinel value... "); bool success = false; try { begin = _stopwatch.Elapsed; sentinelValue = await NaClient.ReadValueAsync(_sentinelKey); end = _stopwatch.Elapsed; clientReadDuration = end - begin; Console.WriteLine("done."); Console.WriteLine($"Sentinel value = {sentinelValue}."); Console.WriteLine($"Read sentinel value in {clientReadDuration.TotalSeconds.ToString(_timeSpanFormat)} seconds."); Console.WriteLine(); } catch (QuorumNotReachedException exception) { // Expect a QuorumNotReachedException because only two of five nodes are online. success = true; ThreadsafeConsole.WriteLine(exception.GetSummary(true, true), ConsoleColor.Red); } catch (Exception exception) { ThreadsafeConsole.WriteLine(exception.GetSummary(true, true), ConsoleColor.Red); } Console.Write("Test result: "); if (success) { ThreadsafeConsole.WriteLine("success.", ConsoleColor.Green); } else { ThreadsafeConsole.WriteLine("failure.", ConsoleColor.Red); } }
// TODO: Add progress bar. private static async Task EncryptAsync(EncryptedFileHeader EncryptedFileHeader) { const string encryptedFileExtension = ".encrypted"; var inputPathIsFile = File.Exists(EncryptedFileHeader.Filename); if (!inputPathIsFile && !Directory.Exists(EncryptedFileHeader.Filename)) { throw new Exception($"{EncryptedFileHeader.Filename} input path does not exist."); } ThreadsafeConsole.WriteLine(inputPathIsFile ? "InputPath is a file." : "InputPath is a directory."); // TODO: Support encrypting entire directories using System.IO.Compression.ZipFile class. if (!inputPathIsFile) { throw new NotSupportedException("Encrypting directories is not supported."); } // Get password from user. // TODO: Hide and confirm password. ThreadsafeConsole.WriteLine(); ThreadsafeConsole.Write("Enter password: "******"Output filename is {outputFilename}."); var encryptionStart = _stopwatch.Elapsed; await using (var inputFileStream = File.Open(EncryptedFileHeader.Filename, FileMode.Open, FileAccess.Read, FileShare.Read)) await using (var outputFileStream = File.Open(outputFilename, FileMode.CreateNew, FileAccess.Write, FileShare.None)) { // Generate key from password and random salt. using (var random = new RNGCryptoServiceProvider()) { random.GetBytes(EncryptedFileHeader.Salt); } using (var keyDerivation = KeyDerivation.Create(EncryptedFileHeader.KeyDerivationAlgorithm, password, EncryptedFileHeader.Salt, EncryptedFileHeader.KeyDerivationIterations)) using (var cipher = Cipher.Create(EncryptedFileHeader.CipherAlgorithm)) { var key = keyDerivation.GetBytes(EncryptedFileHeader.KeyLength); ThreadsafeConsole.WriteLine($"Encryption key (derived from password and a random salt) is {Convert.ToBase64String(key)}."); // Create cipher and generate initialization vector. // Generate a new initialization vector for each encryption to prevent identical plaintexts from producing identical ciphertexts when encrypted using the same key. cipher.GenerateIV(); EncryptedFileHeader.InitializationVector = new byte[cipher.IV.Length]; cipher.IV.CopyTo(EncryptedFileHeader.InitializationVector, 0); ThreadsafeConsole.WriteLine($"Cipher initialization vector is {Convert.ToBase64String(EncryptedFileHeader.InitializationVector)}."); // Write integer length of encrypted file header followed by the the header bytes. var fileHeaderBytes = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(EncryptedFileHeader)); await outputFileStream.WriteAsync(BitConverter.GetBytes(fileHeaderBytes.Length)); await outputFileStream.WriteAsync(fileHeaderBytes); // Create encrypting output stream. var buffer = new byte[cipher.BlockSize]; using (var encryptor = cipher.CreateEncryptor(key, EncryptedFileHeader.InitializationVector)) await using (var cryptoStream = new CryptoStream(outputFileStream, encryptor, CryptoStreamMode.Write)) { // To limit memory usage, repeatedly read a small block from input stream and write it to the encrypted output stream. int bytesRead; while ((bytesRead = await inputFileStream.ReadAsync(buffer, 0, buffer.Length)) > 0) { await cryptoStream.WriteAsync(buffer, 0, bytesRead); } } } } var encryptionDuration = _stopwatch.Elapsed - encryptionStart; ThreadsafeConsole.WriteLine($"Wrote encrypted file to {outputFilename}."); ThreadsafeConsole.WriteLine($"Encryption took {encryptionDuration.TotalSeconds.ToString(_elapsedSecondsFormat)} seconds."); }