--- 模块功能:参数管理 -- @module nvm -- @author openLuat -- @license MIT -- @copyright openLuat -- @release 2017.11.9 require"log" module(...,package.seeall) package.path = "/?.lua;".."/?.luae;"..package.path --默认参数配置存储在configname文件中 --实时参数配置存储在paraname文件中 --para:实时参数表 --config:默认参数表 paraname,paranamebak = "/nvm_para.lua","/nvm_para_bak.lua" local para,libdftconfig,configname,econfigname = {} --[[ 函数名:serialize 功能 :根据不同的数据类型,按照不同的格式,写格式化后的数据到文件中 参数 : pout:文件句柄 o:数据 返回值:无 ]] local function serialize(pout,o) if type(o) == "number" then --number类型,直接写原始数据 pout:write(o) elseif type(o) == "string" then --string类型,原始数据左右各加上双引号写入 pout:write(string.format("%q", o)) elseif type(o) == "boolean" then --boolean类型,转化为string写入 pout:write(tostring(o)) elseif type(o) == "table" then --table类型,加换行,大括号,中括号,双引号写入 pout:write("{\n") for k,v in pairs(o) do pout:write(" [") serialize(pout, k) pout:write("] = ") serialize(pout, v) pout:write(",\n") end pout:write("}\n") else error("cannot serialize a " .. type(o)) end end --[[ 函数名:upd 功能 :更新实时参数表 参数 : overide:是否用默认参数强制更新实时参数 返回值:无 ]] function upd(overide) for k,v in pairs(libdftconfig) do if k ~= "_M" and k ~= "_NAME" and k ~= "_PACKAGE" then if overide or para[k] == nil then para[k] = v end end end end --[[ 函数名:load 功能 :初始化参数 参数 :无 返回值:无 ]] local function load() local f,fBak,fExist,fBakExist f = io.open(paraname,"rb") fBak = io.open(paranamebak,"rb") if f then fExist = f:read("*a")~="" f:close() end if fBak then fBakExist = fBak:read("*a")~="" fBak:close() end print("load fExist fBakExist",fExist,fBakExist) local fResult,fBakResult if fExist then fResult,para = pcall(require,string.match(paraname,"/(.+)%.lua")) end print("load fResult",fResult) if fResult then os.remove(paranamebak) upd() return end if fBakExist then fBakResult,para = pcall(require,string.match(paranamebak,"/(.+)%.lua")) end print("load fBakResult",fBakResult) if fBakResult then os.remove(paraname) upd() return else para = {} restore() end end --[[ 函数名:save 功能 :保存参数文件 参数 : s:是否真正保存,true保存,false或者nil不保存 返回值:无 ]] local function save(s) if not s then return end local f = {} f.write = function(self, s) table.insert(self, s) end f:write("module(...)\n") for k,v in pairs(para) do if k ~= "_M" and k ~= "_NAME" and k ~= "_PACKAGE" then f:write(k .. " = ") serialize(f,v) f:write("\n") end end local fparabak = io.open(paranamebak, 'wb') fparabak:write(table.concat(f)) fparabak:close() os.remove(paraname) os.rename(paranamebak,paraname) end --- 初始化参数存储模块 -- @string defaultCfgFile 默认配置文件名 -- @return nil -- @usage nvm.init("config.lua") function init(defaultCfgFile) local f f,libdftconfig = pcall(require,string.match(defaultCfgFile,"(.+)%.lua")) configname,econfigname = "/lua/"..defaultCfgFile,"/lua/"..defaultCfgFile.."e" --初始化配置文件,从文件中把参数读取到内存中 load() end --- 设置某个参数的值 -- @string k 参数名 -- @param v,可以是任意类型,参数的新值 -- @param r,设置原因,如果传入了非nil的有效参数,并且v值和旧值相比发生了改变,会产生一个PARA_CHANGED_IND消息,携带 k,v,r 3个参数 -- @param s,是否立即写入到文件系统中,false不写入,其余的都写入 -- @return bool或者nil,成功返回true,失败返回nil -- @usage nvm.set("name","Luat"),参数name赋值为Luat,立即写入文件系统 -- @usage nvm.set("age",12,"SVR"),参数age赋值为12,立即写入文件系统,如果旧值不是12,会产生一个PARA_CHANGED_IND消息,携带 "age",12,"SVR" 3个参数 -- @usage nvm.set("class","Class2",nil,false),参数class赋值为Class2,不写入文件系统 -- @usage nvm.set("score",{chinese=100,math=99,english=98}),参数score赋值为{chinese=100,math=99,english=98},立即写入文件系统 function set(k,v,r,s) local bchg = true if type(v) ~= "table" then bchg = (para[k] ~= v) end log.info("nvm.set",bchg,k,v,r,s) if bchg then para[k] = v save(s or s==nil) if r then sys.publish("PARA_CHANGED_IND",k,v,r) end end return true end --- 设置某个table类型参数的某一个索引的值 -- @string k table类型的参数名 -- @param kk table类型参数的某一个索引名 -- @param v,table类型参数的某一个索引的新值 -- @param r,设置原因,如果传入了非nil的有效参数,并且v值和旧值相比发生了改变,会产生一个TPARA_CHANGED_IND消息,携带 k,kk,v,r 4个参数 -- @param s,是否立即写入到文件系统中,false不写入,其余的都写入 -- @return bool或者nil,成功返回true,失败返回nil -- @usage nvm.sett("score","chinese",100),参数score["chinese"]赋值为100,立即写入文件系统 -- @usage nvm.sett("score","chinese",100,"SVR"),参数score["chinese"]赋值为100,立即写入文件系统, -- 如果旧值不是100,会产生一个TPARA_CHANGED_IND消息,携带 "score","chinese",100,"SVR" 4个参数 -- @usage nvm.sett("score","chinese",100,nil,false),参数class赋值为Class2,不写入文件系统 function sett(k,kk,v,r,s) local bchg = true if type(v) ~= "table" then bchg = (para[k][kk] ~= v) end if bchg then para[k][kk] = v save(s or s==nil) if r then sys.publish("TPARA_CHANGED_IND",k,kk,v,r) end end return true end --- 所有参数立即写入文件系统 -- @return nil -- @usage nvm.flush() function flush() save(true) end --- 读取某个参数的值 -- @string k 参数名 -- @return 参数值 -- @usage nameValue = nvm.get("name") function get(k) return para[k] end --- 读取某个table类型参数的某一个索引的值 -- @string k table类型的参数名 -- @param kk table类型参数的某一个索引名 -- @usage nvm.gett("score","chinese") function gett(k,kk) return para[k][kk] end --- 参数恢复出厂设置 -- @return nil -- @usage nvm.restore() function restore() os.remove(paraname) os.remove(paranamebak) local fpara,fconfig = io.open(paraname,"wb"),io.open(configname,"rb") if not fconfig then fconfig = io.open(econfigname,"rb") end fpara:write(fconfig:read("*a")) fpara:close() fconfig:close() upd(true) end --- 请求删除参数文件. -- 此接口一般用在远程升级时,需要用新的config.lua覆盖原来的参数文件的场景,在此场景下,远程升级包下载成功后,在确定要重启前调用此接口 -- 下次开机执行nvm.init("config.lua")时,会用新的config.lua文件自动覆盖参数文件;以后再开机就不会自动覆盖了 -- 也就是说"nvm.remove()->重启->nvm.init("config.lua")"是一个仅执行一次的完整操作 -- @return nil -- @usage nvm.remove() function remove() os.remove(paraname) os.remove(paranamebak) end