コード例 #1
0
// Start library.
// Can be called multiple times during the lifetime of the app
void bibledit_start_library ()
{
  // Repeating start guard.
  if (bibledit_started) return;
  bibledit_started = true;

  // Setup server behaviour.
#ifdef HAVE_CLIENT
  config_globals_client_prepared = true;
#else
  config_globals_client_prepared = false;
#endif
  if (config_logic_demo_enabled ()) {
    config_globals_open_installation = true;
  }
  
  // Ignore SIGPIPE signal on Linux: When the browser cancels the request, it won't kill Bibledit.
  // On Windows, this is not needed.
#ifndef HAVE_WINDOWS
  signal (SIGPIPE, SIG_IGN);
#endif
  
  // Set running flag.
  config_globals_webserver_running = true;
  
  // Whether the plain http server redirects to secure http.
  config_globals_enforce_https_browser = config_logic_enforce_https_browser ();
  config_globals_enforce_https_client = config_logic_enforce_https_client ();
  
  // Run the plain web server in a thread.
  config_globals_http_worker = new thread (http_server);

  // Run the secure web server in a thread.
  config_globals_https_worker = new thread (https_server);
  
  // Run the timers in a thread.
  config_globals_timer = new thread (timer_index);
  
  // Client should sync right after wake up.
  sendreceive_queue_startup ();
}
コード例 #2
0
ファイル: index.cpp プロジェクト: alerque/bibledit
void timer_index ()
{
  bool client = client_logic_client_enabled ();
  int previous_second = -1;
  int previous_minute = -1;
  int previous_fraction = -1;
  while (config_globals_running) {

    try {

      // Wait shortly.
      this_thread::sleep_for (chrono::milliseconds (100));
      
      // Wait tilll the data structures have been initialized.
      if (!config_globals_data_initialized) continue;
      
      // The current time, localized.
      int seconds_since_epoch = filter_date_seconds_since_epoch ();
      int local_seconds = filter_date_local_seconds (seconds_since_epoch);
      int second = filter_date_numerical_second (local_seconds);
      int minute = filter_date_numerical_minute (local_seconds);
      int hour = filter_date_numerical_hour (local_seconds);
      int weekday = filter_date_numerical_week_day (local_seconds);
      
      // Run once per second.
      if (second == previous_second) continue;
      previous_second = second;

      // Every second: Deal with queued and/or active tasks.
      tasks_run_check ();
      
      // Run the part below every so many seconds.
      int fraction = second / 5;
      if (fraction != previous_fraction) {
        previous_fraction = fraction;
      }
      
      // Run the part below once per minute.
      if (minute == previous_minute) continue;
      previous_minute = minute;
      
      // Every minute send out queued email, except in client mode.
      if (!client) tasks_logic_queue (SENDEMAIL);

      // Check for new mail every five minutes.
      // Do not check more often with gmail else the account may be shut down.
      if ((!client) && ((minute % 5) == 0)) {
        tasks_logic_queue (RECEIVEEMAIL);
      }

      // At the nineth minute after every full hour rotate the journal.
      // The nine is chosen, because the journal rotation will summarize the send/receive messages.
      // In case send/receive happens every five minutes, it is expected that under normal circumstances
      // the whole process of sending/receivning will be over, so summarization can then be done.
      if (minute == 9) tasks_logic_queue (ROTATEJOURNAL);
      
      // Client sends/receives Bibles and Consultation.
      sendreceive_queue_sync (minute);
      
      // Sending and receiving Bibles to and from the git repository.
      // On a production website running on an inexpensive virtual private server
      // with 512 Mbyte of memory and a fast network connection,
      // sending and receiving two Bibles takes more than 15 minutes when there are many changes.
      bool sendreceive = ((hour == 0) && (minute == 5));
      bool repeat = ((minute % 5) == 0);
      if (sendreceive || repeat) {
        sendreceive_queue_all (sendreceive);
      }
      
      // Deal with the changes in the Bible made per user.
      // Deal with notifications for the daily changes in the Bibles.
      // This takes a few minutes on a production machine with two Bibles and changes in several chapters.
      // It runs in a server configuration, not on a client.
      if (!client) {
        if ((hour == 0) && (minute == 20)) {
          changes_logic_start ();
        }
      }

      // Run the checks on the Bibles.
      // This takes 15 minutes on a production machine with two Bibles.
      if (!client) {
        if ((hour == 0) && (minute == 30)) {
          checks_logic_start_all ();
        }
      }
      
      // Database maintenance and trimming.
      // It takes a few minutes on a production machine.
      if ((hour == 0) && (minute == 50)) {
        tasks_logic_queue (MAINTAINDATABASE);
      }
      
      // Export the Bibles to the various output formats.
      // This may take an hour on a production machine.
      // This hour was in PHP. In C++ it is much faster.
      if (!client) {
        if ((hour == 1) && (minute == 10)) {
          Export_Logic::scheduleAll ();
        }
      }
      
      // Delete temporal files older than a few days.
      if ((hour == 2) && (minute == 0)) {
        tasks_logic_queue (CLEANTMPFILES);
      }
      
      // Re-index Bibles and notes.
      // Only update missing indexes.
      if ((hour == 2) && (minute == 0)) {
        Database_State::create ();
        Database_Config_General::setIndexBibles (true);
        tasks_logic_queue (REINDEXBIBLES);
        Database_Config_General::setIndexNotes (true);
        tasks_logic_queue (REINDEXNOTES);
      }
      
      // Actions for a demo installation.
      if (minute == 10) {
        if (config_logic_demo_enabled ()) {
          tasks_logic_queue (CLEANDEMO);
        }
      }
      
      // Sprint burndown.
      // It runs every hour in the Cloud.
      // The script itself determines what to do at which hour of the day or day of the week or day of the month.
      if (!client) {
        if (minute == 5) {
          tasks_logic_queue (SPRINTBURNDOWN);
        }
      }

      // Quit at midnight if flag is set.
      if (config_globals_quit_at_midnight) {
        if (hour == 0) {
          if (minute == 1) {
            if (!Database_Config_General::getJustStarted ()) {
              if (tasks_run_active_count ()) {
                Database_Logs::log ("Server is due to restart itself but does not because of active jobs");
              } else {
                Database_Logs::log ("Server restarts itself");
                exit (0);
              }
            }
          }
          // Clear flag in preparation of restart next minute.
          // This flag also has the purpose of ensuring the server restarts once during that minute,
          // rather than restarting repeatedly many times during that minute.
          if (minute == 0) {
            Database_Config_General::setJustStarted (false);
          }
        }
      }
      
      // Email notes statistics to the users.
      if (!client) {
        if ((hour == 3) && (minute == 0)) {
          tasks_logic_queue (NOTESSTATISTICS);
        }
      }

      // Update SWORD stuff once a week.
      if (weekday == 1) {
        // Refresh module list.
        if ((!client) && (hour == 3) && (minute == 5)) {
          tasks_logic_queue (REFRESHSWORDMODULES);
        }
        // Update installed SWORD modules, shortly after the module list has been refreshed.
        if ((!client) && (hour == 3) && (minute == 15)) {
          tasks_logic_queue (UPDATESWORDMODULES);
        }
      }
      
      // The Cloud updates the list of USFM resources once a week.
      if (weekday == 1) {
        if ((!client) && (hour == 3) && (minute == 10)) {
          tasks_logic_queue (LISTUSFMRESOURCES);
        }
      }
      

    } catch (exception & e) {
      Database_Logs::log (e.what ());
    } catch (exception * e) {
      Database_Logs::log (e->what ());
    } catch (...) {
      Database_Logs::log ("A general internal error occurred in the timers");
    }

  }
}
コード例 #3
0
ファイル: manage.cpp プロジェクト: alerque/bibledit
string bible_manage (void * webserver_request)
{
  Webserver_Request * request = (Webserver_Request *) webserver_request;
  
  string page;
  
  Assets_Header header = Assets_Header (translate("Bibles"), webserver_request);
  header.addBreadCrumb (menu_logic_settings_menu (), menu_logic_settings_text ());
  page = header.run ();
  
  Assets_View view;
  
  string success_message;
  string error_message;
  
  // New Bible handler.
  if (request->query.count ("new")) {
    Dialog_Entry dialog_entry = Dialog_Entry ("manage", translate("Please enter a name for the new empty Bible"), "", "new", "");
    page += dialog_entry.run ();
    return page;
  }
  if (request->post.count ("new")) {
    string bible = request->post ["entry"];
    vector <string> bibles = request->database_bibles ()->getBibles ();
    if (find (bibles.begin(), bibles.end(), bible) != bibles.end()) {
      error_message = translate("This Bible already exists");
    } else {
      request->database_bibles ()->createBible (bible);
      // Check / grant access.
      if (!access_bible_write (request, bible)) {
        string me = request->session_logic ()->currentUser ();
        Database_Privileges::setBible (me, bible, true);
      }
      success_message = translate("The Bible was created");
      // Creating a Bible removes any Sample Bible that might have been there.
      if (!config_logic_demo_enabled ()) {
        request->database_bibles ()->deleteBible (demo_sample_bible_name ());
        search_logic_delete_bible (demo_sample_bible_name ());
      }
    }
  }
  
  // Copy Bible handler.
  if (request->query.count ("copy")) {
    string copy = request->query["copy"];
    Dialog_Entry dialog_entry = Dialog_Entry ("manage", translate("Please enter a name for where to copy the Bible to"), "", "", "A new Bible will be created with the given name, and the current Bible copied to it");
    dialog_entry.add_query ("origin", copy);
    page += dialog_entry.run ();
    return page;
  }
  if (request->query.count ("origin")) {
    string origin = request->query["origin"];
    if (request->post.count ("entry")) {
      string destination = request->post["entry"];
      vector <string> bibles = request->database_bibles ()->getBibles ();
      if (find (bibles.begin(), bibles.end(), destination) != bibles.end()) {
        error_message = translate("Cannot copy the Bible because the destination Bible already exists.");
      } else {
        // User needs read access to the original.
        if (access_bible_read (request, origin)) {
          request->database_bibles ()->createBible (destination);
          vector <int> books = request->database_bibles ()->getBooks (origin);
          for (auto & book : books) {
            vector <int> chapters = request->database_bibles ()->getChapters (origin, book);
            for (auto & chapter : chapters) {
              string data = request->database_bibles ()->getChapter (origin, book, chapter);
              Bible_Logic::storeChapter (destination, book, chapter, data);
            }
          }
          success_message = translate("The Bible was copied.");
          // Check / grant access to destination Bible.
          if (!access_bible_write (request, destination)) {
            string me = request->session_logic ()->currentUser ();
            Database_Privileges::setBible (me, destination, true);
          }
          // Creating a Bible removes any Sample Bible that might have been there.
          if (!config_logic_demo_enabled ()) {
            request->database_bibles ()->deleteBible (demo_sample_bible_name ());
            search_logic_delete_bible (demo_sample_bible_name ());
          }
        }
      }
    }
  }

  // Delete Bible handler.
  if (request->query.count ("delete")) {
    string bible = request->query ["delete"];
    string confirm = request->query ["confirm"];
    if (confirm == "yes") {
      // User needs write access for delete operation.
      if (access_bible_write (request, bible)) {
        Bible_Logic::deleteBible (bible);
        string gitdirectory = filter_git_directory (bible);
        if (file_exists (gitdirectory)) {
          filter_url_rmdir (gitdirectory);
        }
        // Remove associated settings and privileges.
        Database_Privileges::removeBible (bible);
        Database_Config_Bible::remove (bible);
      } else {
        page += Assets_Page::error ("Insufficient privileges to complete action");
      }
    }
    if (confirm == "") {
      Dialog_Yes dialog_yes = Dialog_Yes ("manage", translate("Would you like to delete this Bible?") + " (" + bible + ")");
      dialog_yes.add_query ("delete", bible);
      page += dialog_yes.run ();
      return page;
    }
  }

  view.set_variable ("success_message", success_message);
  view.set_variable ("error_message", error_message);
  vector <string> bibles = access_bible_bibles (request);
  string bibleblock;
  for (auto & bible : bibles) {
    bibleblock.append ("<li><a href=\"settings?bible=" + bible + "\">" + bible + "</a></li>\n");
  }
  view.set_variable ("bibleblock", bibleblock);

  if (!client_logic_client_enabled ()) view.enable_zone ("server");

  page += view.render ("bible", "manage");
  
  page += Assets_Page::footer ();
  
  return page;
}