openwrt使用静态html做web界面

目前官网openwrt系统集成的web界面,使用luci和luci2,关于luci和luci2的不同,可参见下面链接,作者介绍的很详细:
http://blog.csdn.net/wdsfup/article/details/51024150?locationNum=11&fps=1

本人也是使用luci2实现前后端数据交互的,只是界面使用的是html写成的界面,这样界面制作会更灵活,界面风格能更自由;
luci2的实现原理如下图所示:ubus使用cs模型进行通讯,可以参考下面的作者写的:
http://blog.csdn.net/flexman09/article/details/51722582?locationNum=10&fps=1

openwrt使用静态html做web界面_第1张图片

1.后台包源码
(1).编写C源码后,编译生成.so放在目录/usr/lib/rpcd/.so(加粗斜线表示在固件中的路径,下同)*中,rpcd会将方法注册到ubus,使用ubus list,查看接口是否注册到ubus; (可以参考luci2.so中各方法的实现)
(2).对ubus的接口,需要在/usr/share/rpcd/acl.d/.json*赋予接口被调用的读写权限;(可以参考luci2.json文件)
(3).可以在后台使用ubus call调用注册的方法,检测使用能使用,排除后台方法调用的错误;
下面是自己编写c代码和编译的CMakeLists.txt后,生成.so文件的过程,还有就是,将.so放到固件中(包的路径package/luci2/;文件路径/packge/luci2/src/rpcd/下面的文件均在此路径下)
C代码文件:lepton.c如下

 1 #include 
  2 #include 
  3 #include 
  4 #include 
  5 #include 
  6 #include 
  7 #include 
  8 #include 
  9 #include 
 10 #include 
 11 #include 
 12 #include 
 13 #include 
 14 #include 
 15 #include 
 16 #include 
 17 #include 
 18
 19 #include 
 20
 21 static const struct rpc_daemon_ops *ops;
 22 static struct blob_buf buf;
 23
 24 enum {
 25         RPC_P_D_DATA,
 26         RPC_P_D_COUNT,
 27         __RPC_P_D_MAX
 28 };
 29
 30 static const struct blobmsg_policy rpc_ping_data_policy[__RPC_P_D_MAX] = {
 31         [RPC_P_D_DATA]   = { .name = "data",  .type = BLOBMSG_TYPE_STRING },
 32         [RPC_P_D_COUNT]   = { .name = "count",  .type = BLOBMSG_TYPE_STRING },
 33 };
 34
 35 static int
 36 rpc_luci2_network_ping(struct ubus_context *ctx, struct ubus_object *obj,
 37                        struct ubus_request_data *req, const char *method,
 38                        struct blob_attr *msg)
 39 {
 40         char *arg;
 41         char *count = "5";
 42
 43         struct blob_attr *tb_ping[__RPC_P_D_MAX];
 44         blobmsg_parse(rpc_ping_data_policy, __RPC_P_D_MAX, tb_ping,
 45                       blob_data(msg), blob_len(msg));
 46
 47         if (!tb_ping[RPC_P_D_DATA] && !tb_ping[RPC_P_D_COUNT])
 48                 return UBUS_STATUS_INVALID_ARGUMENT;
 49
 50         arg = blobmsg_get_string(tb_ping[RPC_P_D_DATA]);
 51         count = blobmsg_get_string(tb_ping[RPC_P_D_COUNT]);
 52
 53         const char *cmds[7] = { "ping", "-c", count, "-W", "1", arg, NULL };
 54
 55         return ops->exec(cmds, NULL, NULL, NULL, NULL, NULL, ctx, req);
 56 }
 57
 58 static int
 59 rpc_luci2_print_lepton(struct ubus_context *ctx, struct ubus_object *obj,
 60                          struct ubus_request_data *req, const char *method,
 61                          struct blob_attr *msg)
 62 {
 63         char conf[10] = "lepton";
 64         blob_buf_init(&buf, 0);
 65         blobmsg_add_string(&buf, "name", conf);
 66
 67         ubus_send_reply(ctx, req, buf.head);
 68         return 0;
 69 }
 70
 71 static int
 72 rpc_luci2_api_init(const struct rpc_daemon_ops *o, struct ubus_context *ctx)
 73 {
 74         int rv = 0;
 75
 76         static const struct ubus_method luci2_network_methods[] = {
 77                 UBUS_METHOD_NOARG("lepton",          rpc_luci2_print_lepton), //无参操作,ubus接口lepton.network对应的方法名
 78                 UBUS_METHOD("ping1",                  rpc_luci2_network_ping, //有参操作,ubus接口lepton.network对应的方法名
 79                                                      rpc_ping_data_policy)
 80         };
 81
 82         static struct ubus_object_type luci2_network_type =
 83                 UBUS_OBJECT_TYPE("luci-rpc-luci2-lepton", luci2_network_methods);
 84
 85         static struct ubus_object network_obj = {
 86                 .name = "lepton.network", //接口名
 87                 .type = &luci2_network_type,
 88                 .methods = luci2_network_methods,
 89                 .n_methods = ARRAY_SIZE(luci2_network_methods),
 90         };
 91
 92         ops = o;
 93
 94         rv |= ubus_add_object(ctx, &network_obj);
 95
 96         return rv;
 97 }
 98
 99 struct rpc_plugin rpc_plugin = {
100         .init = rpc_luci2_api_init
101 };

