nvm.lua 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295
  1. --- 模块功能:参数管理
  2. -- @module nvm
  3. -- @author openLuat
  4. -- @license MIT
  5. -- @copyright openLuat
  6. -- @release 2017.11.9
  7. local nvm = {}
  8. --实时参数配置存储在paraname文件中
  9. --默认参数配置存储在configname文件中
  10. --para:实时参数表
  11. --config:默认参数表
  12. paraname, paranamebak = "/nvm_para.lua", "/nvm_para_bak.lua"
  13. local para, libdftconfig, configname = {}
  14. --[[
  15. 函数名:serialize
  16. 功能 :根据不同的数据类型,按照不同的格式,写格式化后的数据到文件中
  17. 参数 :
  18. pout:文件句柄
  19. o:数据
  20. 返回值:无
  21. ]]
  22. local function serialize(pout, o)
  23. if type(o) == "number" then
  24. --number类型,直接写原始数据
  25. pout:write(o)
  26. elseif type(o) == "string" then
  27. --string类型,原始数据左右各加上双引号写入
  28. pout:write(string.format("%q", o))
  29. elseif type(o) == "boolean" then
  30. --boolean类型,转化为string写入
  31. pout:write(tostring(o))
  32. elseif type(o) == "table" then
  33. --table类型,加换行,大括号,中括号,双引号写入
  34. pout:write("{\n")
  35. for k, v in pairs(o) do
  36. pout:write(" [")
  37. serialize(pout, k)
  38. pout:write("] = ")
  39. serialize(pout, v)
  40. pout:write(",\n")
  41. end
  42. pout:write("}\n")
  43. else
  44. error("cannot serialize a " .. type(o))
  45. end
  46. end
  47. --[[
  48. 函数名:upd
  49. 功能 :更新实时参数表
  50. 参数 :
  51. overide:是否用默认参数强制更新实时参数
  52. 返回值:无
  53. ]]
  54. function nvm.upd(overide)
  55. for k, v in pairs(libdftconfig) do
  56. if k ~= "_M" and k ~= "_NAME" and k ~= "_PACKAGE" then
  57. if overide or para[k] == nil then
  58. para[k] = v
  59. end
  60. end
  61. end
  62. end
  63. local function safePcall(file)
  64. return pcall(require, file)
  65. end
  66. --[[
  67. 函数名:load
  68. 功能 :初始化参数
  69. 参数 :无
  70. 返回值:无
  71. ]]
  72. local function load()
  73. local f, fBak, fExist, fBakExist
  74. f = io.open(paraname, "rb")
  75. fBak = io.open(paranamebak, "rb")
  76. if f then
  77. fExist = f:read("*a") ~= ""
  78. f:close()
  79. end
  80. if fBak then
  81. fBakExist = fBak:read("*a") ~= ""
  82. fBak:close()
  83. end
  84. print("load fExist fBakExist", fExist, fBakExist)
  85. local fResult, fBakResult
  86. if fExist then
  87. fResult, para = safePcall(paraname:match("/(.+)%.lua"))
  88. end
  89. print("load fResult", fResult)
  90. if fResult then
  91. os.remove(paranamebak)
  92. nvm.upd()
  93. return
  94. end
  95. if fBakExist then
  96. fBakResult, para = safePcall(paranamebak:match("/(.+)%.lua"))
  97. end
  98. print("load fBakResult", fBakResult)
  99. if fBakResult then
  100. os.remove(paraname)
  101. nvm.upd()
  102. return
  103. else
  104. para = {}
  105. nvm.restore()
  106. end
  107. end
  108. --[[
  109. 函数名:save
  110. 功能 :保存参数文件
  111. 参数 :
  112. s:是否真正保存,true保存,false或者nil不保存
  113. 返回值:无
  114. ]]
  115. local function save(s)
  116. if not s then return end
  117. local f = {}
  118. f.write = function(self, s)table.insert(self, s) end
  119. f:write("return {\n")
  120. for k, v in pairs(para) do
  121. if k ~= "_M" and k ~= "_NAME" and k ~= "_PACKAGE" then
  122. f:write(string.format("[%q] = ", k))
  123. serialize(f, v)
  124. f:write(",\n")
  125. end
  126. end
  127. f:write("}\n")
  128. local fparabak = io.open(paranamebak, 'wb')
  129. fparabak:write(table.concat(f))
  130. fparabak:close()
  131. os.remove(paraname)
  132. os.rename(paranamebak, paraname)
  133. end
  134. --- 初始化参数存储管理模块
  135. -- @string defaultCfgFile 默认参数文件名
  136. -- @return nil
  137. -- @usage
  138. -- 初始化参数存储管理模块,默认参数文件名为config.lua,本地烧录时清除已有的参数:
  139. -- nvm.init("config.lua")
  140. function nvm.init(defaultCfgFile)
  141. local f
  142. local fname = defaultCfgFile:match("(.+)%.lua")
  143. f, libdftconfig = safePcall(fname)
  144. local LUAT_MODULE_SEARCH_PATH = {"/%s.luac", "/%s.lua", "/lua/%s.luac", "/lua/%s.lua","/luadb/%s.luac", "/luadb/%s.lua"}
  145. for _,j in pairs(LUAT_MODULE_SEARCH_PATH) do
  146. local tf = io.open(string.format(j,fname), "rb")
  147. if tf then
  148. tf:close()
  149. configname = string.format(j,fname)
  150. break
  151. end
  152. end
  153. --初始化配置文件,从文件中把参数读取到内存中
  154. load()
  155. end
  156. --- 设置某个参数的值
  157. -- @string k 参数名
  158. -- @param v,可以是任意类型,参数的新值
  159. -- @param r,设置原因,如果传入了非nil的有效参数,并且v值和旧值相比发生了改变,
  160. -- 会产生一个PARA_CHANGED_IND内部消息,携带 k,v,r 3个参数
  161. -- @param s,是否立即写入到文件系统中,false不写入,其余的都写入
  162. -- @return bool或者nil,成功返回true,失败返回nil
  163. -- @usage
  164. -- 参数name赋值为Luat,立即写入文件系统:
  165. -- nvm.set("name","Luat")
  166. --
  167. -- 参数age赋值为12,立即写入文件系统:
  168. -- 如果旧值不是12,会产生一个PARA_CHANGED_IND消息,携带 "age",12,"SVR" 3个参数:
  169. -- nvm.set("age",12,"SVR")
  170. --
  171. -- 参数class赋值为Class2,不写入文件系统:
  172. -- nvm.set("class","Class2",nil,false)
  173. --
  174. -- 参数score赋值为{chinese=100,math=99,english=98},立即写入文件系统:
  175. -- nvm.set("score",{chinese=100,math=99,english=98})
  176. --
  177. -- 连续写入4个参数,前3个不保存到文件系统中,写第4个时,一次性全部保存到文件系统中:
  178. -- nvm.set("para1",1,nil,false)
  179. -- nvm.set("para2",2,nil,false)
  180. -- nvm.set("para3",3,nil,false)
  181. -- nvm.set("para4",4)
  182. function nvm.set(k, v, r, s)
  183. local bchg = true
  184. if type(v) ~= "table" then
  185. bchg = (para[k] ~= v)
  186. end
  187. log.info("nvm.set", bchg, k, v, r, s)
  188. if bchg then
  189. para[k] = v
  190. save(s or s == nil)
  191. if r then sys.publish("PARA_CHANGED_IND", k, v, r) end
  192. end
  193. return true
  194. end
  195. --- 设置某个table类型参数的某一个索引的值
  196. -- @string k table类型的参数名
  197. -- @param kk table类型参数的某一个索引名
  198. -- @param v,table类型参数的某一个索引的新值
  199. -- @param r,设置原因,如果传入了非nil的有效参数,并且v值和旧值相比发生了改变,会产生一个TPARA_CHANGED_IND消息,携带 k,kk,v,r 4个参数
  200. -- @param s,是否立即写入到文件系统中,false不写入,其余的都写入
  201. -- @return bool或者nil,成功返回true,失败返回nil
  202. -- @usage nvm.sett("score","chinese",100),参数score["chinese"]赋值为100,立即写入文件系统
  203. -- @usage nvm.sett("score","chinese",100,"SVR"),参数score["chinese"]赋值为100,立即写入文件系统,
  204. -- 如果旧值不是100,会产生一个TPARA_CHANGED_IND消息,携带 "score","chinese",100,"SVR" 4个参数
  205. -- @usage nvm.sett("score","chinese",100,nil,false),参数class赋值为Class2,不写入文件系统
  206. function nvm.sett(k, kk, v, r, s)
  207. local bchg = true
  208. if type(v) ~= "table" then
  209. bchg = (para[k][kk] ~= v)
  210. end
  211. if bchg then
  212. para[k][kk] = v
  213. save(s or s == nil)
  214. if r then sys.publish("TPARA_CHANGED_IND", k, kk, v, r) end
  215. end
  216. return true
  217. end
  218. --- 所有参数立即写入文件系统
  219. -- @return nil
  220. -- @usage nvm.flush()
  221. function nvm.flush()
  222. save(true)
  223. end
  224. --- 读取某个参数的值
  225. -- @string k 参数名
  226. -- @return 参数值
  227. -- @usage
  228. -- 读取参数名为name的参数值:
  229. -- nameValue = nvm.get("name")
  230. function nvm.get(k)
  231. return para[k]
  232. end
  233. --- 读取某个table类型参数的键名对应的值
  234. -- @string k table类型的参数名
  235. -- @param kk table类型参数的键名
  236. -- @usage
  237. -- 有一个table参数为score,数据如下:
  238. -- score = {chinese=100, math=100, english=95}
  239. -- 读取score中chinese对应的值:
  240. -- nvm.gett("score","chinese")
  241. function nvm.gett(k, kk)
  242. return para[k][kk]
  243. end
  244. --- 参数恢复出厂设置
  245. -- @return nil
  246. -- @usage nvm.restore()
  247. function nvm.restore()
  248. os.remove(paraname)
  249. os.remove(paranamebak)
  250. local fpara, fconfig = io.open(paraname, "wb"), io.open(configname, "rb")
  251. fpara:write(fconfig:read("*a"))
  252. fpara:close()
  253. fconfig:close()
  254. nvm.upd(true)
  255. end
  256. --- 请求删除参数文件.
  257. -- 此接口一般用在远程升级时,需要用新的config.lua覆盖原来的参数文件的场景,在此场景下,远程升级包下载成功后,在确定要重启前调用此接口
  258. -- 下次开机执行nvm.init("config.lua")时,会用新的config.lua文件自动覆盖参数文件;以后再开机就不会自动覆盖了
  259. -- 也就是说"nvm.remove()->重启->nvm.init("config.lua")"是一个仅执行一次的完整操作
  260. -- @return nil
  261. -- @usage nvm.remove()
  262. function nvm.remove()
  263. os.remove(paraname)
  264. os.remove(paranamebak)
  265. end
  266. return nvm