Russian Qt Forum
Ноябрь 22, 2024, 15:48 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: [1]   Вниз
  Печать  
Автор Тема: Файлы плагинов  (Прочитано 5100 раз)
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« : Июнь 24, 2015, 14:47 »

Добрый день

Есть хост и плагины которые частенько заводят свои файлы данных. Обычно плагин создает фолдер "рядом с собой" и туда льет. При переносе проектов приложения получается не очень хорошо, еще хуже при выполнении сетевой задачи (когда плагины на др конце). При отключении плагина (не удалении самого плагина, а просто сейчас перестали юзать) файлы данных никто не чистит. Ну и.т.п., в общем - бардак. 

Др словами назрела необходимость расширить API плагинов чтобы все было цивильно, плагин не лез сам, а обращался к хосту чтобы создать/удалить/получить файл. Что Вы "рекомендуете"?  Улыбающийся  Как насчет "готовых, проверенных решений" - в данном случае я бы ими с удовольствием воспользовался.

Спасибо
Записан
kai666_73
Крякер
****
Offline Offline

Сообщений: 319


Просмотр профиля
« Ответ #1 : Июнь 24, 2015, 16:00 »

Я бы не ограничивал плагины подобным образом, а дополнил бы их необходимыми абстрактными методами
Код
C++ (Qt)
class IPlugin
{
public:
  ...
  virtual void saveState() const = 0;
  virtual void restoreState() = 0;
  virtual void clear() = 0;
  ...
};
 
А вот хост пусть хранит список плагинов и в соотв. моменты вызывает соотв. методы для всех плагинов.
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #2 : Июнь 24, 2015, 16:20 »

Я бы не ограничивал плагины подобным образом, а дополнил бы их необходимыми абстрактными методами
Код
C++ (Qt)
class IPlugin
{
public:
  ...
  virtual void saveState() const = 0;
  virtual void restoreState() = 0;
  virtual void clear() = 0;
  ...
};
 
А вот хост пусть хранит список плагинов и в соотв. моменты вызывает соотв. методы для всех плагинов.
Не очень понял что делают эти методы. Пример

- пользователь запустил хост и открыл какой-то проект. Добавил в проект плагин, пусть этот плагин создает 3D объект, напр сферу. Потом еще добавил этот же плагин - в проекте (и окнах хоста) появилась еще сфера. Потом решил удалить первую сферу. Но перепутал и не ту удалил. Спохватился, вызвал undo и исправил. Наконец засейвил файл проекта и закрыл приложение-хост.

Это я к тому что плагину рулить файлами самому (как это сейчас) довольно напряжно
Записан
sociopath
Гость
« Ответ #3 : Июнь 24, 2015, 18:04 »

Ничего не понятно.
Архитектура клиент-серверная? Хост - это сервер? Или хост - это просто ядро приложения? Если просто ядро, то и называйте ядром.
Проекты хранятся в ФС клиента или сервера?

Если файл проекта должен быть переносимым, то, значит, файл проекта должен включать в себя всю необходимую информацию, в т.ч. какие плагины использует. Рядом с ним не должны лежать файлы, которые на другой машине понадобятся для корректного запуска проекта. Если просто временные файлы - создайте общий каталог для appdata с разбиением по каталогам для каждого плагина. Работа с ФС должна быть реализована через ядро приложения, плагинам лучше такое не доверять.
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #4 : Июнь 25, 2015, 08:57 »

Архитектура клиент-серверная? Хост - это сервер? Или хост - это просто ядро приложения? Если просто ядро, то и называйте ядром.
И так и так. Приложение может получать задачу по сети, но все может происходить и на одной машине. В любом случае сами плагины - "местные dll". 

Работа с ФС должна быть реализована через ядро приложения, плагинам лучше такое не доверять.
Это я уже прочувствовал, вопрос как лучше это сделать

Если просто временные файлы - создайте общий каталог для appdata с разбиением по каталогам для каждого плагина.
Если "временные" означает "один сеанс работы" - то и проблемы никакой нет, плагин создает такие файлы во временном каталоге ОС, уникальное имя гарантируется.

