示例#1
0
// The client runs this function to fetch a general resource $name from the Cloud,
// or from its local cache,
// and to update the local cache with the fetched content, if needed,
// and to return the requested content.
string resource_logic_client_fetch_cache_from_cloud (string resource, int book, int chapter, int verse)
{
  // Ensure that the cache for this resource exists on the client.
  if (!Database_Cache::exists (resource, book)) {
    Database_Cache::create (resource, book);
  }
  
  // If the content exists in the cache, return that content.
  if (Database_Cache::exists (resource, book, chapter, verse)) {
    return Database_Cache::retrieve (resource, book, chapter, verse);
  }
  
  // Fetch this resource from Bibledit Cloud or from the cache.
  string address = Database_Config_General::getServerAddress ();
  int port = Database_Config_General::getServerPort ();
  if (!client_logic_client_enabled ()) {
    // If the client has not been connected to a cloud instance,
    // fetch the resource from the Bibledit Cloud demo.
    address = demo_address ();
    port = demo_port ();
  }
  
  string url = client_logic_url (address, port, sync_resources_url ());
  url = filter_url_build_http_query (url, "r", filter_url_urlencode (resource));
  url = filter_url_build_http_query (url, "b", convert_to_string (book));
  url = filter_url_build_http_query (url, "c", convert_to_string (chapter));
  url = filter_url_build_http_query (url, "v", convert_to_string (verse));
  string error;
  string content = filter_url_http_get (url, error);
  
  if (error.empty ()) {
    // No error: Cache content.
    Database_Cache::cache (resource, book, chapter, verse, content);
  } else {
    // Error: Log it, and return it.
    Database_Logs::log (resource + ": " + error);
    content.append (error);
  }

  // Done.
  return content;
}
示例#2
0
// Add "parameter" and "value" to be added in the base query, or base url.
// If any $query is passed, if Cancel is clicked in this dialog, it should go go back
// to the original caller page  with the $query added.
// Same for when a selection is made: It adds the $query to the page where to go.
void Dialog_Color::add_query (string parameter, string value)
{
  base_url = filter_url_build_http_query (base_url, parameter, value);
}
示例#3
0
string resource_img (void * webserver_request)
{
  Webserver_Request * request = (Webserver_Request *) webserver_request;
  Database_ImageResources database_imageresources;

  
  string page;
  Assets_Header header = Assets_Header (translate("Image resources"), request);
  page = header.run ();
  Assets_View view;
  string error, success;
  int book1, chapter1, verse1, book2, chapter2, verse2;
  
  
  string name = request->query ["name"];
  view.set_variable ("name", name);

  
  string image = request->query ["image"];
  view.set_variable ("image", image);

  
  int userid = filter_string_user_identifier (webserver_request);

  
  if (request->post.count ("submit")) {
    
    vector <string> errors;
    
    string book = request->post ["book1"];
    book1 = filter_passage_interpret_book (book);
    if (book1 == 0) errors.push_back (translate ("Unknown starting book."));

    chapter1 = convert_to_int (request->post ["chapter1"]);
    if (chapter1 < 0) errors.push_back (translate ("Negative starting chapter."));
    if (chapter1 > 200) errors.push_back (translate ("High starting chapter."));
    
    verse1 = convert_to_int (request->post ["verse1"]);
    if (chapter1 < 0) errors.push_back (translate ("Negative starting verse."));
    if (chapter1 > 200) errors.push_back (translate ("High starting verse."));
    
    book = request->post ["book2"];
    book2 = filter_passage_interpret_book (book);
    if (book2 == 0) errors.push_back (translate ("Unknown ending book."));
    
    chapter2 = convert_to_int (request->post ["chapter2"]);
    if (chapter2 < 0) errors.push_back (translate ("Negative ending chapter."));
    if (chapter2 > 200) errors.push_back (translate ("High ending chapter."));
    
    verse2 = convert_to_int (request->post ["verse2"]);
    if (chapter2 < 0) errors.push_back (translate ("Negative ending verse."));
    if (chapter2 > 200) errors.push_back (translate ("High ending verse."));
    
    int start = filter_passage_to_integer (Passage ("", book1, chapter1, convert_to_string (verse1)));
    int end = filter_passage_to_integer (Passage ("", book2, chapter2, convert_to_string (verse2)));
    if (start > end) {
      errors.push_back (translate ("The starting passage is beyond the ending passage."));
    }

    database_imageresources.assign (name, image, book1, chapter1, verse1, book2, chapter2, verse2);
    
    Database_Volatile::setValue (userid, "imageresources", convert_to_string (end));

    error = filter_string_implode (errors, " ");
    if (errors.empty ()) {
      redirect_browser (request, filter_url_build_http_query (resource_image_url (), "name", name));
      return "";
    }
  }
  
  
  // Retrieve passage range for this image.
  database_imageresources.get (name, image, book1, chapter1, verse1, book2, chapter2, verse2);
  if ((book1 == 0) || (book2 == 0)) {
    string end = Database_Volatile::getValue (userid, "imageresources");
    Passage passage = filter_integer_to_passage (convert_to_int (end));
    book1 = book2 = passage.book;
    chapter1 = chapter2 = passage.chapter;
    verse1 = verse2 = convert_to_int (passage.verse);
    if (book1 == 0) book1 = 1;
    if (book2 == 0) book2 = 1;
  }
  view.set_variable ("book1", Database_Books::getEnglishFromId (book1));
  view.set_variable ("chapter1", convert_to_string (chapter1));
  view.set_variable ("verse1", convert_to_string (verse1));
  view.set_variable ("book2", Database_Books::getEnglishFromId (book2));
  view.set_variable ("chapter2", convert_to_string (chapter2));
  view.set_variable ("verse2", convert_to_string (verse2));
  

  view.set_variable ("success", success);
  view.set_variable ("error", error);
  page += view.render ("resource", "img");
  page += Assets_Page::footer ();
  return page;
}
示例#4
0
void sendreceive_resources ()
{
  if (sendreceive_resources_watchdog) {
    int time = filter_date_seconds_since_epoch ();
    if (time < (sendreceive_resources_watchdog + 900)) {
      return;
    }
    Database_Logs::log ("Resources: " + translate("Watchdog timeout"), Filter_Roles::translator ());
    sendreceive_resources_done ();
  }

  // If any of the prioritized synchronization tasks run, postpone the current task and do not start it.
  if (sendreceive_logic_prioritized_task_is_active ()) {
    sendreceive_resources_done ();
    this_thread::sleep_for (chrono::seconds (5));
    tasks_logic_queue (SYNCRESOURCES);
    return;
  }

  sendreceive_resources_interrupt = false;

  // If there's nothing to cache, bail out.
  vector <string> resources = Database_Config_General::getResourcesToCache ();
  if (resources.empty ()) return;
  
  sendreceive_resources_kick_watchdog ();

  // Error counter.
  int error_count = 0;
  
  // Resource to cache.
  string resource = resources [0];
  
  // Erase the two older storage locations that were used to cache resources in earlier versions of Bibledit.
  {
    Database_OfflineResources database_offlineresources;
    Database_UsfmResources database_usfmresources;
    database_offlineresources.erase (resource);
    database_usfmresources.deleteResource (resource);
  }

  Database_Logs::log ("Starting to install resource:" " " + resource, Filter_Roles::consultant ());
  
  Database_Versifications database_versifications;
  
  vector <int> books = database_versifications.getMaximumBooks ();
  for (auto & book : books) {
    sendreceive_resources_delay_during_prioritized_tasks ();
    if (sendreceive_resources_interrupt) continue;
    
    // Database layout is per book: Create a database for this book.
    Database_Cache::create (resource, book);

    // Last downloaded passage in a previous download operation.
    int last_downloaded_passage = 0;
    {
      pair <int, int> progress = Database_Cache::progress (resource, book);
      int chapter = progress.first;
      int verse = progress.second;
      Passage passage ("", book, chapter, convert_to_string (verse));
      last_downloaded_passage = filter_passage_to_integer (passage);
    }
    
    // List of passages recorded in the database that had errors on a previous download operation.
    vector <int> previous_errors;
    {
      vector <pair <int, int> > errors = Database_Cache::errors (resource, book);
      for (auto & element : errors) {
        int chapter = element.first;
        int verse = element.second;
        Passage passage ("", book, chapter, convert_to_string (verse));
        int numeric_error = filter_passage_to_integer (passage);
        previous_errors.push_back (numeric_error);
      }
    }
    
    string bookName = Database_Books::getEnglishFromId (book);
    
    vector <int> chapters = database_versifications.getMaximumChapters (book);
    for (auto & chapter : chapters) {
      sendreceive_resources_delay_during_prioritized_tasks ();
      if (sendreceive_resources_interrupt) continue;
      bool downloaded = false;
      string message = resource + ": " + bookName + " chapter " + convert_to_string (chapter);
      vector <int> verses = database_versifications.getMaximumVerses (book, chapter);
      for (auto & verse : verses) {
        sendreceive_resources_delay_during_prioritized_tasks ();
        if (sendreceive_resources_interrupt) continue;
        // Numeric representation of passage to deal with.
        Passage passage ("", book, chapter, convert_to_string (verse));
        int numeric_passage = filter_passage_to_integer (passage);
        // Conditions to download this verse:
        // 1. The passage is past the last downloaded passage.
        bool download_verse_past = numeric_passage > last_downloaded_passage;
        // 2. The passage was recorded as an error in a previous download operation.
        bool download_verse_error = in_array (numeric_passage, previous_errors);
        // Whether to download the verse.
        if (download_verse_past || download_verse_error) {
          // Fetch the text for the passage.
          bool server_is_installing_module = false;
          int wait_iterations = 0;
          string html, error;
          do {
            // Fetch this resource from the server.
            string address = Database_Config_General::getServerAddress ();
            int port = Database_Config_General::getServerPort ();
            // If the client has not been connected to a cloud instance,
            // fetch the resource from the Bibledit Cloud demo.
            if (!client_logic_client_enabled ()) {
              address = demo_address ();
              port = demo_port ();
            }
            string url = client_logic_url (address, port, sync_resources_url ());
            url = filter_url_build_http_query (url, "r", filter_url_urlencode (resource));
            url = filter_url_build_http_query (url, "b", convert_to_string (book));
            url = filter_url_build_http_query (url, "c", convert_to_string (chapter));
            url = filter_url_build_http_query (url, "v", convert_to_string (verse));
            error.clear ();
            html = filter_url_http_get (url, error);
            server_is_installing_module = (html == sword_logic_installing_module_text ());
            if (server_is_installing_module) {
              Database_Logs::log ("Waiting while Bibledit Cloud installs the requested SWORD module");
              this_thread::sleep_for (chrono::seconds (60));
              wait_iterations++;
            }
          } while (server_is_installing_module && (wait_iterations < 5));
          // Record the passage as having been done in case it was a regular download,
          // rather than one to retry a previous download error.
          if (download_verse_past) Database_Cache::progress (resource, book, chapter, verse);
          // Clear the registered error in case the verse download corrects it.
          if (download_verse_error) Database_Cache::error (resource, book, chapter, verse, false);
          if (error.empty ()) {
            // Cache the verse data.
            if (!Database_Cache::exists (resource, book)) Database_Cache::create (resource, book);
            Database_Cache::cache (resource, book, chapter, verse, html);
          } else {
            // Record an error.
            Database_Cache::error (resource, book, chapter, verse, true);
            if (message.find (error) == string::npos) {
              message.append ("; " + error);
            }
            error_count++;
            this_thread::sleep_for (chrono::seconds (1));
          }
          downloaded = true;
        }
        sendreceive_resources_kick_watchdog ();
      }
      message += "; done";
      if (downloaded) Database_Logs::log (message, Filter_Roles::manager ());
    }
  }
  
  // Done.
  if (error_count) {
    string msg = "Error count while downloading resource: " + convert_to_string (error_count);
    Database_Logs::log (msg, Filter_Roles::consultant ());
  }
  Database_Logs::log ("Completed installing resource:" " " + resource, Filter_Roles::consultant ());
  // In case of too many errors, schedule the resource download again.
  bool re_schedule_download = false;
  if (error_count) {
    if (!sendreceive_resources_interrupt) {
      re_schedule_download = true;
      Database_Logs::log ("Errors: Re-scheduling resource installation", Filter_Roles::consultant ());
    }
  }
  // Store new download schedule.
  resources = Database_Config_General::getResourcesToCache ();
  resources = filter_string_array_diff (resources, {resource});
  if (re_schedule_download) {
    resources.push_back (resource);
  }
  Database_Config_General::setResourcesToCache (resources);

  sendreceive_resources_done ();
  
  sendreceive_resources_interrupt = false;

  // If there's another resource waiting to be cached, schedule it for caching.
  if (!resources.empty ()) tasks_logic_queue (SYNCRESOURCES);
}
示例#5
0
map <int, string> workspace_get_values (void * webserver_request, int selector, bool use)
{
  Webserver_Request * request = (Webserver_Request *) webserver_request;

  map <int, string> values;
  
  string workspace = workspace_get_active_name (request);
  
  string rawvalue;
  if (selector == URLS) rawvalue = request->database_config_user()->getWorkspaceURLs ();
  if (selector == WIDTHS) rawvalue = request->database_config_user()->getWorkspaceWidths ();
  if (selector == HEIGHTS) rawvalue = request->database_config_user()->getWorkspaceHeights ();
  if (selector == ENTIREWIDTH) rawvalue = request->database_config_user()->getEntireWorkspaceWidths ();
  vector <string> lines = filter_string_explode (rawvalue, '\n');
  for (auto & line : lines) {
    if (line.find (workspace + "_") == 0) {
      vector <string> bits = filter_string_explode (line, '_');
      if (bits.size() == 3) {
        int key = convert_to_int (bits [1]);
        string value = bits [2];
        values [key] = value;
      }
    }
  }
  
  if (values.empty ()) {
    if (selector == URLS) values = workspace_get_default_urls (0);
    if (selector == WIDTHS) values = workspace_get_default_widths (0);
    if (selector == HEIGHTS) values = workspace_get_default_heights (0);
    if (selector == ENTIREWIDTH) values.clear ();
  }

  for (auto & element : values) {
    
    if ((selector == URLS) && use) {
  
      // Add query value for suppressing the topbar as the workspace already has one.
      if (element.second != "") {
        element.second = filter_url_build_http_query (element.second, "topbar", "0");
      }
      
      // Transform the internal URLs to full ones.
      vector <string> bits = filter_string_explode (element.second, '/');
      if (bits.size() == 2) {
        element.second.insert (0, "/");
      }
      
      // Encode URL.
      element.second = filter_string_str_replace (" ", "%20", element.second);
    }

    if (selector == WIDTHS) {
      // Fix the units.
      element.second = workspace_process_units (element.second);
    }

    if (selector == HEIGHTS) {
      // Fix the units.
      element.second = workspace_process_units (element.second);
    }

  }

  return values;
}
示例#6
0
string sword_logic_get_text (string source, string module, int book, int chapter, int verse)
{
#ifdef HAVE_CLIENT

  // Client checks for and optionally creates the cache for this SWORD module.
  if (!Database_Cache::exists (module, book)) {
    Database_Cache::create (module, book);
  }

  // If this module/passage exists in the cache, return it (it updates the access days in the cache).
  if (Database_Cache::exists (module, book, chapter, verse)) {
    return Database_Cache::retrieve (module, book, chapter, verse);
  }

  // Fetch this SWORD resource from the server.
  string address = Database_Config_General::getServerAddress ();
  int port = Database_Config_General::getServerPort ();
  if (!client_logic_client_enabled ()) {
    // If the client has not been connected to a cloud instance,
    // fetch the SWORD content from the Bibledit Cloud demo.
    address = demo_address ();
    port = demo_port ();
  }
  string url = client_logic_url (address, port, sync_resources_url ());
  string resource = "[" + source + "][" + module + "]";
  url = filter_url_build_http_query (url, "r", resource);
  url = filter_url_build_http_query (url, "b", convert_to_string (book));
  url = filter_url_build_http_query (url, "c", convert_to_string (chapter));
  url = filter_url_build_http_query (url, "v", convert_to_string (verse));
  string error;
  string html = filter_url_http_get (url, error, true);
  
  // In case of an error, don't cache that error, but let the user see it.
  if (!error.empty ()) return error;

  // Client caches this info for later.
  // Except in case of predefined responses from the Cloud.
  if (html != sword_logic_installing_module_text ()) {
    if (html != sword_logic_fetch_failure_text ()) {
      Database_Cache::cache (module, book, chapter, verse, html);
    }
  }
  
  return html;
  
#else

  string module_text;
  bool module_available = false;

  string osis = Database_Books::getOsisFromId (book);
  string chapter_verse = convert_to_string (chapter) + ":" + convert_to_string (verse);

  // See notes on function sword_logic_diatheke
  // for why it is not currently fetching content via a SWORD library call.
  // module_text = sword_logic_diatheke (module, osis, chapter, verse, module_available);
  
  // Running diatheke only works when it runs in the SWORD installation directory.
  string sword_path = sword_logic_get_path ();
  // Running several instances of diatheke simultaneously fails.
  sword_logic_diatheke_run_mutex.lock ();
  // The server fetches the module text as follows:
  // diatheke -b KJV -k Jn 3:16
  int result = filter_shell_vfork (module_text, sword_path, "diatheke", "-b", module.c_str(), "-k", osis.c_str(), chapter_verse.c_str());
  sword_logic_diatheke_run_mutex.unlock ();
  if (result != 0) return sword_logic_fetch_failure_text ();
  
  // Touch the cache so the server knows that the module has been accessed just now.
  string url = sword_logic_virtual_url (module, 0, 0, 0);
  database_filebased_cache_get (url);

  // If the module has not been installed, the output of "diatheke" will be empty.
  // If the module was installed, but the requested passage is out of range,
  // the output of "diatheke" contains the module name, so it won't be empty.
  module_available = !module_text.empty ();
  
  if (!module_available) {
    
    // Check whether the SWORD module exists.
    vector <string> modules = sword_logic_get_available ();
    string smodules = filter_string_implode (modules, "");
    if (smodules.find ("[" + module + "]") != string::npos) {
      // Schedule SWORD module installation.
      // (It used to be the case that this function, to get the text,
      // would wait till the SWORD module was installed, and then after installation,
      // return the text from that module.
      // But due to long waiting on Bibledit demo, while it would install multiple modules,
      // the Bibledit demo would become unresponsive.
      // So, it's better to return immediately with an informative text.)
      sword_logic_install_module_schedule (source, module);
      // Return standard 'installing' information. Client knows not to cache this.
      return sword_logic_installing_module_text ();
    } else {
      return "Cannot find SWORD module " + module;
    }
  }
  
  // Remove any OSIS elements.
  filter_string_replace_between (module_text, "<", ">", "");
  
  // Remove the passage name that diatheke adds.
  // A reliable signature for this is the chapter and verse plus subsequent colon.
  size_t pos = module_text.find (" " + chapter_verse + ":");
  if (pos != string::npos) {
    pos += 2;
    pos += chapter_verse.size ();
    module_text.erase (0, pos);
  }
  
  // Remove the module name that diatheke adds.
  module_text = filter_string_str_replace ("(" + module + ")", "", module_text);
  
  // Clean whitespace away.
  module_text = filter_string_trim (module_text);
  
  return module_text;

#endif

  return "";
}