对应的CMakeLists.txt,此处还有别的C文件也在此编译,看lepton的部分即可:

1 cmake_minimum_required(VERSION 2.6)
  2
  3
  4 PROJECT(luci2-plugin C)
  5
  6 ADD_DEFINITIONS(-Os -Wall -Werror --std=gnu99 -g3 -Wmissing-declarations -Iinclude)
  7
  8 SET(CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "")
  9
 10 IF(APPLE)
 11   INCLUDE_DIRECTORIES(/opt/local/include)
 12   LINK_DIRECTORIES(/opt/local/lib)
 13 ENDIF()
 14
 15 FIND_LIBRARY(crypt NAMES crypt)
 16 IF(crypt STREQUAL "LIBS-NOTFOUND")
 17   SET(crypt "")
 18 ENDIF()
 19
 20 ADD_LIBRARY(luci2-plugin MODULE luci2.c)
 21 TARGET_LINK_LIBRARIES(luci2-plugin ubox ubus ${crypt})
 22 SET_TARGET_PROPERTIES(luci2-plugin PROPERTIES OUTPUT_NAME luci2 PREFIX "")
 23
 24 ADD_LIBRARY(bwmon-plugin MODULE bwmon.c)
 25 SET_TARGET_PROPERTIES(bwmon-plugin PROPERTIES OUTPUT_NAME bwmon PREFIX "")
 26
 27 ADD_LIBRARY(firewall-plugin MODULE firewall.c)
 28 SET_TARGET_PROPERTIES(firewall-plugin PROPERTIES OUTPUT_NAME firewall PREFIX "")
 29
 30 ADD_LIBRARY(wireless-plugin MODULE wireless.c)
 31 SET_TARGET_PROPERTIES(wireless-plugin PROPERTIES OUTPUT_NAME wireless PREFIX "")
 32
 33 ADD_LIBRARY(qos-plugin MODULE qos.c)
 34 SET_TARGET_PROPERTIES(qos-plugin PROPERTIES OUTPUT_NAME qos PREFIX "")
 35
 36 ADD_LIBRARY(lepton-plugin MODULE lepton.c)#此处编译本人写的C源码
 37 SET_TARGET_PROPERTIES(lepton-plugin PROPERTIES OUTPUT_NAME lepton PREFIX "")
 38
 39 SET( MY_DIR sub_source/my_string)
 40 SET(SRC_LIST wuxian.c;${MY_DIR}/my_string.c;${MY_DIR}/mylist.c)
 41 ADD_LIBRARY(wuxian-plugin MODULE ${SRC_LIST})
 42
 43 include_directories(sub_source/my_string)
 44 SET_TARGET_PROPERTIES(wuxian-plugin PROPERTIES OUTPUT_NAME wuxian PREFIX "")
 45
 46 INSTALL(TARGETS luci2-plugin bwmon-plugin firewall-plugin wireless-plugin qos-plugin wuxian-plugin lepton-plugin     LIBRARY DESTINATION lib)

以上两个文件写完后,编译后在build_dir/target_XXX/luci2_xXX/rpcd路径下,可以看到编译生成的.so文件,但此时,该.so还没有编译到固件中,需要在引导Makefile中,写明它的安装路径
这里写图片描述

Makefile文件,引导.so编译到固件,如下注释部分

  1 #
  2 # Copyright (C) 2013 Jo-Philipp Wich @openwrt.org>
  3 #
  4 # Licensed under the Apache License, Version 2.0.
  5 #
  6
  7 include $(TOPDIR)/rules.mk
  8
  9 PKG_NAME:=luci2
 10 #PKG_VERSION:=$(shell git --git-dir=$(CURDIR)/../.git log -1 --pretty="%ci %h" | awk '{ print $$1 "-" $$4 }')
 11 PKG_VERSION:=2015-02-14-e452ca6
 12 PKG_MAINTAINER:=Jo-Philipp Wich @openwrt.org>
 13
 14 PKG_LICENSE:=Apache-2.0
 15 PKG_LICENSE_FILES:=
 16
 17 PKG_BUILD_PARALLEL:=1
 18
 19 include $(INCLUDE_DIR)/package.mk
 20 include $(INCLUDE_DIR)/cmake.mk
 21
 22 define Build/Prepare
 23         $(INSTALL_DIR) $(PKG_BUILD_DIR)
 24         $(CP) ./src/* $(PKG_BUILD_DIR)/
 25 endef
 26
 27 define Package/luci2
 28   SECTION:=luci2
 29   CATEGORY:=LuCI2
 30   TITLE:=LuCI2 UI
 31   DEPENDS:=+rpcd +rpcd-mod-iwinfo +uhttpd +uhttpd-mod-ubus +libubox +libubus
 32 endef
 33
 34 define Package/luci2/description
 35  Provides the LuCI2 web interface with standard functionality.
 36 endef
 37
 38 define Package/luci2/install
 39         $(INSTALL_DIR) $(1)/www
 40         $(CP) ./htdocs/* $(1)/www/
 41         $(INSTALL_DIR) $(1)/usr/share/rpcd
 42         $(CP) ./share/* $(1)/usr/share/rpcd/
 43         $(INSTALL_DIR) $(1)/usr/lib/rpcd
 44         $(INSTALL_BIN) $(PKG_BUILD_DIR)/rpcd/luci2.so $(1)/usr/lib/rpcd/
 45         $(INSTALL_BIN) $(PKG_BUILD_DIR)/rpcd/bwmon.so $(1)/usr/lib/rpcd/
 46         $(INSTALL_BIN) $(PKG_BUILD_DIR)/rpcd/firewall.so $(1)/usr/lib/rpcd/
 47         $(INSTALL_BIN) $(PKG_BUILD_DIR)/rpcd/wireless.so $(1)/usr/lib/rpcd/
 48         $(INSTALL_BIN) $(PKG_BUILD_DIR)/rpcd/qos.so $(1)/usr/lib/rpcd/
 49         $(INSTALL_BIN) $(PKG_BUILD_DIR)/rpcd/wuxian.so $(1)/usr/lib/rpcd/
 50         $(INSTALL_BIN) $(PKG_BUILD_DIR)/rpcd/lepton.so $(1)/usr/lib/rpcd/    #安装在固件中的路径是/usr/lib/rpcd
 51         $(INSTALL_DIR) $(1)/usr/libexec $(1)/www/cgi-bin
 52         $(INSTALL_BIN) $(PKG_BUILD_DIR)/io/luci2-io $(1)/usr/libexec/
 53         $(LN) /usr/libexec/luci2-io $(1)/www/cgi-bin/luci-upload
 54         $(LN) /usr/libexec/luci2-io $(1)/www/cgi-bin/luci-backup
 55         $(INSTALL_DIR) $(1)/etc
 56         $(CP) ./script/etc/* $(1)/etc/
 57         $(INSTALL_DIR) $(1)/usr/bin
 58         $(CP) ./script/usr/bin/* $(1)/usr/bin/
 59         $(INSTALL_DIR) $(1)/etc/config
 60         $(CP) ./uci_file/* $(1)/etc/config/
 61 endef
 62
 63 define Package/luci2/postinst
 64 #!/bin/sh
 65
 66 if [ "$$(uci -q get uhttpd.main.ubus_prefix)" != "/ubus" ]; then
 67         uci set uhttpd.main.ubus_prefix="/ubus"
 68         uci commit uhttpd
 69 fi
 70
 71 exit 0
 72 endef
 73
 74 $(eval $(call BuildPackage,luci2))

经过以上的部分,编译后,能在固件中调用到注册的ubus接口,但不能通过web界面调用到注册的接口,因为web界面调用注册的ubus接口,还需要权限,下面在(package/luci2/share/acl.d)路径下,添加lepton.json文件,使注册的接口或得访问权限:

 1 {
  2         "test":{
  3                 "description": "for learn luci2",
  4                 "read":{
  5                         "ubus":{
  6                                 "lepton.network":[
  7                                         "ping1",
  8                                         "lepton"
  9                                 ]
 10                         }
 11                 }
 12         },
 13 }

2.使用putty,进入路由系统验证注册的方法
经下面验证,方法均可成功调用:

openwrt使用静态html做web界面_第2张图片

3.前端对ubus接口调用
在官网集成的luci2源码中有对接口的封装,源码路径(package/luci2/htdocs/),此路径下放着web前端界面的文件,生成固件后在目录*www下,查看/etc/config/uhttpd可以知道web服务器默认访问的路径就是www,我们的html文件就放在www下,下面是前端的源码实例解析(一个登录界面index.html,一个测试界面test.html)
openwrt使用静态html做web界面_第3张图片

原luci2的www中文件替换如下:(编译前替换到package/luci2/htdocs/下,或使用工具WinSCP替换)
这里写图片描述

下面是luci2文件夹下的文件:
文件说明:bootstrap.js, jquery.peity.js, jquery-1.9.1.js保留这三个文件是因为我的html要加载js代码,如果开发时,有js代码库加载,这三个文件可以不要; rpc.js封装了ubus接口发送的函数,不可少; session.js文件中是界面心跳机制的实现,不可少; luci2.js中封装了很多方法,不可少;
注:此处没有加载uci.js,项目中最好保留,因为它对ubus调用uci方法的封装做的很好。

这里写图片描述

添加index.js和test.js后,需要在luci2.js文件中加载,加载代码如下面截图
openwrt使用静态html做web界面_第4张图片

下面是前端新增的5个文件的代码:
1.index.html


<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">

<head>
  <title>luci2title>

    <script type="text/javascript" src="/luci2/jquery-1.9.1.js">script>
    <script type="text/javascript" src="/luci2/jquery.peity.js">script>
    <script type="text/javascript" src="/luci2/bootstrap.js">script>
    <script type="text/javascript" src="luci2/luci2.js">script>
    <script type="text/javascript" src="luci.js">script>

    <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
     <meta http-equiv="content-type" content="text/html; charset=utf-8" />

head>
<body>

    <p>
        login p>
    <p>
        username:<input id="username" type="text" value="root"/>p>
    <p>
        password:<input id="password" type="text" />p>
    <p>
        <input id="login" type="button" value="login" />p>
    body>

html>

2.test.html


<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">

<head>
  <title>luci2title>

    <script type="text/javascript" src="/luci2/jquery-1.9.1.js">script>
    <script type="text/javascript" src="/luci2/jquery.peity.js">script>
    <script type="text/javascript" src="/luci2/bootstrap.js">script>
    <script type="text/javascript" src="luci2/luci2.js">script>
    <script type="text/javascript" src="luci.js">script>

    <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
     <meta http-equiv="content-type" content="text/html; charset=utf-8" />

head>
<body>

    <p>
        name:
        <input id="name" type="text" />p>
    <p>
         p>
    <p>
         p>
    <p>
        ping:p>
    <p>
        addr: 
        <input id="ping_addr" type="text" />p>
    <p>
        count: <input id="ping_count" type="text" />p>
    <p>
        <textarea id="ping_text">result:textarea>p>
    <p>
        <input id="ping_btn" type="button" value="start" />p>
    body>

html>

3.luci.js

$(function () {
    var hr = window.location.href;

    var g_sid = hr.substring(hr.lastIndexOf(':') + 1, hr.length);

    var ln_name = hr.substring(hr.lastIndexOf('/') + 1, hr.lastIndexOf('.'));//使用链接传递权限id值

    var L;
    if (g_sid && g_sid.match(/^[a-f0-9]{32}$/)) {
        if (ln_name == "test") {
            L = new LuCI2("test");
            L.globals.sid = g_sid;    //有这个值后,才能获取到调用后台ubus接口的权限
            L.setHash('id', L.globals.sid);
            L.session.startHeartbeat();
            L.test.load();
        } else {
            var hr = ('%s/test.html').format(window.location.origin);
            window.location.href = hr;
        }
    } else {
            L = new LuCI2("index");
    }

    $("#ping_btn").click(function () {
        L.test.ping_opt();
    });

    $("#login").click(function () {
        L.index.load();
    });
});


4.luci2/index.js

Class.extend({
    load: function () {
        var u = document.getElementById("username").value;
        var p = document.getElementById("password").value;

        L.globals.sid = '00000000000000000000000000000000';
        L.session.login(u, p).then(function (response) {
            L.globals.sid = response.ubus_rpc_session; //此处获取到后台rpcd发送的访问ubus接口的权限了
            L.setHash('id', L.globals.sid);
            L.session.startHeartbeat();

            var hr = ('%s/test.html#id:%s').format(window.location.origin, L.globals.sid);
            window.location.href = hr;
        });
    },
});

5.luci2/test.js

Class.extend({
    get_name: L.rpc.declare({
        object: 'lepton.network',
        method: 'lepton',
        expect: { '': {} }
    }),     //后台ubus接口在前端调用的格式函数,这个是无参,有返回值

    runPing: L.rpc.declare({
        object: 'lepton.network',
        method: 'ping1',
        params: ['data', 'count'],
        expect: { '': { code: -1 } }
    }),     //有参,有返回值

    load: function () {
        L.test.get_name().then(function (info) { //接口函数的调用
            document.getElementById("name").value = info.name; //通过ID使静态界面,获取到固件动态值
        });
    },

    ping_opt: function () {
        var ip_ping = document.getElementById("ping_addr").value;
        var ping_count = document.getElementById("ping_count").value;

        if (ping_count == "") {
            ping_count = "1";
        }

        var ping_v = parseInt(ping_count);
        if (ping_v > 0 && ping_v <= 10) {
            ping_count = ("%s").format(ping_v);
        } else {
            ping_count = "1";
        }

        $("#ping_text").text(("ping : %s ...").format(ip_ping));
        L.test.runPing(ip_ping, ping_count).then(function (rv) {
            $("#ping_text").text(rv.stdout);
        });
    },
});

界面效果如下:
登录界面index.html
openwrt使用静态html做web界面_第5张图片

链接中的id就是每次登录web后,rpcd返回的随机值,多html时,我是使用链接传递这个值得,只要new的luci2中全局变量L.globals.sid 获取到这个值后,就有权限在前端调用ubus接口方法了。
openwrt使用静态html做web界面_第6张图片

你可能感兴趣的:(openwrt开发)