/*
* module_session.c
*
* Created on: 2017-12-3
* Author: zengl
*
* 该模块用于处理和session会话相关的内容
* 在写入会话数据时,zengl脚本中的数组,会先转为json格式,再保存到session会话文件中
* 在读取会话数据时,会先通过json-parser第三方解析程式,将json解析出来,再转为zengl数组等进行返回
* json-parser的github地址:https://github.com/udp/json-parser
*/
................................................
/**
* sessGetData模块函数,根据会话文件名,将会话数据转为zengl脚本可以识别的数据类型
* 如果会话数据是一个json对象或者json数组,那么返回的就会是zengl数组,如果会话数据是整数,返回的也会是整数等
*/
ZL_EXP_VOID module_session_get_data(ZL_EXP_VOID * VM_ARG,ZL_EXP_INT argcount)
{
ZENGL_EXPORT_MOD_FUN_ARG arg = {ZL_EXP_FAT_NONE,{0}};
if(argcount != 1)
zenglApi_Exit(VM_ARG,"usage:sessGetData(sess_file_name)");
// 获取第一个参数,也就是会话文件名
zenglApi_GetFunArg(VM_ARG,1,&arg);
if(arg.type != ZL_EXP_FAT_STR) {
zenglApi_Exit(VM_ARG,"the first argument of sessGetData must be string");
}
char filename[SESSION_FILEPATH_MAX_LEN];
char * session_dir;
long session_expire;
// 先通过main_get_session_config函数获取会话目录,然后根据会话目录和会话文件名生成会话文件的相对路径
main_get_session_config(&session_dir, &session_expire, NULL);
session_make_filename(filename, session_dir, arg.val.str);
int file_size;
struct stat filestatus;
if ( stat(filename, &filestatus) != 0) {
session_return_empty_array(VM_ARG);
return;
}
time_t cur_time = time(NULL);
// 如果会话文件的修改时间(修改时间被用作超时时间)小于当前时间,则该会话文件已经超时,直接删除掉该文件,并返回空数组
if(filestatus.st_mtime < cur_time) {
remove(filename); // 删除超时的会话文件
write_to_server_log_pipe(WRITE_TO_PIPE, "debug info: sessionGetData remove file: %s [m_time:%d < %d]\n", filename, filestatus.st_mtime, cur_time);
session_return_empty_array(VM_ARG);
return;
}
file_size = filestatus.st_size;
FILE * fp = fopen(filename, "rb");
// fp为NULL,直接返回空数组
if (fp == NULL) {
session_return_empty_array(VM_ARG);
return;
}
char * file_contents = (char *)zenglApi_AllocMem(VM_ARG, file_size);
int nread = fread(file_contents, file_size, 1, fp);
if ( nread != 1 ) {
fclose(fp);
zenglApi_Exit(VM_ARG,"sessGetData error: Unable t read content of \"%s\"", filename);
}
fclose(fp);
json_value * value;
json_char * json = (json_char*)file_contents;
json_settings settings = { 0 };
settings.mem_alloc = my_json_mem_alloc;
settings.mem_free = my_json_mem_free;
settings.user_data = VM_ARG;
json_char json_error_str[json_error_max];
// 通过json-parser第三方解析程式来解析会话文件中的json数据,解析的结果是一个json_value结构
value = json_parse_ex (&settings, json, file_size, json_error_str);
if (value == NULL) {
zenglApi_Exit(VM_ARG,"sessGetData error: Unable to parse data, json error: %s", json_error_str);
}
ZENGL_EXPORT_MEMBLOCK memblock;
switch (value->type) {
case json_none: // 将json中的null转为整数0
zenglApi_SetRetVal(VM_ARG, ZL_EXP_FAT_INT, ZL_EXP_NULL, 0, 0);
break;
case json_object:
case json_array:
// 如果是json对象或json数组,则创建一个memblock内存块
if(zenglApi_CreateMemBlock(VM_ARG,&memblock,0) == -1) {
zenglApi_Exit(VM_ARG,zenglApi_GetErrorString(VM_ARG));
}
// 通过process_json_object_array函数,循环将value中的json成员填充到memblock中
process_json_object_array(VM_ARG, &memblock, value);
zenglApi_SetRetValAsMemBlock(VM_ARG,&memblock);
break;
case json_integer:
zenglApi_SetRetVal(VM_ARG, ZL_EXP_FAT_INT, ZL_EXP_NULL, (ZL_EXP_LONG)value->u.integer, 0);
break;
case json_double:
zenglApi_SetRetVal(VM_ARG, ZL_EXP_FAT_FLOAT, ZL_EXP_NULL, 0, value->u.dbl);
break;
case json_string:
zenglApi_SetRetVal(VM_ARG, ZL_EXP_FAT_STR, value->u.string.ptr, 0, 0);
break;
case json_boolean: // 将json中的bool类型转为整数,例如:true转为1,false转为0
zenglApi_SetRetVal(VM_ARG, ZL_EXP_FAT_INT, ZL_EXP_NULL, (ZL_EXP_LONG)value->u.boolean, 0);
break;
default:
zenglApi_SetRetVal(VM_ARG, ZL_EXP_FAT_INT, ZL_EXP_NULL, 0, 0);
break;
}
json_value_free_ex (&settings, value);
zenglApi_FreeMem(VM_ARG, file_contents);
// 设置会话文件session_expire秒后过期,其实就是将会话文件的修改时间设置为当前时间加上session_expire秒后的时间值
// 因此,会话文件的修改时间就是过期时间
session_set_expire(filename, session_expire);
}
/**
* sessSetData模块函数,将zengl数据写入到sess_file_name会话文件
* 在写入时,如果是zengl数组,则会被先转为json格式,再写入会话文件
* 例如:
* a['hello'] = 'world';
* a['name'] = 'zengl';
* sessSetData(sess_id, a);
* 执行后,写入sess_id会话文件中的内容就会是: {"hello":"world","name":"zengl"}
*/
ZL_EXP_VOID module_session_set_data(ZL_EXP_VOID * VM_ARG,ZL_EXP_INT argcount)
{
ZENGL_EXPORT_MOD_FUN_ARG arg = {ZL_EXP_FAT_NONE,{0}};
if(argcount != 2)
zenglApi_Exit(VM_ARG,"usage:sessSetData(sess_file_name, data)");
// 获取第一个参数,也就是会话文件名
zenglApi_GetFunArg(VM_ARG,1,&arg);
if(arg.type != ZL_EXP_FAT_STR) {
zenglApi_Exit(VM_ARG,"the first argument of sessSetData must be string");
}
char filename[SESSION_FILEPATH_MAX_LEN];
char * session_dir;
long session_expire;
// 先通过main_get_session_config函数获取会话目录,然后根据会话目录和会话文件名生成会话文件的相对路径
main_get_session_config(&session_dir, &session_expire, NULL);
session_make_filename(filename, session_dir, arg.val.str);
struct stat filestatus;
if ( stat(filename, &filestatus) == 0) {
time_t cur_time = time(NULL);
if(filestatus.st_mtime < cur_time) {
remove(filename); // 删除超时的会话文件,超时的会话文件,既不能进行读取操作,也不能进行写入操作
write_to_server_log_pipe(WRITE_TO_PIPE, "debug info: sessSetData remove file: %s [m_time:%d < %d]\n", filename, filestatus.st_mtime, cur_time);
zenglApi_SetRetVal(VM_ARG, ZL_EXP_FAT_INT, ZL_EXP_NULL, 0, 0);
return;
}
}
FILE * session_file = fopen(filename, "w+");
if(session_file == NULL) {
zenglApi_Exit(VM_ARG,"sessSetData open file \"%s\" failed [%d] %s", filename, errno, strerror(errno));
}
zenglApi_GetFunArg(VM_ARG,2,&arg);
switch(arg.type) {
case ZL_EXP_FAT_MEMBLOCK:
// 通过session_write_array_to_file函数将zengl数组转为json格式,并写入session_file会话文件
session_write_array_to_file(VM_ARG, session_file, arg.val.memblock);
break;
case ZL_EXP_FAT_INT:
fprintf(session_file, "%ld",arg.val.integer);
break;
case ZL_EXP_FAT_FLOAT:
fprintf(session_file, "%.16g",arg.val.floatnum);
break;
case ZL_EXP_FAT_STR:
fprintf(session_file, "%s",arg.val.str);
break;
default:
fprintf(session_file, "null");
break;
}
fclose(session_file);
// 设置会话文件session_expire秒后过期,其实就是将会话文件的修改时间设置为当前时间加上session_expire秒后的时间值
// 因此,会话文件的修改时间就是过期时间
session_set_expire(filename, session_expire);
// 执行成功,返回整数1
zenglApi_SetRetVal(VM_ARG, ZL_EXP_FAT_INT, ZL_EXP_NULL, 1, 0);
}
/**
* sessMakeId模块函数,生成40个字符的随机字符串,并将该字符串作为结果返回
* 该随机字符串可以用作会话文件名
* 生成随机字符串时,所使用的random_get_bytes函数,是从libuuid库中移植过来的,
* 其中会用到/dev/urandom或者/dev/random等,具有比较高的随机性
*/
ZL_EXP_VOID module_session_make_id(ZL_EXP_VOID * VM_ARG,ZL_EXP_INT argcount)
{
unsigned int v, i;
char buf[50];
char * p = buf;
for (i = 0; i < 5; i++) {
random_get_bytes(&v, sizeof(v));
sprintf(p, "%08x", v);
p += 8;
}
(*p) = '\0';
zenglApi_SetRetVal(VM_ARG, ZL_EXP_FAT_STR, buf, 0, 0);
}
/**
* session模块的初始化函数,里面设置了与该模块相关的各个模块函数及其相关的处理句柄
*/
ZL_EXP_VOID module_session_init(ZL_EXP_VOID * VM_ARG,ZL_EXP_INT moduleID)
{
zenglApi_SetModFunHandle(VM_ARG,moduleID,"sessGetData", module_session_get_data);
zenglApi_SetModFunHandle(VM_ARG,moduleID,"sessSetData", module_session_set_data);
zenglApi_SetModFunHandle(VM_ARG,moduleID,"sessMakeId", module_session_make_id);
}
|