Lua安卓开发相关cocos2dx

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
上一篇下一篇

猜你喜欢

热点阅读