Речь идет о файлах которые требуют значительного времени для их создания и/или специальных действий. Поэтому они должны сохраняться перманентно, напр до тех пор пока установки плагина не изменились. Общий каталог с разбиением - ну так

1) Файл плагина имеет смысл в контексте  данного проекта. Кстати - неясно что делать если вызван напр "Save As" для проекта.

2) Один и тот же плагин может быть задействован в 1 проекте любое число раз с разными установками (см пример со сферой выше)

Хмм... вроде простая задача, начал обдумывать - оказалось совсем непросто  Улыбающийся   
Записан
kai666_73
Крякер
****
Offline Offline

Сообщений: 319


Просмотр профиля
« Ответ #5 : Июнь 25, 2015, 11:42 »

1) Файл плагина имеет смысл в контексте  данного проекта
Вот теперь только задачка вырисовывается ) ...
Хотите готовое решение?
Может кто-то и даст Вам его, но в контексте собственного понятия проекта и собственного понятия плагина.
Оно Вам надо? Оно Вам будет полезно?
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #6 : Июнь 25, 2015, 12:58 »

Вот теперь только задачка вырисовывается ) ...
Ну темы с плагинами здесь мелькают постоянно, думал чего все разжевывать  Улыбающийся

Может кто-то и даст Вам его, но в контексте собственного понятия проекта и собственного понятия плагина.
Оно Вам надо? Оно Вам будет полезно?
Какие "собственные"?  Проект - данные (как собственные так и ссылки на внешние файлы/данные). Плагин - подгружаемый модуль. Проект может использовать плагин(ы). Вот собственно и все "понятия", никогда не видел каких-то других.

Хотите готовое решение?
Звучит типа - бездарь, сам придумать не может, вот и ищет готовое  Улыбающийся
Записан
sociopath
Гость
« Ответ #7 : Июнь 25, 2015, 13:54 »

Перманентно требуемые файлы имхо нужно сохранять тупо в тот же каталог, где и каталог проекта. Если юзверь их удалил - пусть ждет, пока они пересоздадутся. Если изменились настройки проекта - то ядро должно их затереть и создать новые. Если этих файлов хренова туча и не хочется засорять ФС, можно создавать скрытый каталог с этими файлами рядом с проектным файлом (под unix-based системы скрытый каталог делается очень просто, а вот под win придется писать ветку с win api).

Имхо при сохранении проекта нужно все необходимые при переносе файлы запаковывать и сжимать в проектном файле. И этот файл будет переносимым между машинами, при условии, что есть все необходимые плагины. Но обеспечение наличия всех необходимых плагинов, как правило, возлагается на самого пользователя. Или если необходимого плагина нет, то клиент может запросить плагин у сервера. Мы делали такую схему - на стороне БД сервера достаточно простенькой таблицы plugin - os - version - file, где plugin - имя плагина, os - операционная система, version - версия приложения, file - id blob'a, в котором содержимое плагина.

У класса плагина Plugin должна быть функция типа virtual void init(ICoreObject* obj), которая вызывается при загрузке плагина. При выгрузке плагина должна вызываться функция virtual void finalize(). ICoreObject должен выглядеть как-то так:
Код:
class ICoreObject
{
public:
// сохранение перманентно требуемого файла рядом с проектом
   virtual bool saveFile(const QString& file, const QByteArray& data) = 0;
// сохранение данных в проектный файл
   virtual bool saveProject(const QByteArray& data) = 0;
};
В нем должны быть объявлены все функции, которые могут понадобиться плагинам. Так как это будет интерфейс, то плагинам достаточно будет подключать только заголовочный файл.
Ну и конечно должны быть реализованы все эти методы в приватном классе ядра. Причем в приватном классе желательно передавать в конструкторе имя плагина:
Код:
class CoreObject : public ICoreObject
{
public:
   CoreObject(const QString& plugin) : _plugin(plugin) {}
   QString plugin() const { return _plugin; }
// сохранение перманентно требуемого файла рядом с проектом
   bool saveFile(const QString& file, const QByteArray& data);
// сохранение данных в проектный файл
   bool saveProject(const QByteArray& data);

private:
   QString _plugin;
};
Таким образом, будет понятно, какой именно плагин дергает функции. Соответственно, при инициализации плагина ядро будет вызывать функцию loadPlugins:
Код:
QString getPluginNameFromPath(const QString& path);

