梅林AM380软件中心插件开发教程详解

sadoneli edited this page Dec 21, 2017 · 1 revision

梅林软件中心插件开发教程详解

(教程镜像链接)

下面我们将按照以下顺序进行详解

1. 梅林插件介绍

2. 插件目录结构

3. 插件的命名规范

4. 插件相关参数提交及保存

5. 插件如何调用shell执行相关功能

6. 插件安装&卸载脚本

7. 插件打包成离线安装包


1.梅林插件介绍

梅林插件通俗来说是对路由器本身功能的一个扩展,让其原本不支持的功能通过扩展插件的方式实现,那么功能有多强呢?有句话叫:贫穷限制了我们的想象力。只有想不到,没有做不到!


2.插件目录结构

                               kms.tar.gz
                                   |  
    -----------------------------------------------------
    |       |        |         |        |               |
   bin     res     script     web    install.sh     uninstall.sh
    |       |        |         |
 vlmcsd     |        |   Module_kms.asp
        icon-kms.png |
                   kms.sh
  • bin:执行文件目录 ,二进制执行文件都放在里面
  • res:静态资源目录 ,件的图标、css样式、javascript脚本等
  • Script:shell脚本目录 ,当页面提交保存之后需要执行的shell脚本都放在里面
  • Web:插件的页面文件
  • install.sh:插件安装脚本
  • uninstall.sh:插件卸载脚本

3.插件的命名规范

以kms插件为例所有插件都必须以此规范开发 压缩包名:kms.tar.gz Web页面:Module_kms.asp Icon图标:icon-kms.png 以上3个文件必须以这种方式定义,粗体的可以更改为你要开发插件名。 例如 xxx.tar.gz 那么web页面就是: Module_xxx.asp Bin、script不做限制,子页面不做限制


4.插件相关参数提交及保存

首先说一下插件的运作原理:
页面设置保存 – 提交至 dbus 保存参数–dbus执行提交的shell脚本名称 –        shell脚本通过dbus 获取所需执行的参数

这是kms插件的页面代码 Module_kms.asp

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
	<head>
		<meta http-equiv="X-UA-Compatible" content="IE=Edge" />
		<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
		<meta HTTP-EQUIV="Pragma" CONTENT="no-cache" />
		<meta HTTP-EQUIV="Expires" CONTENT="-1" />
		<link rel="shortcut icon" href="images/favicon.png" />
		<link rel="icon" href="images/favicon.png" />
		<title>软件中心 - 系统工具</title>
		<link rel="stylesheet" type="text/css" href="index_style.css" />
		<link rel="stylesheet" type="text/css" href="form_style.css" />
		<link rel="stylesheet" type="text/css" href="usp_style.css" />
		<link rel="stylesheet" type="text/css" href="ParentalControl.css">
		<link rel="stylesheet" type="text/css" href="css/icon.css">
		<link rel="stylesheet" type="text/css" href="css/element.css">
		<script type="text/javascript" src="/state.js"></script>
		<script type="text/javascript" src="/popup.js"></script>
		<script type="text/javascript" src="/help.js"></script>
		<script type="text/javascript" src="/validator.js"></script>
		<script type="text/javascript" src="/js/jquery.js"></script>
		<script type="text/javascript" src="/general.js"></script>
		<script type="text/javascript" src="/switcherplugin/jquery.iphone-switch.js"></script>
		<script language="JavaScript" type="text/javascript" src="/client_function.js"></script>
		<script type="text/javascript" src="/dbconf?p=kms_&v=<% uptime(); %>"></script>
		<script>
			var $j = jQuery.noConflict();
			function init() {
				show_menu(menu_hook);
				buildswitch();
				version_show();
				var rrt = document.getElementById("switch");
				if (document.form.kms_enable.value != "1") {
					rrt.checked = false;
				} else {
					rrt.checked = true;
				}
				 $j('#kms_wan_port').val(db_kms_["kms_wan_port"]);
			}
			function done_validating() {
				return true;
			}
			
			function buildswitch(){
				$j("#switch").click(
					function(){
					if(document.getElementById('switch').checked){
						document.form.kms_enable.value = 1;
					}else{
						document.form.kms_enable.value = 0;
					}
				});
			}
			
			function onSubmitCtrl(o, s) {
				document.form.action_mode.value = s;
				showLoading(3);
				document.form.submit();
			}
			
			function reload_Soft_Center(){
				location.href = "/Main_Soft_center.asp";
			}
			
			function version_show(){
				$j("#kms_version_status").html("<i>当前版本:" + db_kms_['kms_version']);
			    $j.ajax({
			        url: 'https://raw.githubusercontent.com/koolshare/koolshare.github.io/acelan_softcenter_ui/kms/config.json.js',
			        type: 'GET',
			        success: function(res) {
			            var txt = $j(res.responseText).text();
			            if(typeof(txt) != "undefined" && txt.length > 0) {
			                //console.log(txt);
			                var obj = $j.parseJSON(txt.replace("'", "\""));
					$j("#kms_version_status").html("<i>当前版本:" + obj.version);
					if(obj.version != db_kms_["kms_version"]) {
						$j("#kms_version_status").html("<i>有新版本:" + obj.version);
					}
			            }
			        }
			    });
			}
			
			var enable_ss = "<% nvram_get("enable_ss"); %>";
			var enable_soft = "<% nvram_get("enable_soft"); %>";
			function menu_hook(title, tab) {
				tabtitle[tabtitle.length -1] = new Array("", "KMS");
				tablink[tablink.length -1] = new Array("", "Module_kms.asp");
			}
		</script>
	</head>
	<body onload="init();">
		<div id="TopBanner"></div>
		<div id="Loading" class="popup_bg"></div>
		<iframe name="hidden_frame" id="hidden_frame" src="" width="0" height="0" frameborder="0"></iframe>
		<form method="POST" name="form" action="/applydb.cgi?p=kms_" target="hidden_frame">
			<input type="hidden" name="current_page" value="Module_kms.asp" />
			<input type="hidden" name="next_page" value="Module_kms.asp" />
			<input type="hidden" name="group_id" value="" />
			<input type="hidden" name="modified" value="0" />
			<input type="hidden" name="action_mode" value="" />
			<input type="hidden" name="action_script" value="" />
			<input type="hidden" name="action_wait" value="5" />
			<input type="hidden" name="first_time" value="" />
			<input type="hidden" name="preferred_lang" id="preferred_lang" value="<% nvram_get(" preferred_lang "); %>"/>
			<input type="hidden" name="SystemCmd" onkeydown="onSubmitCtrl(this, ' Refresh ')" value="kms.sh" />
			<input type="hidden" name="firmver" value="<% nvram_get(" firmver "); %>"/>
			<input type="hidden" id="kms_enable" name="kms_enable" value='<% dbus_get_def("kms_enable", "0"); %>' />
			<table class="content" align="center" cellpadding="0" cellspacing="0">
				<tr>
					<td width="17">&nbsp;</td>
					<td valign="top" width="202">
						<div id="mainMenu"></div>
						<div id="subMenu"></div>
					</td>
					<td valign="top">
						<div id="tabMenu" class="submenuBlock"></div>
						<table width="98%" border="0" align="left" cellpadding="0" cellspacing="0">
							<tr>
								<td align="left" valign="top">
									<table width="760px" border="0" cellpadding="5" cellspacing="0" bordercolor="#6b8fa3" class="FormTitle" id="FormTitle">
										<tr>
											<td bgcolor="#4D595D" colspan="3" valign="top">
												<div>&nbsp;</div>
												<div style="float:left;" class="formfonttitle">系统工具 - 来自网络的胃軟系统工具</div>
												<div style="float:right; width:15px; height:25px;margin-top:10px">
													<img id="return_btn" onclick="reload_Soft_Center();" align="right" style="cursor:pointer;position:absolute;margin-left:-30px;margin-top:-25px;" title="返回软件中心" src="/images/backprev.png" onMouseOver="this.src='/images/backprevclick.png'" onMouseOut="this.src='/images/backprev.png'"></img>
												</div>
												<div style="margin-left:5px;margin-top:10px;margin-bottom:10px">
													<img src="/images/New_ui/export/line_export.png">
												</div>
												<div class="formfontdesc" id="cmdDesc">该工具用于“鸡或”“胃軟奥菲斯”和“胃軟操作系统”。</div>
												<div class="formfontdesc" id="cmdDesc"></div>
												<table style="margin:10px 0px 0px 0px;" width="100%" border="1" align="center" cellpadding="4" cellspacing="0" bordercolor="#6b8fa3" class="FormTable" id="kms_table">
													<thead>
														<tr>
															<td colspan="2">系统工具选项</td>
														</tr>
													</thead>
													<tr>
														<th>开启系统工具</th>
														<td colspan="2">
															<div class="switch_field" style="display:table-cell;float: left;">
																<label for="switch">
																	<input id="switch" class="switch" type="checkbox" style="display: none;">
																	<div class="switch_container">
																		<div class="switch_bar"></div>
																		<div class="switch_circle transition_style">
																			<div></div>
																		</div>
																	</div>
																</label>
															</div>
															<div id="kms_version_show" style="padding-top:5px;margin-left:230px;margin-top:0px;"><i>当前版本:<% dbus_get_def("kms_version", "未知"); %></i>
															</div>
															<div id="kms_install_show" style="padding-top:5px;margin-left:330px;margin-top:-25px;"></div>
															<a style="margin-left: 318px;" href="https://raw.githubusercontent.com/koolshare/koolshare.github.io/acelan_softcenter_ui/kms/Changelog.txt" target="_blank"><em>[<u> 更新日志 </u>]</em></a>
														</td>
													</tr>
													<tr id="port_tr">
														<th width="35%">外网开关</th>
														<td>
															<div style="float:left; width:165px; height:25px">
																<select id="kms_wan_port" name="kms_wan_port" style="width:164px;margin:0px 0px 0px 2px;" class="input_option">
																	<option value="0">关闭</option>
																	<option value="1">开启</option>
																</select>
															</div>
														</td>
													</tr>
												</table>
												<div class="apply_gen">
													<button id="cmdBtn" class="button_gen" onclick="onSubmitCtrl(this, ' Refresh ')">提交</button>
												</div>
												<div style="margin-left:5px;margin-top:10px;margin-bottom:10px">
													<img src="/images/New_ui/export/line_export.png">
												</div>
												<div id="NoteBox">
													<h2>使用说明:</h2>
													<h3>以管理员身份运行CMD输入以下命令,红色字体代表变量不是固定的,请参照自己的计算机修改。</h3>
													<h3>【1】 奥菲斯鸡或</h3>
													<p>CD <font color="red">X</font>:\Program Files<font color="red">(X86)</font>\Microsoft Office\Office<font color="red">14</font>
													</p>
													<p>cscript ospp.vbs /sethst:<font color="red">192.168.0.1</font>
													</p>
													<p>cscript ospp.vbs /act</p>
													<p>cscript ospp.vbs /dstatus</p>
													<h3>【2】 操作系统鸡或</h3>
													<p>slmgr /ipk <font color="red">MHF9N-XY6XB-WVXMC-BTDCT-MKKG7</font>
													</p>
													<p>slmgr /skms <font color="red">192.168.0.1</font>
													</p>
													<p>slmgr /ato</p>
													<h2>申明:本工具来自国外互联网 <a href="https://forums.mydigitallife.info/threads/50234-Emulated-KMS-Servers-on-non-Windows-platforms" target="_blank">点我跳转</a></h2>
												</div>
												<div style="margin-left:5px;margin-top:10px;margin-bottom:10px">
													<img src="/images/New_ui/export/line_export.png">
												</div>
												<div class="KoolshareBottom">
													<br/>论坛技术支持:
													<a href="http://www.koolshare.cn" target="_blank"> <i><u>www.koolshare.cn</u></i> 
													</a>
													<br/>后台技术支持: <i>Xiaobao</i> 
													<br/>Shell, Web by: <i>fw867</i>
													<br/>
												</div>
											</td>
										</tr>
									</table>
								</td>
								<td width="10" align="center" valign="top"></td>
							</tr>
						</table>
					</td>
				</tr>
			</table>
		</form>
		</td>
		<div id="footer"></div>
	</body>
</html>

dbus中到底存了哪些数据?

我们可以通过http://192.168.x.x/dbconf?p=kms_ 来查看dbus中保存以kms_保存的所有数据 下面是 dbus 中的数据:

var db_kms_=(function() {
var o={};
o['kms_enable']='1';
o['kms_title']='奥菲斯激活工具';
o['kms_version']='1.4';
o['kms_wan_port']='0';
return o;
})();

javascript 和 页面取值的方法

第25行,当你载入页面javascript默认会调用并取出所有kms的参数

<script type="text/javascript" src="/dbconf?p=kms_&v=<% uptime(); %>"></script>

Javascript中,我们用 db_kms_["kms_wan_port"] 来取值,比如:

var $prot = db_kms_["kms_wan_port"];

Html标签中我们用 <% dbus_get_def("kms_enable", "0"); %>

<input id="kms_enable" name="kms_enable" value='<% dbus_get_def("kms_enable", "0"); %>' />

第一个参数代表 dbus中的数据名,第二参数:如果值为空,那么默认为 0


获取路由器NVRAM中数据的方法 <% nvram_get(" firmver "); %>

<input type="hidden" name="firmver" value="<% nvram_get("firmver"); %>"/>

那么除了页面载入获取数据我们可不可以用其他方式获取?当然可以!

$.ajax({
	url: '/dbconf?p=kms_',
	dataType: 'html',
	error: function(xhr) {},
	success: function(response) {
		//do someting here...
	}
});

我们可以通过ajax获取!


如何提交保存?

我们可以看module_kms.asp 第 96 行:

<form method="POST" name="form" action="/applydb.cgi?p=kms_" target="hidden_frame">

这里的 form 定义了提交到dbus的插件数据名(相当于数据库的表名) "applydb.cgi?p=kms_" 只要你点击提交那么input标签里面的值都会保存到dbus中。下面就是执行shell当你执行的时候其实也等于是提交保存。


5. 插件如何调用shell执行相关功能

我们可以通过ajax提交并执行shell脚本!

var dbus={};
dbus["SystemCmd"] = "kms.sh";
dbus["action_mode"] = " Refresh ";
dbus["current_page"] = "Module_kms.asp";
dbus["kms_enable"] = 1;
$.ajax({
	type: "POST",
	url: '/applydb.cgi?p=kms_',
	contentType: "application/x-www-form-urlencoded",
	dataType: 'text',
	data: dbus,
	success: function(response) {
		//do something here...
	}
});

那么提交之后我们总要让路由器做点什么!

dbus["SystemCmd"] = "kms.sh";
dbus["action_mode"] = " Refresh ";
dbus["current_page"] = "Module_kms.asp";

将以上3个参数提交dbus会根据你提交的这3个参数执行以下动作:

  1. 执行kms/script/kms.sh
  2. 执行完会刷新页面
  3. 会跳转到当前页面 Module_kms.asp

除了ajax提交执行外页面也自带提交执行,我们来看 97、98、106行的代码

<input name="current_page" value="Module_kms.asp" />
<input name="next_page" value="Module_kms.asp" />
<input name="SystemCmd" onkeydown="onSubmitCtrl(this, ' Refresh ')" value="kms.sh" />

当你提交之后那么页面也会提交这些参数并执行。

那么我们来看看kms.sh的神秘之处:kms.sh

#!/bin/sh
# load path environment in dbus databse
eval `dbus export kms`
source /koolshare/scripts/base.sh
CONFIG_FILE=/jffs/configs/dnsmasq.d/kms.conf
FIREWALL_START=/jffs/scripts/firewall-start

start_kms(){
	/koolshare/bin/vlmcsd
	echo "srv-host=_vlmcs._tcp.lan,`uname -n`.lan,1688,0,100" > $CONFIG_FILE
	nvram set lan_domain=lan
   	nvram commit
	service restart_dnsmasq
	# creating iptables rules to firewall-start
	mkdir -p /jffs/scripts
	if [ ! -f $FIREWALL_START ]; then 
		cat > $FIREWALL_START <<-EOF
		#!/bin/sh
	EOF
	fi

	# creat start_up file
	if [ ! -L "/koolshare/init.d/S97Kms.sh" ]; then 
		ln -sf /koolshare/scripts/kms.sh /koolshare/init.d/S97Kms.sh
	fi
}
stop_kms(){
	# clear start up command line in firewall-start
	killall vlmcsd
	rm $CONFIG_FILE
	service restart_dnsmasq
}

