修改Luci界面


修改Luci界面

參考 https://blog.csdn.net/hui523hui523hui523/article/details/38943693

參考 https://www.jianshu.com/p/bfb93c4e8dc9

參考 https://blog.csdn.net/weixin_43883277/article/details/98725690

參考 https://blog.csdn.net/weixin_43883277/article/details/99677581

參考 https://blog.csdn.net/weixin_43883277/article/details/98505104

參考 https://blog.csdn.net/weixin_43883277/article/details/99865510

 

LuCI 基礎
Controller 位於: /usr/lib/lua/luci/controller/ 下——定義模塊的入口
Model 位於: /usr/lib/lua/luci/model/cbi/ 下——配置模塊實際的代碼
第一步:定義模塊入口:
eg: module("luci.controller.控制器名/路徑", package.seeall) function index()

        entry(路徑, 調用目標, _("顯示名稱"), 顯示順序)
        end

控制器名/路徑:
       不帶路徑的控制器名默認存在於/usr/lib/lua/luci/controller/下,否則以controller/為根目錄
entry表示添加一個新的模塊入口,官方給出了entry的定義,其中后兩項都是可以為空的:

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

path:
      如果這樣寫{“click”, “here”, “now”},那么就可以在瀏覽器里訪問“http://192.168.x.1/cgi-bin/luci/click/here/now”來訪問這個腳本。我們也可以根據需要按如下方式編寫{“admin”, “一級菜單名”, “菜單項名”},系統會自動在對應的菜單中生成菜單項。比如想在“網絡”菜單下創建一個菜單項,那么一級菜單名可以寫為“network”。
target:
      調用目標分為三種,分別是執行指定方法Action、訪問指定頁面Views以及調用CBI Module
  • 第一種可以直接調用指定的函數,比如點擊菜單項就直接重啟路由器等等,比如寫為call(“function_name”),然后在lua文件下編寫名為function_name的函數就可以調用了。
  • 第二種可以訪問指定的頁面,比如寫為template(“myapp/mymodule”)就可以調用/usr/lib/lua/luci/view/myapp/mymodule.htm文件了
  • 而如果要編寫配置頁面,那么使用第三種方法無非是最方便的,比如寫為cbi(“myapp/mymodule”)就可以調用/usr/lib/lua/luci/model/cbi/myapp/mymodule.lua文件了。
title和order

module("luci.controller.LuoYeLuCI", package.seeall)
function index()
        entry({"admin", "network", "LuoYeconfig"}, cbi("LuoYeCBI"), _("LuoYeTest"), 100)
end

第二步:配置CBI Module
1.首先要需要映射與存儲文件的關系

m = Map("配置文件文件名", "配置頁面標題", "配置頁面說明")

第一個參數即為配置文件存儲的文件名,不包含路徑.
第二與第三個參數則是用在來頁面上顯示的
 
2.接下來需要創建與配置文件中對應的Section
Section分為兩種,NamedSection和TypedSection,前者根據配置文件中的Section名,而后者根據配置文件中的Section類型 http://luci.subsignal.org/trac/wiki/Documentation/CBI

 

3.創建配置文件
文件需要存儲在/etc/config(如果配置文件不存在的話,訪問配置頁面將會報錯)
內容格式如下:

config login
    option username ''
    option password ''
    option ifname 'eth0'
    option domain ''

 

LuCI 頁面修改

簡單的文件配置,路由上路徑主要是/usr/lib/lua/luci/下子目錄:/controller/ 、/model/cbi/ 、 /view/,或者根目錄下的/www/中.可以在路上修改查看效果.
如果想要編譯自定義LuCI頁面的固件,請嘗試修改如下OpenWRT源碼結構路徑內的LuCI文件.

xxx/package/feeds/luci/luci/luci/libs/web/root/etc/config/luci --- AA 版本pakages/feeds/luci/中
xxx\feeds\luci\luci\luci\libs\web\root\etc\config\luci --- AA 版本的feeds/luci文件夾中
xxx/feeds/luci/modules/base/root/etc/config/luci --- BB 版本中feeds中,bb版本open修改了luci配置文件路徑,並且pakages/feeds路徑中也沒有luci配置文件了.不知道這個路徑是不是正確的.
再者就是修改 xxx/dl/ 下的源碼壓縮包,或者 xxx/build_dir/$target/下源碼

注意:如果在xxx/feeds 修改可能需要執行 ./scripts/feeds install luci 更新

 

