LUCI是一个小巧的语言,诞生于2008年3月份,目的是为OpenWrt固件从 Whiterussian 到 Kamikaze实现快速配置接口。轻量级 LUA语言的官方版本只包括一个精简的核心和最基本的库。这使得LUA体积小、启动速度快,从而适合嵌入在别的程序里。UCI是OpenWrt中为实现全部系统配置的一个统一接口,英文名Unified Configuration Interface,即统一配置接口。LuCI,便是这两个项目的合体,能够实现路由的网页配置界面。[·引自百度百科https://baike.baidu.com/item/...]html
其实我接触LUCI并不久,主要用它来为OpenWrt写UCI接口,来存取配置文件里的内容。存取有两种方式:git
这两种我都会介绍。本文主要介绍一些LUCI的基本内容和一种方式的应用。web
LUCI能够归属为web开发行列。由于它的内容都是直接在浏览器里体现出来的。它的基本架构跟不少WEB开发语言的框架同样,都是MVC架构。如下给出一些简单的解释:
M(Model): 模型层,路径是/usr/lib/lua/luci/model/。这个是数据处理的具体代码的层。该层中有一个cbi文件夹,那里面是预约义的一些的逻辑文件。
V(View): 视图层,路径是/usr/lib/lua/luci/view/。这个很容易理解,就是存放视图文件的地方。LUCI里的视图文件是.htm文件。
C(Controller): 控制层,路径是/usr/lib/lua/luci/controller/admin/。这个层最主要的功能是设定路由;它还有一个功能跟模型层一致——处理数据。
根目录: /usr/lib/lua/luci
资源文件存放目录: /www/luci-static/vim
以配置network文件为例,实现一个testnet模块须要完成下面的步骤。
步骤:浏览器
以前介绍的时候有说到,LUCI是用于存取配置文件的信息,因此咱们的若要新建一个模块,须要一个配置文件。配置文件的路径通常是在/etc/config/。因为如今咱们是须要配置network文件,而这个是系统必备文件,它已经存在,因此咱们不须要新建,但咱们要了解一下里面的结构是怎么样的:架构
config interface 'loopback' option ifname 'lo' option proto 'static' option ipaddr '127.0.0.1' option netmask '255.0.0.0' config interface 'lan' option type 'bridge' option ifname 'eth1' option proto 'static' option ipaddr '192.168.1.1' option netmask '255.255.255.0' option ip6assign '60'
这个是配置里有内容,而其余配置文件内容格式也是差很少:框架
-- 编辑配置文件 root@openWrt:~# vim /etc/config/<config name> -- 配置文件格式 config <section type> <section name> option <option name> <option value> option <option name> <option value> option <option name> <option value>
那么咱们创建一个新的配置给testnet模块使用函数
config interface testnets option ifname 'testnets' option type 'test' option ipaddr '192.168.1.1' option net '192.168.251.1'
控制层中,咱们主要定义访问的路由。每个模块的控制都是独立的,那样才能方便控制。路由的定义是在控制器的index()函数里。控制器里还能够定义其余的函数用于处理处理,相信这一点有过WEB开发经验的童鞋们都知道。
接下来咱们创建一个能以/admin/testnet访问的路由
话很少说,直接上代码:oop
-- /controller/admin/testnet.lua module("luci.controller.admin.testnet") function index() entry({"admin", "testnet", "index"}, cbi("admin_test/net"), translate("Test Net"), 10) end function test() return 'This is a test function.' end
module("luci.controller.admin.testnet"):
这一句是命名空间的声明,luci指的是/usr/lib/lua/luci这个的文件夹,也就是LUCI的根目录entry({"admin", "testnet", "index"}, cbi("admin_test/net"), translate("Test Net"), 10):
这一句必须写在控制器文件的index()函数里。它的格式定义是这样子的:post
entry(path, target[[, title][, order]])
{"admin","testnet","index"[[,"..."][,"..."]]}
基本上能够无限延伸,但通常不建议这么干,到五六层已经很深了,再潜就很差了。target: 即页面指向,格式是cbi("admin_test/net")
。这里的cbi的函数指的是调用/luci/model/cbi/里的admin_test/里的net.lua文件。它还有其余的使用方法:
* title: 即标题展现,这个是设置在菜单里显示的内容项。格式有_("Test Net")
或translate("Test Net")
,前一个使用我也没有成功(有点摸不清楚),后一个是调用translate('...')函数,用于与后期的语言包进行适配。该项能够用nil
代替,表示为不在菜单栏显示。
* 若想让某项隐藏,能够写成如下格式:
entry({"admin", "testnet", "index"}, cbi("admin_test/net"), nil)
OK,说了那么多,终于到了咱们最关键的模型层。在模型层,LUCI拥有一套自动生成机制,接下来让咱们一一介绍。先上代码再解释——
-- /model/cbi/admin_test/net.lua m = Map("network", translate("Test Net")) s = m:section(NamedSection, "testnets", "interface", translate("Net Configuration") s.addremove = true s.anonymouse = true ifname = s:option(Value, "ifname", translate("Ifname: ")) ifname.datatype = 'string' itype = s:option(Value, "type", translate("Type: ")) itype.datatype = 'string' ipaddr = s:option(Value, "ipaddr", translate("Ipaddr: ")) ipaddr.datatype = 'ipaddr' net = s:option(Value, "net", translate("Net:")) net.datatype = 'ipaddr' return m
m = Map("network", translate("Test Net"))
:这一句是链接配置文件,是以LUCI机制的必不可少的语句。第一个参数
是配置文件的名称,第二个参数
页面的大标题。s = m:section(NamedSection, "testnets", "interface", translate("Net Configuration")
:这一句是以section
`的name
名链接到指定的section
。
第一个参数
是指定存取section的方法,本文用的是以section的name名进行查找的方式NamedSecton
。其余还有几种方式:
第二个参数
是section的名字第三个参数
是section的类型第四个参数
是模块标题的名称其余类型的代码示例分别以下:
-- TypedSection s = m:section(TypedSection, "interface", translate("Net Configuration") -- SimpleSection s = m:section(SimpleSection, "interface", translate("Net Configuration") -- Table s = m:section(TypedSection, "interface", translate("Net Configuration")--也能够用NamedSection s.Table(Table, "Table Title") -- Tab s = m:section(TypedSection, "interface", translate("Net Configuration")--也能够用NamedSection s.Table(Tab, "Tab Title")
s.addremove = false
:打开/关闭添加删除按钮,这个为true
时,会在页面上添加一个添加和一个删除按钮,这样就可以在页面快速进行增减项了。不过有一点要注意的是,那样的页面比较丑……s.anonymouse = true
:这一句是不显示section的名字在页面上。还能够加上s.template = 'admin_test/net'
这样的语句net = s:option(Value, "net", translate("Net:"))
:这一句是链接具体的option。
第一个参数
是显示类型。经常使用的显示类型有:
第二个参数
是option的名称第三个参数
是显示项的说明net.datatype = 'ipaddr'
:这一句是指定option的类型。这里的是ip地址类型,其余还有不少类型:
这时访问/admin/testnet便可以看到页面了。
参考连接: