【OpenWrt】(Luci)OpenWrt Web GUI 开发之 Luci 框架粗解

2023-10-30 13:40

本文主要是介绍【OpenWrt】(Luci)OpenWrt Web GUI 开发之 Luci 框架粗解,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

本博文全部内容在 GitHub 仓库上同步,可以在 👉 GitHub 🔗 上找到。
本博文是 GitHub 上的 README 内容,故本文内部分链接是以 GitHub 上相对路径放置的,有需要请在 GitHub 中下载/查看。

因为个人的水平和精力是有限的,如果本目录下的内容存在错误,疏忽之处,欢迎指出:可创建 Issue 或者 fork 修改后向本仓库做 pull request

Overview

    • 理解 Luci 架构
      • 目录
      • 正文


理解 Luci 架构

注:

下文“几个元素”中,属于“总结”。

是在编写本文是为了理清思路,边整理思路边写下的。

若有不明之处可以在看完本目录下的内容之后再回过头来看一遍。

几个元素:

  • 在 OpenWrt 使用 Luci – Web。

  • Luci 使用 lua 语言作为后台。

  • Luci 使用 lua 通过 uci 库读取和修改 OpenWrt 协定的 UCI 配置文件。

  • OpenWrt 内协定 UCI 配置文件,并提供了不同的接口操作它,其中之一是实现了 lua 语言的 uci 库。

  • Luci 框架内基于 lua + uci 库编写了 CBI 框架 – CBI 框架是 Luci 的子框架。

  • CBI 框架加载入 uci 配置文件相应的 lua 模块,对于 HTTP GET 能够以 CBI 框架的运行逻辑将 UCI 配置文件转化渲染成用于 Web 前端显示的 HTML 做 HTTP Response;同样对 HTTP POST 也以 CBI 框架运行的逻辑将 form 表单修改写入到 UCI 配置文件中(和生效)。

  • 由于 UCI 有着规范的格式,以及 CBI 框架的 OOP 实现,我们不需要从头如 读取 UCI 配置文件,写出如何渲染成 HTML 的代码再 Response 到 Client(浏览器);这些操作是可以抽象出来的一套可重用的参数和运行逻辑(方法),用户(promgramer)只需要编写针对细分的不同的配置文件内容的 CBI 模块代码即可(即,OOP 中的 class 已经被实现好了,只需要根据不同的实体内容实例和调整实例内容即可)。

  • 因为 CBI 框架的高度可重用性(配置文件大同小异,用户(user)管理网页风格统一),所以我们可以设想只要在编写的 CBI 模块代码中指明该模块关联的 UCI 配置文件,那么 CBI 框架就能够将该 UCI 配置文件以写好的有限的规则读取出来并显示在浏览器上 – 但是因为我们需要控制配置文件中的哪些部分需要显示,哪些部分不需要显示;哪些部分以何种方式显示,另一些部分又以另外的什么方式显示;所以我们除了声明配置文件外,还需要声明这些内容 – 这很类似“声明式”编程,后面具体会感觉到。

    (另外一提,这点和 Web 开发的后台管理网站没有本质区别,后台管理网站也是通过编写大量通用的代码涵盖大范围的内容类型(数据库,数据 type)以做到对大部分编写的数据模型无需额外编写管理页面,直接能够以通用的模板显示出来并且能够操作)

  • Luci 框架亦是 MVC 模式,其中 CBI 即是 model,因为用户(user)管理网页(路由器的 Web GUI)没有很多花样,所以基本上需要的前端模板 luci 都提供了 – 即用户编写了 CBI 模块即可,CBI 框架渲染时的运行逻辑能够使用既有的模板为浏览器提供 HTML 显示。当然,在一些需要以特殊方式显示或者提供更丰富的功能的地方,我们仍然可以自己编写模板(view),然后在 CBI 内指定哪些 UCI 内容使用该模板显示。

  • Luci 框架的控制器是理解 Luci 框架运行逻辑的关键,它主要将用户编写的控制器规则生成 URI(路由)(并且提供了反向解析的接口),用户(user)只需要在浏览器访问 URL,Luci 就能够通过控制器执行程序中定义的处理代码(比如 CBI 模块)得到处理代码(方法)的返回内容作为 HTTP 响应(View),即 controller -> model -> view(view 中又包含 controller URL)。

