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:
// 16×16 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.jsExt.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脚本
exampleset -e. /etc/default/openmediavault
. /usr/share/openmediavault/scripts/helper-functions
OMV_EXAMPLE_XPATH="/config/services/example"OMV_EXAMPLE_CONF="/tmp/example.conf"
cat < ${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/