Commit 7f215008 authored by Aline Gondim Santos's avatar Aline Gondim Santos Committed by Sébastien Blin

plugin: add editable preference

Change-Id: I61c074464e21344b2d7a1d64023f23bd96139c3b
parent b424a5d0
......@@ -154,5 +154,16 @@
</arg>
</method>
<method name="addValueToPreference" tp:name-for-bindings="addValueToPreference">
<tp:added version="9.6.0"/>
<arg type="s" name="pluginId" direction="in">
</arg>
<arg type="s" name="preferenceKey" direction="in">
</arg>
<arg type="s" name="value" direction="in">
</arg>
<arg type="b" name="status" direction="out">
</arg>
</method>
</interface>
</node>
......@@ -132,3 +132,11 @@ DBusPluginManagerInterface::getCallMediaHandlerStatus()
{
return DRing::getCallMediaHandlerStatus();
}
bool
DBusPluginManagerInterface::addValueToPreference(const std::string& pluginId,
const std::string& preferenceKey,
const std::string& value)
{
return DRing::addValueToPreference(pluginId, preferenceKey, value);
}
......@@ -71,4 +71,7 @@ class DRING_PUBLIC DBusPluginManagerInterface :
bool getPluginsEnabled();
void setPluginsEnabled(const bool& state);
std::map<std::string,std::string> getCallMediaHandlerStatus();
bool addValueToPreference(const std::string& pluginId,
const std::string& preferenceKey,
const std::string& value);
};
......@@ -42,4 +42,7 @@ std::map<std::string,std::string> getCallMediaHandlerDetails(const std::string&
bool getPluginsEnabled();
void setPluginsEnabled(bool state);
std::map<std::string,std::string> getCallMediaHandlerStatus();
bool addValueToPreference(const std::string& pluginId,
const std::string& preferenceKey,
const std::string& value);
}
......@@ -2,7 +2,7 @@ dnl Jami - configure.ac for automake 1.9 and autoconf 2.59
dnl Process this file with autoconf to produce a configure script.
AC_PREREQ([2.65])
AC_INIT([Jami Daemon],[9.5.0],[ring@gnu.org],[jami])
AC_INIT([Jami Daemon],[9.6.0],[ring@gnu.org],[jami])
AC_COPYRIGHT([[Copyright (c) Savoir-faire Linux 2004-2020]])
AC_REVISION([$Revision$])
......
project('jami-daemon', ['c', 'cpp'],
version: '9.5.0',
version: '9.6.0',
license: 'GPL3+',
default_options: ['cpp_std=gnu++17', 'buildtype=debugoptimized'],
meson_version:'>= 0.54'
......
......@@ -144,4 +144,14 @@ getCallMediaHandlerStatus()
.getCallServicesManager()
.getCallMediaHandlerStatus();
}
bool
addValueToPreference(const std::string& pluginId,
const std::string& preferenceKey,
const std::string& value)
{
return jami::Manager::instance().getJamiPluginManager().addValueToPreference(pluginId,
preferenceKey,
value);
}
} // namespace DRing
......@@ -53,4 +53,7 @@ DRING_PUBLIC std::map<std::string,std::string> getCallMediaHandlerDetails(const
DRING_PUBLIC bool getPluginsEnabled();
DRING_PUBLIC void setPluginsEnabled(bool state);
DRING_PUBLIC std::map<std::string,std::string> getCallMediaHandlerStatus();
DRING_PUBLIC bool addValueToPreference(const std::string& pluginId,
const std::string& preferenceKey,
const std::string& value);
}
......@@ -1023,5 +1023,35 @@ accessFile(const std::string& file, int mode)
#endif
}
std::string
getFileName(const std::string& filePath)
{
std::string fileName = filePath;
const size_t last_slash_idx = fileName.find_last_of(DIR_SEPARATOR_STR_ESC);
if (std::string::npos != last_slash_idx) {
fileName.erase(0, last_slash_idx + 1);
}
return fileName;
}
std::string
removeExtension(const std::string& filePath)
{
std::string fileName = filePath;
const size_t period_idx = fileName.rfind('.');
if (std::string::npos != period_idx) {
fileName.erase(period_idx);
}
return fileName;
}
std::string
getExtension(const std::string& filePath)
{
std::string fileExt = filePath;
fileExt = fileExt.substr(fileExt.find_last_of('.'));
return fileExt;
}
} // namespace jami
} // namespace fileutils
......@@ -176,6 +176,10 @@ std::string md5sum(const std::vector<uint8_t>& buffer);
*/
int accessFile(const std::string& file, int mode);
std::string getFileName(const std::string& filePath);
std::string removeExtension(const std::string& filePath);
std::string getExtension(const std::string& filePath);
} // namespace fileutils
} // namespace jami
......
......@@ -34,6 +34,7 @@ extern "C" {
#include <archive.h>
}
#include "fileutils.h"
#include <json/json.h>
#include <msgpack.hpp>
......@@ -337,11 +338,10 @@ JamiPluginManager::unloadPlugin(const std::string& rootPath)
void
JamiPluginManager::togglePlugin(const std::string& rootPath, bool toggle)
{
//This function should not be used as is
//One should modify it to perform plugin install followed by load
//rootPath should be the jplpath!
try
{
// This function should not be used as is
// One should modify it to perform plugin install followed by load
// rootPath should be the jplpath!
try {
std::string soPath = getPluginDetails(rootPath).at("soPath");
// remove the previous plugin object if it was registered
pm_.destroyPluginComponents(soPath);
......@@ -372,6 +372,8 @@ std::vector<std::map<std::string, std::string>>
JamiPluginManager::getPluginPreferences(const std::string& rootPath)
{
const std::string preferenceFilePath = getPreferencesConfigFilePath(rootPath);
std::map<std::string, std::map<std::string, std::string>> userPreferences
= getUserPreferencesValuesMap(rootPath);
std::ifstream file(preferenceFilePath);
Json::Value root;
Json::CharReaderBuilder rbuilder;
......@@ -389,11 +391,34 @@ JamiPluginManager::getPluginPreferences(const std::string& rootPath)
std::string key = jsonPreference.get("key", "None").asString();
if (type != "None" && key != "None") {
if (keys.find(key) == keys.end()) {
const auto& preferenceAttributes = parsePreferenceConfig(jsonPreference,
type);
std::map<std::string, std::string> preferenceAttributes
= parsePreferenceConfig(jsonPreference, type);
// If the parsing of the attributes was successful, commit the map and the key
if (!preferenceAttributes.empty()) {
preferences.push_back(std::move(preferenceAttributes));
if (!userPreferences[key].empty()) {
preferenceAttributes["entryValues"]
= userPreferences[key]["entryValues"];
preferenceAttributes["entries"] = userPreferences[key]["entries"];
}
preferenceAttributes["entryValues"]
= std::regex_replace(preferenceAttributes["entryValues"],
std::regex("\\["),
"$2");
preferenceAttributes["entryValues"]
= std::regex_replace(preferenceAttributes["entryValues"],
std::regex("\\]"),
"$2");
preferenceAttributes["entries"]
= std::regex_replace(preferenceAttributes["entries"],
std::regex("\\["),
"$2");
preferenceAttributes["entries"]
= std::regex_replace(preferenceAttributes["entries"],
std::regex("\\]"),
"$2");
preferences.emplace_back(std::move(preferenceAttributes));
keys.insert(key);
}
}
......@@ -443,6 +468,41 @@ JamiPluginManager::getPluginUserPreferencesValuesMap(const std::string& rootPath
return rmap;
}
std::map<std::string, std::map<std::string, std::string>>
JamiPluginManager::getUserPreferencesValuesMap(const std::string& rootPath)
{
const std::string preferencesValuesFilePath = pluginAddedPreferencesValuesFilePath(rootPath);
std::ifstream file(preferencesValuesFilePath, std::ios::binary);
std::map<std::string, std::map<std::string, std::string>> rmap;
// If file is accessible
if (file.good()) {
std::lock_guard<std::mutex> guard(fileutils::getFileLock(preferencesValuesFilePath));
// Get file size
std::string str;
file.seekg(0, std::ios::end);
size_t fileSize = static_cast<size_t>(file.tellg());
// If not empty
if (fileSize > 0) {
// Read whole file content and put it in the string str
str.reserve(static_cast<size_t>(file.tellg()));
file.seekg(0, std::ios::beg);
str.assign((std::istreambuf_iterator<char>(file)), std::istreambuf_iterator<char>());
file.close();
try {
// Unpack the string
msgpack::object_handle oh = msgpack::unpack(str.data(), str.size());
// Deserialized object is valid during the msgpack::object_handle instance is alive.
msgpack::object deserialized = oh.get();
deserialized.convert(rmap);
} catch (const std::exception& e) {
JAMI_ERR() << e.what();
}
}
}
return rmap;
}
bool
JamiPluginManager::setPluginPreference(const std::string& rootPath,
const std::string& key,
......@@ -521,6 +581,69 @@ JamiPluginManager::resetPluginPreferencesValuesMap(const std::string& rootPath)
return returnValue;
}
bool
JamiPluginManager::copyFileToPluginData(const std::string& pluginId,
const std::string& value,
const std::string& preferenceCategory,
std::string& fileName,
std::string& fileExt)
{
if (!fileutils::isFile(value))
return false;
const std::string destinationDir {pluginId + DIR_SEPARATOR_CH + "data" + DIR_SEPARATOR_CH
+ preferenceCategory + DIR_SEPARATOR_CH};
fileName = fileutils::removeExtension(fileutils::getFileName(value));
fileExt = fileutils::getExtension(value);
auto srcData = fileutils::loadFile(value);
if (fileutils::isFile(destinationDir + fileName + fileExt)) {
fileutils::saveFile(destinationDir + fileName + fileExt, srcData);
return false;
}
fileutils::saveFile(destinationDir + fileName + fileExt, srcData);
return true;
}
bool
JamiPluginManager::addValueToPreference(const std::string& pluginId,
const std::string& preferenceKey,
const std::string& value)
{
std::map<std::string, std::map<std::string, std::string>> userPreferences
= getUserPreferencesValuesMap(pluginId);
std::vector<std::map<std::string, std::string>> preferences = getPluginPreferences(pluginId);
for (auto& preference : preferences) {
if (preference["key"] == preferenceKey) {
std::string fileName, fileExt;
if (!copyFileToPluginData(pluginId, value, preference["category"], fileName, fileExt)) {
return setPluginPreference(pluginId, preferenceKey, fileName + fileExt);
}
setPluginPreference(pluginId, preferenceKey, fileName + fileExt);
userPreferences[preferenceKey]["entries"] = preference["entries"] + "," + fileName;
userPreferences[preferenceKey]["entryValues"] = preference["entryValues"] + ","
+ fileName + fileExt;
const std::string preferencesValuesFilePath = pluginAddedPreferencesValuesFilePath(
pluginId);
std::ofstream fs(preferencesValuesFilePath, std::ios::binary);
if (!fs.good()) {
return false;
}
try {
std::lock_guard<std::mutex> guard(fileutils::getFileLock(preferencesValuesFilePath));
msgpack::pack(fs, userPreferences);
return true;
} catch (const std::exception& e) {
JAMI_ERR() << e.what();
return false;
}
}
}
}
std::map<std::string, std::string>
JamiPluginManager::readPluginManifestFromArchive(const std::string& jplPath)
{
......
......@@ -125,6 +125,10 @@ public:
bool resetPluginPreferencesValuesMap(const std::string& rootPath);
bool addValueToPreference(const std::string& pluginId,
const std::string& preferenceKey,
const std::string& value);
public:
CallServicesManager& getCallServicesManager() { return csm_; }
......@@ -180,6 +184,13 @@ private:
}
std::map<std::string, std::string> getPluginUserPreferencesValuesMap(const std::string& rootPath);
std::map<std::string, std::map<std::string, std::string>> getUserPreferencesValuesMap(
const std::string& rootPath);
bool copyFileToPluginData(const std::string& pluginId,
const std::string& value,
const std::string& preferenceCategory,
std::string& fileName,
std::string& fileExt);
/**
* @brief getPreferencesConfigFilePath
......@@ -205,6 +216,18 @@ private:
return rootPath + DIR_SEPARATOR_CH + "preferences.msgpack";
}
/**
* @brief pluginAddedPreferencesValuesFilePath
* Returns the plugin added preferences values file path from the plugin root path
* This is entirely defined by how the plugin files are structured
* @param plugin rootPath
* @return path of the preferences values
*/
std::string pluginAddedPreferencesValuesFilePath(const std::string& rootPath) const
{
return rootPath + DIR_SEPARATOR_CH + "addedPreferences.msgpack";
}
void registerServices();
private:
......
......@@ -40,8 +40,8 @@ public:
* The id is the path of the plugin that created this MediaHandler
* @return
*/
std::string id() const { return id_;}
virtual void setId(const std::string& id) final {id_ = id;}
std::string id() const { return id_; }
virtual void setId(const std::string& id) final { id_ = id; }
private:
std::string id_;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment