• 如何编写一个路由器的界面1Luci开发入门


    Howto:如何写Module(模块)-----------------这一部分主要是翻译github上的document

    注意:如果您打算将模块加入LUCI整合之前,您应该阅读Module参考

    本教程介绍如何编写自己的LUCI WebUI中的模块。在本教程中,我们假设您的luci安装目录lucidir(如果您目前使用的是安装版/usr/lib/LUA/LUCI),并假设你的luci安装经由/cgi-bin/LUCI访问您的Web服务器。
    方法路线(针对调度过程)

    要编写模块,您需要了解LUCI调度过程的基础知识。 LUCI使用,将通过执行每个可供使用的controller的索引功能建立一个调度树。在CGI环境变量PATH_INFO将作为在这个调度树,例如: /cgi-bin/luci/foo/bar/baz将被解析为foo.bar.baz

    要注册在调度树中的功能,你可以使用luci.dispatcher的入口函数(Entry function)。进入需要4参数(其中的2个是可选的):

    entry(path, target, title=nil, order=nil)

     

    • path 是一个table结构,描述了在调度树的的位置: 例如, {"foo", "bar", "baz"}的path 将被插入到 foo.bar.baz. 
    • target 描述当用户请求该节点时将要采取的行动. 其中有三个预定义的对象是最重要的 (call, template, cbi) ,他们将在本页的后边描述
    • title 定义了在可见的菜单中的选项,也就是最终luci界面中可以看到的标题内容(可选) 
    • order 主要依据这个数字来使同一水平上的节点在菜单上的排序 (可选) 

    你可以通过操作节点表的返回值来给entry function赋更多的参数。一些典型的参数例子:

    • i18n 定义了当页面被请求时,自动加载的解释程序(文件)
    • dependent 防止插件在其父节点的确实,也就是添加插件的依赖
    • leaf 停止解析该节点的请求,并没有更进一步的调度树
    • sysauth 要求用户与给定系统的用户帐户进行认证

    下边就是命名与使用过程

    既然你已经了解了调度的基础知识,现在,我们可以开始写module了。但是在这之前,我们必须先选择目录并且命名属于你自己的新节点。

    我们假设你想要创建一个新叫做myapp的应用,而且myappmodulemymodule

    因此你必须创建一个子文件夹lucidir/controller/myapp,在该文件夹下创建一个mymodule.lua的文件,文件内容如下:

    1 module("luci.controller.myapp.mymodule", package.seeall) 
    2 
    3 function index()
    4 
    5 end

     

    第一行要求lua正确识别模块,并建立它的范围。该index function将用于注册在调度树中的动作。

    到目前为止,你就已经有了一个新的节点,只不过是该节点中没有任何的功能。

    我们假设你想要复用你的myapp.mymodule 模块,那么你就必须开始最后一个步骤。

    Actions

    重新打开lucidir/controller/myapp/mymodule.lua并且添加一个函数类似下边的内容:

     1 module("luci.controller.myapp.mymodule", package.seeall)
     2 
     3 function index()   
     4      entry({"click", "here", "now"}, call("action_tryme"), "Click here", 10).dependent=false
     5 
     6 end 
     7 
     8 function action_tryme()    
     9     luci.http.prepare_content("text/plain")   
    10     luci.http.write("Haha, rebooting now...")   
    11     luci.sys.reboot()
    12 end

     

    现在在浏览器中输入/cgi-bin/luci/click/here/now(http://192.168.1.1/luci/click/here/now 在你的openwrt系统上应该是) 

    你可以发现这些动作已经被添加到了调度树上。

    正如你可能会或可能不知道的:CGI规范要求您发送您的内容头之前,首先发送Content-Type。你会发现几个快捷方式(如上面所使用的),以及在模块luci.http重定向功能

     

    Views

    如果你仅仅是想展现给用户一行字符或者一些有意思的家庭图片,那么使用HTML-template就足够了。这些template也可以包含lua代码,但是你必须了解到仅仅使用template可以会写入脏代码。

    现在让我们来创建一个小的lucidir/view/myapp-mymodule/helloworld.htm,内容如下:

    1 <%+header%>
    2 <h1><%:Hello World%></h1> 
    3 <%+footer%>

    然后添加下边的一行index-function 到你的module文件中去。

    entry({"my", "new", "template"}, template("myapp-mymodule/helloworld"), "Hello world", 20).dependent=false

    现在在你的浏览器中输入 /cgi-bin/luci/my/new/template (在你的openwrt系统上是http://192.168.1.1/luci/my/new/template ) 。

     

    你也许注意到了这些奇怪的标签, 这些是被LuCItemplate处理程序使用的标记. 在标准设计中使用headerfooter,是个好的选择

    CBI models 

    CBI是LuCI中最酷的功能. 它创建一个标准的用户接口并且将内容保存在一个特定的UCI config文件中。.你只需要描述配置文件的结构,然后CBI程序会帮你完成剩下的部分。 这包括生成,解析和验证HTML表单和读取和写入UCI文件。  

    所以我们必须认真的创建一个实例 lucidir/model/cbi/myapp-mymodule/netifaces.lua  其内容如下:

     1 m = Map("network", "Network") -- We want to edit the uci config file /etc/config/network 
     2 s = m:section(TypedSection, "interface", "Interfaces") -- Especially the "interface"-sections
     3 s.addremove = true -- Allow the user to create and remove the interfaces
     4 function s:filter(value)  
     5      return value ~= "loopback" and value -- Don't touch loopback
     6 end s:depends("proto", "static") -- Only show thosewith"static"
     7 s:depends("proto", "dhcp") -- or "dhcp" as protocol and leave PPPoE and PPTP alone 
     8 
     9 p = s:option(ListValue, "proto", "Protocol") -- Creates an element list (select box)
    10 p:value("static", "static") -- Key and value pairs
    11 p:value("dhcp", "DHCP")
    12 p.default = "static" 
    13 
    14 s:option(Value, "ifname", "interface", "the physical interface to be used") -- This will give a simple textbox 
    15 
    16 s:option(Value, "ipaddr", translate("IP Address")) -- Ja, das ist eine i18n-Funktion ;-) 
    17 
    18 s:option(Value, "netmask", "Netmask"):depends("proto", "static") -- You may remember this "depends" function from above 
    19 
    20 mtu = s:option(Value, "mtu", "MTU")
    21 mtu.optional = true -- This one is very optional 
    22 dns = s:option(Value, "dns", "DNS-Server")
    23 dns:depends("proto", "static")
    24 dns.optional = true
    25 function dns:validate(value) -- Now, that's nifty, eh?
    26     return value:match("[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+") -- Returns nil if it doesn't match otherwise returns match
    27 end 
    28 
    29 gw = s:option(Value, "gateway", "Gateway")
    30 gw:depends("proto", "static")
    31 gw.rmempty = true -- Remove entry if it is empty 
    32 
    33 return m -- Returns the map

    当然,别忘记添加你自己的index-function函数。

    1 entry({"admin", "network", "interfaces"}, cbi("myapp-mymodule/netifaces"), "Network interfaces", 30).dependent=false

     

  • 相关阅读:
    Linux常用指令整理
    结构型模式-组合模式(树形结构的处理)
    结构型模式-适配器模式(不兼容结构的协调)
    创建型模式-原型模式(对象的克隆)
    创建型模式-单例模式(确保对象唯一性)
    创建型模式-抽象工厂
    Linux之linux下安装mysql
    关于elipse中maven搭建好后,一直building workspace的问题
    idea配置数据库下载驱动
    idea配置maven以及手动添加webapp目录
  • 原文地址:https://www.cnblogs.com/jourluohua/p/5205956.html
Copyright © 2020-2023  润新知