8.Quick-cocos2dx模拟热更新服务器
2017-07-15 本文已影响40人
会写诗的翩翩少年
0.前言
要学习热更新,自然而然要先有个服务器,那么要学服务器的知识么,不必,可以通过简单的ftp服务器进行模拟来实现效果,热更新的服务器无非就是资源清单,和加密过的资源,所以我们模拟的服务器大致也就以下几个功能:
1.添加要上传的文件或文件夹
2.将已添加的资源上传至服务器(本想用post方式,但貌似是不可以,就改成文件拷贝了,有弄过的朋友望给个思路)
3.获取资源信息,对资源进行加密,并拷贝至正式路径
4.生成资源清单(其中用到了dump函数的知识,不熟可以参照前文)
1.简单的ftp服务器
本人用的是这个简单FTP Server V1.0 绿色免费版,你们可以根据爱好自行选择,使用方式很简单,配置如下图:
启动后,在浏览器输入ftp://localhost/就可以看到效果啦!
2.使用方式
完成步骤2,将步骤3的代码拷贝至本地,然后以如下方式调用即可
local CCPost2Server = require("app.scenes.CCPost2Server")
CCPost2Server.new()
:addDir("updCommit") --此处为相对路径
:commit()
3.代码阅读
代码很简单,注释很清晰,阅读建议就是将代码拷贝至sublime(个人感觉看着舒服一些),逐行阅读,开始吧!
require("lfs")
local CCPost2Server = class("CCPost2Server")
--服务器根路径
local PATH_C_SERVER_URL = device.writablePath .. "server/"
--服务器tmp文件夹路径
local PATH_C_TMP_URL = device.writablePath .. "server/tmp/"
--服务器资源清单路径
local PATH_C_RESLIST_URL = device.writablePath .. "server/ResList"
function CCPost2Server:ctor()
--记录要上传文件的信息
self.fileAddedList = {}
end
--上传文件前要先进行add操作
function CCPost2Server:addFile(filePath)
--此处用相对路径,不存在则返回
filePath = device.writablePath .. filePath
if not cc.FileUtils:getInstance():isFileExist(filePath) then
return self
end
--将要上传的路径进行保存
self.fileAddedList[#self.fileAddedList + 1] = filePath
return self
end
--对要上传的文件夹进行add操作
function CCPost2Server:addDir(dirPath)
local traversePath = function(self, dirPath)
for entry in lfs.dir(dirPath) do
if entry ~= '.' and entry ~= '..' then
local path = dirPath .. '/' .. entry
local attr = lfs.attributes(path)
assert(type(attr) == 'table')
if attr.mode == 'directory' then
traversePath(path)
else
self:addFile(path)
end
end
end
end
--此处即为遍历路径,对路径下的所有文件进行add操作
traversePath(self, dirPath)
return self
end
--将已add过得文件上传至服务器,仅为模拟
function CCPost2Server:commit(ver)
--记录要上传的版本
self.commitVer = ver
--此处为模拟,直接将本地资源,拷贝至ftp服务器tmp路径下
cc.FileUtils:getInstance():createDirectory(PATH_C_TMP_URL)
for i, v in ipairs(self.fileAddedList) do
local nameArr = string.split(v, "/")
local name = nameArr[#nameArr]
local ret, msg = os.rename(v, PATH_C_TMP_URL .. name)
if ret == nil then
print(v .. "上传失败, err msg:" .. msg)
else
print(v .. "上传成功")
end
end
print("上传结束")
--生成资源清单ResList
self:generateResList()
end
--生成资源清单ResList
function CCPost2Server:generateResList()
--遍历服务器tmp路径,获取要上传文件信息
local traversePath = function(self, dirPath)
for entry in lfs.dir(dirPath) do
if entry ~= '.' and entry ~= '..' then
local path = dirPath .. '/' .. entry
local attr = lfs.attributes(path)
assert(type(attr) == 'table')
if attr.mode == 'directory' then
traversePath(path)
else
--获取文件信息
local md5 = string.lower(crypto.md5file(path))
local filePathArr = string.split(path, "/")
local fileName = filePathArr[#filePathArr]
local fileNameArr = string.split(fileName, ".")
local fileSuffix = fileNameArr[#fileNameArr]
local act = "res"
if fileSuffix == "zip" then
act = "load"
end
--写入资源清单
self.ResList.stage[self.ResList.fileNum + 1] = {}
self.ResList.stage[self.ResList.fileNum + 1].name = fileName
self.ResList.stage[self.ResList.fileNum + 1].fileCheck = false
self.ResList.stage[self.ResList.fileNum + 1].code = md5
self.ResList.stage[self.ResList.fileNum + 1].act = act
--剔除服务器上同名资源,并将其从tmp路径移出
os.remove(PATH_C_SERVER_URL .. md5)
os.rename(path, PATH_C_SERVER_URL .. md5)
self.ResList.fileNum = self.ResList.fileNum + 1
self.ResList.fileSize = self.ResList.fileSize + cc.FileUtils:getInstance():getFileSize(PATH_C_SERVER_URL .. md5)
end
end
end
end
--此处为打印table至文件中,参照dump函数进行修改
local printTb2File = function(value)
tableName = "ResList"
savePath = PATH_C_RESLIST_URL
local desciption = "local " .. tableName
local nesting = 100
local lookupTable = {}
local result = {}
local function _v(v)
if type(v) == "string" then
v = "\"" .. v .. "\""
end
return tostring(v)
end
local function _dump(value, desciption, indent, nest, keylen)
desciption = desciption or "local list"
local spc = ""
if type(keylen) == "number" then
spc = string.rep(" ", keylen - string.len(desciption))
end
if type(value) ~= "table" then
result[#result +1 ] = string.format("%s%s%s = %s,", indent, desciption, spc, _v(value))
elseif lookupTable[value] then
result[#result +1 ] = string.format("%s%s%s = *REF*", indent, desciption, spc)
else
lookupTable[value] = true
if nest > nesting then
result[#result +1 ] = string.format("%s%s = *MAX NESTING*", indent, desciption)
else
if desciption == "" then
result[#result +1 ] = string.format("%s{", indent)
else
result[#result +1 ] = string.format("%s%s = {", indent, desciption)
end
local indent2 = indent.." "
local keys = {}
local keylen = 0
local values = {}
for k, v in pairs(value) do
keys[#keys + 1] = k
local vk = _v(k)
local vkl = string.len(vk)
if vkl > keylen then keylen = vkl end
values[k] = v
end
for i, k in ipairs(keys) do
local result = tonumber(k)
if result == nil then
_dump(values[k], k, indent2, nest + 1, keylen)
else
_dump(values[k], "", indent2, nest + 1, keylen)
end
end
result[#result +1] = string.format("%s},", indent)
end
end
end
_dump(value, desciption, "", 1)
result[#result] = "}"
io.writefile(savePath, "", "wb+")
for i, line in ipairs(result) do
io.writefile(savePath, line .. "\n", "a+")
end
io.writefile(savePath, "return " .. tableName, "a+")
self.generateResListOk = true
end
--获取服务器已有的ResList,没有则新建一个
if not cc.FileUtils:getInstance():isFileExist(PATH_C_RESLIST_URL) then
self.ResList = {
ver = 1,
stage = {},
fileNum = 0,
fileSize = 0
}
else
self.ResList = dofile(PATH_C_RESLIST_URL)
end
--版本号加1,将ResList输出至文件
self.ResList.ver = self.commitVer or self.ResList.ver + 1
traversePath(self, PATH_C_TMP_URL)
printTb2File(self.ResList)
end
return CCPost2Server