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

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

 1 --小岩<[email protected]>

 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 --小岩<[email protected]>

 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 --小岩<[email protected]>

  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 --小岩<[email protected]>

  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 --小岩<[email protected]>

 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 小岩<[email protected]>",

 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类库以及其他独立功能可以考虑添加测试用例.又或者是需要添加工具,也可以在这里做考虑。

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

 

你可能感兴趣的:(cocos2dx)