主題Logo替換
源碼路徑:xxx/feeds/luci/luci/luci/themes/bootstrap/htdocs/luci-static/bootstrap/logo.jpg
路由路徑:/www/luci-static/bootstrap/logo.jpg

Tips:
由於版本的更新,文件路徑可能變更,此處列出的為BB版本的例子.如果找不到可以用命令手動在/feeds/中查找:find ./ -name logo.jpg.此處為bootstrap主題Logo,其他主題的Logo修改類似.

 

頁面腳標信息
源碼路徑:xxx/feeds/luci/luci/luci/themes/bootstrap/luasrc/view/themes/bootstrap/footer.htm
路由路徑:/usr/lib/lua/luci/view/themes/bootstrap/footer.htm
修改位置:

Powered by <%= luci.__appname__ .. " (" .. luci.__version__ .. ")" %>
    <%=luci.version.distversion%>

 

status狀態欄信息
源碼路徑:xxx/feeds/luci/modules/admin-full/luasrc/view/admin_status/index.htm
路由路徑:/usr/lib/lua/luci/view/admin_status/index.html
修改位置:找到類似的代碼段修改.

<%:System%>
 
<%:Hostname%><%=luci.sys.hostname() or "?"%>
<%:Model%><%=pcdata(model or "?")%>
<%:Firmware Version%>
<%=pcdata(luci.version.distname)%> <%=pcdata(luci.version.distversion)%> /
<%=pcdata(luci.version.luciname)%> (<%=pcdata(luci.version.luciversion)%>)
 
<%:Kernel Version%><%=luci.sys.exec("uname -r")%>
<%:Local Time%>-
<%:Uptime%>-
<%:Load Average%>

 

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

 

在使用OpenWrt路由器的過程中,經常需要根據需要改改配置文件然后重新啟動服務什么的,一般的做法是SSH登錄路由器后台,使用vi編輯器修改文件,然后使用/etc/init.d/xxxx restart 來重啟服務,次數多了就會覺得很繁瑣,光SSH輸入密碼就夠麻煩的,所以不妨自己寫一個luci界面在路由器web后台修改配置文件並完成重啟這一系列操作。下面以Pdnsd為例進行介紹

首先看一下實現效果

 

 

要實現一個luci界面至少需要如下三個文件

A:  /etc/config/pdnsd
B : /usr/lib/lua/luci/controller/pdnsd.lua
C:  /usr/lib/lua/luci/model/cbi/pdnsd.lua


其中

A的作用是存儲你在luci界面上的控件中填入的數值,比如用戶名密碼,是否可用,選擇的選項等等,是一個uci配置文件,可以使用shell的uci命令進行讀取

B的作用是通告OP系統你的自定義界面的顯示位置,相鄰排序,並指向C文件

C是最核心的文件,里面記錄了你luci頁面的控件布局,控件的顯示內容,和控件觸發事件的執行腳本

在創建每個文件之前,首先要了解一個概念,就是luci是MVC架構的,而且MVC的理念在luci上得到了最充分最明顯的闡釋,是理解MVC架構非常形象生動的例子,下面我就簡單介紹一下luci的MVC架構。

首先請看下面的兩個截圖,這是兩個不同OP的路由器安裝同一個luci ipk安裝包之后的界面,界面風格差別很大,不知道的還以為這是兩個不同的軟件。但其實不是,因為他們來源於同一個ipk安裝包,不僅代碼一模一樣,里面控件的類型和數量也是一致的。而且執行效果也是一樣的。

 

這上面左面應該是潘多拉固件或者DreamBox等等固件的截圖,而右面是OP默認界面的原圖,右面的加入了一些bootstrap樣式。

那為什么同樣的luci代碼會產生如此風格迥異的界面,並且自動的適配路由器當前固件的風格呢,這就是luci使用lua腳本使用MVC架構的奧義了。同時我們也知道,luci的開發不是像網頁一樣使用html,css,js進行開發,而是使用lua腳本和uci接口,下面就來仔細介紹一下luci的簡單開發過程。

首先我們創建上面必需的三個文件,做一個簡單的界面

 

/etc/config/pdnsd

 

config arguments

由於這個文件是記錄你配置好的參數的,由於我們現在並不需要記錄什么參數,所以寫個uci的開頭就夠,其中“arguments”是一個固定標志

 


/usr/lib/lua/luci/controller/pdnsd.lua

 

module("luci.controller.pdnsd", package.seeall) function index() if not nixio.fs.access("/etc/config/pdnsd") then return end entry({"admin", "services", "pdnsd"}, cbi("pdnsd"), _("Pdnsd")).dependent = true end

這個文件的含義是:首先檢查有沒有/etc/config/pdnsd文件,如果有就繼續向下執行,沒有就當什么都沒有發生過

 

第一行中,固定格式是“luci.controller.我的項目名”,因為我們所有的lua文件和/etc/config下面的配置文件都是以pdnsd來進行命名的,所以應該填“luci.controller.pdnsd”

倒數第二行是一個固定格式

entry(路徑, 調用目標, _("顯示名稱"), 顯示順序)

路徑:{"admin", "services", "pdnsd"} 意思是登錄用戶可見,“服務”主菜單下,“名字叫pdnsd的配置文件”,如果你想要放到“系統”菜單下,就把“services”改成“system”

調用目標:指向/usr/lib/lua/luci/model/cbi/pdnsd.lua這個控制文件

顯示名稱:顯示為“Pdnsd”,當然這里也可以填UTF-8的中文,用來在主菜單上顯示

顯示順序:這里沒填,使用系統默認的顯示順序

這個文件規定的規則顯示如下,就是下圖中的"Pdnsd"選項

/usr/lib/lua/luci/model/cbi/pdnsd.lua

 

local fs = require "nixio.fs" m=Map("pdnsd",translate("Pdnsd"),translate("Pdnsd可以實現類似ChinaDNS的效果,通過TCP協議進行DNS解析可以有效避免DNS污染,默認上游服務器為114DNS,可以在【DHCP/DNS】中設置【DNS轉發】為【127.0.0.1#5053】即可將所有DNS請求交給pdnsd進行解析,由於pdnsd自帶緩存,所以很快哦。注意SSR如果你勾選了TCP解析DNS會也會開啟一個pdnsd監聽7453接口,並與該頁面的pdnsd沖突,點擊【保存/應用】可以重啟pdnsd。另外你可以使用dig來檢測DNS解析情況,方法dig @127.0.0.1 -p 5053 www.facebook.com")) s=m:section(TypedSection,"arguments","") s.addremove=false s.anonymous=true return m

其中,第1行是引用依賴庫,這個依賴庫是用來讀取和寫入文件的,目前不寫這一行也可以,但是要實現讀寫配置文件的功能,這個庫是必不可少的

 

第2行是固定格式

m = Map("配置文件文件名", "配置頁面標題", "配置頁面說明") 
第一個參數:上一步我們新建配置文件/etc/config/pdnsd.這里就是建立與配置文件的聯系. 
第二個參數:主標題.

第三個參數:副標題,注意不能出現雙引號“”,否則會報錯,中文要使用UTF-8編碼

 

第3行:

m:section(類型,“arguments”,“”)

在一個配置文件中可能有很多Section,所以我們需要創建與配置文件中我們想要的Section的聯系. “arguments”就是section的uci名字,就是我們在/etc/config/pdnsd中寫的那個config arguments
有兩種方式可以選擇:NamedSection(name,type,title,description)和TypedSection(type,title,description),前者根據配置文件中的Section名,而后者根據配置文件中的Section類型.我們選用了第二種.

 

第4行:設定不允許增加或刪除Section,這樣能保證頁面的清爽,不然會多出一些奇奇怪怪的控件
第5行:設定是否顯示Section的名稱,建議為true

這里順帶提一句,lua腳本中使用--來作為注釋的標記,而不是常見的//或者#;另外luci可以顯示中文,但是你在編輯lua文件的時候必須指定“UTF-8”編碼,否則出來的中文是亂碼

把這三個文件通過winscp上傳到路由器對應的目錄上,無需重啟路由器,刷新一下路由器后台就可以看到效果,如下圖

這樣一個簡單的頁面就出來了,只有主標題和副標題,沒有任何其他的控件

下面我們添加一個簡單的checkbox,用來控制是否讓配置立即生效,只需修改C文件

 

--Alex<1886090@gmail.com> local fs = require "nixio.fs" m=Map("pdnsd",translate("Pdnsd"),translate("Pdnsd可以實現類似ChinaDNS的效果,通過TCP協議進行DNS解析可以有效避免DNS污染,默認上游服務器為114DNS,可以在【DHCP/DNS】中設置【DNS轉發】為【127.0.0.1#5053】即可將所有DNS請求交給pdnsd進行解析,由於pdnsd自帶緩存,所以很快哦。注意SSR如果你勾選了TCP解析DNS會也會開啟一個pdnsd監聽7453接口,並與該頁面的pdnsd沖突,點擊【保存/應用】可以重啟pdnsd。另外你可以使用dig來檢測DNS解析情況,方法dig @127.0.0.1 -p 5053 www.facebook.com")) s=m:section(TypedSection,"arguments","") s.addremove=false s.anonymous=true view_enable = s:option(Flag,"enabled",translate("Enable")) return m

