Лингвофорум

Лингвоблоги => Личные блоги => Блоги => Алексей Гринь => Тема начата: Алексей Гринь от января 15, 2015, 01:05

Название: ГриньСкрипт и плагины
Отправлено: Алексей Гринь от января 15, 2015, 01:05
Использую ГриньСкрипт для одной программы, в которой существует идея неких кусков факультативного кода, который может быть добавлен из третьих источников или сделан самим - то, что обычно называется плагинами, расширениями и т.д.

Смысл плагинов заключается в том, что они должны появиться в меню; щёлканье по плагину должно активировать кое-что, что переопределяет пару методов, которые могут основной программой вызываться в контексте её выполнения, чтобы расширить функциональность, стало быть.

Архитектуру для этого я придумал следующую:

а) Сама программа является ничем иным, как runtime-средой ГриньСкрипт, запущенной launcher.exe, чья работа есть запускать ГриньСкрипт с нужными параметрами + показ SplashScreen, пока Гринь-среда загружается. Точкой входа является Гринь-модуль "main".

б) Допустим, новый плагин был предварительно добавлен в определённую папку, "plugins".
в) Перед тем как запустить саму Гринь-среду, launcher сканирует эту папку, строит список плагинов (тупо список файлов) и генерирует скриптовый файл "imports":

import coolplugin;
import editplugin;
и т.д.

г) Стало быть, "main"-модуль заранее спроектирован так, что он импортирует файл "imports" (пусть даже если он поначалу пустой). Это значит, что при запуске Гринь-среда автоматически импортирует все файлы-модули в папке "plugins" (в этом и прелесть скриптовых языков, можно свободно редактировать исходники).

д) Теперь, когда всё импортировано и всё готово, в дело идёт рефлексия. С помощью рефлексии мы проходимся по всем классам, которые наследуют класс X (файлы-модули расширяют его) и с помощью атрибутов и прочей мишуры мы динамически строим меню, добавляем обработчики событий, связываем действия и т.д.

е) Когда наконец-то наступает время вызвать некий функционал в плагине, main-модуль делает это с помощью нового метода под названием Domain::invokeSecure. Этот метод временно переводит текущий домен в режим "sandbox" и вызывает Гринь-замыкание, которое оборачивает защищённый код. Если в плагине произойдёт ошибка, то метод просто возвратит код ошибки. Если плагин попытается использоваться inline C-код, ECalls, Marshal (вне базовых модулей!), или попытается обратиться к диску без разрешения - то такой плагин вылетит с ошибкой "Code access denied", (отому что текущий режим - sandbox). Чтобы определить, вызывает ли метод небезопасный код, ГриньСкрипт рекурсивно инспектирует AST expressions, которые закреплены за замыканиям и которые хранятся в памяти рядом со скомпилированным кодом.

Такие вот дела.