diff options
Diffstat (limited to 'wsd/COOLWSD.cpp')
-rw-r--r-- | wsd/COOLWSD.cpp | 138 |
1 files changed, 135 insertions, 3 deletions
diff --git a/wsd/COOLWSD.cpp b/wsd/COOLWSD.cpp index 0db00648b0..9640177e44 100644 --- a/wsd/COOLWSD.cpp +++ b/wsd/COOLWSD.cpp @@ -868,6 +868,7 @@ std::string COOLWSD::ChildRoot; std::string COOLWSD::ServerName; std::string COOLWSD::FileServerRoot; std::string COOLWSD::ServiceRoot; +std::string COOLWSD::TmpFontDir; std::string COOLWSD::LOKitVersion; std::string COOLWSD::ConfigFile = COOLWSD_CONFIGDIR "/coolwsd.xml"; std::string COOLWSD::ConfigDir = COOLWSD_CONFIGDIR "/conf.d"; @@ -1031,11 +1032,14 @@ public: virtual void handleJSON(Poco::JSON::Object::Ptr json) = 0; + virtual void handleUnchangedJSON() + { } + void start() { if (remoteServerURI.empty()) { - LOG_INF("Remote config url is not specified in coolwsd.xml"); + LOG_INF("Remote " << expectedKind << " is not specified in coolwsd.xml"); return; // no remote config server setup. } #if !ENABLE_DEBUG @@ -1100,6 +1104,7 @@ public: { LOG_WRN("Remote config server has response status code: " + std::to_string(statusCode) + ", JSON has not been changed"); + handleUnchangedJSON(); } else { @@ -1117,6 +1122,8 @@ public: protected: LayeredConfiguration& conf; + +private: Poco::URI remoteServerURI; std::string expectedKind; std::string eTagValue; @@ -1360,6 +1367,115 @@ public: return booleanFlag.toString(); } }; + +class RemoteFontConfigPoll : public RemoteJSONPoll +{ +public: + RemoteFontConfigPoll(LayeredConfiguration& config) + : RemoteJSONPoll(config, Poco::URI(config.getString("remote_font_config.url")), "remotefontconfig_poll", "fontconfiguration") + { + } + + virtual ~RemoteFontConfigPoll() { } + + void handleJSON(Poco::JSON::Object::Ptr remoteJson) override + { + // First mark all fonts we have downloaded previously as "inactive" to be able to check if + // some font gets deleted from the list in the JSON file. + for (auto& it : fonts) + it.second.active = false; + + // Just pick up new fonts. + for (auto& fontPtr : *remoteJson->getArray("fonts")) + { + if (!fontPtr.isString()) + LOG_WRN("Element in fonts array is not a string"); + else + { + fonts[std::string(fontPtr)].active = true; + } + } + + // Any font that has been deleted from the JSON needs to be removed on this side, too. + for (auto it = fonts.begin(); it != fonts.end();) + { + if (!it->second.active) + { + LOG_DBG("Font no longer mentioned in the remote font config: " << it->first); + // FIXME: Removing the font file will make it unusable, but sadly it is not possible + // for ForKit to remove knowledge of it from core, so it would still show up in the + // font menu. Not sure what to do here. + // COOLWSD::sendMessageToForKit("removefont " + it->second.active); + // Oh well, at least remove it from our map. + it = fonts.erase(it); + } + else + ++it; + } + } + + void handleUnchangedJSON() override + { + // Iterate over the fonts that were mentioned in the JSON file when it was last downloaded. + for (auto& it : fonts) + { + const Poco::URI fontURI{it.first}; + std::shared_ptr<http::Session> httpSession(StorageBase::getHttpSession(fontURI)); + http::Request request(fontURI.getPathAndQuery()); + + if (!it.second.eTag.empty()) + { + request.set("If-None-Match", it.second.eTag); + } + + request.set("User-Agent", WOPI_AGENT_STRING); + + const std::shared_ptr<const http::Response> httpResponse + = httpSession->syncRequest(request); + + unsigned int statusCode = httpResponse->statusLine().statusCode(); + + if (statusCode == Poco::Net::HTTPResponse::HTTP_NOT_MODIFIED) + LOG_DBG("Not modified since last time: " << it.first); + else if (statusCode != Poco::Net::HTTPResponse::HTTP_OK) + LOG_WRN("Could not fetch " << it.first); + else + { + it.second.eTag = httpResponse->get("ETag"); + + const std::string body = httpResponse->getBody(); + + const std::string fontFile = COOLWSD::TmpFontDir + "/" + Util::encodeId(Util::rng::getNext()) + ".ttf"; + std::ofstream fontStream(fontFile); + fontStream.write(body.data(), body.size()); + if (fontStream.good()) + { + LOG_DBG("Got " << body.size() << " bytes for " << it.first << " and wrote to " << fontFile); + + it.second.pathName = fontFile; + COOLWSD::sendMessageToForKit("addfont " + fontFile); + } + else + LOG_ERR("Could not write to " << fontFile); + } + } + } + +private: + struct FontData + { + std::string eTag; + + // Where the font has been stored + std::string pathName; + + // Flag that tells whether the font is mentioned in the JSON file that is being handled. + bool active; + }; + + // The key of this map is the download URI of the font. + std::map<std::string, FontData> fonts; +}; #endif void COOLWSD::innerInitialize(Application& self) @@ -4590,13 +4706,12 @@ int COOLWSD::innerMain() initializeSSL(); - // Fetch remote settings from server if configured #if !MOBILEAPP + // Fetch remote settings from server if configured RemoteConfigPoll remoteConfigThread(config()); remoteConfigThread.start(); #endif - #ifndef IOS // We can open files with non-ASCII names just fine on iOS without this, and this code is // heavily Linux-specific anyway. @@ -4644,6 +4759,8 @@ int COOLWSD::innerMain() assert(Server && "The COOLWSDServer instance does not exist."); Server->findClientPort(); + TmpFontDir = SysTemplate + "/tmpfonts"; + // Start the internal prisoner server and spawn forkit, // which in turn forks first child. Server->startPrisoners(); @@ -4716,6 +4833,21 @@ int COOLWSD::innerMain() std::cerr << "Ready to accept connections on port " << ClientPortNumber << ".\n" << std::endl; #endif +#if !MOBILEAPP + // Start the remote font downloading polling thread. + std::unique_ptr<RemoteFontConfigPoll> remoteFontConfigThread; + try + { + // Fetch font settings from server if configured + remoteFontConfigThread = Util::make_unique<RemoteFontConfigPoll>(config()); + remoteFontConfigThread->start(); + } + catch (const Poco::Exception&) + { + LOG_DBG("No remote_font_config"); + } +#endif + const auto startStamp = std::chrono::steady_clock::now(); while (!SigUtil::getTerminationFlag() && !SigUtil::getShutdownRequestFlag()) |