Englishhtml
一直以來OpenWrt都是採用Lua寫的web管理界面LuCI,(開機速度慢不說,竟然比不過騰達等弱路由器開機速度)。 LuCI須要使用多個Lua擴展(如 ubus
, luci.model.uci
, nixio.fs
, 等等)去存取系統信息和設置. 不幸的是這種解決方案在慢CPU和低內存的低配機器設備上是個災難,此方案至關消耗資源且並不能很好的工做。git
這致使開發了LuCI2, 一個不一樣架構的新的web管理節目。它再也不使用Lua,而是使用靜態HTML頁面加JavaScript XHR方法。 這意味着從OpenWrt設備中下載後在客戶端(瀏覽器)中構建HTML頁面, 經過ubus存取各類系統數據(經過uhttpd-mod-ubus提供基於HTTP的接口API).web
如上所述, LuCI2經過ubus
和OpenWrt子系統通訊(包括如network
、service
以及其它)。遺憾的是並不是每一個主要的OpenWrt工具都本身註冊了ubus
,如LuCI2不能使用opkg
(安裝包管理)。 LuCI2經過提供在附加ubus
名稱空間的rpcd
插件解決了這個問題。前面說的opkg
它在ubus
中註冊了一個新的luci2.opkg
路徑來訪問。promise
綜上所述, LuCI2包括兩個方面: 打包的HTML/CSS/JS文件 (htdocs
) 和一些在OpenWrt環境下運行的附加小工具。瀏覽器
在接下來的章節中,你會找到各類關於LuCI2開發幫助的細節。session
首先須要知道的是瀏覽器接收到的關於LuCI2菜單並不固定寫死在任何文件。代替的是經過ubus
使用luci.ui
路徑和menu
方法。能夠經過使用如下命令來查看:架構
ubus call luci2.ui menu '{ "ubus_rpc_session": "invalid" }'
內部的rpcd
插件分析在目錄/usr/share/rpcd/menu.d
的全部文件,當前用戶(基於傳遞的ubus_rpc_session
)不容許增長或者刪除條目。這將致使在一個二級菜單限制當前有權限訪問的條目。app
頂層菜單項用下面的JSON定義:異步
"foo": { "title": "Foo", "index": 12 }
(而且經過index
值排序)。工具
第二層菜單項經過一樣的方法定義:
"foo/bar": { "title": "Bar", "acls": [ "baz", "qux" ], "view": "foo/bar", "index": 5 }
注意,第二層菜單項能夠在獨立的文件中定義,這樣就能夠方便的添加新的菜單項定義而不用修改原有的文件。
每個LuCI2子頁面必須有一個存放在/www/luci2/template/
目錄下的模板。它們提供了很是簡單的內容替換區的HTML文件。須要注意的是它們不包含任何變量的引用,這是JavaScript的功勞:用JavaScript去讀取並寫入內容。在爲本地化系統(i18n)這些文件中惟一特定的語法相似下面的標記:
<p><%:Hello world%></p>
從模板中分離,每一個LuCI2子頁面也須要一個定義並存放在/www/luci2/view/
目錄下的一個視圖,視圖是使用了子頁面特定對象的L.ui.view
擴展的JavaScript文件。Javascript中須要提供execute
方法的實現,該方法將在膜拜加載後被執行。可選的也能夠提供子頁面的title
和description
屬性。
有一點須要注意的是須要提供execute
方法,建立視圖失敗有幾種緣由,特別是當它須要ubus
加載額外的數據使用的時候。因此在execute
方法中提供成功或者失敗的信息是有意義的。不幸的是在異步方法加載特定數據的時候,不能簡單的返回true
或false
,解決的方法是返回一個Promise
對象來運行推遲提供是否成功的信息。
最簡單的視圖能夠以下所示:
L.ui.view.extend({ title: L.tr('Foo'), /* 可選的標題 */ description: 'Bar', /* 可選的描述 */ execute: function() { var deferred = $.Deferred(); /* 建立一個延遲對象 */ deferred.resolve(); /* 當即Resolve,它不作任何事能夠返回失敗 */ return deferred.promise(); /* 返回Promise對象 (延遲對象的子集) */ } });
在開始以前,須要知道的是LuCI2提供了一些存取UCI系統的一些幫助。若是寫一個簡單的管理/etc/config/
下配置文件不須要徹底知道ubus
的調用方法,則能夠跳過該部分。
構建一些更復雜的LuCI2視圖前最好先弄明白使用到的ubus
調用。完整的對象和方法列表能夠經過運行ubus -v list
命令來獲得。
下面這個簡單的例子調用了log
對象和write
方法,它須要提供一個event
參數傳遞進去。使用ubus
命令行國內根據是,須要以下所示命令:
ubus call log write '{ "event": "Foo" }'
LuCI2爲ubus
通信提供了一個叫作L.rpc.declare
的工具,它能夠如魔法般的幫助JavaScript訪問ubus
方法。注意,定義聲明方法的時候方法並不被執行,參數也未傳遞,這是爲之後調用準備的一個方法。下面這個示例的方法調用了log
對象的write
方法:
var writeToLog = L.rpc.declare({ object: 'log', method: 'write', params: [ 'event' ] })
定義了一次這個方法後,能夠在任意時間經過以下示例簡單調用:
writeToLog('Foo');
在上面的例子中執行結果被忽略了,若是視圖須要處理ubus
返回的數據時不能忽略執行結果。下面例子將經過訪問system
對象的info
方法來描述返回結果的處理。在命令行下經過如下命令訪問:
# ubus call system info { "uptime": 123, "localtime": 1234567890, "load": [ 1, 2, 3 ], "memory": { "total": 67108864, "free": 33554432, "shared": 0, "buffered": 16777216 }, "swap": { "total": 0, "free": 0 } }
在LuCI2(JavaScript)定義上面的訪問以下所示:
var readSystemInfo = L.rpc.declare({ object: 'system', method: 'info', expect: { memory: { } } /* 可選, 只提取結果的一部分memory */ })
經過簡單的調用.then
方法可訪問結果數據
readSystemInfo().then(function(memory) { console.log(memory); });
在"feeds.conf"中添加一個feed:
src-git luci2 git://git.openwrt.org/project/luci2/ui.git
安裝luci2包:
./scripts/feeds update ./scripts/feeds install luci2
在menuconfig中勾選Luci2包並編譯新固件。