转载

`cocos2dx非完整` 日志模块 增量更新

在上一篇文章中,说到了"流程"的由来,以及我对流程的使用. 这一片就是对流程的应用.前一篇文章中说到了三条流程 check_log_measure, check_env_measure, check_update_measure.先来看看chenck_log_measure的源码:

 1 --小岩<757011285@qq.com>  2 --2015-5-28 1:29  3 local clm = class("check_log_measure", fw.measure)  4   5 function clm:ctor(dispatcher, next_m)  6     clm.super.ctor(self, dispatcher, next_m)  7 end  8   9 function clm:onlaunch() 10     local appconf  = fw.classickv.new("conf/app_conf") 11     if appconf:get("syslog_enabled") then 12         local sys_logger = fw.logger.new(appconf:get("syslog_limit_level")) 13         if appconf:get("syslog_console_enabled") then 14             local sys_clogger 15             if appconf:get("syslog_console_printfun") then 16                 sys_clogger = fw.console_logger.new(appconf:get("syslog_console_printfun"), 0) 17             else 18                 sys_clogger = fw.console_logger.new(print, 0) 19             end 20             sys_logger:add_log_chanel(sys_clogger) 21         end 22  23         if appconf:get("syslog_file_enabled") then 24             fw.fileutil.make_dir(appconf:get("syslog_file_dir")) 25             local sys_flogger = fw.file_logger.new( 26                     appconf:get("syslog_file_path"), 27                     "w+b", 28                     appconf:get("syslog_file_autoflush"), 29                     0, 30                     appconf:get("syslog_file_parser") 31                 ) 32             sys_logger:add_log_chanel(sys_flogger) 33             sys_logger:info("%s", "创建sylog 日志文件 " .. appconf:get("syslog_file_path") .. "!") 34         end 35  36         fw.objpool.set_object(sys_logger, string.upper("sys_logger")) 37     end 38     fw.objpool.set_object(appconf, string.upper("appconf")) 39  40     _G.sys_logger = { 41         critical = function(fmt, ...) 42             if fw.objpool.get_object(string.upper("appconf")):get("syslog_enabled") then 43                 fw.objpool.get_object(string.upper("sys_logger")):critical(fmt, ...) 44             end 45         end, 46         err = function(fmt, ...) 47             if fw.objpool.get_object(string.upper("appconf")):get("syslog_enabled") then 48                 fw.objpool.get_object(string.upper("sys_logger")):error(fmt, ...) 49             end 50         end,     51         warning = function(fmt, ...) 52             if fw.objpool.get_object(string.upper("appconf")):get("syslog_enabled") then 53                 fw.objpool.get_object(string.upper("sys_logger")):warning(fmt, ...) 54             end 55         end, 56         info = function(fmt, ...) 57             if fw.objpool.get_object(string.upper("appconf")):get("syslog_enabled") then 58                 fw.objpool.get_object(string.upper("sys_logger")):info(fmt, ...) 59             end 60         end, 61         debug = function(fmt, ...) 62             if fw.objpool.get_object(string.upper("appconf")):get("syslog_enabled") then 63                 fw.objpool.get_object(string.upper("sys_logger")):debug(fmt, ...) 64             end 65         end 66     } 67  68     self:finish() 69 end 70  71 function clm:onfinish() 72     sys_logger.info("%s", "执行check_log_measure结束,启动sys_logger成功!") 73     self:remove() 74 end 75  76 function clm:onremove() 77     sys_logger.info("%s", "移除check_log_measure!") 78 end 79  80 return clm