详解 Luci 框架 – 将分以下步骤进行(可以仔细看一下,有助于理清思路):

  1. 软件结构:源码结构和运行结构
    1. 源码分布介绍和“安装/运行”文件分布
    2. 源码编译/打包方式和上传安装
  2. HTTP Server
    1. HTTP Server 和 Luci 交互基本原理
    2. HTTP Server 简单介绍
  3. Luci 用户系统
    1. 多用户支持
    2. 状态保持原理(HTTP 是无状态协议)
    3. 登录系统
  4. Luci 框架
    1. hello world 级 demo – 接触与感受
    2. MVC 简介
    3. Controller 和 URI
    4. View – 模板简介和基本使用/语法
    5. Luci 框架前半部运行逻辑
      1. 从 HTTP Server 到执行 Luci
      2. 从 Luci 入口到 Controller
      3. 从 Controller 到执行 target(函数)
    6. 非 CBI target – call 与 template 实例
    7. Model(模型 )-- CBI 框架
      1. CBI 的 hello world 级 demo
      2. 了解 OOP 基本知识和作用
        1. 基本知识
        2. 基本作用 -> 可实现的声明式编程
        3. 加速编程的好处,隐藏大量细节的坏处
        4. lua OOP 语法与动态语法
        5. 类与实例 – 不容模糊的 self
      3. UCI 协议(约定)
        1. 配置文件格式
        2. 常规对应 Web 页面显示的控件
        3. lua 中的 uci 库与 API
      4. CBI 模块实例 - example 页和 example 配置文件
      5. 处理表单 – 探究 CBI 框架运行逻辑
        1. 模块,节,tab 与 option
        2. 基本类型和动态绑定(组合模式)
        3. lua 脚本代码在什么时候运行?以及 require 和 loader 区别
        4. 运行方法(代码执行逻辑)和重写
        5. 可选的定制化 – 钩子函数
        6. 配置更新的生效和重定向
    8. 模板扩展 – javascript 异步请求
  5. 节选 - 编程关键词与理解
    1. 类,类型,实例,对象
    2. API,框架,模块,(数据)模型
    3. 钩子,重写
    4. 强类型和弱类型,动态和静态
    5. 面向过程,面向对象,面向声明
    6. UML

注:

因为本目录的内容并没有按照上文“步骤”写完,所以只称得上“粗解”。

因为 PPT 是先于本文做完的,虽然 PPT 内容本身可能不够精细,但是根据 PPT 内的文字说明,讲解,结合 Luci 源码查看,想必对框架理解会有一定的帮助。

另外在写 PPT 的时候是为了团队现场讲解,会配置打开的源代码文件讲,所以在 PPT 中主要以概括性、解释性、总结性内容为主,读者需要结合源码看。此处内容后面可能会不定期更新。

本着不等将事情做到完美的那一刻再分享出来的理由,

因为一是这样会过很久之后才分享出来,二是有可能做不到心目中的完美而一直不能分享出来。

若是有需要的读者早一些看到,并且可能能起到一定的帮助,再由读者自身通过结合源码以及翻阅资料补充便可以理解 Luci 框架。那么本目录下分享出来的内容便是有用的。

通过我也期望于即使目前此处的内容还很粗糙,但是若有读者能够 fork > 编辑补重小节小段或者是几句话,几行代码解释介绍,那也是甚好的。

粗解 Luci 框架:

目录

  1. 软件结构:源码结构和运行结构
    1. 源码分布介绍和“安装/运行”文件分布
    2. 源码编译/打包方式和上传安装
  2. HTTP Server
    1. HTTP Server 和 Luci 交互基本原理
    2. HTTP Server 简单介绍
  3. Luci 用户系统 《== 未完成
    1. 多用户支持
    2. 状态保持原理(HTTP 是无状态协议)
    3. 登录系统
  4. Luci 框架
    1. hello world 级 demo – 接触与感受
    2. MVC 简介
    3. Controller 和 URI
    4. View – 模板简介和基本使用/语法
    5. Luci 框架前半部运行逻辑《== 参见 luci框架代码”逻辑”流程图.pdf
      1. 从 HTTP Server 到执行 Luci
      2. 从 Luci 入口到 Controller
      3. 从 Controller 到执行 target(函数)
    6. 非 CBI target – call 与 template 实例
    7. Model(模型 )-- CBI 框架
      1. CBI 的 hello world 级 demo
      2. 了解 OOP 基本知识和作用《== 未完成
        1. 基本知识
        2. 基本作用 -> 可实现的声明式编程
        3. 加速编程的好处,隐藏大量细节的坏处
        4. lua OOP 语法与动态语法
        5. 类与实例 – 不容模糊的 self
      3. UCI 协议(约定)
        1. 配置文件格式
        2. 常规对应 Web 页面显示的控件
        3. lua 中的 uci 库与 API《== 未完成
      4. CBI 模块实例 - example 页和 example 配置文件
        1. 模块,节,tab 与 option
        2. 基本类型和动态绑定(组合模式)《== 未完成
        3. input-Value,select-ListValue,checkbox-Flag
      5. 处理表单 – 探究 CBI 框架运行逻辑
        1. lua 脚本代码在什么时候运行?以及 require 和 loader 区别《== 未完成
        2. 运行方法(代码执行逻辑)和重写
        3. 可选的定制化 – 钩子函数《== 未完成
        4. 配置更新的生效和重定向
    8. 模板扩展 – javascript 异步请求《== 未完成
  5. 节选 - 编程关键词与理解《== 未完成
    1. 类,类型,实例,对象
    2. API,框架,模块,(数据)模型
    3. 钩子,重写
    4. 强类型和弱类型,动态和静态
    5. 面向过程,面向对象,面向声明
    6. UML

