zoukankan      html  css  js  c++  java
  • luci页面“save&apply”的实现分析

    页面上配置的“保存&应用”功能的实现:

    最终调用到/etc/config/ucitrack的配置文件。


    例如配置无线时,对应ucitrack配置文件中的
    config network
        option init network
        list affects dhcp
        list affects radvd

    config wireless
        list affects network   // 更改无线参数时,会影响network相关的配置,会重新调用其初始化脚本initscript
    段部分

    问题一、那么如何添加到ucitrack配置文件中的呢?
    答:是通过uci-defaults手动添加的。
    搜索一下可以发现:
    ./feeds/packages/net/mwan3-luci/files/etc/uci-defaults
    ./feeds/oldpackages/net/wing/files/etc/uci-defaults
    ./feeds/luci/i18n/portuguese-brazilian/root/etc/uci-defaults
    ./feeds/luci/i18n/hungarian/root/etc/uci-defaults
    ./feeds/luci/i18n/ukrainian/root/etc/uci-defaults
    ./feeds/luci/i18n/hebrew/root/etc/uci-defaults
    ./feeds/luci/i18n/vietnamese/root/etc/uci-defaults
    ./feeds/luci/i18n/catalan/root/etc/uci-defaults
    ./feeds/luci/i18n/german/root/etc/uci-defaults
    ./feeds/luci/i18n/norwegian/root/etc/uci-defaults
    ./feeds/luci/i18n/english/root/etc/uci-defaults
    ./feeds/luci/i18n/chinese/root/etc/uci-defaults
    ./feeds/luci/i18n/greek/root/etc/uci-defaults
    ./feeds/luci/i18n/spanish/root/etc/uci-defaults
    ./feeds/luci/i18n/russian/root/etc/uci-defaults
    ./feeds/luci/i18n/polish/root/etc/uci-defaults
    ./feeds/luci/i18n/romanian/root/etc/uci-defaults
    ./feeds/luci/i18n/japanese/root/etc/uci-defaults
    ./feeds/luci/i18n/malay/root/etc/uci-defaults
    ./feeds/luci/i18n/french/root/etc/uci-defaults
    ./feeds/luci/i18n/swedish/root/etc/uci-defaults
    ./feeds/luci/i18n/italian/root/etc/uci-defaults
    ./feeds/luci/i18n/portuguese/root/etc/uci-defaults
    ./feeds/luci/themes/freifunk-bno/root/etc/uci-defaults
    ./feeds/luci/themes/openwrt/root/etc/uci-defaults
    ./feeds/luci/themes/bootstrap/root/etc/uci-defaults
    ./feeds/luci/themes/freifunk-generic/root/etc/uci-defaults
    ./feeds/luci/applications/luci-mmc-over-gpio/root/etc/uci-defaults
    ./feeds/luci/applications/luci-meshwizard/root/etc/uci-defaults
    ./feeds/luci/applications/luci-ushare/root/etc/uci-defaults
    ./feeds/luci/applications/luci-hwmqos/root/etc/uci-defaults
    ./feeds/luci/applications/luci-hd-idle/root/etc/uci-defaults
    ./feeds/luci/applications/luci-wshaper/root/etc/uci-defaults
    ./feeds/luci/applications/luci-p910nd/root/etc/uci-defaults
    ./feeds/luci/applications/luci-p2pblock/root/etc/uci-defaults
    ./feeds/luci/applications/luci-upnp/root/etc/uci-defaults
    ./feeds/luci/applications/luci-olsr/root/etc/uci-defaults
    ./feeds/luci/applications/luci-ser2net/root/etc/uci-defaults
    ./feeds/luci/applications/luci-polipo/root/etc/uci-defaults
    ./feeds/luci/applications/luci-statistics/root/etc/uci-defaults
    ./feeds/luci/applications/luci-backdoor/root/etc/uci-defaults
    ./feeds/luci/applications/luci-watchcat/root/etc/uci-defaults
    ./feeds/luci/applications/luci-ahcp/root/etc/uci-defaults
    ./feeds/luci/applications/luci-freifunk-diagnostics/root/etc/uci-defaults
    ./feeds/luci/applications/luci-vnstat/root/etc/uci-defaults
    ./feeds/luci/applications/luci-radvd/root/etc/uci-defaults
    ./feeds/luci/applications/luci-minidlna/root/etc/uci-defaults
    ./feeds/luci/applications/luci-transmission/root/etc/uci-defaults
    ./feeds/luci/applications/luci-asterisk/root/etc/uci-defaults
    ./feeds/luci/contrib/uci/hostfiles/bin/uci-defaults
    ./feeds/luci/contrib/package/freifunk-common/files/etc/uci-defaults
    ./feeds/luci/contrib/package/freifunk-gwcheck/root/etc/uci-defaults
    ./feeds/luci/contrib/package/freifunk-mapupdate/root/etc/uci-defaults
    ./feeds/luci/contrib/package/freifunk-policyrouting/files/etc/uci-defaults
    ./build_dir/target-mips_34kc_uClibc-0.9.33.2/root-ar71xx/etc/uci-defaults


    查看 ./feeds/luci/i18n/chinese/root/etc/uci-defaults 文件,可以看到
    文件内容如下:
    #!/bin/sh
    uci batch <<-EOF
       set luci.languages.zh_cn=chinese
       commit luci
    EOF
    利用uci命令,配置了两条,
    1) uci set luci.languages.zh_cn=chinese  配置了/etc/config/luci中的languages
    2) uci commit luci 提交luci的更改
    这个并没有使用到ucitrack配置文件。

    再看另外一个 ./feeds/luci/applications/luci-hwmqos/root/etc/uci-defaults 文件,可以看到
    文件内容如下:
    #!/bin/sh

    #add service depends

    uci -q batch <<-EOF >/dev/null
              delete ucitrack.@hwmqos[-1]
              add ucitrack hwmqos
              set ucitrack.@hwmqos[-1].init=hwmqos
              commit ucitrack  
    EOF

    rm -f /tmp/luci-indexcahe
    exit 0
    利用uci命令,批量配置了如下命令:
    1)uci delete ucitrack.@hwmqos[-1]  删除ucitrack配置文件中的hwmqos相关内容
    2)uci add ucitrack hwmqos     增加ucitrack配置文件中的hwmqos
    3)uci set ucitarck.@hwmqos[-1].init=hwmqos  相关的起始脚本(initscript)为/etc/init.d/hwmqos
    4)uci commit ucitrack  提交变更的文件


    问题二、配置文件中的affects干嘛用?
    答:其实直接作用就是查找到相关的配置文件,再根据配置文件找到相关的起始脚本。当配置变更时,重新启用脚本。

    关于affects 在uci.lua中定义如下:

    -- Return a list of initscripts affected by configuration changes.
    -- 返回一些跟此配置更改相关的初始化脚本列表,
    function Cursor._affected(self, configlist)
       configlist = type(configlist) == "table" and configlist or {configlist}

     local c = cursor()
     c:load("ucitrack")

     -- Resolve dependencies
     -- 分解依赖情况
     local reloadlist = {}

     local function _resolve_deps(name)
      local reload = {name}
      local deps = {}

      c:foreach("ucitrack", name,
       function(section)
        if section.affects then
         for i, aff in ipairs(section.affects) do
          deps[#deps+1] = aff         -- 将依赖的配置文件保存到deps数组中去(本例中是将network保存进去)
         end
        end
       end)

      for i, dep in ipairs(deps) do
       for j, add in ipairs(_resolve_deps(dep)) do
        reload[#reload+1] = add      -- 将所有依赖列表保存到一个数组reload中去(此处wireless只有一个依赖项affects,就是network)
       end
      end

      return reload
     end

     -- Collect initscripts
     -- 搜集初始化脚本
     for j, config in ipairs(configlist) do
      for i, e in ipairs(_resolve_deps(config)) do
       if not util.contains(reloadlist, e) then   -- 检测包reloadlist中是否含配置文件(cofig),若有包含,将其加入到reloadlist数组中
        reloadlist[#reloadlist+1] = e   
      end
     end

     return reloadlist
    end 
     
     
    问题三、html页面“save&apply”如何实现的

    通过调用"cbi.apply"最后调用到uci.lua脚本中的Cursor.apply.

    其实现过程为:

    --- Applies UCI configuration changes
    -- @param configlist  List of UCI configurations
    -- @param command   Don't apply only return the command
    function Cursor.apply(self, configlist, command)
     configlist = self:_affected(configlist)
     if command then
          return { "/sbin/luci-reload", unpack(configlist) }    // 调用luci-reload
     else
      return os.execute("/sbin/luci-reload %s >/dev/null 2>&1" % table.concat(configlist, " "))   // 调用luci-reload
     end
    end

    从函数apply可以看出,均是调用luci-reload。

    问题四、luci-reload的实现过程,luci-reload是个shell脚本。

    #!/bin/sh
    . /lib/functions.sh

    apply_config() {
     config_get init "$1" init             
     config_get exec "$1" exec
     config_get test "$1" test

     echo "$2" > "/var/run/luci-reload-status"     // 将状态写入到临时文件中

     [ -n "$init" ] && reload_init "$2" "$init" "$test"   // 若ucitrack配置文件中init相关参数存在,则进行reload_init
     [ -n "$exec" ] && reload_exec "$2" "$exec" "$test"  // 若ucitrack配置文件中exec相关参数存在,则进行reload_exec

    }

    reload_exec() {
     local service="$1"
     local ok="$3"
     set -- $2
     local cmd="$1"; shift
     
     [ -x "$cmd" ] && {     // cmd具有可执行权限
      echo "Reloading $service... "
      ( $cmd "$@" ) 2>/dev/null 1>&2   // 执行 “cmd +所有参数”
      [ -n "$ok" -a "$?" != "$ok" ] && echo '!!! Failed to reload' $service '!!!'   // 若执行失败,则打印消息
     }
    }

    reload_init() {
     [ -x /etc/init.d/$2 ] && /etc/init.d/$2 enabled && {
      echo "Reloading $1... "
      /etc/init.d/$2 reload >/dev/null 2>&1     // 执行脚本的 reload
      [ -n "$3" -a "$?" != "$3" ] && echo '!!! Failed to reload' $1 '!!!'    // 若执行失败,则打印消息
      }
    }

    lock "/var/run/luci-reload"            // 1、防止多个线程同时调用luci-reload脚本,加锁

    config_load ucitrack                    // 2、加载配置文件/etc/config/ucitrack

    for i in $*; do              
     config_foreach apply_config $i $i  // 3、遍历所有相关配置和文件,进行重新初始化相关进程
    done

    rm -f "/var/run/luci-reload-status" // 删除luci-reload-status状态文件
    lock -u "/var/run/luci-reload"         // 解锁


     ===========================================

    2017年1月16日补充:

    整个实现过程如下:

    (1)页面上有"Save & Apply"的功能选项的页面,在单击按钮时,会调用到"changes.htm"页面。页面中关于按钮定义如下:

            <form class="inline" method="get" action="<%=controller%>/admin/uci/saveapply">
                 <input type="hidden" name="redir" value="<%=pcdata(luci.http.formvalue("redir"))%>" />
               <input class="cbi-button cbi-button-save" type="submit" value="<%:Save & Apply%>" />
          </form>

          对应的动作为 ../admin/uci/saveapply

    (2)打开对应的 uci.lua文件,可以看到 saveapply对应的定义如下:

             entry({"admin", "uci", "saveapply"}, call("action_apply"), _("Save &#38; Apply"), 10).query = {redir=redir}

             action_apply()函数实现如下:

            

        function action_apply()
           local path = luci.dispatcher.context.path
           local uci = luci.model.uci.cursor()
           local changes = uci:changes()
           local reload = {}

         -- Collect files to be applied and commit changes
           for r, tbl in pairs(changes) do
              table.insert(reload, r)
              if path[#path] ~= "apply" then
                 uci:load(r)
                 uci:commit(r)
                 uci:unload(r)
              end
            end

         luci.template.render("admin_uci/apply", {                    跳转到界面apply.htm
            changes = next(changes) and changes,
            configs = reload
          })
        end

     (3)apply.htm中主要内容如下:

            

       <%+cbi/apply_xhr%>              添加页面 apply_xhr.htm
       <%+admin_uci/changelog%>           添加页面 changelog.htm

       <%- cbi_apply_xhr('uci-apply', configs) -%>    去掉调用脚本cbi_apply_xhr

    (4)查看 apply_xhr.htm

        

  • 相关阅读:
    Java-Class-@I:org.springframework.web.bind.annotation.RequestBody.java
    Java-Class-@I:org.springframework.validation.annotation.Validated.java
    Java-Class-@I:org.springframework.beans.factory.annotation.Autowired.java
    Java-Class-@I:org.springframework.stereotype.Service.java
    Murano环境搭建、使用介绍和思考
    简洁经常使用权限系统的设计与实现(一):构造权限菜单树的N(N&gt;=4)种方法
    Android 依赖注入: Dagger 2 实例解说(一)
    mybatis的#和$的差别
    国内外优秀呼叫中心系统简单介绍
    openWRT学习之LUCI之中的一个helloworld演示样例
  • 原文地址:https://www.cnblogs.com/rohens-hbg/p/5358307.html
Copyright © 2011-2022 走看看