openmediavault 插件开发
OpenMediaVault,简称omv,是一个开源的基于Debian Linux的下一代网络附加存储(NAS)解决方案。它包含众多服务,如SSH,(S)FTP,SMB / CIFS,DAAP媒体服务器,RSync,BitTorrent客户机等。 并具有通过插件可增强的模块化设计框架特性。
OMV的插件开发,由三个部分组成
GUI
配置文件与RPC
模块与shell脚本
GUI(web界面)
后台自动扫描以下目录及其子目录
/var/www/openmediavault/js/omv/module/admin/ /var/www/openmediavault/js/omv/module/user/ /var/www/openmediavault/js/omv/module/public/
1.在service目录下新加一个目录example
/var/www/openmediavault/js/omv/module/admin/service/example
2.新增一个node(左侧导航栏的一个tree对象),创建/var/www/openmediavault/js/omv/module/admin/service/example/EXample.js
// Register a node in the navigation tree. // // id: // Set the ID of the node. // path: // Parent path in the navigation view. // Text: // Service name/title. This is displayed in the navigation. // icon16: // 16x16 pixel icon that is displayed in the navigation tree. // iconSvg: // SVG icon that is displayed in the navigation view. OMV.WorkspaceManager.registerNode({ id: 'example', path: '/service', text: _('Example'), icon16: 'p_w_picpaths/example.png', iconSvg: 'p_w_picpaths/example.svg'});
注:test:_()这里面的内容能跟随页面自动翻译成各国语言
3.node的主视图(workspace)
从workspace类派生,创建Settings.js
Ext.define('OMV.module.admin.service.example.Settings', { extend: 'OMV.workspace.form.Panel', // This path tells which RPC module and methods this panel will call to get // and fetch its form values. rpcService: 'Example', rpcGetMethod: 'getSettings', rpcSetMethod: 'setSettings', // getFormItems is a method which is automatically called in the // instantiation of the panel. This method returns all fields for // the panel. getFormItems: function() { return [{ // xtype defines the type of this entry. Some different types // is: fieldset, checkbox, textfield and numberfield. xtype: 'fieldset', title: _('General'), fieldDefaults: { labelSeparator: '' }, // The items array contains items inside the fieldset xtype. items: [{ xtype: 'checkbox', // The name option is sent together with is value to RPC // and is also used when fetching from the RPC. name: 'enable', fieldLabel: _('Enable'), // checked sets the default value of a checkbox. checked: false }, { xtype: 'numberfield', name: 'max_value', fieldLabel: _('Max value'), minValue: 0, maxValue: 100, allowDecimals: false, allowBlank: true }] }]; } }); // Register a panel into the GUI. // // path: // We want to add the panel in our example node. // The node was configured with the path /service and the id example. // The path is therefore /service/example. className: // The panel which should be registered and added (refers to // the class name). OMV.WorkspaceManager.registerPanel({ id: 'settings', path: '/service/example', text: _('Settings'), position: 10, className: 'OMV.module.admin.service.example.Settings'});
注:定义了rpc,此时在页面刷新会报错。“RPC service not found (name=Example)”,此时需要添加rpc文件/usr/share/openmediavault/engined/rpc/example.inc,内容见第二部分
配置文件config.xml和RPC
Config.xml
/etc/openmediavault/config.xml储存了插件设置项,可以在制作debian包时,写在postinst脚本里
#!/bin/shset -e . /etc/default/openmediavault . /usr/share/openmediavault/scripts/helper-functions case "$1" in configure) SERVICE_XPATH_NAME="example" SERVICE_XPATH="/config/services/${SERVICE_XPATH_NAME}" # Add the default configuration if ! omv_config_exists "${SERVICE_XPATH}"; then omv_config_add_element "/config/services" "${SERVICE_XPATH_NAME}" omv_config_add_element "${SERVICE_XPATH}" "enable" "0" omv_config_add_element "${SERVICE_XPATH}" "max_value" "0" fi # Activate package triggers. These triggers are only set during the # package installation. dpkg-trigger update-fixperms dpkg-trigger update-locale ;; abort-upgrade|abort-remove|abort-deconfigure) ;; *) echo "postinst called with unknown argument" >&2 exit 1 ;;esac #DEBHELPER# exit 0
The RPC = Remote Procedure Call
RPC文件存储在/usr/share/openmediavault/engined/rpc目录下,inc结尾的php文件,rpc文件连接了web GUI和config.xml,使得界面可以控制config文件
example.inc
<?php
require_once 'openmediavault/config.inc';
require_once 'openmediavault/error.inc';
require_once 'openmediavault/notify.inc';
require_once 'openmediavault/rpcservice.inc';
class OMVRpcServiceExample extends OMVRpcServiceAbstract{
/**
* The main event message path.
*
* @var string
*/
private $eventMessagePath = 'org.openmediavault.services.example'; /**
* Get the base XPath of the service. This is a helper function to avoid
* "magic numbers".
*
* @return string
*/
private function getXpath()
{ return '/config/services/example';
}
/**
* Get the name of the RPC service.
*
* @return string
*/
public function getName()
{ return 'Example';
}
/**
* Initialize the RPC service. The RPC methods are registered in this
* function with $this->registerMethod.
*
* @return void
*/
public function initialize()
{ $this->registerMethod('getSettings');
$this->registerMethod('setSettings');
}
public function getSettings($params, $context)
{
// $xmlConfig is needed when reading and writing from the configuration.
global $xmlConfig;
// Validate the RPC caller context.
//
// validateMethodContext takes the currentcontext as the first
// parameter. The second paramter is the valid context and that can be
// OMV_ROLE_ADMINISTRATOR, OMV_ROLE_USER or OMV_ROLE_EVERYONE.
// This is used to make sure that the right user accesses the method.
$this->validateMethodContext($context, ['role' => OMV_ROLE_ADMINISTRATOR]);
// Get the configuration object.
$object = $xmlConfig->get($this->getXpath());
// If no data was found, throw an exception and provide the XPath that
// failed.
if (is_null($object)) {
throw new OMVException(
OMVErrorMsg::E_CONFIG_GET_OBJECT_FAILED,
$this->getXpath()
);
}
// Modify the result data.
// boolval and intval converts strings and numbers to their boolean
// and integer value.
$object['enable'] = boolval($object['enable']);
$object['max_value'] = intval($object['max_value']);
return $object;
}
public function setSettings($params, $context)
{
global $xmlConfig;
$this->validateMethodContext($context, array(
"role" => OMV_ROLE_ADMINISTRATOR
));
// Validate the parameters of the RPC service method.
//
// OpenMediavault uses JSON Schema to validate parameters. A more
// detailed specification is provided here http://json-schema.org/
$this->validateMethodParams(
$params, '{
"type": "object",
"properties": {
"enable": {
"type": "boolean"
},
"max_value":{
"type": "integer",
"minimum": 1,
"maximum": 100
}
}
}'
);
// Update the configuration object.
$object = [
'enable' => boolval($params['enable']),
'max_value' => $params['max_value'],
];
// Update the configuration file. If it fails it throws an exception.
if ($xmlConfig->replace($this->getXpath(), $object) === false) {
throw new OMVException(
OMVErrorMsg::E_CONFIG_SET_OBJECT_FAILED,
$this->getXpath()
);
}
// Notify configuration changes.
//
// This will notify event listeners such as the service module
// to perform certain tasks. The most common one is to mark the
// service as dirty.
$dispatcher = &OMVNotifyDispatcher::getInstance();
$dispatcher->notify(OMV_NOTIFY_MODIFY, $this->eventMessagePath, $object);
return $object;
}
}
// Register the RPC service.
$rpcServiceMgr = &OMVRpcServiceMgr::getInstance();
$rpcServiceMgr->registerService(new OMVRpcServiceExample());
模块与shell脚本
module
RPC用来实现界面修改和获取配置文件,模块用来监控和使其修改生效。模块目录在/usr/share/openmediavault/engined/module
Example.inc
<?php
require_once 'openmediavault/config.inc';
require_once 'openmediavault/error.inc';
require_once 'openmediavault/initscript.inc';
require_once 'openmediavault/module.inc';
class OMVModuleExample extends OMVModuleServiceAbstract implements
OMVINotifyListener,
OMVIModuleServiceStatus{
/**
* The main event message path.
*
* @var string
*/
private $eventMessagePath = 'org.openmediavault.services.example';
}
/**
* Get the base XPath of the service. This is a helper function to avoid
* "magic numbers".
*
* @return string
*/
private function getXpath()
{ return '/config/services/example';
}
/**
* Get the module name.
*
* @return string
*/
public function getName()
{ return 'example';
}
/**
* Get the module status.
*
* @return array
*
* @throws OMVException
*/
public function getStatus()
{
global $xmlConfig;
// Get the configuration object.
$object = $xmlConfig->get($this->getXpath());
if (is_null($object)) {
throw new OMVException(
OMVErrorMsg::E_CONFIG_GET_OBJECT_FAILED,
$this->getXpath()
);
}
// Return the status of the service. This information is displayed
// under Diagnostics/Services.
return array(
'name' => $this->getName(),
'title' => gettext('Example'),
'enabled' => boolval($object['enable']),
'running' => false
);
}
/**
* Generate the configuration.
*
* @return void
*
* @throws OMVException
*/
public function applyConfig()
{
global $xmlConfig;
$cmd = sprintf('export LANG=C; omv-mkconf %s 2>&1', $this->getName());
if (0 !== $this->exec($cmd, $output)) {
throw new OMVException(
OMVErrorMsg::E_EXEC_FAILED,
$cmd,
implode(PHP_EOL, $output)
);
}
}
/**
* Bind listeners.
*
* @param OMVNotifyDispatcher $dispatcher
* @return void
*/
public function bindListeners(OMVNotifyDispatcher $dispatcher)
{
$moduleMgr = &OMVModuleMgr::getInstance();
// Add listeners here. The most common thing is to monitor configuration
// changes on the service. When the config is changed the module
// sets itself as dirty (as seen below). Setting a module as dirty
// makes the apply button appear in the web interface (which in turn
// calls the applyConfig function on each module with a dirty state).
$dispatcher->addListener(
OMV_NOTIFY_MODIFY,
$this->eventMessagePath,
[$this, 'setDirty']
);
}
}
// Register the module.
$moduleMgr = &OMVModuleMgr::getInstance();
$moduleMgr->registerModule(new OMVModuleExample());
注:模块注册了notify,rpc在修改配置文件后会通知notify文件为dirty状态,从而在页面触发apply change提示。
Shell脚本生成配置文件
在module中的applyconfig函数中,执行了omv-mkconf example命令,该命令调用了/usr/share/openmediavault/mkconf/example脚本
example
set -e. /etc/default/openmediavault . /usr/share/openmediavault/scripts/helper-functions OMV_EXAMPLE_XPATH="/config/services/example"OMV_EXAMPLE_CONF="/tmp/example.conf" cat <<EOF > ${OMV_EXAMPLE_CONF}enable = $(omv_config_get "${OMV_EXAMPLE_XPATH}/enable") max_value = $(omv_config_get "${OMV_EXAMPLE_XPATH}/max_value") EOF exit 0
注:需要755权限,执行完该脚本将会生成/tmp/example.conf文件。
至此,一个openmediavault的简单插件源码已经制作完成,接下来只需要制作包就可以啦。
refer:https://forum.openmediavault.org/index.php/Thread/5600-DIY-Plugin-Development/
转载于:https://blog.51cto.com/qujunorz/1940118