僅添加了一行

 

view_enable = s:option(Flag,"enabled",translate("Enable"))

Flag是checkbox控件的意思,如果改成Value就是文本框,相當於html中的input標簽

“enabled”是/etc/config/pdnsd這個uci文件的字段名,所以我們可以順帶在這個文件里加入一個默認值,如下:

 

config arguments option enabled '1'

0就是默認不選,也就是進入luci界面之后checkbox不勾選,1就是默認勾選

 

tanslate(“Enable”)就是checkbox前面的提示文字,如果你安裝了luci-i18n等ipk,會自動翻譯成你選擇的語言,目前實現的效果如下

 

 

頁面中果然多了一個“啟用”checkbox,此時如果你點擊“保存&應用”就會把該checkbox的狀態記錄到/etc/config/pdnsd文件中,如果勾選就是1,不勾選為0或者不顯示該項

 

下面再來添加一個大文本框並顯示我們要修改的文本文件。

 

--Alex<1886090@gmail.com> local fs = require "nixio.fs" m=Map("pdnsd",translate("Pdnsd"),translate("Pdnsd可以實現類似ChinaDNS的效果,通過TCP協議進行DNS解析可以有效避免DNS污染,默認上游服務器為114DNS,可以在【DHCP/DNS】中設置【DNS轉發】為【127.0.0.1#5053】即可將所有DNS請求交給pdnsd進行解析,由於pdnsd自帶緩存,所以很快哦。注意SSR如果你勾選了TCP解析DNS會也會開啟一個pdnsd監聽7453接口,並與該頁面的pdnsd沖突,點擊【保存/應用】可以重啟pdnsd。另外你可以使用dig來檢測DNS解析情況,方法dig @127.0.0.1 -p 5053 www.facebook.com")) s=m:section(TypedSection,"arguments","") s.addremove=false s.anonymous=true view_enable = s:option(Flag,"enabled",translate("Enable")) view_cfg = s:option(TextValue, "1", nil) view_cfg.rmempty = false view_cfg.rows = 43 function view_cfg.cfgvalue() return nixio.fs.readfile("/etc/pdnsd.conf") or "" end return m

上面的代碼中TextValue就是大文本框的意思,相當於html中的text標簽,

 

.rmempty = false是設置該文本框不許留空,如果為空在“保存&應用”中會出現相應的提示

.rows = 43是這個大文本框的高度為43行,如果內容超出會出現滾動條

要實現進入該界面的時候該文本框自動顯示/etc/pdnsd.conf這個配置文件的內容,需要重寫大文本框自帶的.cfgvalue()方法,這樣瀏覽器進入pdnsd頁面之后luci后台就會自動調用該控件的.cfgvalue()方法,把文件內容呈現在瀏覽器上。

nixio.fs.readfile("文件路徑")會讀取一個文件的全部內容,返回值就是該文件的內容 or ""意思是如果前面那句報錯,就輸出空字符串

現在已經實現了文件的讀取功能,那么如何實現文件的寫入功能呢?我們需要實現TextValue控件的另一個自帶方法,如下

 

local fs = require "nixio.fs" function sync_value_to_file(value, file) value = value:gsub("\r\n?", "\n") local old_value = nixio.fs.readfile(file) if value ~= old_value then nixio.fs.writefile(file, value) end end m=Map("pdnsd",translate("Pdnsd"),translate("Pdnsd可以實現類似ChinaDNS的效果,通過TCP協議進行DNS解析可以有效避免DNS污染,默認上游服務器為114DNS,可以在【DHCP/DNS】中設置【DNS轉發】為【127.0.0.1#5053】即可將所有DNS請求交給pdnsd進行解析,由於pdnsd自帶緩存,所以很快哦。注意SSR如果你勾選了TCP解析DNS會也會開啟一個pdnsd監聽7453接口,並與該頁面的pdnsd沖突,點擊【保存/應用】可以重啟pdnsd。另外你可以使用dig來檢測DNS解析情況,方法dig @127.0.0.1 -p 5053 www.facebook.com")) s=m:section(TypedSection,"arguments","") s.addremove=false s.anonymous=true view_enable = s:option(Flag,"enabled",translate("Enable")) view_cfg = s:option(TextValue, "1", nil) view_cfg.rmempty = false view_cfg.rows = 43 function view_cfg.cfgvalue() return nixio.fs.readfile("/etc/pdnsd.conf") or "" end function view_cfg.write(self, section, value) sync_value_to_file(value, "/etc/pdnsd.conf") end return m

