/// <summary> /// This function copies the schemas and geography data off an existing Swarmops installation. Runs in its own thread. /// </summary> public static void InitDatabaseThread() { // Ignore the session object, that method of sharing data didn't work, but a static variable did. _initProgress = 1; _initMessage = "Loading schema from Swarmops servers; creating tables and procs..."; Thread.Sleep(100); try { // Get the schema and initialize the database structures. Requires ADMIN access to database. DatabaseMaintenance.FirstInitialization(); _initProgress = 3; _initMessage = "Applying all post-baseline database schema upgrades..."; DatabaseMaintenance.UpgradeSchemata(); Thread.Sleep(100); _initProgress = 5; _initMessage = "Getting list of countries from Swarmops servers..."; Thread.Sleep(100); // Create translation lists Dictionary <string, int> countryIdTranslation = new Dictionary <string, int>(); // Initialize the root geography (which becomes #1 if everything works) int rootGeographyId = SwarmDb.GetDatabaseForWriting().CreateGeography("[LOC]World", 0); // Get the list of countries GetGeographyData geoDataFetcher = new GetGeographyData(); Country[] countries = geoDataFetcher.GetCountries(); _initProgress = 7; _initMessage = "Creating all countries on local server..."; Thread.Sleep(100); int count = 0; int total = countries.Length; // Create all countries in our own database foreach (Country country in countries) { countryIdTranslation[country.Code] = SwarmDb.GetDatabaseForWriting().CreateCountry(country.Name, country.Code, country.Culture, rootGeographyId, country.PostalCodeLength, string.Empty); count++; _initMessage = String.Format("Creating all countries on local server... ({0}%)", count * 100 / total); } _initProgress = 10; // Construct list of countries that have geographic data List <string> initializableCountries = new List <string>(); foreach (Country country in countries) { if (country.GeographyId != 1) { initializableCountries.Add(country.Code); } } float initStepPerCountry = 90f / initializableCountries.Count; int countryCount = 0; // For each country... foreach (string countryCode in initializableCountries) { // Get the geography layout _initMessage = "Initializing geography for country " + countryCode + "... "; Thread.Sleep(100); GeographyUpdate.PrimeCountry(countryCode); GuidCache.Set("DbInitProgress", string.Empty); countryCount++; _initProgress = 10 + (int)(countryCount * initStepPerCountry); } // Set Geography at baseline (TODO: Ask for what baseline we got) Persistence.Key["LastGeographyUpdateId"] = "0"; Persistence.Key["LastGeographyUpdate"] = "1900-01-01"; // Set an installation ID Persistence.Key["SwarmopsInstallationId"] = Guid.NewGuid().ToString(); _initMessage = "Initializing currencies..."; // Create initial currencies (European et al) Currency.Create("EUR", "Euros", "€"); Currency.Create("USD", "US Dollars", "$"); Currency.Create("CAD", "Canadian Dollars", "CA$"); Currency.Create("SEK", "Swedish Krona", string.Empty); Currency.Create("NOK", "Norwegian Krona", string.Empty); Currency.Create("DKK", "Danish Krona", string.Empty); Currency.Create("ISK", "Icelandic Krona", string.Empty); Currency.Create("CHF", "Swiss Franc", string.Empty); Currency.Create("GBP", "Pounds Sterling", "£"); Currency.Create("BTC", "Bitcoin", "฿"); // Fetch the first set of exchange rates, completing the currency collection ExchangeRateSnapshot.Create(); // Create the sandbox Organization.Create(0, "Sandbox", "Sandbox", "Sandbox", "swarmops.com", "Ops", rootGeographyId, true, true, 0).EnableEconomy(Currency.FromCode("EUR")); _initProgress = 100; _initMessage = "Complete."; } catch (Exception failedException) { // Use initMessage to push info about what went wrong to the user _initMessage = failedException.ToString(); } Thread.Sleep(1000); // give some time for static var to stick and web interface to react before killing thread }
/// <summary> /// This function copies the schemas and geography data off an existing Swarmops installation. Runs in its own thread. /// </summary> public static void InitDatabaseThread() { // Ignore the session object, that method of sharing data didn't work, but a static variable did. _initProgress = 1; _initMessage = "Loading schema from Swarmops servers; creating tables and procs..."; Thread.Sleep(100); try { // Get the schema and initialize the database structures. Requires ADMIN access to database. DatabaseMaintenance.FirstInitialization(); _initProgress = 3; _initMessage = "Applying all post-baseline database schema upgrades..."; DatabaseMaintenance.UpgradeSchemata(); Thread.Sleep(100); // SECURITY: With schemata to hold them in place, initialize the encryption keys Authentication.InitializeSymmetricDatabaseKey(); Authentication.InitializeSymmetricFileSystemKey(); // Set Geography at baseline (TODO: Ask for what baseline we got) Persistence.Key["LastGeographyUpdateId"] = "0"; Persistence.Key["LastGeographyUpdate"] = Constants.DateTimeLow.ToString("yyyy-MM-dd"); // Set an installation ID // Doubles as start signal to daemons (if installation ID exists, db is ready for processing) Persistence.Key["SwarmopsInstallationId"] = Guid.NewGuid().ToString(); _initProgress = 4; _initMessage = "Initializing currencies..."; // Create initial currencies (European et al) Currency.CreateFiat("EUR", "Euros", "€"); Currency.CreateFiat("USD", "US Dollars", "$"); Currency.CreateFiat("CAD", "Canadian Dollars", "CA$"); Currency.CreateFiat("SEK", "Swedish Krona", string.Empty); Currency.CreateFiat("NOK", "Norwegian Krona", string.Empty); Currency.CreateFiat("DKK", "Danish Krona", string.Empty); Currency.CreateFiat("ISK", "Icelandic Krona", string.Empty); Currency.CreateFiat("CHF", "Swiss Franc", string.Empty); Currency.CreateFiat("GBP", "Pounds Sterling", "£"); Currency.CreateCrypto("BTC", "Bitcoin Core", "฿"); Currency.CreateCrypto("BCH", "Bitcoin Cash", "฿"); // Fetch the first set of exchange rates, completing the currency collection ExchangeRateSnapshot.Create(); // Disable SSL required - the user must turn this on manually SystemSettings.RequireSsl = false; _initProgress = 5; _initMessage = "Getting list of countries from Swarmops servers..."; Thread.Sleep(100); // Create translation lists Dictionary <string, int> countryIdTranslation = new Dictionary <string, int>(); // Initialize the root geography (which becomes #1 if everything works) int rootGeographyId = SwarmDb.GetDatabaseForWriting().CreateGeography("[LOC]World", 0); // Create the sandbox Organization sandbox = Organization.Create(0, "Sandbox", "Sandbox", "Sandbox", "swarmops.com", "Ops", rootGeographyId, true, true, 0); sandbox.EnableEconomy(Currency.FromCode("EUR")); Positions.CreateOrganizationDefaultPositions(sandbox); // Get the list of countries GetGeographyData geoDataFetcher = new GetGeographyData(); Country[] countries = null; _initProgress = 7; _initMessage = "Creating all countries on local server..."; Thread.Sleep(100); int count = 0; int countryRetries = 0; try { countries = geoDataFetcher.GetCountries(); } catch (Exception) { // ignore for now, retrying below } while (++countryRetries < 10 && (countries == null || countries.Length < 20)) { _initMessage = "Network problem, retrying... "; if (countryRetries > 1) { _initMessage += String.Format("({0})", countryRetries); } Thread.Sleep(500); try { countries = geoDataFetcher.GetCountries(); } catch (Exception) { if (countryRetries > 8) { throw; } // otherwise ignore for now } } int total = countries.Length; // Create all countries in our own database foreach (Country country in countries) { countryIdTranslation[country.Code] = SwarmDb.GetDatabaseForWriting().CreateCountry(country.Name, country.Code, country.Culture, rootGeographyId, country.PostalCodeLength, string.Empty); count++; _initMessage = String.Format("Creating all countries on local server... ({0}%)", count * 100 / total); } _initProgress = 10; // Construct list of countries that have geographic data List <string> initializableCountries = new List <string>(); foreach (Country country in countries) { if (country.GeographyId != 1) { initializableCountries.Add(country.Code); } } float initStepPerCountry = 90f / initializableCountries.Count; int countryCount = 0; // For each country... foreach (string countryCode in initializableCountries) { // Get the geography layout _initMessage = "Initializing geography for country " + countryCode + "... "; Thread.Sleep(100); GeographyUpdate.PrimeCountry(countryCode); GuidCache.Set("DbInitProgress", string.Empty); countryCount++; _initProgress = 10 + (int)(countryCount * initStepPerCountry); } _initProgress = 100; _initMessage = "Complete."; } catch (Exception failedException) { // Use initMessage to push info about what went wrong to the user _initMessage = failedException.ToString(); } Thread.Sleep(1000); // give some time for static var to stick and web interface to react before killing thread }
private static void OnMidnight() { try { BotLog.Write(0, "MainCycle", "Midnight entry"); try { if (!testMode) { /*TestTrace("Running RosterHousekeeping.ChurnExpiredMembers()..."); * RosterHousekeeping.ChurnExpiredMembers(); * TestTrace(" done.\r\n");*/ } ExchangeRateSnapshot.Create(); } catch (Exception e) { TraceAndReport(e); } try { /*TestTrace("Running InternalPollMaintenance.Run()..."); * InternalPollMaintenance.Run(); * TestTrace(" done.\r\n");*/ } catch (Exception e) { TraceAndReport(e); } try { /*TestTrace("Running SwedishForumMemberCheck.Run()..."); * SwedishForumMemberCheck.Run(); * TestTrace(" done.\r\n");*/ } catch (Exception e) { TraceAndReport(e); } try { /*TestTrace("Running SalaryProcessor.Run()..."); * SalaryProcessor.Run(); * TestTrace(" done.\r\n");*/ } catch (Exception e) { TraceAndReport(e); } try { /*TestTrace("Running TurnaroundTracker.Housekeeping()..."); * TurnaroundTracker.Housekeeping(); * TestTrace(" done.\r\n");*/ } catch (Exception e) { TraceAndReport(e); } try { /*TestTrace("Running Mappery.CreateUngPiratUptakeMap()..."); * Mappery.CreateUngPiratUptakeMap(); * TestTrace(" done.\r\n");*/ } catch (Exception e) { TraceAndReport(e); } try { /*TestTrace("Running RosterHousekeeping.TimeoutVolunteers()..."); * RosterHousekeeping.TimeoutVolunteers(); * TestTrace(" done.\r\n");*/ } catch (Exception e) { TraceAndReport(e); } BotLog.Write(0, "MainCycle", "Midnight exit"); } catch (Exception e) { ExceptionMail.Send(e, true); TestTrace(e.ToString()); } }
private static void Main(string[] args) { // Are we running yet? if (!SystemSettings.DatabaseInitialized) { // will restart the service every 15s until db initialized on OOBE // also, the read of DatabaseInitialized can and will fail if // we're not initalized enough to even have a database throw new InvalidOperationException(); } // Checking for schemata upgrade first of all, after seeing that db exists int startupDbVersion = Database.SwarmDb.DbVersion; DatabaseMaintenance.UpgradeSchemata(); testMode = false; SystemSettings.BackendHostname = Dns.GetHostName(); // Force TLS 1.2 (why do I need to do this? The framework should enforce this) ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12; // Other one-time initializations FinancialTransactions.FixAllUnsequenced(); SupportFunctions.OperatingTopology = OperatingTopology.Backend; // Begin main loop UnixSignal[] killSignals = null; if (!Debugger.IsAttached) { killSignals = new UnixSignal[] { new UnixSignal(Signum.SIGINT), new UnixSignal(Signum.SIGTERM) }; } BotLog.Write(0, "MainCycle", string.Empty); BotLog.Write(0, "MainCycle", "-----------------------------------------------"); BotLog.Write(0, "MainCycle", string.Empty); if (args.Length > 0) { if (args[0].ToLower() == "test") { BotLog.Write(0, "MainCycle", "Running self-tests"); testMode = true; Console.WriteLine("Testing All Maintenance Processes (except membership-changing ones)."); Console.WriteLine("\r\n10-second intervals:"); OnEveryTenSeconds(); Console.WriteLine("\r\nEvery minute:"); OnEveryMinute(); Console.WriteLine("\r\nEvery five minutes:"); OnEveryFiveMinutes(); Console.WriteLine("\r\nEvery hour:"); OnEveryHour(); Console.WriteLine("\r\nNoon:"); OnNoon(); Console.WriteLine("\r\nMidnight:"); OnMidnight(); Console.WriteLine("\r\nMonday Morning:"); OnMondayMorning(); Console.WriteLine("\r\nTesting database access..."); Console.WriteLine(SwarmDb.GetDatabaseForReading().GetPerson(1).Name); Console.WriteLine(SwarmDb.GetDatabaseForReading().GetPerson(1).PasswordHash); Console.WriteLine("Creating OutboundComm..."); OutboundComm.CreateNotification(null, NotificationResource.System_Startup_Backend); Console.WriteLine("Transmitting..."); OutboundComms comms = OutboundComms.GetOpen(); Console.WriteLine("{0} open items in outbound comms.", comms.Count); foreach (OutboundComm comm in comms) { if (comm.TransmitterClass != "Swarmops.Utility.Communications.CommsTransmitterMail") { throw new NotImplementedException(); } ICommsTransmitter transmitter = new CommsTransmitterMail(); OutboundCommRecipients recipients = comm.Recipients; PayloadEnvelope envelope = PayloadEnvelope.FromXml(comm.PayloadXml); foreach (OutboundCommRecipient recipient in recipients) { transmitter.Transmit(envelope, recipient.Person); } } Console.Write("\r\nAll tests run. Waiting for mail queue to flush... "); while (!MailTransmitter.CanExit) { Thread.Sleep(50); } Console.WriteLine("done."); BotLog.Write(0, "MainCycle", "Exiting self-tests"); return; } if (args[0].ToLower() == "console") { Console.WriteLine("\r\nRunning Swarmops-Backend in ONE OFF CONSOLE mode.\r\n"); // ------------------------------------------------------------------------------------- // ------------------------------------------------------------------------------------- // ------------------------------------------------------------------------------------- // ----------------------- INSERT ANY ONE-OFF ACTIONS HERE ------------------------- // ------------------------------------------------------------------------------------- Console.Write("\r\nWaiting for mail queue to flush... "); while (!MailTransmitter.CanExit) { Thread.Sleep(50); } Console.WriteLine("done."); return; } if (args[0].ToLowerInvariant() == "pdfregen") { if (args.Length > 1) { int docId = Int32.Parse(args[1]); PdfProcessor.Rerasterize(Document.FromIdentity(docId)); } else { Console.WriteLine("Regenerating all bitmaps from PDF uploads."); //PdfProcessor.RerasterizeAll(); Console.WriteLine("Done."); } return; } if (args[0].ToLower() == "rsm") { Console.WriteLine("Testing character encoding: räksmörgås RÄKSMÖRGÅS"); return; } if (args[0].ToLower() == "update-currencies") { Console.WriteLine("Updating currencies and exiting"); ExchangeRateSnapshot.Create(); return; } } /* * MailMessage message = new MailMessage(); * message.From = new MailAddress(Strings.MailSenderAddress, Strings.MailSenderName); * message.To.Add (new MailAddress ("*****@*****.**", "Rick Falkvinge (Piratpartiet)")); * message.Subject = "Räksmörgåsarnas ékÖNÖMÏåvdëlnïng"; * message.Body = "Hejsan hoppsan Räksmörgåsar."; * message.BodyEncoding = Encoding.Default; * message.SubjectEncoding = Encoding.Default; * * SmtpClient smtpClient = new SmtpClient ("localhost"); * smtpClient.Credentials = null; // mono bug * smtpClient.Send (message);*/ Console.WriteLine(" * Swarmops Backend starting"); BotLog.Write(0, "MainCycle", "Backend STARTING"); // Disable certificate checking due to Mono not installing with a certificate repository - this is UTTERLY broken SupportFunctions.DisableSslCertificateChecks(); // MONO BUG/MISFEATURE: Mono has no root certificates, so can't verify cert // Tell sysop we're starting OutboundComm.CreateNotification(null, NotificationResource.System_Startup_Backend); // Check for existence of installation ID. If not, create one. Warning: has privacy implications when communicated. if (Persistence.Key["SwarmopsInstallationId"] == string.Empty) { Persistence.Key["SwarmopsInstallationId"] = Guid.NewGuid().ToString(); } // Check for existence of bitcoin hotwallet root BitcoinUtility.VerifyBitcoinHotWallet(); // Initialize backend socket server int backendSocketPort = SystemSettings.WebsocketPortBackend; _socketServer = new WebSocketServer(backendSocketPort); _socketServer.AddWebSocketService <BackendServices>("/Backend"); _socketServer.Start(); // Initialize socket client to Blockchain.Info (pending our own services) using ( _blockChainInfoSocket = new WebSocket("ws://ws.blockchain.info/inv?api_code=" + SystemSettings.BlockchainSwarmopsApiKey)) { // Begin maintenance loop DateTime cycleStartTime = DateTime.UtcNow; DateTime cycleEndTime; int lastSecond = cycleStartTime.Second; int lastMinute = cycleStartTime.Minute; int lastHour = cycleStartTime.Hour; bool exitFlag = false; _blockChainInfoSocket.OnOpen += new EventHandler(OnBlockchainOpen); _blockChainInfoSocket.OnError += new EventHandler <ErrorEventArgs>(OnBlockchainError); _blockChainInfoSocket.OnClose += new EventHandler <CloseEventArgs>(OnBlockchainClose); _blockChainInfoSocket.OnMessage += new EventHandler <MessageEventArgs>(OnBlockchainMessage); _blockChainInfoSocket.Connect(); while (!exitFlag) // exit is handled by signals handling at end of loop { BotLog.Write(0, "MainCycle", "Cycle Start"); cycleStartTime = DateTime.UtcNow; cycleEndTime = cycleStartTime.AddSeconds(10); try { OnEveryTenSeconds(); if (cycleStartTime.Second < lastSecond) { OnEveryMinute(); if (cycleStartTime.Minute % 5 == 0) { OnEveryFiveMinutes(); } } if (cycleStartTime.Minute < lastMinute) { OnEveryHour(); if (DateTime.Now.Hour == 10 && DateTime.Today.DayOfWeek == DayOfWeek.Tuesday) { OnTuesdayMorning(); } if (DateTime.Now.Hour == 7 && DateTime.Today.DayOfWeek == DayOfWeek.Monday) { OnMondayMorning(); } } if (cycleStartTime.Hour >= 12 && lastHour < 12) { OnNoon(); } if (cycleStartTime.Hour < lastHour) { OnMidnight(); } } catch (Exception e) { // Note each "OnEvery..." catches its own errors and sends Exception mails, // so that failure in one should not stop the others from running. This particular // code should never run. ExceptionMail.Send(new Exception("Failed in swarmops-backend main loop", e), true); } lastSecond = cycleStartTime.Second; lastMinute = cycleStartTime.Minute; lastHour = cycleStartTime.Hour; // Wait for a maximum of ten seconds (the difference between cycleStartTime and cycleEndTime) int iterationCount = 0; DateTime utcNow = DateTime.UtcNow; while (utcNow < cycleEndTime && !exitFlag) { int signalIndex = 250; // Handle important service orders (those that can't be lost in a random loss // of connection of a socket): BackendServiceOrders backendOrders = BackendServiceOrders.GetNextBatch(5); backendOrders.Execute(); // takes at most 250ms per BSO reqs // Block until a SIGINT or SIGTERM signal is generated, or 1/4 second has passed. // However, we can't do that in a development environment - it won't have the // Mono.Posix assembly, and won't understand UnixSignals. So people running this in // a dev environment will need to stop it manually. if (!Debugger.IsAttached) { signalIndex = UnixSignal.WaitAny(killSignals, 250); } else { TimeSpan timeLeft = (cycleEndTime - utcNow); BotLog.Write(0, "MainCycle Debug", string.Format(CultureInfo.InvariantCulture, "Waiting for {0:F2} more seconds for cycle end", timeLeft.TotalMilliseconds / 1000.0)); Thread.Sleep(250); } if (signalIndex < 250) { exitFlag = true; Console.WriteLine("Caught signal " + killSignals[signalIndex].Signum + ", exiting"); BotLog.Write(0, "MainCycle", "EXIT SIGNAL (" + killSignals[signalIndex].Signum + "), terminating backend"); } utcNow = DateTime.UtcNow; // Every second, send an internal heartbeat if (iterationCount++ % 4 == 0) { InternalHeartbeat(); } } } } Console.WriteLine(" * Swarmops Backend stopping"); BotLog.Write(0, "MainCycle", "BACKEND EXITING, sending backend-termination notices"); /* * if (HeartBeater.Instance.WasKilled) * { * // removed unconditional delete, cron job that restarts bot uses it to know that it is intentionally down. * ExceptionMail.Send(new Exception("HeartBeater triggered restart of Swarmops Backend. Will commence after 800 seconds."), false); * }*/ BotLog.Write(0, "MainCycle", "...done"); /* * while (!MailTransmitter.CanExit) * { * System.Threading.Thread.Sleep(50); * }*/ _socketServer.Stop(); Thread.Sleep(2000); }