正文

参阅 luci-web(GUI)-for-develop.pptx

以下为 PPT 幻灯片截图:
n/a
n/a
n/a
n/a
n/a
n/a
n/a
n/a
n/a

添加一个导航栏 tab,需要在 controller/ 下增加一个相应名称的 *.lua 脚本文件。
框架会读取 controller/ 下的所有 *.lua 脚本文件生成框架内部使用的结构树。每个 *.lua 脚本文件对应一个导航栏 tab。
框架读取 *.lua 内的 function index() 函数,其函数内的 entry 会在页面显示上作为导航栏 tab 的子页标签(页面入口)。

entry(path, target, title, order)
path : router – url
target: Target function to call when dispatched
title : 显示的名称
order : 顺序

source code(dispatch.lua)

function entry(path, target, title, order)local c = node(unpack(path))c.target = targetc.title  = titlec.order  = orderc.module = getfenv(2)._NAMEreturn c
end

n/a
n/a
n/a
n/a

luci 框架本身也就是 lua 脚本代码。
访问 url 并非访问某个特定的 *.lua 脚本文件。
而是通过 luci 框架执行相应的 lua 代码。

n/a
n/a
n/a

Client端和serv端采用cgi方式交互,uhttpd服务器的cgi方式中,fork出一个子进程,
子进程利用execl替换为luci进程空间,并通过setenv环境变量的方式,传递一些固定格式的数据(如PATH_INFO)给luci。

另外一些非固定格式的数据(post-data)则由父进程通过一个w_pipe写给luci的stdin,
而luci的返回数据则写在stdout上,由父进程通过一个r_pipe读取。

n/a
n/a

  1. 首次运行时,是以普通的file方式获得docroot/index.html,该文件中以meta的方式自动跳转到cgi的url,这是web服务器的一般做法。

  2. 然后第一次执行luci,path_info=‘/’,会alise到’/admin’(‘/‘会索引到 tree.rootnode,并执行其target方法,即alise(’/admin’),即重新去索引adminnode,这在后面会详细描述),
    该节点需要认证,所以返回一个登录界面。

  3. 第3次交互,过程同上一次的,只是这时已post来了登录信息,所以serv端会生成一个session值,然后执行’/admin’的target(它的target为firstchild,即索引第一个子节点),
    最终返回/admin/status.html,同时会把session值以cookie的形式发给client。这就是从原始状态到得到显示页面的过程,之后主要就是点击页面上的连接,产生新的request。

  4. 每个链接的url中都会带有一个stok值(它是serv生成的,并放在html中的url里),并且每个新request都要带有session值,它和stok值一起供serv端联合认证。

  5. 先介绍 luci 如何生成 router(路由)。
    然后关于 luci 框架如何加载模板,渲染数据后 response 到 client——先介绍 MVC(和 CBI),然后介绍连接 MVC 和处理请求接口的 dispatcher.lua。
    最后 dispatcher.lua 的其它代码,如何调用执行 controller 中的代码。

n/a

luci 框架会对解析得到的数据结构缓存在 /tmp/ 目录下
function 是 *.lua -> index -> entry 内的 target

luci框架代码“逻辑”流程图.vsdx == luci框架代码”逻辑”流程图.pdf

用户管理
luci 是一个单用户框架,公用的模块放置在 */luci/controller/ 下面,各个用户的模块放置在 */luci/controller/ 下面对应的文件夹里面。
比如 admin 登录,最终的页面只显示 /luci/controller/admin 下面的菜单。
这样既有效的管理了不同管理员的权限。

n/a
n/a
n/a

HowTo: Write Modules: https://github.com/openwrt/luci/wiki/ModulesHowTo

module <> Tab
action <
> page

n/a
n/a

Writing variables and function values
Syntax:
<% write (value) %>
Short-markup:
<%=value%>

Note: index 内部的另外一种写法!!!!!!!!!

n/a
n/a

通过 API 接口“声明式”编程关联配置文件 – 像 html, css 由浏览器读取 html, css 代码,然后执行浏览器内部的代码最后“显示”。

n/a

on_commit, on_apply 等方法在源码中以“钩子”的含义运行。

n/a

亦:CBI 模块也可以自行编写 template 模板然后指定使用。

n/a

类与 API 源码位置:qsdk\qca\feeds\luci\modules\luci-base\luasrc\cbi.lua

n/a

Abstract 即说明这是抽象类型;不能直接使用该类,需要继承出类型。
AbstractSection, AbstractValue 即两种不同的类,从效果上看,AbstractValue 的继承类在 CBI 模块中会根据配置文件需要而实例化绑定在继承 AbstractSection 类的实例下;这一点也可以从 AbstractSection 中的 option 方法内的代码看出。

parse 函数决定了框架内运行逻辑。

n/a

“uci"是"Unified Configuration Interface”(统一配置界面)的缩写,意在OpenWrt整个系统的配置集中化。
系统配置应容易,更直接且在此有文档描述,从而使你的生活更轻松!
(它是White Russian系列OpenWrt基于nvram的配置的后继改进。)
许多程序在系统某处拥有自己的配置文件,
比如/etc/network/interfaces, /etc/exports, /etc/dnsmasq.conf或者 /etc/samba/samba.conf,
有时它们还使用稍有不同的语法。
在OpenWrt中你无需为此烦恼,我们只需更改UCI配置文件!
你不需要为了某个更改起效而重启系统!参阅下文中的命令行实用工具以了解如何做到这点。
还有不要忘了官方程序包(official binaries)里包含了很多后台程序,但默认情况下并未启用!
比如cron后台程序默认并未激活,因而只编辑crontab并无作用。
你需要用/etc/init.d/crond start起动它或用/etc/init.d/crond enable激活它。 大部分后台程序都可以disable(禁用),stop(停止)和restart(重起)。 还有一些非UCI配置你可以参阅。

共同原则
OpenWrt的所有配置文件皆位于/etc/config/目录下。每个文件大致与它所配置的那部分系统相关。可用文本编辑器、“uci” 命令行实用程序或各种编程API(比如 Shell, Lua and C)来编辑/修改这些配置文件。

n/a

参考:
https://lvii.gitbooks.io/outman/content/openwrt.uci.html

实例:

# cat /etc/config/wireless config wifi-device 'wifi0'option type 'qcawificfg80211'option macaddr '00:03:7f:12:20:df'option hwmode '11a'option channel 'auto'config wifi-ifaceoption device 'wifi0'option mode 'ap'option ssid 'AAAAAAATest-5G'option bssid 'admin'option network 'lan'option key '12345678'option wps_pushbutton '0'option encryption 'none'config wifi-device 'wifi1'。。。略。。。# cat /etc/config/ddns config ddns 'global'option ddns_dateformat '%F %R'option ddns_loglines '250'option upd_privateip '0'config service 'myddns_ipv4'option lookup_host 'yourhost.example.com'option domain 'yourhost.example.com'option username 'your_username'option password 'your_password'option interface 'wan'option ip_source 'network'option ip_network 'wan'option service_name 'dyn.com'config service 'myddns_ipv6'。。。略。。。

n/a

参考:
https://blog.csdn.net/rainforest_c/article/details/70139962

  • package 'example’中的’example’实际上就是UCI文件的文件名,例如/etc/config/network对应 package ‘network’,但是这个语句不会存在文件中,需要通过命令uci export network查看。
  • config ‘example’ 'test’语句定义了一个type为example,名字为test的section。section可以只有type而没有名字,这类section称为匿名的section,后文会有说明。
  • option ‘string’ 'some value’语句定义了section下的一个option,该option标识为string,值为some value。
  • list ‘collection’ 'first item’语句定义了section下的一个list,list与option不同之处在于list可以有多个值,该例子中的list collection有first item和second item两个值。

n/a

此处直接在 OpenWrt 运行系统中直接修改。

n/a
n/a
n/a
n/a

s <= m:section()
taboption() 指定了该 Option 类在指定的 section->tab 下,并返回 option 实例。
option:write 方法重写定义了该方法的内容。write 方法在 post form 时被调用 – 参考前面幻灯片和源码。
m.uci:set, m.uci:delete 这些即使用 lua 的 uci 模块操作 UCI 配置文件 – 命令行操作 UCI 配置文件,Web(Lua)操作 UCI 配置文件两种方式的后一种。
面向对象编程中,m.uci 使用的是 lua 的 uci 模块,通过 m.uci 对象绑定(将 m 实例以 self 的形式传递给 uci 模块)即操作的是 m 指定的 UCI 配置文件。

n/a

这篇关于【OpenWrt】(Luci)OpenWrt Web GUI 开发之 Luci 框架粗解的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/308288

相关文章

Spring Boot + MyBatis Plus 高效开发实战从入门到进阶优化(推荐)

《SpringBoot+MyBatisPlus高效开发实战从入门到进阶优化(推荐)》本文将详细介绍SpringBoot+MyBatisPlus的完整开发流程,并深入剖析分页查询、批量操作、动... 目录Spring Boot + MyBATis Plus 高效开发实战:从入门到进阶优化1. MyBatis

Python基于wxPython和FFmpeg开发一个视频标签工具

《Python基于wxPython和FFmpeg开发一个视频标签工具》在当今数字媒体时代,视频内容的管理和标记变得越来越重要,无论是研究人员需要对实验视频进行时间点标记,还是个人用户希望对家庭视频进行... 目录引言1. 应用概述2. 技术栈分析2.1 核心库和模块2.2 wxpython作为GUI选择的优

JSON Web Token在登陆中的使用过程

《JSONWebToken在登陆中的使用过程》:本文主要介绍JSONWebToken在登陆中的使用过程,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录JWT 介绍微服务架构中的 JWT 使用结合微服务网关的 JWT 验证1. 用户登录,生成 JWT2. 自定义过滤

一文教你如何将maven项目转成web项目

《一文教你如何将maven项目转成web项目》在软件开发过程中,有时我们需要将一个普通的Maven项目转换为Web项目,以便能够部署到Web容器中运行,本文将详细介绍如何通过简单的步骤完成这一转换过程... 目录准备工作步骤一:修改​​pom.XML​​1.1 添加​​packaging​​标签1.2 添加

Python Dash框架在数据可视化仪表板中的应用与实践记录

《PythonDash框架在数据可视化仪表板中的应用与实践记录》Python的PlotlyDash库提供了一种简便且强大的方式来构建和展示互动式数据仪表板,本篇文章将深入探讨如何使用Dash设计一... 目录python Dash框架在数据可视化仪表板中的应用与实践1. 什么是Plotly Dash?1.1

基于Flask框架添加多个AI模型的API并进行交互

《基于Flask框架添加多个AI模型的API并进行交互》:本文主要介绍如何基于Flask框架开发AI模型API管理系统,允许用户添加、删除不同AI模型的API密钥,感兴趣的可以了解下... 目录1. 概述2. 后端代码说明2.1 依赖库导入2.2 应用初始化2.3 API 存储字典2.4 路由函数2.5 应

Python GUI框架中的PyQt详解

《PythonGUI框架中的PyQt详解》PyQt是Python语言中最强大且广泛应用的GUI框架之一,基于Qt库的Python绑定实现,本文将深入解析PyQt的核心模块,并通过代码示例展示其应用场... 目录一、PyQt核心模块概览二、核心模块详解与示例1. QtCore - 核心基础模块2. QtWid

利用Python开发Markdown表格结构转换为Excel工具

《利用Python开发Markdown表格结构转换为Excel工具》在数据管理和文档编写过程中,我们经常使用Markdown来记录表格数据,但它没有Excel使用方便,所以本文将使用Python编写一... 目录1.完整代码2. 项目概述3. 代码解析3.1 依赖库3.2 GUI 设计3.3 解析 Mark

利用Go语言开发文件操作工具轻松处理所有文件

《利用Go语言开发文件操作工具轻松处理所有文件》在后端开发中,文件操作是一个非常常见但又容易出错的场景,本文小编要向大家介绍一个强大的Go语言文件操作工具库,它能帮你轻松处理各种文件操作场景... 目录为什么需要这个工具?核心功能详解1. 文件/目录存javascript在性检查2. 批量创建目录3. 文件

最新Spring Security实战教程之Spring Security安全框架指南

《最新SpringSecurity实战教程之SpringSecurity安全框架指南》SpringSecurity是Spring生态系统中的核心组件,提供认证、授权和防护机制,以保护应用免受各种安... 目录前言什么是Spring Security?同类框架对比Spring Security典型应用场景传统