这边是启动sys_logger, 我在启动结束的时候添加到全局表,这样方便操作.启动sys_logger以后,方便记录app在运行时候的情况.出现了问题也方便定位.当然,不同开发者对于问题的处理方式是不一样的,我是习惯这样做.然后给出check_env_measure的源码:

 1 --小岩<757011285@qq.com>  2 --2015-5-27 17:53  3 local cem = class("check_env_measure", fw.measure)  4   5 function cem:ctor(dispatcher, next_m)  6     cem.super.ctor(self, dispatcher, next_m)  7 end  8   9 function cem:onlaunch() 10     sys_logger.info("%s", "启动check_env_measure!") 11     local envconf = fw.classickv.new("conf/env_conf") 12     fw.fileutil.set_search_paths(envconf:get("search_paths")) 13  14     local envprofile_cls = require "game.env_profile" 15     local envprofile = envprofile_cls.new() 16  17     envprofile:set_os_code(fw.platform.arch_code) 18     envprofile:set_os_name(fw.platform.arch_name) 19     envprofile:set_os_lancode(fw.platform.arch_lancode) 20     envprofile:set_os_lanname(fw.platform.arch_lanname) 21  22     envprofile:set_checkupdate(envconf:get("check_update")) 23     envprofile:set_updatealways(envconf:get("update_always")) 24     envprofile:set_http_server_url(envconf:get("http_server_url")) 25  26     envprofile:set_network_enabled(fw.network.is_network_enabled()) 27     envprofile:set_network_type(fw.network.get_network_type()) 28  29     fw.objpool.set_object(envconf, string.upper("envconf")) 30     fw.objpool.set_object(envprofile, string.upper("envprofile")) 31  32     self:finish() 33 end 34  35 function cem:onfinish() 36     sys_logger.info("%s", "执行check_env_measure结束,检查env成功!") 37     self:remove() 38 end 39  40 function cem:onremove() 41     sys_logger.info("%s", "移除check_env_measure!") 42 end 43  44 return cem

check_env主要是对平台的一些处理,我模仿操作系统去初始化一些环境变量,并以oop的方式添加到env_profile里面,env_profile主要是简单数据结构,提供的只是getter/setter方法。这里有一点需要注意的是,我根据配置文件修改了searchpaths,这主要是应对我们的更新模块,如果更新了新的文件,放在writable_path下面的一个指定目录,那么应该先从这个目录搜索,然后再去搜索apk中的资源目录.其他的环境变量有一些是配置文件配置的,有一些则是网络启用相关的判断,当然,在启动的过程中,依次初始化判定网络状态是不可靠的,因为网络状态可能随时关闭,不过我有仔细想过这个问题:在这么极短的时间内,我们可以认为这个环境变量是可靠的,所以不需要要担心这个问题了.

下面是配置文件env_conf:

 1 search_paths = {  2     fw.platform.get_writable_path() .. "res",  3     fw.platform.get_writable_path() .. "src",  4     "res",  5     "src",      6 },  7   8 check_update = true,  9 update_always= true, 10  11 http_server_url = "http://192.168.1.131:8000/web/serverInfo",

配置文件我是使用classickv模式读取的,也就是支持lua syntax的,所以我们可以直接使用之前初始化的lua模块.这样很方便.我现在主要是配置了searchpath和更新模块的相应参数.下面看一下更新流程的源码:

  1 --小岩<757011285@qq.com>   2 --2015-5-27 17:59   3 local cum = class("check_update_measure", fw.measure)   4    5 function cum:ctor(dispatcher, next_m)   6     cum.super.ctor(self, dispatcher, next_m)   7     self.proxy_ = fw.proxy.new(self.dispatcher_)   8     self.percent_ = 0   9 end  10   11 function cum:onlaunch()  12     sys_logger.info("%s", "启动check_update_measure!")  13   14     self.proxy_:add_listener(fw.ircu.START_IRCU_UPDATE,   15                     function(e)  16                         self:on_START_IRCU_UPDATE(e)  17                     end, self:get_name() .. "tag")  18                 :add_listener(fw.ircu.CANNOT_CONN_TO_HOST,   19                     function(e)  20                         self:on_CANNOT_CONN_TO_HOST(e)  21                     end, self:get_name() .. "tag")  22                 :add_listener(fw.ircu.IRCU_UPDATE_FINISH_SUCC,   23                     function(e)  24                         self:on_IRCU_UPDATE_FINISH_SUCC(e)  25                     end, self:get_name() .. "tag")  26                 :add_listener(fw.ircu.IRCU_UPDATE_FINISH_PART,   27                     function(e)  28                         self:on_IRCU_UPDATE_FINISH_PART(e)  29                     end, self:get_name() .. "tag")  30                 :add_listener(fw.ircu.IRCU_UNCOMPRESS_FILE,   31                     function(e)  32                         self:on_IRCU_UNCOMPRESS_FILE(e)  33                     end, self:get_name() .. "tag")  34                 :add_listener(fw.ircu.ALREADY_NEWEST,   35                     function(e)  36                         self:on_ALREADY_NEWEST(e)  37                     end, self:get_name() .. "tag")  38                 :add_listener(fw.ircu.IRCU_UPDATE_START_PART,  39                     function(e)  40                         self:on_IRCU_UPDATE_START_PART(e)  41                     end, self:get_name() .. "tag")  42   43     local envprofile = fw.objpool.get_object(string.upper("envprofile"))  44   45     if not envprofile:get_network_enabled() then  46         sys_logger.info("%s", "本地网络没开启, 不执行check_update!")  47         self:finish()  48         return  49     end  50     sys_logger.info("%s", "本地网络已开启,执行check_update!")  51   52     local ircu_update = fw.ircu.new(  53                     self.dispatcher_,   54                     envprofile:get_http_server_url(),  55                     envprofile:get_network_type()  56                 )  57       58     ircu_update:check_update()  59 end  60   61 function cum:on_START_IRCU_UPDATE(e)  62     sys_logger.info("%s", "------------------")  63     sys_logger.info("%s", "开始执行版本更新!")  64 end  65   66 function cum:on_CANNOT_CONN_TO_HOST(e)  67     sys_logger.info("%s", e.name)  68     sys_logger.info("%s", "执行版本更新失败!")  69     self:finish()  70 end  71   72 function cum:on_IRCU_UPDATE_FINISH_SUCC(e)  73     sys_logger.info("%s", e.name)  74     sys_logger.info("%s", "执行版本更新成功!")  75     self:finish()  76 end  77   78 function cum:on_IRCU_UPDATE_FINISH_PART(e)  79     sys_logger.info("%s", e.name)  80     sys_logger.info("%s [%s]", "成功更新版本", e.patch)  81 end  82   83 function cum:on_IRCU_UNCOMPRESS_FILE(e)  84     sys_logger.info("%s", e.name)  85     sys_logger.info("%s, -->[%s] [%.4f]", "成功解压", e.file, e.percent)  86     self.percent_ = self.percent_ + e.percent   87     sys_logger.info("%s --> [%.4f]", "更新总进度", self.percent_)  88 end  89   90 function cum:on_ALREADY_NEWEST(e)  91     sys_logger.info("%s", e.name)  92     sys_logger.info("%s", "已经是最新版本了, 不需要更新!")  93     self:finish()  94 end  95   96 function cum:on_IRCU_UPDATE_START_PART(e)  97     sys_logger.info("%s", e.name)  98     sys_logger.info("%s --[%s] [%.4f]", "开始下载", e.path, e.size/e.total*100)  99 end 100  101 function cum:onfinish() 102     sys_logger.info("%s", "执行check_update_measure结束!") 103     self:remove() 104 end 105  106 function cum:onremove() 107     sys_logger.info("%s", "移除check_update_measure!") 108     self.proxy_:remove_all_listeners() 109 end 110  111  112 return cum

可以看到这个流程其实主要都是处理ircu模块抛出的事件,然后就执行流程跳转的相关操作.根据之前的env_conf配置文件中的相关参数,我们可以给项目添加debug开关,如果在开发过程中可以屏蔽掉更新模块,当然我是没有添加

这个也很容易做到.在合适的配置添加:

1 if not envprofile:get("check_update") then 2      sys_logger.info("%s", "更新模块没有开启!“) 3      self:finish() 4      return 5 end

这个还是很简单的.下面就看看ircu模块,也就是我们的增量更新模块:

  1 --小岩<757011285@qq.com>   2 --2015-5-28 17:44   3 local network = require "fw.util.network"   4 local fileutil= require "fw.util.fileutil"   5 local encrypt = require "fw.util.encrypt"   6 local ini     = require "fw.util.ini"   7    8 local ircu = class("ircu")   9   10 ircu.CANNOT_CONN_TO_HOST = "CANNOT_CONNECTION_TO_HOST"  11 ircu.START_IRCU_UPDATE   = "START_IRCU_UPDATE"  12 ircu.ALREADY_NEWEST      = "ALREADY_NEWEST"  13 ircu.IRCU_UPDATE_FINISH_SUCC = "IRCU_UPDATE_FINISH_SUCC"  14 ircu.IRCU_UPDATE_FINISH_PART = "IRCU_UPDATE_FINISH_PART"  15 ircu.IRCU_UNCOMPRESS_FILE    = "IRCU_UNCOMPRESS_FILE"  16 ircu.IRCU_UPDATE_START_PART  = "IRCU_UPDATE_START_PART"  17   18 ircu.TMP = fileutil.get_writable_path() .. "TMP"  19   20 function ircu:ctor(dispatcher, http_server_url, network_type)  21     self.dispatcher_ = dispatcher  22     self.http_server_url_ = http_server_url  23     self.http_request_ = cc.XMLHttpRequest:new()  24     self.responseType  = cc.XMLHTTPREQUEST_RESPONSE_STRING  25     self.network_type_ = network_type  26 end  27   28 function ircu:check_update()  29     self:check_local_version_file()  30     self:requrest_http_server_url()  31 end  32   33 --检查本地版本文件  34 function ircu:check_local_version_file()  35     local local_version_file = fileutil.get_writable_path() .. "version"  36     if not fileutil.is_exists(local_version_file) then  37         fileutil.write_content(local_version_file, encrypt.encrypt("[current]/nv=0"), "wb")  38     end  39 end  40   41 --请求http服务器地址  42 function ircu:requrest_http_server_url()  43     self.http_request_:open("GET", self.http_server_url_)  44     self.http_request_:registerScriptHandler(function()  45             if self.http_request_.readyState == 4 and (self.http_request_.status >= 200 and self.http_request_.status <= 207) then  46                 self.dispatcher_:dispatch({name = ircu.START_IRCU_UPDATE})  47                 self:requrest_version_file(self.http_request_.response)  48             elseif self.http_request_.readyState == 1 then  49                 self.dispatcher_:dispatch({name = ircu.CANNOT_CONN_TO_HOST})  50             end  51         end)  52     self.http_request_:send()  53 end  54   55 --请求版本文件  56 function ircu:requrest_version_file(version_file_url)  57     self.http_request_:open("GET", version_file_url)  58     self.http_request_:registerScriptHandler(function()  59             if self.http_request_.readyState == 4 and (self.http_request_.status >= 200 and self.http_request_.status <= 207) then  60                 if self.network_type_ == network.t.WIFI then  61                     self:update_wifi_mode(self.http_request_.response)  62                 elseif self.network_type_ == network.t.GPRS then  63                     self:update_gprs_mode(self.http_request_.response)  64                 end  65             elseif self.http_request_.readyState == 1 then  66                 self.dispatcher_:dispatch({name = ircu.CANNOT_CONN_TO_HOST})  67             end  68         end)  69     self.http_request_:send()  70 end  71   72 function ircu:update_wifi_mode(version_file_content)  73     local tmp_version_file = fileutil.get_writable_path() .. "tmp_version"  74     fileutil.write_content(tmp_version_file, encrypt.encrypt(version_file_content), "wb")  75     self.tmp_ini = ini.new(tmp_version_file)  76   77     local tmp_t = {}  78     local total_size = 0  79   80     for s, _ in pairs(self.tmp_ini.props_) do  81         table.insert(tmp_t, s)  82     end  83   84     --给版本排序   85     table.sort(tmp_t, function(v1, v2)  86             return tonumber(v1) <= tonumber(v2)  87         end)  88   89     self.local_version_ini_ = ini.new(fileutil.get_writable_path() .. "version")  90     local local_version = self.local_version_ini_:get("current", "v")  91   92     --检查是不是最新版本  93     if tonumber(local_version) == tonumber(tmp_t[#tmp_t]) then  94         self.dispatcher_:dispatch({name = ircu.ALREADY_NEWEST})  95         return  96     end  97   98     local tt = {}  99  100     for _, v in ipairs(tmp_t) do 101         if tonumber(v) >= tonumber(local_version) then 102  103             table.insert(tt, v) 104             total_size = total_size + tonumber(self.tmp_ini:get(v, "size")) 105         end 106     end 107  108     self.new_version_t_ = tt 109     self.total_size_ = total_size 110  111     self:download_patch() 112 end 113  114 function ircu:update_gprs_mode(version_file_content) 115  116 end 117  118 function ircu:download_patch() 119     if #self.new_version_t_ == 0 then 120         self.dispatcher_:dispatch({name = ircu.IRCU_UPDATE_FINISH_SUCC}) 121         fileutil.remove(ircu.TMP) 122         return 123     end 124  125     fw.ircu_helper.download(self.tmp_ini:get(self.new_version_t_[1], "path"), ircu.TMP, 126             function(code)  end, 127             function(p) 128                 if p == 100 then 129                     local patch_size = tonumber(self.tmp_ini:get(self.new_version_t_[1], "size")) 130                     local patch_percent = patch_size / self.total_size_ 131                     self.dispatcher_:dispatch({ 132                         name = ircu.IRCU_UPDATE_START_PART,  133                         path = self.new_version_t_[1],  134                         size = patch_size, 135                         total= self.total_size_ 136                     }) 137  138  139                     fw.ircu_helper.uncompress(fileutil.get_writable_path(), ircu.TMP, 140                         function(f, n, t) 141                             self.dispatcher_:dispatch({ 142                                 name = ircu.IRCU_UNCOMPRESS_FILE,  143                                 file = f,  144                                 num  = n,  145                                 total   = t, 146                                 percent = 1/t*patch_percent * 100, 147                             }) 148                         end, 149  150                         function() 151                             self.local_version_ini_:update("current", "v", self.new_version_t_[1]) 152                             self.local_version_ini_:save() 153                             self.dispatcher_:dispatch({name = ircu.IRCU_UPDATE_FINISH_PART, patch=self.new_version_t_[1]}) 154                             table.remove(self.new_version_t_, 1) 155                             self:download_patch() 156                         end) 157                 end 158             end 159         ) 160 end 161  162 return ircu

这个模块使用很简单,需要注意的就是下面这几个抛出的事件就行了,我将这个模块独立封装出来,就是依靠事件来保持低耦合的.

1 ircu.CANNOT_CONN_TO_HOST = "CANNOT_CONNECTION_TO_HOST" 2 ircu.START_IRCU_UPDATE   = "START_IRCU_UPDATE" 3 ircu.ALREADY_NEWEST      = "ALREADY_NEWEST" 4 ircu.IRCU_UPDATE_FINISH_SUCC = "IRCU_UPDATE_FINISH_SUCC" 5 ircu.IRCU_UPDATE_FINISH_PART = "IRCU_UPDATE_FINISH_PART" 6 ircu.IRCU_UNCOMPRESS_FILE    = "IRCU_UNCOMPRESS_FILE" 7 ircu.IRCU_UPDATE_START_PART  = "IRCU_UPDATE_START_PART"

当然,这几个事件除了错误代码之外,其他都是用来做更新界面百分比显示,以及显示更新信息的.ircu模块中使用了我写的c++的异步下载和解压函数.也就是fw.ircu_helper.download/uncompress.下面我给出我的这个C++模块:

  1 #include "lua_ircu.h"   2 #include "tolua_fix.h"   3 #include "CCLuaEngine.h"   4 #include <curl/curl.h>   5 #include <curl/easy.h>   6 #include <stdio.h>   7 #include <vector>   8 #include <thread>   9   10 #include <cocos2d.h>  11   12 #if (CC_TARGET_PLATFORM != CC_PLATFORM_WIN32) && (CC_TARGET_PLATFORM != CC_PLATFORM_WP8) && (CC_TARGET_PLATFORM != CC_PLATFORM_WINRT)  13 #include <sys/types.h>  14 #include <sys/stat.h>  15 #include <errno.h>  16 #include <dirent.h>  17 #endif  18   19 #ifdef MINIZIP_FROM_SYSTEM  20 #include <minizip/unzip.h>  21 #else  22 #include "unzip.h"  23 #endif  24   25 #if __cplusplus  26 extern "C" {  27 #endif  28 #include <lualib.h>  29 #include <lauxlib.h>  30 #if __cplusplus  31 }  32 #endif  33   34 #define BUFFER_SIZE    8192  35 #define MAX_FILENAME   512  36   37 #define LOW_SPEED_LIMIT 1L  38 #define LOW_SPEED_TIME 5L  39   40 bool createDirectory(const char *path)  41 {  42 #if (CC_TARGET_PLATFORM == CC_PLATFORM_WINRT) || (CC_TARGET_PLATFORM == CC_PLATFORM_WP8)  43     return FileUtils::getInstance()->createDirectory(_storagePath.c_str());  44 #elif (CC_TARGET_PLATFORM == CC_PLATFORM_WIN32)  45     BOOL ret = CreateDirectoryA(path, nullptr);  46     if (!ret && ERROR_ALREADY_EXISTS != GetLastError())  47     {  48         return false;  49     }  50     return true;  51 #else  52     mode_t processMask = umask(0);  53     int ret = mkdir(path, S_IRWXU | S_IRWXG | S_IRWXO);  54     umask(processMask);  55     if (ret != 0 && (errno != EEXIST))  56     {  57         return false;  58     }  59   60     return true;  61 #endif  62 }  63   64 static int  65 lua_fw_ircu_download(lua_State* lua_state) {  66     std::string url = lua_tostring(lua_state, 1);  67     std::string tmppath = lua_tostring(lua_state, 2);  68     int h1 = toluafix_ref_function(lua_state, 3, 0);  69     int h2 = toluafix_ref_function(lua_state, 4, 0);  70     auto t = std::thread(fw::ircu::download, url, tmppath, h1, h2);  71     t.detach();  72     return 0;  73 }  74   75 static int  76 lua_fw_ircu_uncompress(lua_State* lua_state) {  77     std::string dstpath = lua_tostring(lua_state, 1);  78     std::string filepath = lua_tostring(lua_state, 2);  79     int h1 = toluafix_ref_function(lua_state, 3, 0);  80     int h2 = toluafix_ref_function(lua_state, 4, 0);  81     auto t = std::thread(fw::ircu::uncompress, dstpath, filepath, h1, h2);  82     t.detach();  83     return 0;  84 }  85   86 namespace fw {  87   88     static size_t   89     downloadPatch(void *ptr, size_t size, size_t nmemb, void *userdata) {  90         FILE *fp = (FILE*)userdata;  91         size_t written = fwrite(ptr, size, nmemb, fp);  92         return written;  93     }  94   95     static int   96     downloadProgressFunc(void *ptr, double totalToDownload, double nowDownloaded, double totalToUpLoad, double nowUpLoaded) {  97         typedef cocos2d::LuaStack LuaStack;  98         typedef cocos2d::LuaEngine LuaEngine;  99         LuaStack *pStack = LuaEngine::getInstance()->getLuaStack(); 100         static int percent = 0; 101         int tmp = (int)(nowDownloaded / totalToDownload * 100); 102         if (percent != tmp) 103         { 104             percent = tmp; 105             cocos2d::Director::getInstance()->getScheduler()->performFunctionInCocosThread([=]{ 106                 pStack->pushInt(tmp); 107                 pStack->executeFunctionByHandler((int)ptr,1); 108             }); 109         } 110         return 0; 111     } 112  113  114     void 115     ircu::download(const std::string& url, const std::string& tmppath, int h1, int h2) { 116         typedef cocos2d::LuaStack LuaStack; 117         typedef cocos2d::LuaEngine LuaEngine; 118         LuaStack *pStack = LuaEngine::getInstance()->getLuaStack(); 119  120         FILE *fp = fopen(tmppath.c_str(), "wb"); 121         if(!fp) { 122             cocos2d::Director::getInstance()->getScheduler()->performFunctionInCocosThread([=]{ 123             if (h1) 124                 pStack->pushInt(ircu::CREATE_FILE); 125                 pStack->executeFunctionByHandler(h1,1); 126             }); 127             return; 128         } 129         void *_curl; 130         _curl = curl_easy_init(); 131          132         if(!_curl) { 133             return; 134         } 135  136         CURLcode res; 137         curl_easy_setopt(_curl, CURLOPT_URL, url.c_str()); 138         curl_easy_setopt(_curl, CURLOPT_WRITEFUNCTION, downloadPatch);  139         curl_easy_setopt(_curl, CURLOPT_WRITEDATA, fp); 140         curl_easy_setopt(_curl, CURLOPT_NOPROGRESS, false); 141         curl_easy_setopt(_curl, CURLOPT_PROGRESSFUNCTION, downloadProgressFunc); 142         curl_easy_setopt(_curl, CURLOPT_PROGRESSDATA, h2); 143         curl_easy_setopt(_curl, CURLOPT_NOSIGNAL, 1L); 144         curl_easy_setopt(_curl, CURLOPT_LOW_SPEED_LIMIT, LOW_SPEED_LIMIT); 145         curl_easy_setopt(_curl, CURLOPT_LOW_SPEED_TIME, LOW_SPEED_TIME); 146         curl_easy_setopt(_curl, CURLOPT_FOLLOWLOCATION, 1 ); 147  148         res = curl_easy_perform(_curl); 149         curl_easy_cleanup(_curl); 150  151         if (res != 0 ) { 152             cocos2d::Director::getInstance()->getScheduler()->performFunctionInCocosThread([=]{ 153                 pStack->pushInt(ircu::NETWORK); 154                 pStack->executeFunctionByHandler(h1,1); 155             }); 156             fclose(fp); 157             return; 158         }     159  160         fclose(fp); 161         return; 162     } 163  164     void 165     ircu::uncompress(const std::string& dstpath, const std::string& filepath, int h1, int h2) { 166         typedef cocos2d::LuaStack LuaStack; 167         typedef cocos2d::LuaEngine LuaEngine; 168         LuaStack *pStack = LuaEngine::getInstance()->getLuaStack(); 169  170         unzFile zipFile = cocos2d::unzOpen(filepath.c_str()); 171         if (!zipFile) { 172             return; 173         } 174         cocos2d::unz_global_info global_info; 175         if (cocos2d::unzGetGlobalInfo(zipFile, &global_info) != UNZ_OK) { 176             cocos2d::unzClose(zipFile); 177             return ; 178         } 179         char readBuffer[BUFFER_SIZE]; 180         uLong i; 181  182         for (i = 0; i < global_info.number_entry; ++i) 183         { 184             cocos2d::unz_file_info fileInfo; 185             char fileName[MAX_FILENAME]; 186             if (cocos2d::unzGetCurrentFileInfo(zipFile, 187                                       &fileInfo, 188                                       fileName, 189                                       MAX_FILENAME, 190                                       nullptr, 191                                       0, 192                                       nullptr, 193                                       0) != UNZ_OK) 194             { 195                 cocos2d::unzClose(zipFile); 196                 return; 197             } 198          199             const std::string fullPath = dstpath + "/" + fileName; 200          201             const size_t filenameLength = strlen(fileName); 202             if (fileName[filenameLength-1] == '/') 203             { 204                 if (!createDirectory(fullPath.c_str())) 205                 { 206                     cocos2d::unzClose(zipFile); 207                     return; 208                 } 209             } 210             else 211             { 212                 const std::string fileNameStr(fileName); 213              214                 size_t startIndex=0; 215              216                 size_t index=fileNameStr.find("/",startIndex); 217              218                 while(index != std::string::npos) 219                 { 220                     const std::string dir=dstpath+fileNameStr.substr(0,index); 221                  222                     FILE *out = fopen(dir.c_str(), "r"); 223                  224                     if(!out) 225                     { 226                         if (!createDirectory(dir.c_str())) 227                         { 228                             cocos2d::unzClose(zipFile); 229                             return; 230                         } 231                         else 232                         { 233                             //CCLOG("create directory %s",dir.c_str()); 234                         } 235                     } 236                     else 237                     { 238                         fclose(out); 239                     } 240                  241                     startIndex=index+1; 242                  243                     index=fileNameStr.find("/",startIndex); 244                  245                 } 246              247                 if (cocos2d::unzOpenCurrentFile(zipFile) != UNZ_OK) 248                 { 249                     cocos2d::unzClose(zipFile); 250                     return; 251                 } 252              253                 FILE *out = fopen(fullPath.c_str(), "wb"); 254                 if (! out) 255                 { 256                     cocos2d::unzCloseCurrentFile(zipFile); 257                     cocos2d::unzClose(zipFile); 258                     return; 259                 } 260              261                 int error = UNZ_OK; 262                 do 263                 { 264                     error = cocos2d::unzReadCurrentFile(zipFile, readBuffer, BUFFER_SIZE); 265                     if (error < 0) 266                     { 267                         cocos2d::unzCloseCurrentFile(zipFile); 268                         cocos2d::unzClose(zipFile); 269                         return; 270                     } 271                  272                     if (error > 0) 273                     { 274                         fwrite(readBuffer, error, 1, out); 275                     } 276                 } while(error > 0); 277                  278                 fclose(out); 279  280                  281             } 282             cocos2d::Director::getInstance()->getScheduler()->performFunctionInCocosThread([=](){ 283                     pStack->pushString(fullPath.c_str()); 284                     pStack->pushInt(i+1); 285                     pStack->pushInt(global_info.number_entry); 286                     pStack->executeFunctionByHandler(h1, 3); 287                 }); 288          289             cocos2d::unzCloseCurrentFile(zipFile); 290          291             if ((i+1) < global_info.number_entry) 292             { 293                 if (cocos2d::unzGoToNextFile(zipFile) != UNZ_OK) 294                 { 295                     cocos2d::unzClose(zipFile); 296                     return; 297                 } 298             } 299         } 300         cocos2d::Director::getInstance()->getScheduler()->performFunctionInCocosThread([=](){ 301             pStack->executeFunctionByHandler(h2, 0); 302         }); 303  304         cocos2d::unzClose(zipFile); 305         return; 306     } 307  308     const luaL_reg g_ircu_funcs[] = { 309         {"download",   lua_fw_ircu_download}, 310         {"uncompress", lua_fw_ircu_uncompress}, 311         {NULL, NULL}, 312     }; 313  314     void 315     register_fw_ircu(lua_State* lua_state) { 316         luaL_register(lua_state, "fw.ircu_helper", g_ircu_funcs); 317     } 318 }

好吧,就到这里了.下面来说一下log. 之前我也写过log模块,但是没有文件记录模块,我这边想要的功能就是同时在终端显示,然后又可以写入到文件.好了,从这个需求出发,我到Github去浏览了一下lua的代码,最后发现了zengrong的仓库, 这里给出他的地址: github.com/zengrong.所以我就从他的log模块取出了部分修改了一下:

 1 --小岩<757011285@qq.com>  2 --2015-5-28 1:37  3 local l = class("logger")  4   5 l.CRITICAL = 50  6 l.ERROR    = 40  7 l.WARNING  = 30  8 l.INFO     = 20  9 l.DEBUG    = 10 10 l.NOSET    =  0 11  12 function l:ctor(level, ...) 13     self:set_limit_level(level or l.NOSET) 14     self.chanels_ = {...} 15 end 16  17 function l:set_limit_level(ll) 18     self.ll_ = ll 19 end 20  21 function l:get_limit_level() 22     return self.ll_ 23 end 24  25 function l:add_log_chanel(lc) 26     self.chanels_[#self.chanels_ + 1] = lc 27 end 28  29 function l:clear_chanel() 30     self.chanels_ = {} 31 end 32  33 function l:flush() 34     for __, lc in pairs(self.chanels_) do 35         lc:flush() 36     end 37 end 38  39 function l:log(level, fmt, ...) 40     if level < self.ll_ then  41         return 42     end 43     args = {...} 44     for __, lc in pairs(self.chanels_) do 45         lc:emit(level, fmt, args) 46     end  47 end 48  49 function l:critical(fmt, ...) 50     self:log(l.CRITICAL, fmt, ...) 51 end 52  53 function l:error(fmt, ...) 54     self:log(l.ERROR, fmt, ...) 55 end 56  57 function l:warning(fmt, ...) 58     self:log(l.WARNING, fmt, ...) 59 end 60  61 function l:info(fmt, ...) 62     self:log(l.INFO, fmt, ...) 63 end 64  65 function l:debug(fmt, ...) 66     self:log(l.DEBUG, fmt, ...) 67 end 68  69 return l

我这边只是给出了logger的接口,如果需要的话,请直接去看zr的github.请原谅我并没有在源码中给出引用出处.下面就是app配置Logger的文件:

 1 luagarbage_setpause_val     = 100,  2 luagarbage_setstepmul_val    = 5000,  3   4 app_name = "firework 小岩<757011285@qq.com>",  5   6 gl_win_size       = cc.rect(0,0,960, 640),  7 gl_frame_size     = cc.size(1140, 650),  8   9 dr_size         = cc.size(480, 320), 10 dr_policy        = cc.ResolutionPolicy.FIXED_HEIGHT, 11  12 show_status        = false, 13  14 animation_interval = 1/60, 15  16 app                = "game.application", 17  18 syslog_enabled  = true, 19 syslog_console_enabled = true, 20 syslog_console_printfun = function(str) 21         print(">> syslog " .. str) 22     end, 23 syslog_limit_level = fw.logger.NOSET, 24  25 syslog_file_enabled = true, 26 syslog_file_autoflush = true, 27 syslog_file_parser = function(str) 28         return fw.encrypt.encrypt(str .. '/n') 29     end, 30 syslog_file_dir = fw.platform.get_writable_path() .. "log", 31 syslog_file_path= fw.platform.get_writable_path() .. "log/sys_log",

当然,这份是app配置文件,可以看到在logger写入函数我采用了xxtea加密方式写入,如果在开发期,可以屏蔽掉加密.直接写入就好了.当然也可以不写.好了,就到这里了.

这里是可以添加测试用例的,方法就是修改其中的app属性配置,从app.lua继承实现一个自己的test_application,然后修改配置文件,启动的时候就切换了入口.看需求添加吧,如果是有独立封装的ui类库以及其他独立功能可以考虑添加测试用例.又或者是需要添加工具,也可以在这里做考虑。

这次的文章篇幅比较的长,希望大家耐心点看. 终于我算是完成了自己的承诺了. 嘻嘻嘻嘻嘻~

正文到此结束
Loading...