上面代碼中又重寫了.write(self,section,value)這個方法,其中value這個參數就是當前TextValue這個控件中顯示的文字,於是我又寫了一個函數 sync_value_to_file(文本,文件路徑)方法來將控件中的內容寫入到文件中去。

 

而那個信函數主要作用就是先把windows中的換行符“\r\n”換成linux的換行符“\n”

然后檢查一下新舊文本有沒有發生變化,如果發生變化才調用庫函數nixio.fs.writefile(file, value)將文本寫入到文件中去。

截至目前,我們已經實現了使用luci頁面讀寫配置文件的功能了。

 

可是我們還想在配置文件發生修改之后自動重啟后台的服務,應該怎么做呢,首先我們記得我們上面的checkbox記錄了啟用與否,並記在了/etc/config/pdnsd這個文件里。那么我們可以根據這個文件記錄的內容,如果是1就restart pdnsd這個服務並enable,如果是0就stop這個服務並disable。那么我們先寫一個shell腳本來讀取uci文件的記錄值並完成這一系列動作,我新建了一個/etc/pdnsd_init.sh 並添加執行權限,內容如下

 

echo luci for pdnsd local vt_enabled=`uci get pdnsd.@arguments[0].enabled 2>/dev/null` echo $vt_enabled if [ "$vt_enabled" = 1 ]; then logger -t alex restarting pdnsd echo "restarting pdnsd" /etc/init.d/pdnsd enable /etc/init.d/pdnsd restart else logger -t alex stopping pdnsd echo "stopping pdnsd" /etc/init.d/pdnsd disable /etc/init.d/pdnsd stop fi

一個很普通的shell腳本,其中echo語句只有使用控制台執行的時候才輸出,而logger語句會輸出到OpenWrt主界面【狀態】-【系統日志】中去,方便記錄log和分析bug

 

上面的uci get pdnsd.@arguments[0].enabled 就是獲取uci配置文件中enabled這個字段的值,因為一個config可以有多個section,每個section下面都可以有一個叫enabled的變量,所以要填寫arguments[0]。比如像如下這種uci文件,就會有多個seciton(uci和lua中nil就是null的意思)

 

config transparent_proxy option main_server 'nil' option udp_relay_server 'nil' option local_port '1234' config socks5_proxy option server 'nil' option local_port '1080' config port_forward option server 'nil' option local_port '5300' option destination '8.8.4.4:53' 


然后使用終端執行/etc/pdnsd_init.sh系統就會根據/etc/config/pdnsd中記錄的值來判斷是啟動還是停止pdnsd服務了,下面我們要把這個shell文件放到luci中執行,我的方法是放在之前寫的文件寫入方法中直接執行,這樣應該是不太對的方法,不過由於我剛剛接觸luci,也沒發現別的方法,如果有大神發現可以告訴我。

 

 

function sync_value_to_file(value, file) value = value:gsub("\r\n?", "\n") local old_value = nixio.fs.readfile(file) if value ~= old_value then nixio.fs.writefile(file, value) end os.execute("/etc/pdnsd_init.sh >/dev/null") end

其中,os.excute("shell命令")就可以執行我們自定義的代碼,然后點擊”保存&應用“luci頁面會轉圈圈,提示”正在應用更改...“然后”配置已應用“,其中”正在應用更改...“取決於上面自定義shell腳本的運行時間,我試過如果在shell腳本中添加一句”sleep 10s“會讓”正在應用更改...“的時間明顯延長。

 

那么為什么要加上>/dev/null這個呢?其實非常必要,因為luci需要一個規定格式的輸出,如果不寫這句,你點擊”保存&應用“之后就會出現白屏錯誤,然后就沒有下文了,如下

所以必須把我們自己shell腳本的輸出全部丟棄,只需添加>/dev/null就好,注意2>/dev/null是沒有用的

至此,我們的通過luci修改配置文件並控制啟動、停止的功能就全部完成了。

參考文章:http://www.right.com.cn/forum/thread-183560-1-1.html

http://blog.csdn.net/icy_river/article/details/48179649

 

=========== End

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM