osnosn

  博客园 :: 首页 :: :: 联系 :: 订阅 :: 管理 ::

openwrt_用lua_ucode编写动态网页.uHTTPd_独立于luci之外_php_python3

openwrt_用lua_ucode编写动态网页.uHTTPd_独立于luci之外_php_python3

转载注明来源: 本文链接 来自osnosn的博客,写于 2023-02-17.

参考

修改openwrt uhttpd 使用的 ssl 证书

  • op21, op22, op24 测试OK。
  • 如果使用 https 访问,对默认证书的信息不满意。
  • 修改 /etc/config/uhttpdconfig cert 'defaults' 部分的内容。
    uci -q batch << EOF
    set uhttpd.defaults.organization='my organization'  #组织
    set uhttpd.defaults.commonname='my common name'     #通用名称
    set uhttpd.defaults.location='my location'   #地址
    set uhttpd.defaults.state='my state'    #省/州
    set uhttpd.defaults.country='CN'        #国家代码
    set uhttpd.defaults.days='730'          #有效期,两年
    commit uhttpd
    EOF
    
  • 删除旧证书 (.crt和.key)。rm /etc/uhttpd.*
  • 重启 uhttpd,会自动重新生成证书。/etc/init.d/uhttpd restart

CGI测试

  • 不想安装 php-fpm 或者 python3,它们的体积都比较大,小路由器空间不太够。
  • 不修改 openwrt的 uhttpd的配置。因为不想改变 luci的页面。
    • uhttpd 的 root 目录是 /www/
    • /www/中,只支持静态html文件。不支持lua脚本。
    • /www/cgi-bin/中,支持各种可执行文件,包括lua脚本,包括shell脚本,ucode脚本。
      脚本文件无后缀要求,需要设置执行权限 chmod +x
  • 最简单的办法就是,创建 /www/cgi-bin/test
    • chmod +x test
    • print() 和 io.write() 尽量不要混用,防止因缓存,导致输出顺序不正确。
      test 内容如下。op22,op24测试可用。
      #!/usr/bin/lua
      io.write("Content-type: text/html\n\n")
      io.write('test\n')
      -- print('test')
      io.write(os.date("%x", os.time()).."\n")
      
      注意:CGI脚本必须要输出"Content-type: text/html\n\n",uhttpd才会认为脚本正确进行了响应,才会输出内容到浏览器。​

CGI, lua

如果要操作 sqlite3文件。试试这两个包。

  • 二选一。
    opkg install lsqlite3      #lsqlite3(64kB) 依赖 libsqlite3(840kB)
    opkg install luasql-sqlite3   #luasql-sqlite3(64kB) 依赖 libsqlite3(840kB)
    
  • 在 lua中 可以用 require "lsqlite3" 或者 require "luasql.sqlite3" 引入。
  • sqlite3 命令行工具
    opkg install sqlite3-cli   #sqlite3-cli(193kB) 依赖 libsqlite3(840kB),libedit(194kB)
    

lua 读取 sqlite3 测试,TEST.db 是有内容的数据库文件。

  • op22,op24测试可用。
    #!/usr/bin/lua
    io.write("Content-type: text/html;charset=utf-8\n\n")
    
    local sql3=require "luasql.sqlite3"
    local env=sql3.sqlite3()
    local conn=env:connect("/tmp/tmp/TEST.db")
    name="tom"
    sql_str=string.format("select * from tasktab where id='%s' order by rowid desc limit 10",name)
    cur,err=conn:execute(sql_str)
    print(cur,err,"<br>")
    row=cur:fetch({},"a")
    while row do
      for k,v in pairs(row) do  -- 打印所有字段
        print(k,v,"<br>")
      end
      row=cur:fetch(row,"a")
    end
    cur:close()
    conn:close()
    env:close()
    

openwrt中cgi脚本获取GET提交的内容,是通过环境变量获取。

  • op22,op24测试可用。
    os.getenv("QUERY_STRING")
    

lua 遍历全局变量,环境变量

  • 遍历全局变量。
    for k,v in ipairs(_G) do print(k,v) end
    
  • lua中,没找到遍历 局部变量 的方法。
  • 可以使用 shell脚本打印出所有的环境变量。op22测试可用。
    #!/bin/sh
    echo Content-type: text/html;charset=utf8
    echo
    echo 'test <pre>'
    set
    
  • 或者,用 openwrt中的 NIXIO POSIX library,遍历环境变量。op22测试可用。
    local nixio=require "nixio"
    local env=nixio.getenv()
    for k,v in ipairs(env) do print(k,v) end
    

openwrt中cgi脚本获取POST提交的内容。

  • op22测试可用。
    local POST_DATA = nil
    local POSTLength = tonumber(os.getenv("CONTENT_LENGTH")) or 0
    if (POSTLength > 0) then
       POST_DATA = io.read(POSTLength)
       --POST_DATA = io.read("*a")
    end
    -- POST_DATA -> "test1=1234&test2=abcd%2B"
    
  • urldecode
    local http=require "luci.http"
    posted_str=http.urldecode(posted_str, true)
    --local util=require "luci.util"
    --有函数 util.urlencode()  util.urldecode()
    --local lhttp=require "lucihttp"
    --有函数 lhttp.urlencode()  lhttp.urldecode()
    

判断文件是否存在。

  • op22测试可用。
    function file_exists(name)
      local f=io.open(name,"rb")
      if f~=nil then io.close(f) return true else return false end
    end
    
  • 或者,用 openwrt中的 NIXIO POSIX library。op22测试可用。
    local fs=require "nixio.fs"
    function file_exists(name)
      local f=fs.stat(name)
      if f~=nil then return true else return false end
    end
    

获取文件大小,不引入其他库。用"rb"二进制读方式,不容易出错。

  • op22测试可用。
    function length_of_file(filename)
      local fh = assert(io.open(filename, "rb"))
      local len = assert(fh:seek("end"))
      fh:close()
      return len
    end
    -- file:seek([whence][,offset])
    -- whence=set, cur, end 文件头,当前位置,文件尾。offset可为负数。
    

文件的写锁。

  • lua 本身没找到 文件读写锁 的操作函数,无论是咨询锁,还是强制锁,都没有。
  • openwrt中的 nixio.open() 提供 文件锁 的操作。 看 nixio.File 的文档。op22测试可用。
    local nixio=require "nixio"
    fp=nixio.open("test-file.txt","w")
    fp:lock('lock')
    fp:write('abcdefghij\n')
    fp:lock('ulock')
    fp:close()
    
    • nixio.open() 打开后,没有 lines() 函数。
    • nixio.open() 以只读打开,不能加锁 lock("lock"),lock("tlock")。

Basic WEB 认证。

  • op22,op24测试可用。
    #!/bin/sh
    echo Content-type: text/html;charset=utf8;
    if [ -z $HTTP_AUTHORIZATION ]; then
      echo Status: 401 Unauthorized
      echo WWW-Authenticate: Basic realm="My Realm"
    fi
    echo
    echo HTTP_AUTHORIZATION=$HTTP_AUTHORIZATION
    # 如:user=test, pwd=test, HTTP_AUTHORIZATION="Basic dGVzdDp0ZXN0"
    
  • 纯lua实现Base64加密与解密
  • openwrt中lua版base64脚本】使用nixio库。
  • openwrt 的 nixio包,有base64decode函数。op22测试可用。
    #!/usr/bin/lua
    require "os"
    local nixio=require "nixio"
    -- "test:test" -> "Basic dGVzdDp0ZXN0"
    local HTTP_AUTHORIZATION=os.getenv("HTTP_AUTHORIZATION")
    local auth_ok=false
    if HTTP_AUTHORIZATION ~= nil then
      local user_pwd=HTTP_AUTHORIZATION:sub(7)
      user_pwd=nixio.bin.b64decode(user_pwd)
      if user_pwd == 'test:test' then
        auth_ok=true
      end
    end
    if auth_ok == false then
      io.write("Status: 401 Unauthorized\n")
      io.write('WWW-Authenticate: Basic realm="My Realm2"\n')
    end
    io.write("Content-type: text/html;charset=utf8\n\n")
    
    print(HTTP_AUTHORIZATION, '<br>')
    print('auth_ok=',auth_ok, '<br>')
    

session管理

方法1

  • 暂时只有思路,未实测。// 假设,保存session文件的目录是/tmp/myweb/。目录路径自己定义。
  • 检查 header 有没有 sessionid 的 cookie。
    • 。就从/tmp/myweb/中吧session文件读入table中。
      如果session文件找不到。则,同下面的"无"。重新生成 sessionid。
    • 。通过 /dev/urandom 设备获取随机数,加上当前时间,混合生成 sessionid。
      通过 cookie把 sessionid写入返回的 header中。
      用 sessionid创建 lua的table,用于保存session数据。
  • 通过 读,改,增,删 这个table中的成员变量。实现对 session变量的读写。
  • 在cgi结束前,把这个 session 的 table写入文件,在/tmp/myweb/目录中。
  • 另外跑一个 cron任务,定时把长时间未修改的 session文件删除了。

方法2

  • openwrt中的 ubus 中有 session 的实现。session保存在内存中。
  • ubus session
    可以创建session_id,然后用这个id设置cookie。
    可以销毁session,可以把变量保存到session中。
  • 35-Openwrt rpcd】【35-Openwrt rpcd】【Openwrt进程间通信-Ubus】【关于openwrt ubus框架中的rpcd插件提供的session服务
  • 例程,op24可用,(2026-03测)
    op-22.03/luci/http.lua】【lucihttp
    #!/usr/bin/lua
    local os=require "os"
    local lhttp=require "lucihttp"
    local util=require "luci.util"
    -- 以下两个function抄自op22.03; 后续版本被删除了
    function urldecode_params(url, tbl)
            local parser, name
            local params = tbl or { }
            parser = lhttp.urlencoded_parser(function (what, buffer, length)
                    if what == parser.TUPLE then
                            name, value = nil, nil
                    elseif what == parser.NAME then
                            name = lhttp.urldecode(buffer)
                    elseif what == parser.VALUE and name then
                            params[name] = lhttp.urldecode(buffer) or ""
                    end
                    return true
            end)
            if parser then
                    parser:parse((url or ""):match("[^?]*$"))
                    parser:parse(nil)
            end
            return params
    end
    function getcookie(name)
       return lhttp.header_attribute("cookie; " .. (os.getenv("HTTP_COOKIE") or ""), name)
    end
    -- ------------web登录
    local cookie_name='my_cookie'
    local QUERY_STR=os.getenv("QUERY_STRING")
    local get_param=urldecode_params(QUERY_STR)
    local session_sid=getcookie(cookie_name)
    local staffid
    if session_sid ~= nil then
       if get_param['do']=='logout' then  -- 退出登录
          util.ubus("session","unset", {
             ubus_rpc_session= session_sid,
             keys= {'staffid', 'other' }
          })
       end
       local buf=util.ubus("session","get", {
          ubus_rpc_session= session_sid,
          keys= {'staffid', 'other' }
       })
       if buf == nil then
            session_sid=nil
       else
          --staffid=buf['values']['staffid']
          staffid=buf.values.staffid
       end
    end
    
    local POSTLength = tonumber(os.getenv("CONTENT_LENGTH")) or 0
    if (POSTLength > 0) then
       POST_DATA = io.read(POSTLength)
    end
    local post_param={}
    if os.getenv('REQUEST_METHOD')=='POST' then
       post_param=urldecode_params(POST_DATA)
    end
    if staffid ==nil then
      --post_param={"usr":"abc","usrpw":"123"};
      if post_param['usr']=='abc' and post_param['usrpw']=='123' then
         if session_sid==nil then  -- create新session
            local session=util.ubus("session","create", { timeout=110 })
            session_sid=session['ubus_rpc_session']
            io.write('Set-Cookie: '..cookie_name..'='..session_sid..'; path=/cgi-bin; SameSite=strict;\n')
         end
         util.ubus("session","set", {
              ubus_rpc_session= session_sid,
              values= {staffid= post_param.usr }
              })
         --staffid=post_param['usr']
         staffid=post_param.usr
      end
    end
    
    io.write("Content-type: text/html;charset=utf8\n\n")
    
    local HTTP_COOKIE=os.getenv("HTTP_COOKIE") or ''
    print('cookie:',HTTP_COOKIE,'<br>\n')
    print('---get---','<br>\n')
    for kk,vv in pairs(get_param) do print(kk,vv,'<br>\n') end
    print('---post---','<br>\n')
    for kk,vv in pairs(post_param) do print(kk,vv,'<br>\n') end
    print('----------','<br>\n')
    local REMOTE_ADDR=os.getenv("REMOTE_ADDR")
    print('REMOTE_ADDR:', REMOTE_ADDR,'<br>\n')
    print('session_sid:',session_sid,'<br>\n')
    print('staffid:', staffid,'<br>\n');
    
    io.write(string.format([[
    <!DOCTYPE html>
    <html>
    <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0">
    <style type="text/css">
    body { background: white; font-family: arial, helvetica, sans-serif; }
    a { color: black; }
    .err { color: #000; background: #fdd }
    .done { color: #000; background: #cfc }
    </style>
    <title>mysite</title>
    </head>
    <body>
      <div style='margin:20px 0 0 10px'>
        <a href="?do=logout">退出登录</a><br>
        <form action="%s" method="POST">
          user:<input type=text name=usr size=7> &nbsp;
          pwd: <input type=text name=usrpw size=7> &nbsp;
          <input type=submit> &emsp;
          <input type=reset>
        </form> <br>
        <p>查看</p>
    ]],os.getenv('SCRIPT_NAME')or './') )
    

执行shell命令

  • local sys=require("luci.sys")
    local buf=sys.exec("ip addr")
    print(buf)
    

openwrt中其他的 lua可用包

  • local jsonc=require "luci.jsonc"
  • local sys= require "luci.sys"
  • local http=require "luci.http"
  • local ip= require "luci.ip"
  • local xml= require "luci.xml"
  • local util=require "luci.util"
  • 这些包的使用文档【luci api Reference

lua 引用其他文件

  • 把其他文件写成模块,放入系统目录,用 xx=require 引入
  • 用 xx=assert(dofile()) 引入,不限位置。
  • 用 xx=assert(loadfile()) 引入,

读写ini配置文件

openwrt的shell字符串通配符比较

  • openwrt 的 shell支持这个写法 [[ ]]。op22测试可用。
    CHECK="abc 123 456 789"
    fnd="456"
    if [[ "$CHECK" == abc* ]]; then
       echo found abc
    fi
    if [[ "$CHECK" == *"$fnd"* ]]; then
       echo found 456
    fi
    

openwrt中ms毫秒级的sleep

三个方案,都不会占用 CPU时间。op22测试可用。

  • 方案一,安装opkg install coreutils-sleep,约占32k的rom空间。
    支持毫秒级精度的 sleep。定时误差就是启动 sleep进程的时间。
  • 方案二,使用 lua的nixio.nanosleep(seconds, nanoseconds)函数,接受纳秒参数。
    毫秒级精度应该 OK,纳秒级精度估计不行。定时误差就是启动 lua进程的时间。mt7620的小路由,启动 lua要20ms。
    下面的例子,可以在 shell中执行./luasleep 2.5延时 2s+500ms。
    #!/usr/bin/lua
    -- filename: luasleep
    if arg[1] == nil then
      local usage="\nUsage: %s s[.ms]\n   s; seconds\n   ms: milliSeconds 0-999\n"
      print(usage:format(arg[0]) )
      os.exit()
    end
    local nixio=require "nixio"
    local ss,ms=math.modf(arg[1])
    ms=ms *1000
    --nixio.nanosleep(ss, ms*1000000)
    --因精度原因,有的数相乘后的结果值带小数,就会出错。例如xxx.99999,xxx.000001
    nixio.nanosleep(ss, math.floor(ms*1000000))
    
  • 方案三,使用 lua的nixio.poll(fds, milliseconds)函数,接受毫秒参数。
    local nixio=require "nixio"
    nixio.poll({},6000)  -- 6 sec
    

openwrt中随机sleep

  • 0-3秒内的sleep
    #!/usr/bin/lua
    require("math")
    require("nixio")
    --seed 包含 微秒。如果同时运行两个,应该rand会不同。
    sec,usec=nixio.gettimeofday()  --秒,微秒
    seed=(sec%1000)*1000000 + usec
    math.randomseed(seed)
    rand=math.random()*1000 *3  --乘以3
    ms=math.floor(rand)
    print(rand, ms)
    nixio.poll({},ms)
    --或者seed 用 os.time仅精确到秒,os.clock有微秒。
    seed=os.time()+1000000*os.clock()
    
  • 0-3060ms 的sleep
    #!/usr/bin/lua
    require("nixio")
    require("nixio.fs")
    local rand=nixio.fs.readfile("/dev/urandom",12)  --取12个byte
    aa={string.byte(rand,1,12)}
    ms=0
    for kk,vv in ipairs(aa) do
      print(kk,vv)
      ms = ms+vv
    end
    rndhex=nixio.bin.hexlify(rand)
    print(ms,rndhex)
    nixio.poll({},ms)
    

lua获取自身脚本所在的目录

  • 比如文件 /root/abc/def/test.lua。op22测试可用。
    local selfpath=debug.getinfo(1,'S').source:sub(2):match('^.*/')
    print(selfpath) -- "/root/abc/def/"或"def/"或"./" 相对路径,有"/"结尾
    
    local selfname=debug.getinfo(1,'S').source:sub(2)
    local fs=require "nixio.fs"
    print(fs.dirname(selfname)) --相对路径,无"/"结尾
    print(fs.realpath(fs.dirname(selfname))) --"/root/abc/def" 绝对路径,无"/"结尾
    
    local nixio=require "nixio"
    print(nixio.getcwd())  -- 工作目录 current working directory
    

CGI, ucode

  • ucode Documentation
  • 创建 /www/cgi-bin/test2
    • chmod +x test2
    • test2 内容如下。op24测试可用。(2026-03测)
      #!/usr/bin/ucode -T
      Content-type: text/html
      
      test <br>
      {%
      tm=localtime();
      printf("%d-%02d-%02d_%02d:%02d:%02d \n", tm.year, tm.mon, tm.mday, tm.hour, tm.min, tm.sec);
      %}
      
      或者
      #!/usr/bin/utpl
      Content-type: text/html
      
      test <br>
      
      或者
      #!/usr/bin/env utpl
      Content-type: text/html
      
      test <br>
      

ucode 代码注释

  • 块注释,用 {# ... #} 可以多行注释,但不能在 {% ... %}中。官方文档中有说明。
  • 行注释,用 // ...{% ... %}代码块中使用。官方文档中没有说明。
  • 字符串,可以用 双引号"",单引号'',反引号``。官方文档中没有说明。
    print("abc");
    print('abc');
    print(`abc ${variable}`);  //变量会被替换为值
    

打印对象中的"函数"和"变量"

  • import * as lucihttp from 'lucihttp';
    printf('%.2J \n', lucihttp);
    

获取所有环境变量

  • printf('%.2J \n', getenv());

全局变量

  • printf('%.2J \n', modules; 打印所有载入的模块。
  • printf('%.2J \n', global); 打印所有全局变量,内置函数。
  • printf('%.2J \n', SCRIPT_NAME); 当前执行的脚本的文件名。
  • printf('%.2J \n', ARGV); 执行脚本的命令行参数。

ucode 读取sqlite3

  • 没找到方法。

获取GET提交的内容,是通过环境变量获取

  • 操作和lua-cgi类似

获取POST提交的内容,是stdin获取

  • 操作和lua-cgi类似
  • urlencode(), urldecode()
    import * as http from 'luci.http';
    print(http.urlencode("df=sdf2345&hh=23#44"),'\n');
    print(http.urldecode("df%3Dsdf2345%26hh%3D23%23%2544"),'\n');
    // import {urlencode,urldecode} from 'lucihttp'
    

session管理

  • openwrt中的 ubus 中有 session 的实现。session保存在内存中。
  • ubus session
    可以创建session_id,然后用这个id设置cookie。
    可以销毁session,可以把变量保存到session中。
  • 例程, op24可用, (2026-03测)
    #!/usr/bin/utpl
    {%
    'use strict';
    import { stdin, stdout } from 'fs';
    import {urldecode_params as http_urldecode_params} from 'luci.http';
    const input_buffsize=2048;
    let input_available= +getenv('CONTENT_LENGTH') || 0;
    function read(len) {
       if (input_available==0) {
          stdin.close();
          return null;
       }
       let chunk =stdin.read(min(input_available,len ?? input_buffsize,input_buffsize));
       if (chunk==null) {
          input_available=0;
          stdin.close();
       } else {
          input_available-=length(chunk);
       }
       return chunk;
    }
    function write(data) {
       return stdout.write(data);
    }
    //----http弹框认证
    let HTTP_AUTHORIZATION=getenv('HTTP_AUTHORIZATION');
    let auth_ok=false;
      //auth_ok=true;
    if (HTTP_AUTHORIZATION != null){
      let user_pwd=substr(HTTP_AUTHORIZATION,6);
      user_pwd=b64dec(user_pwd);
      if (user_pwd == 'abc:def'){
         auth_ok=true;
      }
    }
    if (auth_ok == false) {
      write("Status: 401 Unauthorized\n");
      write('WWW-Authenticate: Basic realm="My Realm2"\n');
      write("Content-type: text/html;charset=utf8\n\n");
      write("401 Authorization Required\n");
      exit(0);
    }
    //----网页登录
    const cookie_name='my_cookie';
    import { header_attribute } from 'lucihttp';
    import { connect } from 'ubus';
    function get_cookie(name) {
      return header_attribute(`cookie; ${getenv('HTTP_COOKIE') ?? ''}`, name);
    }
    let QUERY_STR=getenv('QUERY_STRING');
    let get_param=http_urldecode_params(QUERY_STR);
    let session_sid=get_cookie(cookie_name);
    let staffid;
    if (session_sid !=null) {
      let ubus=connect();
      if (get_param.do=='logout') {  //----退出登录
        ubus.call("session", "unset", {
          ubus_rpc_session: session_sid,
          keys: [ 'staffid','other' ]
        });
      }
      let buf=ubus.call("session", "get", {
          ubus_rpc_session: session_sid,
          keys: [ 'staffid','other' ]
      });
      ubus.disconnect();
      if (buf ==null) {  //session expired
        session_sid=null
      } else {
        staffid=buf.values.staffid;
      }
    }
    let POST_STR=read(input_available);
    let post_param={};
    if (getenv("REQUEST_METHOD")=="POST") {
      post_param=http_urldecode_params(POST_STR);
    }
    if (staffid ==null) {
      //post_param={"usr":"myuser","usrpw":"123"};
      if (post_param.usr=='myuser' && post_param.usrpw=='123') {
        let ubus=connect();
        if (session_sid ==null) {  //----创建新的session
          let session=ubus.call("session", "create", {timeout: 310 } );
          session_sid=session.ubus_rpc_session;
          write(`Set-Cookie: ${cookie_name}=${session_sid}; path=/cgi-bin; SameSite=strict;\n`);
        }
        ubus.call("session", "set", {
              ubus_rpc_session: session_sid,
              values: {staffid: post_param.usr }
              });
        ubus.disconnect();
        staffid=post_param.usr;
      }
    }
    write("Content-type: text/html;charset=utf8\n\n");
    
    let REMOTE_ADDR=getenv('REMOTE_ADDR');
    print('<pre>');
    printf('GET: %.2J\n', get_param);
    printf('POST: %.2J\n', post_param);
    printf('REMOTE_ADDR: %.2J\n', REMOTE_ADDR);
    printf('sessionid: %.2J\n', session_sid);
    printf('staffid: %.2J\n', staffid);
    print('</pre>');
    %}
    
    <!DOCTYPE html>
    <html>
    <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0">
    <style type="text/css">
    body { background: white; font-family: arial, helvetica, sans-serif; }
    a { color: black; }
    .err { color: #000; background: #fdd }
    .done { color: #000; background: #cfc }
    </style>
    <title>mysite</title>
    </head>
    <body>
      <div style='margin:20px 0 0 10px'>
        <a href="?do=logout">退出登录</a><br>
        <form action="{{getenv("SCRIPT_NAME")}}" method="POST">
          user:<input type=text name=usr size=7> &nbsp;
          pwd:<input type=text name=usrpw size=7> &nbsp;
          <input type=submit> &emsp;
          <input type=reset>
        </form> <br>
        <p>查看</p>
    
    ubus 管理的 session,自动管理超时(expires),expires每秒自动减1,当减到0时自动删除session。
    ubus对 session做 get,set,unset操作时,expires自动复位到 timeout值。
    使用 ubus的 session,建议不要设置 "acls"权限,会造成 ubus的 web接口权限泄漏,除非你明确知道此机制。

判断文件是否存在

  • 用 fs.access()函数
    import * as fs from 'fs';
    isexists=fs.access("/path/file","f");
    

获取文件大小

  • 用 fs.stat()函数
    import * as fs from 'fs';
    mystat=fs.stat("/path/file");
    

文件的读写锁

  • fs.file.lock()

Basic WEB 认证

  • base64, 有 b64dec(), b64enc() 函数。

引用其他文件

  • include() 函数。

ms毫秒级的sleep

  • sleep(milliseconds) 函数。
  • 随机数,
    import { srand, rand } from 'math';
    srand(seed);
    rand(a,b);
    

ucode获取自身脚本所在的目录

  • sourcepath() 函数。

ucode 中调用lua

  • 需要 opkg install ucode-mod-lua 模块。
  • contrib: introduce ucode-mod-lua#5818
  • op24可用, (2026-03测)
    const lua = require("lua");
    let vm = lua.create();
    printf('%.2J \n', vm);
    //vm.get('_G');  //获取 lua的全局变量
    //vm.set({});    //传递变量到 lua中
    vm.set({
      hello: function(...args) {
          print(`Got arguments: ${args}\n`);
      },
      u_data: {
          bb: true,
          ff: 1.3,
      }
    });
    vm.invoke("hello", true, 123, "Foo");  //调用 lua的函数
    vm.eval('print("Hi", u_data.ff);');  //执行 lua的语句
    vm.include("./xx.lua");  //执行lua脚本
    
  • 可以考虑在lua中操作sqlite3.

配置到uhttpd中

lua

  • opkg install uhttpd-mod-lua
    安装了 /usr/lib/uhttpd_lua.so
  • 然后配置 /etc/config/uhttpd 中 "main" 部分的配置项 lua_prefixlua_handler
  • 未测试。

ucode

  • opkg install uhttpd-mod-ucode
    安装了 /usr/lib/uhttpd_ucode.so
  • 然后配置 /etc/config/uhttpd 中 "main" 部分的配置项 ucode_prefix
  • 未测试。

php8

python3

  • 同 php8
    使用 list interpreter配置
  • 需要 opkg install python3-cgi
  • 未测试。

----end----


转载注明来源: 本文链接 https://www.cnblogs.com/osnosn/p/17131543.html
来自 osnosn的博客 https://www.cnblogs.com/osnosn/ .


posted on 2023-02-17 23:20  osnosn  阅读(1853)  评论(0)    收藏  举报