[关闭]
@9168131 2017-12-21T22:22:05.000000Z 字数 12921 阅读 20485

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


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

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

  1. <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
  2. <html xmlns="http://www.w3.org/1999/xhtml">
  3. <head>
  4. <meta http-equiv="X-UA-Compatible" content="IE=Edge" />
  5. <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
  6. <meta HTTP-EQUIV="Pragma" CONTENT="no-cache" />
  7. <meta HTTP-EQUIV="Expires" CONTENT="-1" />
  8. <link rel="shortcut icon" href="images/favicon.png" />
  9. <link rel="icon" href="images/favicon.png" />
  10. <title>软件中心 - 系统工具</title>
  11. <link rel="stylesheet" type="text/css" href="index_style.css" />
  12. <link rel="stylesheet" type="text/css" href="form_style.css" />
  13. <link rel="stylesheet" type="text/css" href="usp_style.css" />
  14. <link rel="stylesheet" type="text/css" href="ParentalControl.css">
  15. <link rel="stylesheet" type="text/css" href="css/icon.css">
  16. <link rel="stylesheet" type="text/css" href="css/element.css">
  17. <script type="text/javascript" src="/state.js"></script>
  18. <script type="text/javascript" src="/popup.js"></script>
  19. <script type="text/javascript" src="/help.js"></script>
  20. <script type="text/javascript" src="/validator.js"></script>
  21. <script type="text/javascript" src="/js/jquery.js"></script>
  22. <script type="text/javascript" src="/general.js"></script>
  23. <script type="text/javascript" src="/switcherplugin/jquery.iphone-switch.js"></script>
  24. <script language="JavaScript" type="text/javascript" src="/client_function.js"></script>
  25. <script type="text/javascript" src="/dbconf?p=kms_&v=<% uptime(); %>"></script>
  26. <script>
  27. var $j = jQuery.noConflict();
  28. function init() {
  29. show_menu(menu_hook);
  30. buildswitch();
  31. version_show();
  32. var rrt = document.getElementById("switch");
  33. if (document.form.kms_enable.value != "1") {
  34. rrt.checked = false;
  35. } else {
  36. rrt.checked = true;
  37. }
  38. $j('#kms_wan_port').val(db_kms_["kms_wan_port"]);
  39. }
  40. function done_validating() {
  41. return true;
  42. }
  43. function buildswitch(){
  44. $j("#switch").click(
  45. function(){
  46. if(document.getElementById('switch').checked){
  47. document.form.kms_enable.value = 1;
  48. }else{
  49. document.form.kms_enable.value = 0;
  50. }
  51. });
  52. }
  53. function onSubmitCtrl(o, s) {
  54. document.form.action_mode.value = s;
  55. showLoading(3);
  56. document.form.submit();
  57. }
  58. function reload_Soft_Center(){
  59. location.href = "/Main_Soft_center.asp";
  60. }
  61. function version_show(){
  62. $j("#kms_version_status").html("<i>当前版本:" + db_kms_['kms_version']);
  63. $j.ajax({
  64. url: 'https://raw.githubusercontent.com/koolshare/koolshare.github.io/acelan_softcenter_ui/kms/config.json.js',
  65. type: 'GET',
  66. success: function(res) {
  67. var txt = $j(res.responseText).text();
  68. if(typeof(txt) != "undefined" && txt.length > 0) {
  69. //console.log(txt);
  70. var obj = $j.parseJSON(txt.replace("'", "\""));
  71. $j("#kms_version_status").html("<i>当前版本:" + obj.version);
  72. if(obj.version != db_kms_["kms_version"]) {
  73. $j("#kms_version_status").html("<i>有新版本:" + obj.version);
  74. }
  75. }
  76. }
  77. });
  78. }
  79. var enable_ss = "<% nvram_get("enable_ss"); %>";
  80. var enable_soft = "<% nvram_get("enable_soft"); %>";
  81. function menu_hook(title, tab) {
  82. tabtitle[tabtitle.length -1] = new Array("", "KMS");
  83. tablink[tablink.length -1] = new Array("", "Module_kms.asp");
  84. }
  85. </script>
  86. </head>
  87. <body onload="init();">
  88. <div id="TopBanner"></div>
  89. <div id="Loading" class="popup_bg"></div>
  90. <iframe name="hidden_frame" id="hidden_frame" src="" width="0" height="0" frameborder="0"></iframe>
  91. <form method="POST" name="form" action="/applydb.cgi?p=kms_" target="hidden_frame">
  92. <input type="hidden" name="current_page" value="Module_kms.asp" />
  93. <input type="hidden" name="next_page" value="Module_kms.asp" />
  94. <input type="hidden" name="group_id" value="" />
  95. <input type="hidden" name="modified" value="0" />
  96. <input type="hidden" name="action_mode" value="" />
  97. <input type="hidden" name="action_script" value="" />
  98. <input type="hidden" name="action_wait" value="5" />
  99. <input type="hidden" name="first_time" value="" />
  100. <input type="hidden" name="preferred_lang" id="preferred_lang" value="<% nvram_get(" preferred_lang "); %>"/>
  101. <input type="hidden" name="SystemCmd" onkeydown="onSubmitCtrl(this, ' Refresh ')" value="kms.sh" />
  102. <input type="hidden" name="firmver" value="<% nvram_get(" firmver "); %>"/>
  103. <input type="hidden" id="kms_enable" name="kms_enable" value='<% dbus_get_def("kms_enable", "0"); %>' />
  104. <table class="content" align="center" cellpadding="0" cellspacing="0">
  105. <tr>
  106. <td width="17">&nbsp;</td>
  107. <td valign="top" width="202">
  108. <div id="mainMenu"></div>
  109. <div id="subMenu"></div>
  110. </td>
  111. <td valign="top">
  112. <div id="tabMenu" class="submenuBlock"></div>
  113. <table width="98%" border="0" align="left" cellpadding="0" cellspacing="0">
  114. <tr>
  115. <td align="left" valign="top">
  116. <table width="760px" border="0" cellpadding="5" cellspacing="0" bordercolor="#6b8fa3" class="FormTitle" id="FormTitle">
  117. <tr>
  118. <td bgcolor="#4D595D" colspan="3" valign="top">
  119. <div>&nbsp;</div>
  120. <div style="float:left;" class="formfonttitle">系统工具 - 来自网络的胃軟系统工具</div>
  121. <div style="float:right; width:15px; height:25px;margin-top:10px">
  122. <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>
  123. </div>
  124. <div style="margin-left:5px;margin-top:10px;margin-bottom:10px">
  125. <img src="/images/New_ui/export/line_export.png">
  126. </div>
  127. <div class="formfontdesc" id="cmdDesc">该工具用于“鸡或”“胃軟奥菲斯”和“胃軟操作系统”。</div>
  128. <div class="formfontdesc" id="cmdDesc"></div>
  129. <table style="margin:10px 0px 0px 0px;" width="100%" border="1" align="center" cellpadding="4" cellspacing="0" bordercolor="#6b8fa3" class="FormTable" id="kms_table">
  130. <thead>
  131. <tr>
  132. <td colspan="2">系统工具选项</td>
  133. </tr>
  134. </thead>
  135. <tr>
  136. <th>开启系统工具</th>
  137. <td colspan="2">
  138. <div class="switch_field" style="display:table-cell;float: left;">
  139. <label for="switch">
  140. <input id="switch" class="switch" type="checkbox" style="display: none;">
  141. <div class="switch_container">
  142. <div class="switch_bar"></div>
  143. <div class="switch_circle transition_style">
  144. <div></div>
  145. </div>
  146. </div>
  147. </label>
  148. </div>
  149. <div id="kms_version_show" style="padding-top:5px;margin-left:230px;margin-top:0px;"><i>当前版本:<% dbus_get_def("kms_version", "未知"); %></i>
  150. </div>
  151. <div id="kms_install_show" style="padding-top:5px;margin-left:330px;margin-top:-25px;"></div>
  152. <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>
  153. </td>
  154. </tr>
  155. <tr id="port_tr">
  156. <th width="35%">外网开关</th>
  157. <td>
  158. <div style="float:left; width:165px; height:25px">
  159. <select id="kms_wan_port" name="kms_wan_port" style="width:164px;margin:0px 0px 0px 2px;" class="input_option">
  160. <option value="0">关闭</option>
  161. <option value="1">开启</option>
  162. </select>
  163. </div>
  164. </td>
  165. </tr>
  166. </table>
  167. <div class="apply_gen">
  168. <button id="cmdBtn" class="button_gen" onclick="onSubmitCtrl(this, ' Refresh ')">提交</button>
  169. </div>
  170. <div style="margin-left:5px;margin-top:10px;margin-bottom:10px">
  171. <img src="/images/New_ui/export/line_export.png">
  172. </div>
  173. <div id="NoteBox">
  174. <h2>使用说明:</h2>
  175. <h3>以管理员身份运行CMD输入以下命令,红色字体代表变量不是固定的,请参照自己的计算机修改。</h3>
  176. <h3>【1】 奥菲斯鸡或</h3>
  177. <p>CD <font color="red">X</font>:\Program Files<font color="red">(X86)</font>\Microsoft Office\Office<font color="red">14</font>
  178. </p>
  179. <p>cscript ospp.vbs /sethst:<font color="red">192.168.0.1</font>
  180. </p>
  181. <p>cscript ospp.vbs /act</p>
  182. <p>cscript ospp.vbs /dstatus</p>
  183. <h3>【2】 操作系统鸡或</h3>
  184. <p>slmgr /ipk <font color="red">MHF9N-XY6XB-WVXMC-BTDCT-MKKG7</font>
  185. </p>
  186. <p>slmgr /skms <font color="red">192.168.0.1</font>
  187. </p>
  188. <p>slmgr /ato</p>
  189. <h2>申明:本工具来自国外互联网 <a href="https://forums.mydigitallife.info/threads/50234-Emulated-KMS-Servers-on-non-Windows-platforms" target="_blank">点我跳转</a></h2>
  190. </div>
  191. <div style="margin-left:5px;margin-top:10px;margin-bottom:10px">
  192. <img src="/images/New_ui/export/line_export.png">
  193. </div>
  194. <div class="KoolshareBottom">
  195. <br/>论坛技术支持:
  196. <a href="http://www.koolshare.cn" target="_blank"> <i><u>www.koolshare.cn</u></i>
  197. </a>
  198. <br/>后台技术支持: <i>Xiaobao</i>
  199. <br/>Shell, Web by: <i>fw867</i>
  200. <br/>
  201. </div>
  202. </td>
  203. </tr>
  204. </table>
  205. </td>
  206. <td width="10" align="center" valign="top"></td>
  207. </tr>
  208. </table>
  209. </td>
  210. </tr>
  211. </table>
  212. </form>
  213. </td>
  214. <div id="footer"></div>
  215. </body>
  216. </html>

dbus中到底存了哪些数据?

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

  1. var db_kms_=(function() {
  2. var o={};
  3. o['kms_enable']='1';
  4. o['kms_title']='奥菲斯激活工具';
  5. o['kms_version']='1.4';
  6. o['kms_wan_port']='0';
  7. return o;
  8. })();

javascript 和 页面取值的方法

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

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

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

  1. var $prot = db_kms_["kms_wan_port"];

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

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

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


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

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

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

  1. $.ajax({
  2. url: '/dbconf?p=kms_',
  3. dataType: 'html',
  4. error: function(xhr) {},
  5. success: function(response) {
  6. //do someting here...
  7. }
  8. });

我们可以通过ajax获取!


如何提交保存?

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

  1. <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脚本!

  1. var dbus={};
  2. dbus["SystemCmd"] = "kms.sh";
  3. dbus["action_mode"] = " Refresh ";
  4. dbus["current_page"] = "Module_kms.asp";
  5. dbus["kms_enable"] = 1;
  6. $.ajax({
  7. type: "POST",
  8. url: '/applydb.cgi?p=kms_',
  9. contentType: "application/x-www-form-urlencoded",
  10. dataType: 'text',
  11. data: dbus,
  12. success: function(response) {
  13. //do something here...
  14. }
  15. });

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

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

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

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

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

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

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

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

  1. #!/bin/sh
  2. # load path environment in dbus databse
  3. eval `dbus export kms`
  4. source /koolshare/scripts/base.sh
  5. CONFIG_FILE=/jffs/configs/dnsmasq.d/kms.conf
  6. FIREWALL_START=/jffs/scripts/firewall-start
  7. start_kms(){
  8. /koolshare/bin/vlmcsd
  9. echo "srv-host=_vlmcs._tcp.lan,`uname -n`.lan,1688,0,100" > $CONFIG_FILE
  10. nvram set lan_domain=lan
  11. nvram commit
  12. service restart_dnsmasq
  13. # creating iptables rules to firewall-start
  14. mkdir -p /jffs/scripts
  15. if [ ! -f $FIREWALL_START ]; then
  16. cat > $FIREWALL_START <<-EOF
  17. #!/bin/sh
  18. EOF
  19. fi
  20. # creat start_up file
  21. if [ ! -L "/koolshare/init.d/S97Kms.sh" ]; then
  22. ln -sf /koolshare/scripts/kms.sh /koolshare/init.d/S97Kms.sh
  23. fi
  24. }
  25. stop_kms(){
  26. # clear start up command line in firewall-start
  27. killall vlmcsd
  28. rm $CONFIG_FILE
  29. service restart_dnsmasq
  30. }
  31. open_port(){
  32. ifopen=`iptables -S -t filter | grep INPUT | grep dport |grep 1688`
  33. if [ -z "$ifopen" ];then
  34. iptables -t filter -I INPUT -p tcp --dport 1688 -j ACCEPT
  35. fi
  36. if [ ! -f $FIREWALL_START ]; then
  37. cat > $FIREWALL_START <<-EOF
  38. #!/bin/sh
  39. EOF
  40. fi
  41. fire_rule=$(cat $FIREWALL_START | grep 1688)
  42. if [ -z "$fire_rule" ];then
  43. cat >> $FIREWALL_START <<-EOF
  44. iptables -t filter -I INPUT -p tcp --dport 1688 -j ACCEPT
  45. EOF
  46. fi
  47. }
  48. close_port(){
  49. ifopen=`iptables -S -t filter | grep INPUT | grep dport |grep 1688`
  50. if [ ! -z "$ifopen" ];then
  51. iptables -t filter -D INPUT -p tcp --dport 1688 -j ACCEPT
  52. fi
  53. fire_rule=$(cat $FIREWALL_START | grep 1688)
  54. if [ ! -z "$fire_rule" ];then
  55. sed -i '/1688/d' $FIREWALL_START >/dev/null 2>&1
  56. fi
  57. }
  58. case $ACTION in
  59. start)
  60. if [ "$kms_enable" == "1" ]; then
  61. logger "[软件中心]: 启动KMS!"
  62. start_kms
  63. [ "$kms_wan_port" == "1" ] && open_port
  64. else
  65. logger "[软件中心]: KMS未设置开机启动,跳过!"
  66. fi
  67. ;;
  68. stop)
  69. close_port >/dev/null 2>&1
  70. stop_kms
  71. ;;
  72. *)
  73. if [ "$kms_enable" == "1" ]; then
  74. close_port >/dev/null 2>&1
  75. stop_kms
  76. start_kms
  77. [ "$kms_wan_port" == "1" ] && open_port
  78. else
  79. close_port
  80. stop_kms
  81. fi
  82. ;;
  83. esac

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

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

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

6.插件安装&卸载脚本

插件的安装脚本:install.sh

  1. #!/bin/sh
  2. # stop kms first
  3. enable=`dbus get kms_enable`
  4. if [ "$enable" == "1" ];then
  5. restart=1
  6. dbus set kms_enable=0
  7. sh /koolshare/scripts/kms.sh
  8. fi
  9. # cp files
  10. cp -rf /tmp/kms/scripts/* /koolshare/scripts/
  11. cp -rf /tmp/kms/bin/* /koolshare/bin/
  12. cp -rf /tmp/kms/webs/* /koolshare/webs/
  13. cp -rf /tmp/kms/res/* /koolshare/res/
  14. # delete install tar
  15. rm -rf /tmp/kms* >/dev/null 2>&1
  16. chmod a+x /koolshare/scripts/kms.sh
  17. chmod 0755 /koolshare/bin/vlmcsd
  18. # re-enable kms
  19. if [ "$restart" == "1" ];then
  20. dbus set kms_enable=1
  21. sh /koolshare/scripts/kms.sh
  22. fi

插件的卸载脚本:uninstall.sh

  1. #!/bin/sh
  2. rm /koolshare/bin/vlmcsd
  3. rm /koolshare/res/icon-kms.png
  4. rm /koolshare/scripts/kms.sh
  5. rm /koolshare/webs/Module_kms.asp

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

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


再一次感谢您花费时间阅读这份开发教程,这也是我第一次用makedown写教程,如果你觉得乱先将就着看,以后我会慢慢改进,如果你在开发过程中还有什么不理解的可以和我联系。

QQ:9168131
Telegram:https://t.me/JSMonkey

如果有大神愿意捐赠的欢迎点击:捐赠链接

作者 JSMonkey
2017 年 12月 21日

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注