如何編寫一個路由器的介面1-Luci開發入門

來源:互聯網
上載者:User

標籤:

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的應用,而且myapp的module是mymodule。

因此你必須建立一個子檔案夾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 ) 。

 

你也許注意到了這些奇怪的標籤, 這些是被LuCI的template處理常式使用的標記. 在標準設計中使用header和footer,是個好的選擇. 

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 pairs11 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 = true25 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 match27 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

 

 

如何編寫一個路由器的介面1-Luci開發入門

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.