`cocos2dx非完整` 日志模块 增量更新
在上一篇文章中,说到了"流程"的由来,以及我对流程的使用. 这一片就是对流程的应用.前一篇文章中说到了三条流程 check_log_measure, check_env_measure, check_update_measure.先来看看chenck_log_measure的源码:
- --小岩<757011285@qq.com>
- --2015-5-28 1:29
- local clm = class("check_log_measure", fw.measure)
- function clm:ctor(dispatcher, next_m)
- clm.super.ctor(self, dispatcher, next_m)
- end
- function clm:onlaunch()
- local appconf = fw.classickv.new("conf/app_conf")
- if appconf:get("syslog_enabled") then
- local sys_logger = fw.logger.new(appconf:get("syslog_limit_level"))
- if appconf:get("syslog_console_enabled") then
- local sys_clogger
- if appconf:get("syslog_console_printfun") then
- sys_clogger = fw.console_logger.new(appconf:get("syslog_console_printfun"), )
- else
- sys_clogger = fw.console_logger.new(print, )
- end
- sys_logger:add_log_chanel(sys_clogger)
- end
- if appconf:get("syslog_file_enabled") then
- fw.fileutil.make_dir(appconf:get("syslog_file_dir"))
- local sys_flogger = fw.file_logger.new(
- appconf:get("syslog_file_path"),
- "w+b",
- appconf:get("syslog_file_autoflush"),
- ,
- appconf:get("syslog_file_parser")
- )
- sys_logger:add_log_chanel(sys_flogger)
- sys_logger:info("%s", "创建sylog 日志文件 " .. appconf:get("syslog_file_path") .. "!")
- end
- fw.objpool.set_object(sys_logger, string.upper("sys_logger"))
- end
- fw.objpool.set_object(appconf, string.upper("appconf"))
- _G.sys_logger = {
- critical = function(fmt, ...)
- if fw.objpool.get_object(string.upper("appconf")):get("syslog_enabled") then
- fw.objpool.get_object(string.upper("sys_logger")):critical(fmt, ...)
- end
- end,
- err = function(fmt, ...)
- if fw.objpool.get_object(string.upper("appconf")):get("syslog_enabled") then
- fw.objpool.get_object(string.upper("sys_logger")):error(fmt, ...)
- end
- end,
- warning = function(fmt, ...)
- if fw.objpool.get_object(string.upper("appconf")):get("syslog_enabled") then
- fw.objpool.get_object(string.upper("sys_logger")):warning(fmt, ...)
- end
- end,
- info = function(fmt, ...)
- if fw.objpool.get_object(string.upper("appconf")):get("syslog_enabled") then
- fw.objpool.get_object(string.upper("sys_logger")):info(fmt, ...)
- end
- end,
- debug = function(fmt, ...)
- if fw.objpool.get_object(string.upper("appconf")):get("syslog_enabled") then
- fw.objpool.get_object(string.upper("sys_logger")):debug(fmt, ...)
- end
- end
- }
- self:finish()
- end
- function clm:onfinish()
- sys_logger.info("%s", "执行check_log_measure结束,启动sys_logger成功!")
- self:remove()
- end
- function clm:onremove()
- sys_logger.info("%s", "移除check_log_measure!")
- end
- return clm
这边是启动sys_logger, 我在启动结束的时候添加到全局表,这样方便操作.启动sys_logger以后,方便记录app在运行时候的情况.出现了问题也方便定位.当然,不同开发者对于问题的处理方式是不一样的,我是习惯这样做.然后给出check_env_measure的源码:
- --小岩<757011285@qq.com>
- --2015-5-27 17:53
- local cem = class("check_env_measure", fw.measure)
- function cem:ctor(dispatcher, next_m)
- cem.super.ctor(self, dispatcher, next_m)
- end
- function cem:onlaunch()
- sys_logger.info("%s", "启动check_env_measure!")
- local envconf = fw.classickv.new("conf/env_conf")
- fw.fileutil.set_search_paths(envconf:get("search_paths"))
- local envprofile_cls = require "game.env_profile"
- local envprofile = envprofile_cls.new()
- envprofile:set_os_code(fw.platform.arch_code)
- envprofile:set_os_name(fw.platform.arch_name)
- envprofile:set_os_lancode(fw.platform.arch_lancode)
- envprofile:set_os_lanname(fw.platform.arch_lanname)
- envprofile:set_checkupdate(envconf:get("check_update"))
- envprofile:set_updatealways(envconf:get("update_always"))
- envprofile:set_http_server_url(envconf:get("http_server_url"))
- envprofile:set_network_enabled(fw.network.is_network_enabled())
- envprofile:set_network_type(fw.network.get_network_type())
- fw.objpool.set_object(envconf, string.upper("envconf"))
- fw.objpool.set_object(envprofile, string.upper("envprofile"))
- self:finish()
- end
- function cem:onfinish()
- sys_logger.info("%s", "执行check_env_measure结束,检查env成功!")
- self:remove()
- end
- function cem:onremove()
- sys_logger.info("%s", "移除check_env_measure!")
- end
- return cem
check_env主要是对平台的一些处理,我模仿操作系统去初始化一些环境变量,并以oop的方式添加到env_profile里面,env_profile主要是简单数据结构,提供的只是getter/setter方法。这里有一点需要注意的是,我根据配置文件修改了searchpaths,这主要是应对我们的更新模块,如果更新了新的文件,放在writable_path下面的一个指定目录,那么应该先从这个目录搜索,然后再去搜索apk中的资源目录.其他的环境变量有一些是配置文件配置的,有一些则是网络启用相关的判断,当然,在启动的过程中,依次初始化判定网络状态是不可靠的,因为网络状态可能随时关闭,不过我有仔细想过这个问题:在这么极短的时间内,我们可以认为这个环境变量是可靠的,所以不需要要担心这个问题了.
下面是配置文件env_conf:
- search_paths = {
- fw.platform.get_writable_path() .. "res",
- fw.platform.get_writable_path() .. "src",
- "res",
- "src",
- },
- check_update = true,
- update_always= true,
- http_server_url = "http://192.168.1.131:8000/web/serverInfo",
配置文件我是使用classickv模式读取的,也就是支持lua syntax的,所以我们可以直接使用之前初始化的lua模块.这样很方便.我现在主要是配置了searchpath和更新模块的相应参数.下面看一下更新流程的源码:
- --小岩<757011285@qq.com>
- --2015-5-27 17:59
- local cum = class("check_update_measure", fw.measure)
- function cum:ctor(dispatcher, next_m)
- cum.super.ctor(self, dispatcher, next_m)
- self.proxy_ = fw.proxy.new(self.dispatcher_)
- self.percent_ =
- end
- function cum:onlaunch()
- sys_logger.info("%s", "启动check_update_measure!")
- self.proxy_:add_listener(fw.ircu.START_IRCU_UPDATE,
- function(e)
- self:on_START_IRCU_UPDATE(e)
- end, self:get_name() .. "tag")
- :add_listener(fw.ircu.CANNOT_CONN_TO_HOST,
- function(e)
- self:on_CANNOT_CONN_TO_HOST(e)
- end, self:get_name() .. "tag")
- :add_listener(fw.ircu.IRCU_UPDATE_FINISH_SUCC,
- function(e)
- self:on_IRCU_UPDATE_FINISH_SUCC(e)
- end, self:get_name() .. "tag")
- :add_listener(fw.ircu.IRCU_UPDATE_FINISH_PART,
- function(e)
- self:on_IRCU_UPDATE_FINISH_PART(e)
- end, self:get_name() .. "tag")
- :add_listener(fw.ircu.IRCU_UNCOMPRESS_FILE,
- function(e)
- self:on_IRCU_UNCOMPRESS_FILE(e)
- end, self:get_name() .. "tag")
- :add_listener(fw.ircu.ALREADY_NEWEST,
- function(e)
- self:on_ALREADY_NEWEST(e)
- end, self:get_name() .. "tag")
- :add_listener(fw.ircu.IRCU_UPDATE_START_PART,
- function(e)
- self:on_IRCU_UPDATE_START_PART(e)
- end, self:get_name() .. "tag")
- local envprofile = fw.objpool.get_object(string.upper("envprofile"))
- if not envprofile:get_network_enabled() then
- sys_logger.info("%s", "本地网络没开启, 不执行check_update!")
- self:finish()
- return
- end
- sys_logger.info("%s", "本地网络已开启,执行check_update!")
- local ircu_update = fw.ircu.new(
- self.dispatcher_,
- envprofile:get_http_server_url(),
- envprofile:get_network_type()
- )
- ircu_update:check_update()
- end
- function cum:on_START_IRCU_UPDATE(e)
- sys_logger.info("%s", "------------------")
- sys_logger.info("%s", "开始执行版本更新!")
- end
- function cum:on_CANNOT_CONN_TO_HOST(e)
- sys_logger.info("%s", e.name)
- sys_logger.info("%s", "执行版本更新失败!")
- self:finish()
- end
- function cum:on_IRCU_UPDATE_FINISH_SUCC(e)
- sys_logger.info("%s", e.name)
- sys_logger.info("%s", "执行版本更新成功!")
- self:finish()
- end
- function cum:on_IRCU_UPDATE_FINISH_PART(e)
- sys_logger.info("%s", e.name)
- sys_logger.info("%s [%s]", "成功更新版本", e.patch)
- end
- function cum:on_IRCU_UNCOMPRESS_FILE(e)
- sys_logger.info("%s", e.name)
- sys_logger.info("%s, -->[%s] [%.4f]", "成功解压", e.file, e.percent)
- self.percent_ = self.percent_ + e.percent
- sys_logger.info("%s --> [%.4f]", "更新总进度", self.percent_)
- end
- function cum:on_ALREADY_NEWEST(e)
- sys_logger.info("%s", e.name)
- sys_logger.info("%s", "已经是最新版本了, 不需要更新!")
- self:finish()
- end
- function cum:on_IRCU_UPDATE_START_PART(e)
- sys_logger.info("%s", e.name)
- sys_logger.info("%s --[%s] [%.4f]", "开始下载", e.path, e.size/e.total*)
- end
- function cum:onfinish()
- sys_logger.info("%s", "执行check_update_measure结束!")
- self:remove()
- end
- function cum:onremove()
- sys_logger.info("%s", "移除check_update_measure!")
- self.proxy_:remove_all_listeners()
- end
- return cum
可以看到这个流程其实主要都是处理ircu模块抛出的事件,然后就执行流程跳转的相关操作.根据之前的env_conf配置文件中的相关参数,我们可以给项目添加debug开关,如果在开发过程中可以屏蔽掉更新模块,当然我是没有添加
这个也很容易做到.在合适的配置添加:
- if not envprofile:get("check_update") then
- sys_logger.info("%s", "更新模块没有开启!“)
- self:finish()
- return
- end
这个还是很简单的.下面就看看ircu模块,也就是我们的增量更新模块:
- --小岩<757011285@qq.com>
- --2015-5-28 17:44
- local network = require "fw.util.network"
- local fileutil= require "fw.util.fileutil"
- local encrypt = require "fw.util.encrypt"
- local ini = require "fw.util.ini"
- local ircu = class("ircu")
- ircu.CANNOT_CONN_TO_HOST = "CANNOT_CONNECTION_TO_HOST"
- ircu.START_IRCU_UPDATE = "START_IRCU_UPDATE"
- ircu.ALREADY_NEWEST = "ALREADY_NEWEST"
- ircu.IRCU_UPDATE_FINISH_SUCC = "IRCU_UPDATE_FINISH_SUCC"
- ircu.IRCU_UPDATE_FINISH_PART = "IRCU_UPDATE_FINISH_PART"
- ircu.IRCU_UNCOMPRESS_FILE = "IRCU_UNCOMPRESS_FILE"
- ircu.IRCU_UPDATE_START_PART = "IRCU_UPDATE_START_PART"
- ircu.TMP = fileutil.get_writable_path() .. "TMP"
- function ircu:ctor(dispatcher, http_server_url, network_type)
- self.dispatcher_ = dispatcher
- self.http_server_url_ = http_server_url
- self.http_request_ = cc.XMLHttpRequest:new()
- self.responseType = cc.XMLHTTPREQUEST_RESPONSE_STRING
- self.network_type_ = network_type
- end
- function ircu:check_update()
- self:check_local_version_file()
- self:requrest_http_server_url()
- end
- --检查本地版本文件
- function ircu:check_local_version_file()
- local local_version_file = fileutil.get_writable_path() .. "version"
- if not fileutil.is_exists(local_version_file) then
- fileutil.write_content(local_version_file, encrypt.encrypt("[current]\nv=0"), "wb")
- end
- end
- --请求http服务器地址
- function ircu:requrest_http_server_url()
- self.http_request_:open("GET", self.http_server_url_)
- self.http_request_:registerScriptHandler(function()
- if self.http_request_.readyState == and (self.http_request_.status >= and self.http_request_.status <= ) then
- self.dispatcher_:dispatch({name = ircu.START_IRCU_UPDATE})
- self:requrest_version_file(self.http_request_.response)
- elseif self.http_request_.readyState == then
- self.dispatcher_:dispatch({name = ircu.CANNOT_CONN_TO_HOST})
- end
- end)
- self.http_request_:send()
- end
- --请求版本文件
- function ircu:requrest_version_file(version_file_url)
- self.http_request_:open("GET", version_file_url)
- self.http_request_:registerScriptHandler(function()
- if self.http_request_.readyState == and (self.http_request_.status >= and self.http_request_.status <= ) then
- if self.network_type_ == network.t.WIFI then
- self:update_wifi_mode(self.http_request_.response)
- elseif self.network_type_ == network.t.GPRS then
- self:update_gprs_mode(self.http_request_.response)
- end
- elseif self.http_request_.readyState == then
- self.dispatcher_:dispatch({name = ircu.CANNOT_CONN_TO_HOST})
- end
- end)
- self.http_request_:send()
- end
- function ircu:update_wifi_mode(version_file_content)
- local tmp_version_file = fileutil.get_writable_path() .. "tmp_version"
- fileutil.write_content(tmp_version_file, encrypt.encrypt(version_file_content), "wb")
- self.tmp_ini = ini.new(tmp_version_file)
- local tmp_t = {}
- local total_size =
- for s, _ in pairs(self.tmp_ini.props_) do
- table.insert(tmp_t, s)
- end
- --给版本排序
- table.sort(tmp_t, function(v1, v2)
- return tonumber(v1) <= tonumber(v2)
- end)
- self.local_version_ini_ = ini.new(fileutil.get_writable_path() .. "version")
- local local_version = self.local_version_ini_:get("current", "v")
- --检查是不是最新版本
- if tonumber(local_version) == tonumber(tmp_t[#tmp_t]) then
- self.dispatcher_:dispatch({name = ircu.ALREADY_NEWEST})
- return
- end
- local tt = {}
- for _, v in ipairs(tmp_t) do
- if tonumber(v) >= tonumber(local_version) then
- table.insert(tt, v)
- total_size = total_size + tonumber(self.tmp_ini:get(v, "size"))
- end
- end
- self.new_version_t_ = tt
- self.total_size_ = total_size
- self:download_patch()
- end
- function ircu:update_gprs_mode(version_file_content)
- end
- function ircu:download_patch()
- if #self.new_version_t_ == then
- self.dispatcher_:dispatch({name = ircu.IRCU_UPDATE_FINISH_SUCC})
- fileutil.remove(ircu.TMP)
- return
- end
- fw.ircu_helper.download(self.tmp_ini:get(self.new_version_t_[], "path"), ircu.TMP,
- function(code) end,
- function(p)
- if p == then
- local patch_size = tonumber(self.tmp_ini:get(self.new_version_t_[], "size"))
- local patch_percent = patch_size / self.total_size_
- self.dispatcher_:dispatch({
- name = ircu.IRCU_UPDATE_START_PART,
- path = self.new_version_t_[],
- size = patch_size,
- total= self.total_size_
- })
- fw.ircu_helper.uncompress(fileutil.get_writable_path(), ircu.TMP,
- function(f, n, t)
- self.dispatcher_:dispatch({
- name = ircu.IRCU_UNCOMPRESS_FILE,
- file = f,
- num = n,
- total = t,
- percent = /t*patch_percent * ,
- })
- end,
- function()
- self.local_version_ini_:update("current", "v", self.new_version_t_[])
- self.local_version_ini_:save()
- self.dispatcher_:dispatch({name = ircu.IRCU_UPDATE_FINISH_PART, patch=self.new_version_t_[]})
- table.remove(self.new_version_t_, )
- self:download_patch()
- end)
- end
- end
- )
- end
- return ircu
这个模块使用很简单,需要注意的就是下面这几个抛出的事件就行了,我将这个模块独立封装出来,就是依靠事件来保持低耦合的.
- ircu.CANNOT_CONN_TO_HOST = "CANNOT_CONNECTION_TO_HOST"
- ircu.START_IRCU_UPDATE = "START_IRCU_UPDATE"
- ircu.ALREADY_NEWEST = "ALREADY_NEWEST"
- ircu.IRCU_UPDATE_FINISH_SUCC = "IRCU_UPDATE_FINISH_SUCC"
- ircu.IRCU_UPDATE_FINISH_PART = "IRCU_UPDATE_FINISH_PART"
- ircu.IRCU_UNCOMPRESS_FILE = "IRCU_UNCOMPRESS_FILE"
- ircu.IRCU_UPDATE_START_PART = "IRCU_UPDATE_START_PART"
当然,这几个事件除了错误代码之外,其他都是用来做更新界面百分比显示,以及显示更新信息的.ircu模块中使用了我写的c++的异步下载和解压函数.也就是fw.ircu_helper.download/uncompress.下面我给出我的这个C++模块:
- #include "lua_ircu.h"
- #include "tolua_fix.h"
- #include "CCLuaEngine.h"
- #include <curl/curl.h>
- #include <curl/easy.h>
- #include <stdio.h>
- #include <vector>
- #include <thread>
- #include <cocos2d.h>
- #if (CC_TARGET_PLATFORM != CC_PLATFORM_WIN32) && (CC_TARGET_PLATFORM != CC_PLATFORM_WP8) && (CC_TARGET_PLATFORM != CC_PLATFORM_WINRT)
- #include <sys/types.h>
- #include <sys/stat.h>
- #include <errno.h>
- #include <dirent.h>
- #endif
- #ifdef MINIZIP_FROM_SYSTEM
- #include <minizip/unzip.h>
- #else
- #include "unzip.h"
- #endif
- #if __cplusplus
- extern "C" {
- #endif
- #include <lualib.h>
- #include <lauxlib.h>
- #if __cplusplus
- }
- #endif
- #define BUFFER_SIZE 8192
- #define MAX_FILENAME 512
- #define LOW_SPEED_LIMIT 1L
- #define LOW_SPEED_TIME 5L
- bool createDirectory(const char *path)
- {
- #if (CC_TARGET_PLATFORM == CC_PLATFORM_WINRT) || (CC_TARGET_PLATFORM == CC_PLATFORM_WP8)
- return FileUtils::getInstance()->createDirectory(_storagePath.c_str());
- #elif (CC_TARGET_PLATFORM == CC_PLATFORM_WIN32)
- BOOL ret = CreateDirectoryA(path, nullptr);
- if (!ret && ERROR_ALREADY_EXISTS != GetLastError())
- {
- return false;
- }
- return true;
- #else
- mode_t processMask = umask();
- int ret = mkdir(path, S_IRWXU | S_IRWXG | S_IRWXO);
- umask(processMask);
- if (ret != && (errno != EEXIST))
- {
- return false;
- }
- return true;
- #endif
- }
- static int
- lua_fw_ircu_download(lua_State* lua_state) {
- std::string url = lua_tostring(lua_state, );
- std::string tmppath = lua_tostring(lua_state, );
- int h1 = toluafix_ref_function(lua_state, , );
- int h2 = toluafix_ref_function(lua_state, , );
- auto t = std::thread(fw::ircu::download, url, tmppath, h1, h2);
- t.detach();
- return ;
- }
- static int
- lua_fw_ircu_uncompress(lua_State* lua_state) {
- std::string dstpath = lua_tostring(lua_state, );
- std::string filepath = lua_tostring(lua_state, );
- int h1 = toluafix_ref_function(lua_state, , );
- int h2 = toluafix_ref_function(lua_state, , );
- auto t = std::thread(fw::ircu::uncompress, dstpath, filepath, h1, h2);
- t.detach();
- return ;
- }
- namespace fw {
- static size_t
- downloadPatch(void *ptr, size_t size, size_t nmemb, void *userdata) {
- FILE *fp = (FILE*)userdata;
- size_t written = fwrite(ptr, size, nmemb, fp);
- return written;
- }
- static int
- downloadProgressFunc(void *ptr, double totalToDownload, double nowDownloaded, double totalToUpLoad, double nowUpLoaded) {
- typedef cocos2d::LuaStack LuaStack;
- typedef cocos2d::LuaEngine LuaEngine;
- LuaStack *pStack = LuaEngine::getInstance()->getLuaStack();
- static int percent = ;
- int tmp = (int)(nowDownloaded / totalToDownload * );
- if (percent != tmp)
- {
- percent = tmp;
- cocos2d::Director::getInstance()->getScheduler()->performFunctionInCocosThread([=]{
- pStack->pushInt(tmp);
- pStack->executeFunctionByHandler((int)ptr,);
- });
- }
- return ;
- }
- void
- ircu::download(const std::string& url, const std::string& tmppath, int h1, int h2) {
- typedef cocos2d::LuaStack LuaStack;
- typedef cocos2d::LuaEngine LuaEngine;
- LuaStack *pStack = LuaEngine::getInstance()->getLuaStack();
- FILE *fp = fopen(tmppath.c_str(), "wb");
- if(!fp) {
- cocos2d::Director::getInstance()->getScheduler()->performFunctionInCocosThread([=]{
- if (h1)
- pStack->pushInt(ircu::CREATE_FILE);
- pStack->executeFunctionByHandler(h1,);
- });
- return;
- }
- void *_curl;
- _curl = curl_easy_init();
- if(!_curl) {
- return;
- }
- CURLcode res;
- curl_easy_setopt(_curl, CURLOPT_URL, url.c_str());
- curl_easy_setopt(_curl, CURLOPT_WRITEFUNCTION, downloadPatch);
- curl_easy_setopt(_curl, CURLOPT_WRITEDATA, fp);
- curl_easy_setopt(_curl, CURLOPT_NOPROGRESS, false);
- curl_easy_setopt(_curl, CURLOPT_PROGRESSFUNCTION, downloadProgressFunc);
- curl_easy_setopt(_curl, CURLOPT_PROGRESSDATA, h2);
- curl_easy_setopt(_curl, CURLOPT_NOSIGNAL, 1L);
- curl_easy_setopt(_curl, CURLOPT_LOW_SPEED_LIMIT, LOW_SPEED_LIMIT);
- curl_easy_setopt(_curl, CURLOPT_LOW_SPEED_TIME, LOW_SPEED_TIME);
- curl_easy_setopt(_curl, CURLOPT_FOLLOWLOCATION, );
- res = curl_easy_perform(_curl);
- curl_easy_cleanup(_curl);
- if (res != ) {
- cocos2d::Director::getInstance()->getScheduler()->performFunctionInCocosThread([=]{
- pStack->pushInt(ircu::NETWORK);
- pStack->executeFunctionByHandler(h1,);
- });
- fclose(fp);
- return;
- }
- fclose(fp);
- return;
- }
- void
- ircu::uncompress(const std::string& dstpath, const std::string& filepath, int h1, int h2) {
- typedef cocos2d::LuaStack LuaStack;
- typedef cocos2d::LuaEngine LuaEngine;
- LuaStack *pStack = LuaEngine::getInstance()->getLuaStack();
- unzFile zipFile = cocos2d::unzOpen(filepath.c_str());
- if (!zipFile) {
- return;
- }
- cocos2d::unz_global_info global_info;
- if (cocos2d::unzGetGlobalInfo(zipFile, &global_info) != UNZ_OK) {
- cocos2d::unzClose(zipFile);
- return ;
- }
- char readBuffer[BUFFER_SIZE];
- uLong i;
- for (i = ; i < global_info.number_entry; ++i)
- {
- cocos2d::unz_file_info fileInfo;
- char fileName[MAX_FILENAME];
- if (cocos2d::unzGetCurrentFileInfo(zipFile,
- &fileInfo,
- fileName,
- MAX_FILENAME,
- nullptr,
- ,
- nullptr,
- ) != UNZ_OK)
- {
- cocos2d::unzClose(zipFile);
- return;
- }
- const std::string fullPath = dstpath + "/" + fileName;
- const size_t filenameLength = strlen(fileName);
- if (fileName[filenameLength-] == '/')
- {
- if (!createDirectory(fullPath.c_str()))
- {
- cocos2d::unzClose(zipFile);
- return;
- }
- }
- else
- {
- const std::string fileNameStr(fileName);
- size_t startIndex=;
- size_t index=fileNameStr.find("/",startIndex);
- while(index != std::string::npos)
- {
- const std::string dir=dstpath+fileNameStr.substr(,index);
- FILE *out = fopen(dir.c_str(), "r");
- if(!out)
- {
- if (!createDirectory(dir.c_str()))
- {
- cocos2d::unzClose(zipFile);
- return;
- }
- else
- {
- //CCLOG("create directory %s",dir.c_str());
- }
- }
- else
- {
- fclose(out);
- }
- startIndex=index+;
- index=fileNameStr.find("/",startIndex);
- }
- if (cocos2d::unzOpenCurrentFile(zipFile) != UNZ_OK)
- {
- cocos2d::unzClose(zipFile);
- return;
- }
- FILE *out = fopen(fullPath.c_str(), "wb");
- if (! out)
- {
- cocos2d::unzCloseCurrentFile(zipFile);
- cocos2d::unzClose(zipFile);
- return;
- }
- int error = UNZ_OK;
- do
- {
- error = cocos2d::unzReadCurrentFile(zipFile, readBuffer, BUFFER_SIZE);
- if (error < )
- {
- cocos2d::unzCloseCurrentFile(zipFile);
- cocos2d::unzClose(zipFile);
- return;
- }
- if (error > )
- {
- fwrite(readBuffer, error, , out);
- }
- } while(error > );
- fclose(out);
- }
- cocos2d::Director::getInstance()->getScheduler()->performFunctionInCocosThread([=](){
- pStack->pushString(fullPath.c_str());
- pStack->pushInt(i+);
- pStack->pushInt(global_info.number_entry);
- pStack->executeFunctionByHandler(h1, );
- });
- cocos2d::unzCloseCurrentFile(zipFile);
- if ((i+) < global_info.number_entry)
- {
- if (cocos2d::unzGoToNextFile(zipFile) != UNZ_OK)
- {
- cocos2d::unzClose(zipFile);
- return;
- }
- }
- }
- cocos2d::Director::getInstance()->getScheduler()->performFunctionInCocosThread([=](){
- pStack->executeFunctionByHandler(h2, );
- });
- cocos2d::unzClose(zipFile);
- return;
- }
- const luaL_reg g_ircu_funcs[] = {
- {"download", lua_fw_ircu_download},
- {"uncompress", lua_fw_ircu_uncompress},
- {NULL, NULL},
- };
- void
- register_fw_ircu(lua_State* lua_state) {
- luaL_register(lua_state, "fw.ircu_helper", g_ircu_funcs);
- }
- }
好吧,就到这里了.下面来说一下log. 之前我也写过log模块,但是没有文件记录模块,我这边想要的功能就是同时在终端显示,然后又可以写入到文件.好了,从这个需求出发,我到Github去浏览了一下lua的代码,最后发现了zengrong的仓库, 这里给出他的地址: github.com/zengrong.所以我就从他的log模块取出了部分修改了一下:
- --小岩<757011285@qq.com>
- --2015-5-28 1:37
- local l = class("logger")
- l.CRITICAL =
- l.ERROR =
- l.WARNING =
- l.INFO =
- l.DEBUG =
- l.NOSET =
- function l:ctor(level, ...)
- self:set_limit_level(level or l.NOSET)
- self.chanels_ = {...}
- end
- function l:set_limit_level(ll)
- self.ll_ = ll
- end
- function l:get_limit_level()
- return self.ll_
- end
- function l:add_log_chanel(lc)
- self.chanels_[#self.chanels_ + ] = lc
- end
- function l:clear_chanel()
- self.chanels_ = {}
- end
- function l:flush()
- for __, lc in pairs(self.chanels_) do
- lc:flush()
- end
- end
- function l:log(level, fmt, ...)
- if level < self.ll_ then
- return
- end
- args = {...}
- for __, lc in pairs(self.chanels_) do
- lc:emit(level, fmt, args)
- end
- end
- function l:critical(fmt, ...)
- self:log(l.CRITICAL, fmt, ...)
- end
- function l:error(fmt, ...)
- self:log(l.ERROR, fmt, ...)
- end
- function l:warning(fmt, ...)
- self:log(l.WARNING, fmt, ...)
- end
- function l:info(fmt, ...)
- self:log(l.INFO, fmt, ...)
- end
- function l:debug(fmt, ...)
- self:log(l.DEBUG, fmt, ...)
- end
- return l
我这边只是给出了logger的接口,如果需要的话,请直接去看zr的github.请原谅我并没有在源码中给出引用出处.下面就是app配置Logger的文件:
- luagarbage_setpause_val = ,
- luagarbage_setstepmul_val = ,
- app_name = "firework 小岩<757011285@qq.com>",
- gl_win_size = cc.rect(,,, ),
- gl_frame_size = cc.size(, ),
- dr_size = cc.size(, ),
- dr_policy = cc.ResolutionPolicy.FIXED_HEIGHT,
- show_status = false,
- animation_interval = /,
- app = "game.application",
- syslog_enabled = true,
- syslog_console_enabled = true,
- syslog_console_printfun = function(str)
- print(">> syslog " .. str)
- end,
- syslog_limit_level = fw.logger.NOSET,
- syslog_file_enabled = true,
- syslog_file_autoflush = true,
- syslog_file_parser = function(str)
- return fw.encrypt.encrypt(str .. '\n')
- end,
- syslog_file_dir = fw.platform.get_writable_path() .. "log",
- syslog_file_path= fw.platform.get_writable_path() .. "log/sys_log",
当然,这份是app配置文件,可以看到在logger写入函数我采用了xxtea加密方式写入,如果在开发期,可以屏蔽掉加密.直接写入就好了.当然也可以不写.好了,就到这里了.
这里是可以添加测试用例的,方法就是修改其中的app属性配置,从app.lua继承实现一个自己的test_application,然后修改配置文件,启动的时候就切换了入口.看需求添加吧,如果是有独立封装的ui类库以及其他独立功能可以考虑添加测试用例.又或者是需要添加工具,也可以在这里做考虑。
这次的文章篇幅比较的长,希望大家耐心点看. 终于我算是完成了自己的承诺了. 嘻嘻嘻嘻嘻~
`cocos2dx非完整` 日志模块 增量更新的更多相关文章
- `cocos2dx非完整` 游戏架构缩影 添加启动流程
这期的话题可能不是很好, 我没有想到很好的词句去更好的表达. 我一直都是很固执的认为, 同一类型的游戏,在开发做的前期工作上面其实都是可以复用的,也就是大同小异的.从游戏启动,启动日志,启动检查,检查 ...
- `cocos2dx非完整` 开始自己的FW模块
上一篇的文章中说到了一些个人习惯的东西以及一些简单的项目配置,这一篇文章我们来进一步完善一些东西.首先,打开编译以后的客户端执行,会看到一大堆的fileutils加载luac文件的提示,在终端显示一大 ...
- `cocos2dx 非完整` UI解析模块
昨天在cocos2dx的一个群里,遇到一位匿名为x的朋友询问的问题,是关于ui的.他使用c++写了不少的ui封装节点,用来实现游戏中的各种不同效果.然后现在想改用lua,于是尝试使用最小代价去复用自己 ...
- `cocos2dx非完整` 添加xxtea加密模块
在上一篇文章中,我已经开始着手写自己的模块,也就是fw部分.其中上一篇文章中完成的是lua部分的配置解析部分,涉及一点点平台方面的封装.这一片文章我来说明一下我是如何处理cocos2dx资源加密的.首 ...
- `cocos2dx非完整`开篇
相信每个人都有一些自己的项目开发习惯,在·开篇·中我主要是会提到一些项目的配置问题.无论做一款什么样的手游项目,我们总是会从需求的角度出发去选择开发引擎,开发工具等一些列的工具去完善我们的开发环境.当 ...
- 转 基于Quick-cocos2dx 2.2.3 的动态更新实现完整篇。(打包,服务器接口,模块自更新
1,如何设计更新服务器接口. 2,不改变原框架的代码的情况下如何实现更新,并且可以实现精确的进度. 3,如何按照版本打包. 4,如何跨n个小版本更新. 5,版本回滚. 6,如何更新你的自动更新模块和f ...
- 一条更新SQL的内部执行及日志模块
一条更新SQL的内部执行 学习MySQL实战45讲,非常推荐学 还是老图: 上文复习 在执行查询语句的时候,会执行连接器(总要连上才能搞事情),然后去查询缓存(MySQL8+删除了),有数据返回,没数 ...
- ReactNative学习笔记(四)热更新和增量更新
概括 关于RN的热更新,网上有很多现成方案,但是一般都依赖第三方服务,我所希望的是能够自己管控所有一切,所以只能自己折腾. 热更新的思路 热更新一般都是更新JS和图片,也就是在不重新安装apk的情况下 ...
- uni-app: 如何实现增量更新功能?
都知道,很多APP都有增量更新功能,Uni APP也是在今年初,推出了增量更新功能,今天我们就来学习一波. 当然,很多应用市场为了防止开发者不经市场审核许可,给用户提供违法内容,对增量更新大多持排斥态 ...
随机推荐
- JavaBean与Jsp
这一节我们总结一下JavaBean和Jsp的关系. 1. JavaBean javaBean是一个遵循特定写法的Java类,它通常具有如下特点: 1)这个java类必须具有一个无参构造函 ...
- 这样leetcode简单题都更完了
这样leetcode简单题都更完了,作为水题王的我开始要更新leetcode中等题和难题了,有些挖了很久的坑也将在在这个阶段一一揭晓,接下来的算法性更强,我就要开始分专题更新题目,而不是再以我的A题顺 ...
- 微信开发——OAuth2.0授权
微信公众平台最近新推出微信认证,认证后可以获得高级接口权限,其中一个是OAuth2.0网页授权,很多朋友在使用这个的时候失败了或者无法理解其内容,希望我出个教程详细讲解一下,于是便有了这篇文章. 一. ...
- Linux Buffers和Cached的区别(转)
在linux下使用free命令查看内存使用情况,有buffers和cached两项,以下是它们的区别: buffers是为块设备设计的缓冲.比如磁盘读写,把分散的写操作集中进行,减少磁盘I/O,从而提 ...
- adb devices指令实例讲解
在讲这个指令之前,我首先启动了一个名称为“Galaxy_Nexus_4.4.2”的手机模拟器(有时我们也管其叫安卓虚拟设备),并且通过USB数据线将我的手机设备和PC进行了连接,而后我应用“Andro ...
- win10蓝屏问题,关于驱动kisSaasUrlRedirectKnl64.sys 的
上周末刚从win7升级到win10:今天出现了两次蓝屏了,都是显示: xxxxxxx 百度知道链接---http://zhidao.baidu.com/question/164141456570387 ...
- 多功能表单填报系统V1.2.1-适用于在线报名系统、调查、数据收集等
多功能表单系统V1.2.1 前台:http://www.schoolms.net/mysoft/biaodan/index.asp 后台:http://www.schoolms.net/myso ...
- java匹配中文的正则表达式
[\u4E00-\u9FA5]* public static void regxChinese(){ // 要匹配的字符串 String source = "<span title=' ...
- WIN7只能上QQ打不开网页,使用CMD输入netsh winsock reset
此类问题可以用腾讯电脑管家电脑诊所一键修复,请点击上方的[立即修复]即可. 附:手动修复步骤(来源:腾讯电脑管家电脑诊所,自动修复请点击上方的[立即修复])方案一:手动设置DNS(说明:如果您使用DN ...
- PHP in_array效率问题
in_array的效率问题就是在比较上,默认要比较的字符串转成整形,所以耗费时间.可以使用强制类型比较 in_array($x, $arr, TRUE);