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

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

  • 相关阅读:
    MySQL语句创建表、插入数据遇到的问题-20/4/18
    【Navicat】MySQL 8.0.17 数据库报2059错误
    MySQL 8.0.17 版安装 || Windows
    C#--Invoke和BeginInvoke用法和区别
    C#--params关键字
    C#--typeof() 和 GetType()区别
    C#--利用反射编写的SqlHelper类
    C#--反射基础
    C#--LINQ--2--LINQ高级查询
    C#--LINQ--1--初学LINQ基础和查询
  • 原文地址:https://www.cnblogs.com/respawn/p/4539812.html
Copyright © 2020-2023  润新知