skynet啟動時讀取配置檔案
阿新 • • 發佈:2022-12-08
新入門skynet系列視訊b站網址 https://www.bilibili.com/video/BV19d4y1678X
skynet啟動時讀取配置檔案
行11 skynet啟動時,我們啟動了一個lua虛擬機器
,這個虛擬機器是在整個skynet生命週期中存在的。我們把他叫做skynet的環境虛擬機器
。
行13 之後啟動了一個臨時虛擬機器
,把配置資訊裡面的配置選項都讀取出來,然後儲存到skynet的環境虛擬機器中。之後關閉這個臨時虛擬機器
void skynet_env_init() { E = skynet_malloc(sizeof(*E)); SPIN_INIT(E) E->L = luaL_newstate();//啟動一個環境虛擬機器 } int main(int argc, char *argv[]) { //... skynet_env_init(); //... struct lua_State *L = luaL_newstate();//啟動一個臨時虛擬機器 luaL_openlibs(L); // link lua lib int err = luaL_loadbufferx(L, load_config, strlen(load_config), "=[skynet config]", "t"); assert(err == LUA_OK); lua_pushstring(L, config_file); err = lua_pcall(L, 1, 1, 0);//執行配置檔案 if (err) { fprintf(stderr,"%s\n",lua_tostring(L,-1)); lua_close(L); return 1; } _init_env(L); }
我們下面看配置項都是怎麼讀取出來的。
行16 是 load_config表示的 字串載入,然後編譯成一個匿名函式
行18 是給這個匿名函式提供一個引數 引數就是我們skynet啟動時提供的 配置檔案的路徑+檔名 比如 ./example/config
行20 是執行這個匿名函式 把配置項都存入一個表result中
行26 最終把這個result表中的鍵值對都儲存到 環境虛擬機器
中
我們先看 load_config 表示的lua程式碼
local result = {} --收集配置項 即鍵值對 local function getenv(name) return assert(os.getenv(name), [[os.getenv() failed: ]] .. name) end local sep = package.config:sub(1,1) --sep是 / local current_path = [[.]]..sep local function include(filename) local last_path = current_path local path, name = filename:match([[(.*]]..sep..[[)(.*)$]])--這裡表示字串的形式是 [[字串]] if path then if path:sub(1,1) == sep then --絕對路徑 即path是 /xxx/yyy/zzz/ current_path = path else current_path = current_path .. path --相對路徑 即path是 aaa/bbb/ end else name = filename end local f = assert(io.open(current_path .. name)) --開啟配置檔案 local code = assert(f:read [[*a]]) --讀取 code = string.gsub(code, [[%$([%w_%d]+)]], getenv)--把系統的環境變數替換成對應的值 f:close() --注意下面的程式碼 每次都把鍵值對放到result中儲存 assert(load(code,[[@]]..filename,[[t]],result))() --把配置檔案編譯成匿名函式並執行 注意環境 current_path = last_path end setmetatable(result, { __index = { include = include } }) local config_name = ...--這裡就是我們啟動skynet時的配置檔案 比如 ./example/config include(config_name) --開始處理配置檔案 setmetatable(result, nil) return result --最終返回配置項的集合
行5->行23 是我們主要討論的讀取配置檔案的函式 local function include(filename) --dosomething end
我們給一個配置檔案的樣子
include(/one/two/config1) --這裡是絕對路徑
include(three/config2) --這裡是config2是相對於當前配置檔案的位置 也就是 ./three/config2
key1 = "xxxxx"
key2 = "yyyyy"
最終讀取到全域性虛擬機器中的函式是 _init_env(L);
這個函式實際上就是把result裡面的鍵值對遍歷出來。
static void _init_env(lua_State *L) {//L是臨時的lua虛擬機器 lua_pushnil(L); /* first key */ //此時-2的位置起始就是result表 while (lua_next(L, -2) != 0) {//此時已經把result表中的一對鍵值對讀取出來, int keyt = lua_type(L, -2);//key放在-2的位置 if (keyt != LUA_TSTRING) { fprintf(stderr, "Invalid config table\n"); exit(1); } const char * key = lua_tostring(L,-2);//key放在-2的位置 if (lua_type(L,-1) == LUA_TBOOLEAN) {//如果value是lua的布林型別 int b = lua_toboolean(L,-1); skynet_setenv(key,b ? "true" : "false" ); } else { const char * value = lua_tostring(L,-1);//value放在-1的位置 if (value == NULL) { fprintf(stderr, "Invalid config table key = %s\n", key); exit(1); } skynet_setenv(key,value); } lua_pop(L,1); } lua_pop(L,1); }
我們看skynet_setenv(key,value);
就是最終把鍵值對儲存到環境虛擬機器
void
skynet_setenv(const char *key, const char *value) {
SPIN_LOCK(E)
lua_State *L = E->L;
lua_getglobal(L, key);
assert(lua_isnil(L, -1));//注意 重複設定鍵值對是會報錯的
lua_pop(L,1);//下面兩行設定鍵值對
lua_pushstring(L,value);
lua_setglobal(L,key);
SPIN_UNLOCK(E)
}