open_port(){
	ifopen=`iptables -S -t filter | grep INPUT | grep dport |grep 1688`
	if [ -z "$ifopen" ];then
		iptables -t filter -I INPUT -p tcp --dport 1688 -j ACCEPT
	fi

	if [ ! -f $FIREWALL_START ]; then
		cat > $FIREWALL_START <<-EOF
		#!/bin/sh
		EOF
	fi
	
	fire_rule=$(cat $FIREWALL_START | grep 1688)
	if [ -z "$fire_rule" ];then
		cat >> $FIREWALL_START <<-EOF
		iptables -t filter -I INPUT -p tcp --dport 1688 -j ACCEPT
		EOF
	fi
}

close_port(){
	ifopen=`iptables -S -t filter | grep INPUT | grep dport |grep 1688`
	if [ ! -z "$ifopen" ];then
		iptables -t filter -D INPUT -p tcp --dport 1688 -j ACCEPT
	fi

	fire_rule=$(cat $FIREWALL_START | grep 1688)
	if [ ! -z "$fire_rule" ];then
		sed -i '/1688/d' $FIREWALL_START >/dev/null 2>&1
	fi
}

case $ACTION in
start)
	if [ "$kms_enable" == "1" ]; then
		logger "[软件中心]: 启动KMS!"
		start_kms
		[ "$kms_wan_port" == "1" ] && open_port
	else
		logger "[软件中心]: KMS未设置开机启动,跳过!"
	fi
	;;
stop)
	close_port >/dev/null 2>&1
	stop_kms
	;;
*)
	if [ "$kms_enable" == "1" ]; then
		close_port >/dev/null 2>&1
		stop_kms
   		start_kms
   		[ "$kms_wan_port" == "1" ] && open_port
   	else
   		close_port
		stop_kms
	fi
	;;
esac

如何让脚本开机自启动呢?下面的脚本就是:

 # creat start_up file
    if [ ! -L "/koolshare/init.d/S97Kms.sh" ]; then 
        ln -sf /koolshare/scripts/kms.sh /koolshare/init.d/S97Kms.sh
    fi

其实就是将kms.sh 做了个软连接到init.d文件夹下并以S+数字的形式。 这样软件中心就会在开机自动执行该脚本的 $ACTION start方法。

6.插件安装&卸载脚本

插件的安装脚本:install.sh

#!/bin/sh

# stop kms first
enable=`dbus get kms_enable`
if [ "$enable" == "1" ];then
	restart=1
	dbus set kms_enable=0
	sh /koolshare/scripts/kms.sh
fi

# cp files
cp -rf /tmp/kms/scripts/* /koolshare/scripts/
cp -rf /tmp/kms/bin/* /koolshare/bin/
cp -rf /tmp/kms/webs/* /koolshare/webs/
cp -rf /tmp/kms/res/* /koolshare/res/

# delete install tar
rm -rf /tmp/kms* >/dev/null 2>&1

chmod a+x /koolshare/scripts/kms.sh
chmod 0755 /koolshare/bin/vlmcsd

# re-enable kms
if [ "$restart" == "1" ];then
	dbus set kms_enable=1
	sh /koolshare/scripts/kms.sh
fi

插件的卸载脚本:uninstall.sh

#!/bin/sh

rm /koolshare/bin/vlmcsd
rm /koolshare/res/icon-kms.png
rm /koolshare/scripts/kms.sh
rm /koolshare/webs/Module_kms.asp

7.插件打包成离线安装包

只要按照将先压缩成tar格式再压缩成gz就行了。 注意的是 install.sh 不能缺失,否则无法安装。


You can’t perform that action at this time.
You signed in with another tab or window. Reload to refresh your session. You signed out in another tab or window. Reload to refresh your session.
Press h to open a hovercard with more details.