static async Task Main(string[] args) { try { GetSettings(args); // Output start. WriteLine("*** PolyDeploy Client ***"); WriteLine(); // Do we have a target uri. if (Options.TargetUri.Equals(string.Empty)) { throw new ArgumentException("No target uri has been set."); } // Do we have an api key? if (Options.APIKey.Equals(string.Empty)) { throw new ArgumentException("No api key has been set."); } // Do we have an encryption key? if (Options.EncryptionKey.Equals(string.Empty)) { throw new ArgumentException("No encryption key has been set."); } // Output identifying module archives. WriteLine("Identifying module archives..."); // Read zip files in current directory. string currentDirectory = Directory.GetCurrentDirectory(); List <string> zipFiles = new List <string>(Directory.GetFiles(currentDirectory, "*.zip")); // Is there something to do? if (zipFiles.Count <= 0) { // No, exit. WriteLine("No module archives found."); WriteLine("Exiting."); ReadLine(); Environment.Exit((int)ExitCode.NoModulesFound); } // Inform user of modules found. WriteLine(string.Format("Found {0} module archives in {1}:", zipFiles.Count, currentDirectory)); foreach (string zipFile in zipFiles) { WriteLine(string.Format("\t{0}. {1}", zipFiles.IndexOf(zipFile) + 1, Path.GetFileName(zipFile))); } WriteLine(); if (!Options.NoPrompt) { // Prompt to continue. WriteLine("Would you like to continue? (y/n)"); // Continue? if (!Confirm()) { // No, exit. WriteLine("Exiting."); Environment.Exit((int)ExitCode.UserExit); } WriteLine(); } // Get a session. string sessionGuid = await API.CreateSessionAsync(); WriteLine(string.Format("Got session: {0}", sessionGuid)); DateTime startTime = DateTime.Now; // Inform user of encryption. WriteLine("Starting encryption and upload..."); TimeSpan interval = TimeSpan.FromSeconds(2); DateTime apiNotFoundAbortTime = DateTime.Now.AddSeconds(Options.InstallationStatusTimeout); foreach (string zipFile in zipFiles) { using (FileStream fs = new FileStream(zipFile, FileMode.Open)) { WriteLine(string.Format("\t{0}", Path.GetFileName(zipFile))); Write("\t\t...encrypting..."); using (Stream es = Crypto.Encrypt(fs, Options.EncryptionKey)) { Write("uploading..."); var success = false; do { try { await API.AddPackageAsync(sessionGuid, es, Path.GetFileName(zipFile)); success = true; } catch { // Api is returning a 404 - wait and try again System.Threading.Thread.Sleep(interval); Write("error...retrying..."); } } while (!success && DateTime.Now < apiNotFoundAbortTime); } WriteLine("done."); } } WriteLine(string.Format("Finished encryption and upload in {0} ms.", (DateTime.Now - startTime).TotalMilliseconds)); WriteLine(); WriteLine("Starting installation..."); DateTime installStartTime = DateTime.Now; JavaScriptSerializer jsonSer = new JavaScriptSerializer(); // Start. (bool installSuccess, SortedList <string, dynamic> results) = await API.InstallAsync(sessionGuid); if (!installSuccess) { Dictionary <string, dynamic> response; var successfullyReachedApi = false; apiNotFoundAbortTime = DateTime.Now.AddSeconds(Options.InstallationStatusTimeout); // Attempt to get the status of the session from the remote api. // This can fail shortly after an installation as the api has not yet been initialised, // so attempt to get it for the given timespan. do { // Get whether we can reach the api (bool getSessionSuccess, Dictionary <string, dynamic> getSessionResponse) = await API.GetSessionAsync(sessionGuid); successfullyReachedApi = getSessionSuccess; response = getSessionResponse; if (!successfullyReachedApi) { // Api is returning a 404 - wait and try again System.Threading.Thread.Sleep(interval); } } while (!successfullyReachedApi && DateTime.Now < apiNotFoundAbortTime); // If the api couldn't be reached by the given time, something has gone wrong if (!successfullyReachedApi) { throw new HttpException("Remote API returned status 404"); } int status = -1; string previousPrint = null; DateTime abortTime = DateTime.Now.AddMinutes(10); // Get the installation status from the API until it is complete or until the abort time is reached do { if (response.ContainsKey("Status")) { // Yes, get the status. status = response["Status"]; } // Is there a response key? if (response.ContainsKey("Response")) { // Yes, get the response. results = jsonSer.Deserialize <SortedList <string, dynamic> >(response["Response"]); } // As long as we have something. if (status != -1 && results != null) { // Build feedback. string print = BuildUpdateString(results); // Same as previous feedback? if (print != previousPrint) { WriteLine(print); previousPrint = print; } } // Is finished? if (status == 2) { break; } System.Threading.Thread.Sleep(interval); (bool success, Dictionary <string, dynamic> getSessionResponse) = await API.GetSessionAsync(sessionGuid); response = getSessionResponse; // The api should not be returning a 404 status at this point if (!success) { throw new HttpException("Remote API returned status 404"); } } while (status < 2 && DateTime.Now < abortTime); } else { // Build feedback. string print = BuildUpdateString(results); // Print feedback. WriteLine(print); } // Finished install. WriteLine(string.Format("Finished installation in {0} ms.", (DateTime.Now - installStartTime).TotalMilliseconds)); ReadLine(); int succeeded = ParseResults(results).succeeded; bool allSucceeded = succeeded == results.Count; ExitCode exitCode = allSucceeded ? ExitCode.Success : ExitCode.InstallFailure; Environment.Exit((int)exitCode); } catch (Exception ex) { // Output exception message and stack trace. WriteLine(string.Format("Exception caught at: {0}.", DateTime.Now.ToString())); WriteException(ex); ReadLine(); Environment.Exit((int)ExitCode.Error); } }