void loadPlugins(const QStringList& pluginPaths)
{
    foreach (QString pluginPath, pluginPaths) {
        QPluginLoader l(pluginPath);
        if (!l.load())
            continue;
        Plugin* p = dynamic_cast<Plugin*>(l.instance());
        if (p == 0)
            continue;
        QString plugin = getPluginNameFromPath(pluginPath);
        CoreObject* obj = new CoreObject(plugin);
        p->init(obj);
        _plugins.insert(plugin, p);
        _objects.insert(plugin, obj);
    }
}

QString getPluginNameFromPath(const QString& path)
{
    QString result = QFileInfo(path).fileName();
#ifdef Q_WS_WIN
    result.chop(4);       // убираем с конца ".dll"
#else
#ifdef Q_WS_MAC
    result.chop(6);       // убираем с конца ".dylib"
#else
    result.chop(3);       // убираем с конца ".so"
#endif
    result = result.mid(3); // убираем с начала "lib"
#endif
    return result;
}

Но это такое. На самом деле, без знания алгоритмов, как формируется проектный и прочие файлы, сложно сказать, как лучше построить архитектуру.
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #8 : Июнь 25, 2015, 15:16 »

Но это такое. На самом деле, без знания алгоритмов, как формируется проектный и прочие файлы, сложно сказать, как лучше построить архитектуру.
Не вижу никакой "специфики" которую необходимо дополнительно знать. Проблемы-то видны невооруженным глазом. Мои соображения

1) Куда писать (место для файлов). Фолдер рядом с файлом проекта, напр "Plugin Data". Не вижу никакой необходимости делать его скрытым. Наоборот, юзер может в любой момент его очистить, да, будет ждать пересоздания.

2) Конфликт "несколько (инстансов) плагинов в одном проекте" - ну видимо решается уникальным ID которое хранится в хосте для каждого подключенного плагина. Именем файла (как оно в ФС) должен рулить хост, также хранить "внутреннее" имя, по которому плагин обращается к файлу.

3) Конфликт "несколько проектов в 1 фолдере" - пожалуй самый проблематичный случай. Городить "свой фолдер данных для каждого проекта" - думаю нехорошо.  Юзер решил работать с неск проектами в 1 фолдере (часто с неск версиями 1 проекта) - ну и "Plugin Data" один. Нужно какое-то "ID проекта" + полное имя файла проекта записанное в нем самом. Так можно отловить что проект скопирован/перемещен. Правда что дальше (и как синхронизировать файлы плагинов) - неясно. Обычно файл читается/используется гораздо чаще чем пишется, поэтому ничего плохого если неск проектов шарят файл(ы) по чтению.
Записан
sociopath
Гость
« Ответ #9 : Июнь 25, 2015, 17:19 »

Если очень хочется синхронизировать plugin data между разными проектами - флаг вам в руки) Я бы поленился таким заниматься. Имхо для каждого проекта свой plugin data будет и проще в реализации, и проще для пользователя (раз каталог не скрыт, то пользователь должен ясно понимать, к какому проекту он относится; в случае shared каталога он этого не поймет). Если файл проекта скопирован, программа должна иметь возможность восстановить рабочее состояние проекта, сгенерировав plugin data по новому пути. Ну это все имхо основанное на наблюдениях, как работает большинство софта с проектными файлами.
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #10 : Июнь 26, 2015, 09:24 »

Кажется все придумалось. Все-таки жаль что не удалось "попользоваться готовым" Улыбающийся Ну ладно, это не последняя задача

Спасибо принявшим участие в обсуждении
Записан
Страниц: [1]   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.107 секунд. Запросов: 22.