Compare commits

...

27 Commits

Author SHA1 Message Date
02a9d73817 修复内存池泄漏 2026-02-21 15:27:56 +08:00
d81a3c8042 log管理器内存分配池化,修复部分log写入部分与内存池部分存在的恶性bug 2026-02-21 15:04:04 +08:00
b618cc359a Merge remote-tracking branch 'origin/main' 2026-02-18 14:50:45 +08:00
b23828cd5c 修复部分bug,添加内存池,为后续内存池化分配打基础 2026-02-18 14:46:33 +08:00
bdf8ef62f7 modified: .gitignore 2026-02-09 09:33:47 +08:00
a8c5f0dabf test 2026-02-09 09:32:42 +08:00
19e0392db6 优化内存不足时的日志管理行为 2026-02-02 21:05:10 +08:00
d01219da30 优化日志内存不足时的写入逻辑 2026-02-02 21:04:52 +08:00
4445567169 优化日志 2026-01-30 22:33:24 +08:00
674f611d07 修复端口绑定取消异常 2026-01-29 14:03:43 +08:00
3673b10942 修改readme 2026-01-29 12:20:17 +08:00
ee596a654d 修复日志处理,优化磁盘io,优化退出流程 2026-01-29 12:10:36 +08:00
65115e1a74 修复http解析 2025-12-18 06:25:26 +08:00
73a94417b0 deleted: .vscode/settings.json 2025-12-17 18:14:19 +08:00
a73b317547 改用自行实现的http读取与解析,同时修复部分bug 2025-12-17 18:13:39 +08:00
e0a3f0d3f1 弃用mongoose,倒霉玩意 2025-12-16 18:08:39 +08:00
cd75b098f5 优化源码配置宏位置,方便个性化编译 2025-12-16 09:13:30 +08:00
08589dfe79 修复部分bug 2025-11-21 18:02:37 +08:00
26dac05e5b 修复log记录错误(第一个节点无法落盘),更新http解析为现成库实现,优化退出逻辑。 2025-11-21 11:40:08 +08:00
331c6b9f89 完善日志系统,修复读取配置文件时的内存泄漏,初步添加熔断机制与指数退避机制 2025-10-11 16:57:27 +08:00
f518bf5064 修复http解析 2025-10-03 10:57:53 +08:00
d11c1559ab 时间原因,暂存部分更改 2025-10-03 10:01:01 +08:00
3ada071d44 优化模拟终端稳定性 2025-10-01 19:30:44 +08:00
69ce2eed50 修复日志缓存计数错误 2025-09-30 07:43:13 +08:00
ef6acafd34 修改网络监听退出流程 2025-09-29 16:50:51 +08:00
8c52e4ba84 优化退出流程,统一注册到on_exit( 2025-09-29 16:07:11 +08:00
afe70e6d17 优化退出信号传递流程 2025-09-28 14:26:09 +08:00
43 changed files with 1083 additions and 231 deletions

2
.gitignore vendored Normal file → Executable file
View File

@ -6,7 +6,7 @@ __pycache__/
# C extensions # C extensions
*.so *.so
.vscode/
# Distribution / packaging # Distribution / packaging
.Python .Python
build/ build/

0
LICENSE Normal file → Executable file
View File

2
README.md Normal file → Executable file
View File

@ -1,6 +1,6 @@
# OneBot Chatbot Framework # OneBot Chatbot Framework
该项目是一个基于OneBot标准的聊天机器人后端框架采用高度可扩展的插件架构设计支持消息的模块化处理和插件热加载。 该项目是一个基于OneBot标准的聊天机器人后端框架采用高度可扩展的插件架构设计支持消息的模块化处理和插件热加载。如果你有任何意见或建议,可以通过 jianfeee@outlook.com 联系我。
## 项目特点 ## 项目特点

13
c/CMakeLists.txt Normal file → Executable file
View File

@ -1,15 +1,24 @@
cmake_minimum_required(VERSION 3.28.3) cmake_minimum_required(VERSION 3.28.3)
project (Onebot_back C) project (Onebot_back C)
if(CMAKE_C_COMPILER_ID MATCHES "GNU|Clang")
add_compile_options(-O0 -g -fno-omit-frame-pointer)
add_link_options(-O0)
endif()
if(MSVC)
add_compile_options(/Od /Zi)
endif()
add_executable(Start_Onebot_back main.c tem/ctl.c) add_executable(Start_Onebot_back main.c tem/ctl.c)
add_executable(Run_pluginmanager run_pluginmanager/run_pluginmanager.c) add_executable(Run_pluginmanager run_pluginmanager/run_pluginmanager.c)
add_library(Network SHARED network/network.c network/swap.c network/cJSON.c network/http_rel.c) add_library(Network SHARED network/network.c network/swap.c network/cJSON.c network/http/http_rel.c network/erroprocess/erroprocess.c)
add_library(Swmem SHARED network/swap.c) add_library(Swmem SHARED network/swap.c)
add_library(Interpre SHARED interpreter/interpreter.c tools/pkgmanager/pkginstall.c) add_library(Interpre SHARED interpreter/interpreter.c tools/pkgmanager/pkginstall.c)
add_library(Log SHARED tools/log/log.c) add_library(Log SHARED tools/log/log.c)
add_library(Toml SHARED tools/toml/toml.c) add_library(Toml SHARED tools/toml/toml.c)
add_library(Quit SHARED tools/quit/quit.c)
add_library(Memctl SHARED memctl/memctl.c)
target_link_libraries(Start_Onebot_back Network Swmem Interpre Log Toml) target_link_libraries(Start_Onebot_back Network Swmem Interpre Log Toml Quit Memctl)
include_directories(${PROJECT_SOURCE_DIR}) include_directories(${PROJECT_SOURCE_DIR})

37
c/config.h Executable file
View File

@ -0,0 +1,37 @@
#ifndef SEVERCONFG
#define SEVERCONFG
/*------日志管理---------*/
#define MAX_LOG 50
#define MAX_LOG_LENGTH 4080
#define INFO_LENGTH 8
#define LOG_SLEEP_LENGTH 1
/*------日志管理---------*/
/*-------终端管理-------*/
#define TEM_MAX_BUF 256
#define TEM_HISTORY_BUF 210
#define TEM_PROMPT "chatbot$$ "
/*----终端管理--------*/
/*-------网路池管理-----*/
#define NET_MAX_POOL 1
#define NET_MAX_MESSAGE_BUF 1024
#define HTTP_BLOCK_SIZE 512
#define MAX_HTTP_LENGTH 20
/*-------网路池管理-----*/
/*------解释器管理-------*/
#define INTER_MAX_BUF 256
/*------解释器管理-------*/
/*------内存池管理------*/
#define MAX_MEM_SIZE 512
#define COMINE_MEM_SIZE 448
#define MEM_BLOCK_SIZE 4096
#define POOL_EXPEND_ID 3
#define POOL_EXPEND_SIZE 4
#define CYCLE_NUM 7
/*------内存池管理------*/
#endif

39
c/interpreter/interpreter.c Normal file → Executable file
View File

@ -9,12 +9,22 @@
#include "interpreter.h" #include "interpreter.h"
#include "tools/pkgmanager/pkginstall.h" #include "tools/pkgmanager/pkginstall.h"
int inter_in_log(const char *log,const char *info,log_manager *manager)
{
if(strlen(log)>1024)
return -1;
manager->in_log(manager,log,info);
return 0;
}
int init_interpreter(Cmd *cmd_dic,ctx *self,int fifo[2]) int init_interpreter(Cmd *cmd_dic,ctx *self,int fifo[2],log_manager *log_manager)
{ {
printf("SYS:prepare env\n"); printf("SYS:prepare env\n");
inter_in_log("prepare env\n","SYS",log_manager);
printf("SYS:env ready\n"); printf("SYS:env ready\n");
inter_in_log("env ready\n","SYS",log_manager);
printf("SYS:loading cmd_dic\n"); printf("SYS:loading cmd_dic\n");
inter_in_log("loading cmd_dic\n","SYS",log_manager);
sprintf(cmd_dic[0].name, "pkginstall"); sprintf(cmd_dic[0].name, "pkginstall");
cmd_dic[0].cmd = INSTALL; cmd_dic[0].cmd = INSTALL;
@ -25,6 +35,7 @@ int init_interpreter(Cmd *cmd_dic,ctx *self,int fifo[2])
cmd_dic[2].cmd = QUIT; cmd_dic[2].cmd = QUIT;
printf("SYS:cmd_dir load complite\n"); printf("SYS:cmd_dir load complite\n");
inter_in_log("cmd_dir load complite\n","SYS",log_manager);
for(int i =0;i<10;i++) for(int i =0;i<10;i++)
{ {
@ -32,8 +43,9 @@ int init_interpreter(Cmd *cmd_dic,ctx *self,int fifo[2])
} }
self->arg = NULL; self->arg = NULL;
printf("SYS:Creating ctl fifo\n"); printf("SYS:Creating ctl fifo\n");
inter_in_log("Creating ctl fifo\n","SYS",log_manager);
memcpy(self->fifofd,fifo,2*sizeof(int)); memcpy(self->fifofd,fifo,2*sizeof(int));
self->log_manager = log_manager;
} }
int get_args(ctx *self) int get_args(ctx *self)
@ -57,6 +69,7 @@ int get_args(ctx *self)
arg->next = (args*)malloc(sizeof(args)); arg->next = (args*)malloc(sizeof(args));
if(arg->next == NULL){ if(arg->next == NULL){
perror("ERROR:fail to get mem"); perror("ERROR:fail to get mem");
inter_in_log("fail to get mem\n","ERROR",self->log_manager);
return -1; return -1;
} }
arg = arg->next; arg = arg->next;
@ -124,34 +137,43 @@ int match_cmd(const Cmd* cmd_dic,char *cmd_buf)
} }
int exce(const int command,ctx *all_ctx) int exec(const int command,ctx *all_ctx)
{ {
switch (command) switch (command)
{ {
case BAD_INPUT: case BAD_INPUT:
printf("SYS:bad input,try again\n"); printf("SYS:bad input,try again\n");
inter_in_log("bad input,try again\n","SYS",all_ctx->log_manager);
return BAD_INPUT; return BAD_INPUT;
case INSTALL: case INSTALL:
if(all_ctx->arg == NULL){ if(all_ctx->arg == NULL){
printf("SYS:Missing args\n"); printf("SYS:Missing args\n");
inter_in_log("Missng args\n","SYS",all_ctx->log_manager);
return 1; return 1;
} }
printf("SYS:init pkgmanager\n"); printf("SYS:init pkgmanager\n");
inter_in_log("init pkgmanager\n","SYS",all_ctx->log_manager);
pkger *manager = init_pkginstaller(); pkger *manager = init_pkginstaller();
printf("SYS:installing\n"); printf("SYS:installing\n");
inter_in_log("installing\n","SYS",all_ctx->log_manager);
manager->packup(manager); manager->packup(manager);
return 1; return 1;
case RUN: case RUN:
printf("runing\n"); printf("SYS:runing\n");
inter_in_log("running\n","SYS",all_ctx->log_manager);
return 1; return 1;
case QUIT: case QUIT:
printf("shuting down\n"); printf("SYS:shuting down\n");
inter_in_log("shuting down\n","SYS",all_ctx->log_manager);
all_ctx->statue = -1; all_ctx->statue = -1;
write(all_ctx->fifofd[1],"q",1);
return 1; return 1;
default :
return -1;
} }
} }
@ -164,7 +186,7 @@ int interpret(int mod, ctx *all_ctx,Cmd *cmd_dic)
split(all_ctx->command,all_ctx); split(all_ctx->command,all_ctx);
get_args(all_ctx); get_args(all_ctx);
char *cmd_buf = malloc(MAX_BUF); char *cmd_buf = malloc(INTER_MAX_BUF);
int len; int len;
if(all_ctx->space_index[0]==0) if(all_ctx->space_index[0]==0)
{ {
@ -178,7 +200,7 @@ int interpret(int mod, ctx *all_ctx,Cmd *cmd_dic)
if(cmd_buf[len-1] == '\n') if(cmd_buf[len-1] == '\n')
cmd_buf[len-1] = '\0'; cmd_buf[len-1] = '\0';
//执行命令 //执行命令
exce(match_cmd(cmd_dic, cmd_buf),all_ctx); exec(match_cmd(cmd_dic, cmd_buf),all_ctx);
//释放所有堆内存 //释放所有堆内存
free(cmd_buf); free(cmd_buf);
@ -192,5 +214,8 @@ int interpret(int mod, ctx *all_ctx,Cmd *cmd_dic)
if (mod == FILE_MOD) if (mod == FILE_MOD)
{ {
//todo 读取命令脚本并执行
return -1;
} }
return -1;
} }

9
c/interpreter/interpreter.h Normal file → Executable file
View File

@ -1,11 +1,13 @@
#ifndef INTERPRETER #ifndef INTERPRETER
#define INTERPRETER #define INTERPRETER
#define MAX_BUF 256 #include "config.h"
#define SIG_MOD 0 #define SIG_MOD 0
#define FILE_MOD 1 #define FILE_MOD 1
#include "tools/log/log.h"
typedef struct typedef struct
{ {
char name[256]; char name[256];
@ -35,14 +37,15 @@ typedef struct ctx
int line;//当前行长度 int line;//当前行长度
int word;//当前解释词位置 int word;//当前解释词位置
args *arg;//当前环境下参数链表 args *arg;//当前环境下参数链表
char command[MAX_BUF];//当前行缓存 char command[INTER_MAX_BUF];//当前行缓存
int statue;//当前状态 int statue;//当前状态
int fifofd[2]; int fifofd[2];
log_manager *log_manager;
}ctx;//上下文管理 }ctx;//上下文管理
int interpret(int mod, ctx *all_ctx,Cmd *cmd_dic); int interpret(int mod, ctx *all_ctx,Cmd *cmd_dic);
int init_interpreter(Cmd *cmd_dic,ctx *self,int fifo[2]); int init_interpreter(Cmd *cmd_dic,ctx *self,int fifo[2],log_manager *log_manager);
#define ARG_LENGTH 256 #define ARG_LENGTH 256

44
c/main.c Normal file → Executable file
View File

@ -1,6 +1,10 @@
#define _GNU_SOURCE
#include "tem/ctl.h" #include "tem/ctl.h"
#include "network/network.h" #include "network/network.h"
#include "tools/toml/toml.h" #include "tools/toml/toml.h"
#include "tools/quit/quit.h"
#include "memctl/memctl.h"
#include <unistd.h> #include <unistd.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
@ -31,10 +35,14 @@ int main()
perror("load config error"); perror("load config error");
int port = (int)toml_int_in(server,"list_port").u.i; int port = (int)toml_int_in(server,"list_port").u.i;
//加载配置文件,读取端口 //加载配置文件,读取端口
mem_ctl *mem_ctler = (mem_ctl*)malloc(sizeof(mem_ctl));
init_memctl(mem_ctler);
log_manager *logsmanager=(log_manager*)malloc(sizeof(log_manager)); log_manager *logsmanager=(log_manager*)malloc(sizeof(log_manager));
init_loger(logsmanager); //创建日志管理器与定时清理线层
init_loger(logsmanager,mem_ctler);
pthread_create(&logsmanager->pid,NULL,logsmanager->clear_log,logsmanager);
Ctl *teml = init_tem(logsmanager); Ctl *teml = init_tem(logsmanager);
teml->config = server;
//初始化终端对象 //初始化终端对象
int fifo[2]; int fifo[2];
if(pipe(fifo)==-1) if(pipe(fifo)==-1)
@ -42,17 +50,27 @@ int main()
netm *networkmanager = (netm*)malloc(sizeof(netm)); netm *networkmanager = (netm*)malloc(sizeof(netm));
init_networkmanager(networkmanager,fifo,logsmanager,port); init_networkmanager(networkmanager,fifo,logsmanager,port);
//初始化网络管理器对象 //初始化网络管理器对象
pthread_t network_id;
pthread_create(&network_id,NULL,networkmanager->run_network,(void*)networkmanager);
//启动网络监听与线程池,并加载插件
teml->run(teml,fifo);
//启动终端
pthread_join(network_id,NULL);
//等待网络管理器进程结束
free(teml); pthread_create(&networkmanager->pid,NULL,networkmanager->run_network,(void*)networkmanager);
free(networkmanager); //启动网络监听与线程池,并加载插件
free(logsmanager); alres *resource = (alres*)malloc(sizeof(alres));
//释放内存 resource->loger = logsmanager;
resource->network = networkmanager;
resource->tem = teml;
resource->memctler = mem_ctler;
on_exit(quit_all,resource);
//注册清理函数
teml->run(teml,fifo);
//启动终端
//等待网络管理器进程结束
pthread_join(networkmanager->pid,NULL);
networkmanager->pid = -1;
close(fifo[1]);
log_manager_stop(logsmanager);
pthread_join(logsmanager->pid,NULL);
logsmanager->pid = -1;
return 1; return 1;
} }

159
c/memctl/memctl.c Normal file
View File

@ -0,0 +1,159 @@
#include "memctl.h"
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#define container_of(ptr, type, member) \
((type *)((char *)(ptr) - offsetof(type, member)))
int extend_pool(mem_ctl* self,int size)
{
if(self == NULL)//入参检查
{
return -1;
}
int poolsize = atomic_load(&self->poolsize);
int target = poolsize +size;//计算目标大小
if(target >MAX_MEM_SIZE)
target = MAX_MEM_SIZE;//计算限制
for(int i = poolsize;i<target;i++)//分配内存
{
if(self->blocks[i].location !=NULL)//若存在未释放内存
free(self->blocks[i].location);
self->blocks[i].location = malloc(MEM_BLOCK_SIZE);
if(self->blocks[i].location == NULL)
return target-i;//堆内存不足
atomic_store(&self->blocks[i].condition,MEM_FREE);
}
atomic_fetch_add(&self->poolsize,size);
int log = atomic_load(&self->logbuf)+size/2;
atomic_store(&self->logbuf,log);//重新划定日志区
return 0;
}
void **GetBlock(mem_ctl* self,int type)
{
int status = 0;
int sp=0,start = 0;
int id;
//模式判断
if(type == LOGMOD)
{
id = atomic_load(&self->Loglast_loc);
sp = atomic_load(&self->poolsize);
start = atomic_load(&self->logbuf);
if(id<start)
id = start;
}
else
{
id = atomic_load(&self->Commenlast_loc);
sp = atomic_load(&self->logbuf)+1;
if(id>sp)
id = start;
}
int i = id;
for(status;status<CYCLE_NUM;status++)//最多扫描轮次
{
//获取空闲块
for(i;i<sp;i++)
{
if(atomic_fetch_sub(&self->blocks[i].condition,1) == MEM_FREE)
{
atomic_fetch_sub(&self->blocks[i].condition,1);
if(i>self->logbuf)
atomic_store(&self->Loglast_loc,i);
else
atomic_store(&self->Commenlast_loc,i);
return &self->blocks[i].location;
}
else{
atomic_fetch_add(&self->blocks[i].condition,1);//回滚路径
}
}
i = start;
atomic_fetch_add(&self->mem_e_indicator,1);
//检查是否需要扩池
if(atomic_fetch_sub(&self->mem_e_indicator,POOL_EXPEND_ID)>POOL_EXPEND_ID)
{
extend_pool(self,POOL_EXPEND_SIZE);
}
else{
atomic_fetch_add(&self->mem_e_indicator,POOL_EXPEND_ID);
}
}
return NULL;
}
int FreeBlock(mem_ctl* self,void** block_p)
{
mem_block *block;
block = container_of(block_p,mem_block,location);
if(self == NULL)
return -1;
if(block == NULL)
return -1;
if(block < &self->blocks[COMINE_MEM_SIZE])//标准池部分归还
{
atomic_fetch_add(&block->condition,2);
block = NULL;
return 0;
}
else//扩容池尝试回收
{
atomic_fetch_add(&block->condition,1);
free(block->location);
block->location = NULL;
int poolsize = atomic_load(&self->poolsize);
if(&self->blocks[poolsize-1] == block)
{
for(int i = poolsize -1;i>COMINE_MEM_SIZE;i--)
{
if(atomic_load(&self->blocks[i].condition) == PROCESSING)
{
poolsize--;
}
else{
break;
}
if(poolsize-COMINE_MEM_SIZE%2 == 0)
{
atomic_fetch_sub(&self->logbuf,1);
}
}
}
atomic_store(&self->poolsize,poolsize);
}
}
int init_memctl(mem_ctl *self)
{
if(self == NULL)
return -1;
self->poolsize = 0;
for(int i =0;i<MAX_MEM_SIZE;i++)
{
self->blocks[i].location = NULL;
atomic_init(&self->blocks[i].condition,PROCESSING);//初始化池
}
extend_pool(self,COMINE_MEM_SIZE);//预分配内存
self->Commenlast_loc = 0;
self->logbuf = COMINE_MEM_SIZE/2;
self->mem_e_indicator = 0;
self->FreeBlock = FreeBlock;
self->GetBlock = GetBlock;
return 0;
}
int free_memctl(mem_ctl *self)//清除内存池
{
if(self == NULL)
return -1;
for(int i = 0;i<MAX_MEM_SIZE;i++)
{
if(self->blocks[i].location!=NULL)
free(self->blocks[i].location);
}
return 0;
}

36
c/memctl/memctl.h Normal file
View File

@ -0,0 +1,36 @@
#ifndef MEMCTL
#define MEMCTL
#include "config.h"
#include <stdatomic.h>
#define MEM_FREE 1
#define INUSE -1
#define PROCESSING 0
#define LOGMOD 0
#define COMMENMOD 1
typedef struct mem_block
{
void *location;//块地址
atomic_int condition;//块状态
}mem_block;
typedef struct mem_ctl
{
mem_block blocks[MAX_MEM_SIZE];
atomic_int logbuf;
atomic_int poolsize;
atomic_int Commenlast_loc;//分配起始
atomic_int Loglast_loc;
atomic_int mem_e_indicator;//内存不足指示器
//获取一个内存块
void** (*GetBlock)(struct mem_ctl*,int);
//释放一个内存块
int (*FreeBlock)(struct mem_ctl*,void**);
}mem_ctl;
int init_memctl(mem_ctl *self);
int free_memctl(mem_ctl *self);
#endif

18
c/network/cJSON.c Normal file → Executable file
View File

@ -160,25 +160,11 @@ typedef struct internal_hooks
void *(CJSON_CDECL *reallocate)(void *pointer, size_t size); void *(CJSON_CDECL *reallocate)(void *pointer, size_t size);
} internal_hooks; } internal_hooks;
#if defined(_MSC_VER)
/* work around MSVC error C2322: '...' address of dllimport '...' is not static */
static void * CJSON_CDECL internal_malloc(size_t size)
{
return malloc(size);
}
static void CJSON_CDECL internal_free(void *pointer)
{
free(pointer);
}
static void * CJSON_CDECL internal_realloc(void *pointer, size_t size)
{
return realloc(pointer, size);
}
#else
#define internal_malloc malloc #define internal_malloc malloc
#define internal_free free #define internal_free free
#define internal_realloc realloc #define internal_realloc realloc
#endif
/* strlen of character literals resolved at compile time */ /* strlen of character literals resolved at compile time */
#define static_strlen(string_literal) (sizeof(string_literal) - sizeof("")) #define static_strlen(string_literal) (sizeof(string_literal) - sizeof(""))

0
c/network/cJSON.h Normal file → Executable file
View File

View File

@ -0,0 +1,17 @@
#include "erroprocess.h"
#include <stdio.h>
#include <stddef.h>
int give_upjobs(indiector *self)
{
if(self == NULL)
{
return -1;
}
return 1;
}
int init_indector(indiector *self)
{
}

View File

@ -0,0 +1,24 @@
#ifndef ERROPROCESS
#define ERROPROCESS
#define BASE_INDIECTOR 2
#define MAX_index 5
#define CIR_TIME 20
typedef struct jobs
{
struct jobs* next;
int job;
}jobs;
typedef struct indiector
{
int status;//熔断标志位
int retreat_index;//退避指数
jobs *head_job;
jobs *rear_job;
int (*give_upjobs)(struct indiector *);
}indiector;
#endif

108
c/network/http/http_rel.c Executable file
View File

@ -0,0 +1,108 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <fcntl.h>
#include <errno.h>
#include <netinet/in.h>
#include "errno.h"
#include "tools/log/log.h"
#include "http_rel.h"
int write_in_bk(char input,httpbuf* blk){
}
char *recv_http_request(int cfd){
}
/**
* @brief 初始化HTTP监听socket所有错误通过logmanager记录
* @param port 监听端口
* @param logger 日志管理器实例指针
* @return 成功返回监听fd失败返回-1并记录日志
*/
int init_http_network(int port, log_manager *logger)
{
int fd;
char log[MAX_LOG_LENGTH];
/* 1. 创建socket */
fd = socket(AF_INET, SOCK_STREAM, 0);
if (fd == -1) {
snprintf(log, sizeof(log),
"socket() failed: %s", strerror(errno));
logger->in_log(logger, log,"FATAL");
return -1;
}
/* 2. 设置SO_REUSEADDR避免TIME_WAIT状态导致bind失败 */
int opt = 1;
if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) == -1) {
snprintf(log, sizeof(log),
"setsockopt(SO_REUSEADDR) on fd=%d failed: %s",
fd, strerror(errno));
logger->in_log(logger,log,"ERROR:");
close(fd);
return -1;
}
/* 3. 设置为非阻塞模式配合epoll使用 */
int flags = fcntl(fd, F_GETFL, 0);
if (flags == -1) {
snprintf(log, sizeof(log),
"fcntl(F_GETFL) on fd=%d failed: %s", fd, strerror(errno));
logger->in_log(logger,log,"ERROR:");
close(fd);
return -1;
}
if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1) {
snprintf(log, sizeof(log),
"fcntl(O_NONBLOCK) on fd=%d failed: %s", fd, strerror(errno));
logger->in_log(logger,log,"ERROR:");
close(fd);
return -1;
}
/* 4. 绑定到指定端口 */
struct sockaddr_in addr = {0};
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
addr.sin_addr.s_addr = htonl(INADDR_ANY); // 监听所有网卡
if (bind(fd, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
snprintf(log, sizeof(log),
"bind(port %d) failed: %s (fd=%d)",
port, strerror(errno), fd);
logger->in_log(logger,log,"FATAL:");
close(fd);
return -1;
}
/* 5. 开始监听 */
if (listen(fd, 10) == -1) {
snprintf(log, sizeof(log),
"listen(fd=%d, backlog=10) failed: %s",
fd, strerror(errno));
logger->in_log(logger,log,"FATAL:");
close(fd);
return -1;
}
/* 6. 成功日志 */
snprintf(log, sizeof(log),
"Successfully listening on port %d (fd=%d)", port, fd);
logger->in_log(logger, log,"HTTP:");
return fd;
}

15
c/network/http/http_rel.h Executable file
View File

@ -0,0 +1,15 @@
#ifndef HTTP_REL
#define HTTP_REL
#include "config.h"
#include "memctl/memctl.h"
typedef struct httpbuf{
int size;
char buf[MEM_BLOCK_SIZE-5];
}httpbuf;//http分块结构体
char *recv_http_request(int cfd);
int init_http_network(int port, log_manager *logger);
#endif

View File

@ -1,24 +0,0 @@
#include <stddef.h>
#include <string.h>
#include "http_rel.h"
const char *http_get_body(const char *buf)
{
if (!buf) return NULL;
/* 找到 header 与 body 之间的空行 "\r\n\r\n" */
const char *sep = strstr(buf, "\r\n\r\n");
if (!sep) return NULL; /* 格式错误 */
const char *body = sep + 4; /* 跳过 "\r\n\r\n" */
/* 简单判断:如果后面还有数据,就认为是 body */
if (*body == '\0') return NULL; /* 没有 body */
return body;
}
const char *resave_http(int fd)
{
}

View File

@ -1,6 +0,0 @@
#ifndef HTTP_REL
#define HTTP_REL
const char *http_get_body(const char *buf);
#endif

198
c/network/network.c Normal file → Executable file
View File

@ -2,19 +2,24 @@
#include "network.h" #include "network.h"
#include "swap.h" #include "swap.h"
#include "http_rel.h" #include "http/http_rel.h"
#include "cJSON.h" #include "cJSON.h"
#include "tools/log/log.h" #include "tools/log/log.h"
#include "tools/quit/quit.h"
#include "erroprocess/erroprocess.h"
#include <semaphore.h> #include <semaphore.h>
#include <unistd.h> #include <unistd.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <fcntl.h>
#include <string.h> #include <string.h>
#include <stddef.h> #include <stddef.h>
#include <errno.h> #include <errno.h>
#include <sys/socket.h> #include <sys/socket.h>
#include <netinet/in.h> #include <netinet/in.h>
#include <sys/epoll.h> #include <sys/epoll.h>
#include <sys/mman.h>
static void safe_strcpy(char *dst, size_t dst_size, const char *src) static void safe_strcpy(char *dst, size_t dst_size, const char *src)
{ {
@ -28,6 +33,8 @@ static void safe_strcpy(char *dst, size_t dst_size, const char *src)
/* 主解析 */ /* 主解析 */
int rbt_parse_json(const char *json_text, rbt_msg *out) int rbt_parse_json(const char *json_text, rbt_msg *out)
{ {
if(json_text == NULL)
return -1;
memset(out, 0, sizeof(*out)); // 统一清 0gid 天然 '\0' memset(out, 0, sizeof(*out)); // 统一清 0gid 天然 '\0'
cJSON *root = cJSON_Parse(json_text); cJSON *root = cJSON_Parse(json_text);
@ -69,53 +76,66 @@ int rbt_parse_json(const char *json_text, rbt_msg *out)
out->message_type = 'p'; out->message_type = 'p';
/* else 保持 0 */ /* else 保持 0 */
} }
cJSON_Delete(root); cJSON_Delete(root);
return 0; // 成功 return 0; // 成功
} }
int init_network(int port)
{
int fd = socket(AF_INET, SOCK_STREAM, 0);
struct sockaddr_in addr = {0};
addr.sin_family = AF_INET; // 和 socket() 一致
addr.sin_port = htons(port); // 端口号必须网络字节序
addr.sin_addr.s_addr = htonl(INADDR_ANY); // 0.0.0.0:本机所有网卡
bind(fd, (struct sockaddr *)&addr, sizeof(addr));
return fd;
}
ssize_t read_req(int fd, void *buf) ssize_t read_req(int fd, void *buf)
{ {
ssize_t n = read(fd, buf, MAX_MESSAGE_BUF); // TODO 修改读取任务函数
ssize_t n = read(fd, buf, NET_MAX_MESSAGE_BUF);
if (n == 0) /* 写端已关闭,管道永不会再有数据 */ if (n == 0) /* 写端已关闭,管道永不会再有数据 */
return -1; return 0;
return (n > 0) ? n : -1; return (n > 0) ? n : -1;
} }
int process_message(char *req,log_manager *logger) int process_message(char *req, log_manager *logger,rbt_msg *swap) {
{ if(req == NULL) return 0;
const char *body = http_get_body(req);
rbt_msg message; int fd;
rbt_parse_json(body,&message); char type[16], end[16];
make_swap((void*)&message); if(sscanf(req, "%15s/%d/%15s", type, &fd, end) != 3) {
logs *log = malloc(sizeof log); free(req);
if(snprintf(log->log,sizeof(log->log), return -1;
"%s message %s processd ok\n",message.nickname,message.raw_message)<1024); }
logger->in_log(log,logger);
const char *body = recv_http_request(fd);
if(rbt_parse_json(body,swap) == 0) {
char log[MAX_LOG_LENGTH];
// cppcheck-suppress uninitdata
snprintf(log, sizeof(log), "%s message %s processed ok\n",
swap->nickname,swap->raw_message);
make_swap(swap);
logger->in_log(logger,log,"PROCESSER:");
}
//通知前端已收到消息
const char *response =
"HTTP/1.1 200 OK\r\n"
"Content-Type: text/plain\r\n"
"Content-Length: 2\r\n"
"\r\n"
"OK";
write(fd, response, strlen(response));
close(fd);
free(req);
return 0;
} }
int iss_work(netm *self,char *command) int iss_work(netm *self,char *command)
{ {
int i = self->last_alc+1; int i = self->last_alc;
//查询空闲线程 //查询空闲线程
while(self->pool[i].fifo_fd ==0) while(atomic_load(&(self->pool[i].status)) ==0)
{ {
if(i<MAX_POOL) if(i<NET_MAX_POOL)
i++; i++;
else else{
i=0; i=0;
} }
}
//向空闲线程发送数据 //向空闲线程发送数据
write(self->pool[i].fifo_fd[0],command,strlen(command)); write(self->pool[i].fifo_fd[0],command,strlen(command));
//设置线程程为working //设置线程程为working
@ -125,16 +145,17 @@ int iss_work(netm *self,char *command)
void *pth_module(void *args_p) void *pth_module(void *args_p)
{ {
args *argms = (args*)args_p; net_args *argms = (net_args*)args_p;
pth_m *pmd = argms->pth; pth_m *pmd = argms->pth;
log_manager *logger = argms->log; log_manager *logger = argms->log;
//参数解析 //参数解析
free(args_p);
char name[256] = {'\0'}; char name[256] = {'\0'};
sprintf(name,"chatrebot%lu",pmd->pthread_id); sprintf(name,"chatrebot%lu",pthread_self());
int swap = create_swap(name); int swapfd = create_swap(name);
//创建共享内存 //创建共享内存
char swap_arg[64] = {'\0'}; char swap_arg[64] = {'\0'};
sprintf(swap_arg,"%d",swap); sprintf(swap_arg,"%d",swapfd);
pid_t id = fork(); pid_t id = fork();
if(id == 0) if(id == 0)
{ {
@ -144,13 +165,19 @@ void *pth_module(void *args_p)
NULL}; NULL};
execv("Run_pluhginmanager",args); execv("Run_pluhginmanager",args);
} }
char pth_log[40];
// cppcheck-suppress uninitdata
sprintf(pth_log,"launched python plugines,pid:%ld\n",pthread_self());
logger->in_log(logger,pth_log,"PROCESSER:");
rbt_msg *swap = (rbt_msg*)mmap(NULL, sizeof(rbt_msg), PROT_READ|PROT_WRITE, MAP_SHARED,swapfd, 0);
//拉起python插件管理器 //拉起python插件管理器
for(;;){ for(;;){
//线程池中,单个线程模型 //线程池中,单个线程模型
char req[64*1024]; char *req = (char*)malloc(NET_MAX_MESSAGE_BUF);
//从管道中读取请求,并解析,无内容时休眠 //从管道中读取请求,并解析,无内容时休眠
int n = read_req(pmd->fifo_fd[0],req); int n = read_req(pmd->fifo_fd[0],(void*)req);
//管道关闭时退出; //管道关闭时退出;
if (n == EOF) { if (n == EOF) {
@ -158,7 +185,7 @@ void *pth_module(void *args_p)
break; break;
} }
else{ else{
process_message(req,logger); process_message(req,logger,swap);
atomic_fetch_add(&pmd->status, 1); atomic_fetch_add(&pmd->status, 1);
} }
} }
@ -166,64 +193,113 @@ void *pth_module(void *args_p)
int start_pool(netm *self) int start_pool(netm *self)
{ {
for(int i = 0;i<MAX_POOL;i++) for(int i = 0;i<NET_MAX_POOL;i++)
{ {
//为线程开辟管道 //为线程开辟管道
pipe(self->pool[i].fifo_fd); pipe(self->pool[i].fifo_fd);
//启动线程 //启动线程
args arg; net_args *arg = (net_args*)malloc(sizeof(net_args));
arg.pth =&self->pool[i]; arg->pth = &self->pool[i];
arg.log = self->logmanager; arg->log = self->logmanager;
self->pool[i].status = 1; self->pool[i].status = 1;
pthread_create(&self->pool[i].pthread_id,NULL,pth_module,(void*)&arg); pthread_create(&self->pool[i].pthread_id,NULL,pth_module,(void*)arg);
} }
} }
int shutdown_pool(netm *self) int shutdown_pool(netm *self)
{ {
for(int i = 0;i<MAX_POOL;i++) for(int i = 0;i<NET_MAX_POOL;i++)
{ {
close(self->pool[i].fifo_fd[0]); if(self->pool[i].status == -1)
continue;
self->pool[i].status = -1;
close(self->pool[i].fifo_fd[1]);
} }
self->statue = ALL_STOP;
return 1;
} }
int server_run(int port,int fifo_fd,netm *self) int server_run(int port,int fifo_fd,netm *self)
{ {
int epfd = epoll_create1(EPOLL_CLOEXEC); // 推荐 int epfd = epoll_create1(EPOLL_CLOEXEC);
if (epfd == -1) { if (epfd == -1) {
perror("epoll_create1"); perror("epoll_create1");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
struct epoll_event ev;
//设置epoll同时监听控制管道与http请求
ev.events = EPOLLIN;
ev.data.fd = fifo_fd;
epoll_ctl(epfd, EPOLL_CTL_ADD, fifo_fd, &ev);
char iss_buf[256]; char iss_buf[256];
int http_fd = init_network(port); self->http_fd = init_http_network(port,self->logmanager);
struct epoll_event events;
ev.data.fd = self->http_fd;
epoll_ctl(epfd, EPOLL_CTL_ADD, self->http_fd, &ev);
struct epoll_event events[10];
self->epoll_fd = epfd;
self->statue = SERVER_ON;
for(;;) for(;;)
{ {
int nf = epoll_wait(epfd,&events,1,-1); /*工作循环-----------------------------*/
int nf = epoll_wait(epfd,events,10,-1);
if (nf == -1) { if (nf == -1) {
perror("epoll_wait"); perror("epoll_wait");
break; break;
} }
if(events.data.fd ==http_fd) for(int i = 0; i<nf;i++){
if(events[i].data.fd ==self->http_fd)
{ {
sprintf(iss_buf,"s/%d/e",accept4(http_fd,NULL,NULL,SOCK_NONBLOCK | SOCK_CLOEXEC)); int nt_fd = accept4(self->http_fd,NULL,NULL,SOCK_NONBLOCK | SOCK_CLOEXEC);
printf("%d\n",nt_fd);
if(nt_fd == -1)
continue;
sprintf(iss_buf,"s/%d/e",nt_fd);
self->iss_work(self,iss_buf); self->iss_work(self,iss_buf);
} }
if(events.data.fd == fifo_fd) if(events[i].data.fd == fifo_fd) {
{ char buffer[256];
char command; ssize_t bytes_read;
while(read(fifo_fd,&command,1)==1)
{ // 一次性读取所有可用数据
switch(command){ bytes_read = read(fifo_fd, buffer, sizeof(buffer));
if (bytes_read > 0) {
printf("DEBUG: Read %zd bytes from pipe: ", bytes_read);
for (int j = 0; j < bytes_read; j++) {
printf("%c ", buffer[j]);
}
printf("\n");
// 处理每个命令(按接收顺序)
for (int j = 0; j < bytes_read; j++) {
printf("Processing command[%d]: %c\n", j, buffer[j]);
switch(buffer[j]) {
case 'q': case 'q':
//退出逻辑 printf("Quit command found at position %d\n", j);
break; quit_server(self);
return 1; // 立即退出,不处理后续命令
case 'u': case 'u':
//插件更新逻辑 printf("Update command\n");
// 更新逻辑
break; break;
default:
printf("Unknown command: %c (ASCII: %d)\n",
buffer[j], buffer[j]);
}
}
} else if (bytes_read == 0) {
printf("Pipe closed by writer\n");
close(fifo_fd);
} else if (errno != EAGAIN && errno != EWOULDBLOCK) {
perror("Error reading from pipe");
} }
} }
} }
/*工作循环----------------------------*/
} }
} }
@ -231,7 +307,8 @@ void *run_network(void *self_d)
{ {
netm *self = (netm*)self_d; netm *self = (netm*)self_d;
self->start_pool(self); self->start_pool(self);
server_run(self->port,self->fifo_fd[1],self); self->statue = POOL_ON;
server_run(self->port,self->fifo_fd[0],self);
self->shutdown_pool(self); self->shutdown_pool(self);
} }
@ -245,7 +322,10 @@ int init_networkmanager(netm *self,int *fifo,log_manager *logmanager,int port)
self->fifo_fd[0]= fifo[0]; self->fifo_fd[0]= fifo[0];
self->fifo_fd[1]= fifo[1]; self->fifo_fd[1]= fifo[1];
self->last_alc = 0; self->last_alc = 0;
self->port = port;
//初始化参数 //初始化参数
self->logmanager = logmanager; self->logmanager = logmanager;
self->port = port; self->err_indictor = (indiector*)malloc(sizeof(indiector));
self->statue = ALL_STOP;
return 0;
} }

31
c/network/network.h Normal file → Executable file
View File

@ -1,10 +1,13 @@
#ifndef NETWORK #ifndef NETWORK
#define NETWORK #define NETWORK
#define MAX_POOL 24 #define POOL_ON 1
#define MAX_MESSAGE_BUF 10240 #define SERVER_ON 2
#define ALL_STOP 0
#include <pthread.h> #include <pthread.h>
#include<tools/log/log.h> #include "tools/log/log.h"
#include "erroprocess/erroprocess.h"
#include <stdatomic.h> #include <stdatomic.h>
//单个线程模型 //单个线程模型
typedef struct pthread_module typedef struct pthread_module
@ -13,32 +16,38 @@ typedef struct pthread_module
int fifo_fd[2]; int fifo_fd[2];
atomic_int status; atomic_int status;
}pth_m; }pth_m;
//打包线程模型参数
typedef struct args typedef struct net_args
{ {
log_manager *log; log_manager *log;
pth_m *pth; pth_m *pth;
}args; }net_args;
typedef struct network_manager typedef struct network_manager//网络管理器
{ {
void *(*run_network)(void*); pth_m pool[NET_MAX_POOL];
void *(*run_network)(void*);//启动网络监听
int (*start_pool)(struct network_manager*); int (*start_pool)(struct network_manager*);
int (*shutdown_pool)(struct network_manager*); int (*shutdown_pool)(struct network_manager*);
int (*iss_work)(struct network_manager*,char *); int (*iss_work)(struct network_manager*,char *);
pth_m pool[MAX_POOL];
int fifo_fd[2]; int fifo_fd[2];
pthread_t pid;
log_manager *logmanager; log_manager *logmanager;
indiector *err_indictor;
int last_alc; int last_alc;
int port; int port;
int epoll_fd;
int http_fd;
int statue;
}netm; }netm;
typedef struct rebot_message typedef struct rebot_message
{ {
char raw_message[NET_MAX_MESSAGE_BUF];
char nickname[64];
char gid[32]; char gid[32];
char uid[32]; char uid[32];
char nickname[64];
char raw_message[MAX_MESSAGE_BUF];
char message_type; char message_type;
sem_t status; sem_t status;
int state; int state;

17
c/network/protocal.h Normal file
View File

@ -0,0 +1,17 @@
#ifndef PROTOCAL
#define PROTOCAL
typedef struct network_pakage
{
char *data;
int buf_block;
}network_package;
typedef struct net_protocal
{
void *protocal;
int (*init)(void *self);
int (*rev_message)(void *self,network_package *data);
}net_protocal;
#endif

39
c/network/swap.c Normal file → Executable file
View File

@ -8,27 +8,46 @@
#include <linux/memfd.h> #include <linux/memfd.h>
#include <sys/syscall.h> #include <sys/syscall.h>
#include <sys/mman.h> #include <sys/mman.h>
#include "network.h" #include <fcntl.h>
int make_swap(void *message) #include "network.h"
#include "swap.h"
int make_swap(rbt_msg *swap)
{ {
rbt_msg *msg = (rbt_msg*)message; swap->state = NEWMSG;
printf("gid=%s uid=%s nick=%s raw=%s type=%c\n", sem_post(&swap->status);
msg->gid, msg->uid, msg->nickname,
msg->raw_message, msg->message_type);
} }
int create_swap(const char *name) int create_swap(const char *name)
{ {
int fd = memfd_create(name,0); int fd = memfd_create(name,0);
//申请共享内存 //申请共享内存
ftruncate(fd, sizeof(rbt_msg)); ftruncate(fd, sizeof(rbt_msg));
//调整关闭策略
int flags = fcntl(fd, F_GETFD);
flags &= ~FD_CLOEXEC;
fcntl(fd, F_SETFD, flags);
//调整大小 //调整大小
rbt_msg *init_msg = (rbt_msg*)mmap(NULL, sizeof(rbt_msg), PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); rbt_msg *init_msg = (rbt_msg*)mmap(NULL, sizeof(rbt_msg), PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
char buf[MAX_MESSAGE_BUF] = {'\0'}; char buf[NET_MAX_MESSAGE_BUF] = {'\0'};
memcpy(init_msg->raw_message,buf,MAX_MESSAGE_BUF);
memcpy(init_msg->nickname,buf,64);
munmap((void*)init_msg,sizeof(rbt_msg));
//初始化 //初始化
memcpy(init_msg->raw_message,buf,NET_MAX_MESSAGE_BUF);
memcpy(init_msg->nickname,buf,64);
sem_init(&init_msg->status,1,1);
init_msg->raw_message[0] = '\0';
init_msg->state = MEM_FREE;
init_msg->uid[0] = '\0';
munmap((void*)init_msg,sizeof(rbt_msg));
return fd; return fd;
} }
int close_swap(int shmid,rbt_msg *swap)
{
swap->state = QUITPLG;//置退出态
sem_post(&swap->status);//发送信号量
close(shmid);//关闭共享内存
}

8
c/network/swap.h Normal file → Executable file
View File

@ -1,7 +1,13 @@
#ifndef SWAP #ifndef SWAP
#define SWAP #define SWAP
int make_swap(void *); #include "config.h"
#define QUITPLG 0
#define NEWMSG 1
#define SW_FREE 2
int make_swap(rbt_msg *swap);
int create_swap(const char *name); int create_swap(const char *name);
int close_swap(int shmid,rbt_msg *swap);
#endif #endif

2
c/run_pluginmanager/run_pluginmanager.c Normal file → Executable file
View File

@ -4,6 +4,6 @@ int main(int argc,char **argv)
{ {
for(;;) for(;;)
{ {
sleep(10);
} }
} }

0
c/run_pluginmanager/run_pluginmanager.h Normal file → Executable file
View File

58
c/tem/ctl.c Normal file → Executable file
View File

@ -5,7 +5,11 @@
#include <stddef.h> #include <stddef.h>
#include <string.h> #include <string.h>
#include <termios.h> #include <termios.h>
#include <pthread.h>
#include <signal.h>
#include "ctl.h" #include "ctl.h"
#include "interpreter/interpreter.h" #include "interpreter/interpreter.h"
#include "tools/log/log.h" #include "tools/log/log.h"
@ -31,7 +35,9 @@ int replace_chars(int start_pos, int old_len, const char *new_str) {
// 3. 如果新内容比原内容短,删除剩余部分 // 3. 如果新内容比原内容短,删除剩余部分
if (new_len < old_len) { if (new_len < old_len) {
write(STDOUT_FILENO, "\033[K", 3); write(STDOUT_FILENO, "\033[K", 3);
return 0 ;
} }
return 0;
} }
int take_history(Ctl *self,int *currant_index,int *length,char *buf,int toward) int take_history(Ctl *self,int *currant_index,int *length,char *buf,int toward)
@ -41,12 +47,12 @@ int take_history(Ctl *self,int *currant_index,int *length,char *buf,int toward)
if(*currant_index>0) if(*currant_index>0)
(*currant_index)--; (*currant_index)--;
else else
*currant_index = HISTORY_BUF-1; *currant_index = TEM_HISTORY_BUF-1;
} }
else if(toward == 0) else if(toward == 0)
{ {
if(*currant_index <HISTORY_BUF-1) if(*currant_index <TEM_HISTORY_BUF-1)
(*currant_index)++; (*currant_index)++;
else else
*currant_index = 0; *currant_index = 0;
@ -56,8 +62,8 @@ int take_history(Ctl *self,int *currant_index,int *length,char *buf,int toward)
*length = *length-2; *length = *length-2;
return 0; return 0;
} }
replace_chars(sizeof(PROMPT)-1,*length,self->history[*currant_index]); replace_chars(sizeof(TEM_PROMPT)-1,*length,self->history[*currant_index]);
memcpy(buf,self->history[*currant_index],MAX_BUF); memcpy(buf,self->history[*currant_index],TEM_MAX_BUF);
buf[strlen(buf)-1] = '\0'; buf[strlen(buf)-1] = '\0';
*length = strlen(buf); *length = strlen(buf);
return 0; return 0;
@ -67,7 +73,7 @@ int take_history(Ctl *self,int *currant_index,int *length,char *buf,int toward)
int del_char(int length, int index, char *buf) int del_char(int length, int index, char *buf)
{ {
int buf_idx = index - sizeof(PROMPT); // 待删字符在 buf 中的下标 int buf_idx = index - sizeof(TEM_PROMPT); // 待删字符在 buf 中的下标
if (length == index) // 行尾退格 if (length == index) // 行尾退格
{ {
@ -82,7 +88,7 @@ int del_char(int length, int index, char *buf)
goto_col(length - 2); goto_col(length - 2);
write(STDOUT_FILENO, "\033[K", 3); write(STDOUT_FILENO, "\033[K", 3);
goto_col(index - 1); goto_col(index - 1);
char *restr = buf+index-sizeof(PROMPT)+1; char *restr = buf+index-sizeof(TEM_PROMPT)+1;
memcpy(restr,new_str,str_len); memcpy(restr,new_str,str_len);
free(new_str); free(new_str);
return 1; return 1;
@ -125,7 +131,7 @@ int read_line(char *buf,Ctl *self)
char input_buf; char input_buf;
int cursor_index = 0; int cursor_index = 0;
int currant_index = self->index; int currant_index = self->index;
while(read(0,&input_buf,1)==1&&length<MAX_BUF) while(read(0,&input_buf,1)==1&&length<TEM_MAX_BUF)
{ {
switch (input_buf) { switch (input_buf) {
case '\n': case '\n':
@ -141,7 +147,7 @@ int read_line(char *buf,Ctl *self)
break; break;
length--; length--;
get_cursor(&cursor_index); get_cursor(&cursor_index);
del_char(length+sizeof(PROMPT),cursor_index-1,buf); del_char(length+sizeof(TEM_PROMPT),cursor_index-1,buf);
break; break;
//方向键 //方向键
case 0x41: case 0x42: case 0x43: case 0x44: case 0x41: case 0x42: case 0x43: case 0x44:
@ -161,7 +167,7 @@ int read_line(char *buf,Ctl *self)
case 0x43: case 0x43:
get_cursor(&cursor_index); get_cursor(&cursor_index);
length = length-2; length = length-2;
if(cursor_index == sizeof(PROMPT)+length) if(cursor_index == sizeof(TEM_PROMPT)+length)
{ {
break; break;
} }
@ -170,7 +176,7 @@ int read_line(char *buf,Ctl *self)
case 0x44: case 0x44:
get_cursor(&cursor_index); get_cursor(&cursor_index);
length = length -2; length = length -2;
if(cursor_index == sizeof(PROMPT)) if(cursor_index == sizeof(TEM_PROMPT))
{ {
break; break;
} }
@ -188,28 +194,32 @@ int read_line(char *buf,Ctl *self)
} }
} }
if(length>=MAX_BUF) if(length>=TEM_MAX_BUF)
{ {
perror("SYS:input pass edge"); perror("SYS:input pass edge");
return 0;
} }
return 0;
} }
int infifo(Ctl *self,const char *cmd) int infifo(Ctl *self,const char *cmd)
{ {
if(self->history[self->index]!=NULL){ if(self->history[self->index]!=NULL){
memcpy(self->history[self->index],cmd,MAX_BUF); memcpy(self->history[self->index],cmd,TEM_MAX_BUF);
} }
else{ else{
self->history[self->index] = (char*)malloc(MAX_BUF*sizeof(char)); self->history[self->index] = (char*)malloc(TEM_MAX_BUF*sizeof(char));
memcpy(self->history[self->index],cmd,MAX_BUF); memcpy(self->history[self->index],cmd,TEM_MAX_BUF);
} }
//存储命令历史s //存储命令历史s
if(self->index<HISTORY_BUF){ if(self->index<TEM_HISTORY_BUF){
self->index++; self->index++;
return 0;
} }
else{ else{
self->index = 0; self->index = 0;
return 0;
} }
} }
@ -228,29 +238,29 @@ int free_history(Ctl *self)
int teml(Ctl *self,int fifo[2]) int teml(Ctl *self,int fifo[2])
{ {
char input[MAX_BUF] = {'\0'}; char input[TEM_MAX_BUF] = {'\0'};
ctx *command = (ctx*)malloc(sizeof(ctx)); ctx *command = (ctx*)malloc(sizeof(ctx));
Cmd cmd_dir[10]; Cmd cmd_dir[10];
init_interpreter(cmd_dir,command,fifo);//初始化解释器 init_interpreter(cmd_dir,command,fifo,self->logmanager);
//创建线程用于定期清理日志
pthread_create(&self->logwathcher,NULL,self->logmanager->clear_log,self->logmanager);
command->statue = 0; command->statue = 0;
self->command = command;
do do
{ //设置缓冲区,接收用户输入 { //设置缓冲区,接收用户输入
write(STDOUT_FILENO,PROMPT,sizeof(PROMPT)); write(STDOUT_FILENO,TEM_PROMPT,sizeof(TEM_PROMPT));
command->line = read_line(input,self); command->line = read_line(input,self);
if(command->line == -1) if(command->line == -1)
perror("sys error"); perror("sys error");
//将用户输入入队 //将用户输入入队
infifo(self,input); infifo(self,input);
self->logmanager->in_log(self->logmanager,input,"USER:");
memcpy(command->command,input,sizeof(input)); memcpy(command->command,input,sizeof(input));
interpret(SIG_MOD,command,cmd_dir); interpret(SIG_MOD,command,cmd_dir);
const char fexp[256] = {'\0'}; const char fexp[256] = {'\0'};
memcpy(&input,&fexp,MAX_BUF); memcpy(&input,&fexp,TEM_MAX_BUF);
}while(command->statue == 0); }while(command->statue == 0);
close(fifo[0]);
close(fifo[1]);
free_history(self); free_history(self);
self->command = NULL;
free(command); free(command);
} }
@ -262,6 +272,8 @@ Ctl *init_tem(log_manager *logmanager)
tem->infifo = infifo; tem->infifo = infifo;
tem->index = 0; tem->index = 0;
tem->logmanager = logmanager; tem->logmanager = logmanager;
char *his_buf[TEM_HISTORY_BUF] = {NULL};
memcpy(tem->history,his_buf,TEM_HISTORY_BUF);
for(int i =0;i<6;i++) for(int i =0;i<6;i++)
{ {
tem->history[i] = NULL; tem->history[i] = NULL;

13
c/tem/ctl.h Normal file → Executable file
View File

@ -2,11 +2,11 @@
#define CTL #define CTL
#include <pthread.h> #include <pthread.h>
#include "tools/toml/toml.h"
#include "tools/log/log.h" #include "tools/log/log.h"
#include "interpreter/interpreter.h"
#include "config.h"
#define MAX_BUF 256
#define HISTORY_BUF 256
#define PROMPT "chatbot$$ "
typedef struct Ctl typedef struct Ctl
@ -14,11 +14,14 @@ typedef struct Ctl
int (*run)(struct Ctl*,int *); int (*run)(struct Ctl*,int *);
int (*infifo)(struct Ctl*,const char*); int (*infifo)(struct Ctl*,const char*);
int index; int index;
char *history[HISTORY_BUF]; char *history[TEM_HISTORY_BUF];
pthread_t logwathcher;
log_manager *logmanager; log_manager *logmanager;
ctx *command;//解释器上下文
toml_table_t *config;
}Ctl; }Ctl;
Ctl *init_tem(log_manager *logmanager); Ctl *init_tem(log_manager *logmanager);
int free_history(Ctl *self);
#endif #endif

233
c/tools/log/log.c Normal file → Executable file
View File

@ -1,36 +1,191 @@
#define _POSIX_C_SOURCE 200112L
#include "log.h" #include "log.h"
#include <stdio.h> #include <stdio.h>
#include <stddef.h> #include <stddef.h>
#include <stdlib.h> #include <stdlib.h>
#include <unistd.h> #include <unistd.h>
#include <time.h>
#include <errno.h>
#include <fcntl.h>
#include <string.h>
int in_log(logs *log,log_manager *self)
logs* getbody(void **log_p)
{ {
sem_wait(&self->log_sem);//加锁 return (logs*)*log_p;
logs *buf = self->rear; }
if(self->log == NULL){ int write_into_block(char *writein,char *org,size_t* length,size_t maxlength,char *logname)
self->log = log; {
self->rear = log; if(writein == NULL||org == NULL||length == NULL||logname == NULL)
return -1;
if(*length+strlen(org)<maxlength-1)
{
strcpy(&writein[*length],org);
*length +=strlen(org);//栈内存充足
}
else
{
int n = *length + strlen(org) - maxlength+1;
strncpy(&writein[*length],org,strlen(org)-n);//栈内存不足
writein[maxlength-1] = '\0';
int fd = open(logname,O_CREAT | O_WRONLY | O_APPEND, 0644);
if(fd != -1)
{
int eno = write(fd,writein,strlen(writein));
if(eno <strlen(writein))
perror("log");
close(fd);
}
else if(fd == -1)
perror("log:");//仅警告
strncpy(writein,&org[0],n);//剩余部分拷贝
*length = n;
}
return 0; return 0;
} }
self->count++;
buf->next = log; int in_log(log_manager *self,const char *logbody,const char *info)
{
if(self == NULL)
return -1;
void **log_p = self->mempool->GetBlock(self->mempool,LOGMOD);
if(log_p == NULL)
{
perror("Mem_runout");
return -1;
}
logs *log = getbody(log_p);
snprintf(log->info,INFO_LENGTH,"%s",info);
snprintf(log->log,MAX_LOG_LENGTH,"%s",logbody);
log->log[MAX_LOG_LENGTH-1] = '\0';
log->next = NULL; log->next = NULL;
sem_wait(&self->log_sem);//加锁
if(self->log == NULL){
self->log = log_p;
self->rear = getbody(log_p);
atomic_fetch_add(&self->count,1);
sem_post(&self->log_sem);
return self->count;
}
if(self->count == 1){
logs *p = getbody(self->log);
p->next = log_p;
}
self->count++;
log->next = NULL;
self->rear->next = log_p;
self->rear = log; self->rear = log;
sem_post(&self->log_sem); sem_post(&self->log_sem);
return self->count; return self->count;
} }
logs *out_log(log_manager *self) int sleep_with_signal(log_manager *self)
{ {
sem_wait(&self->log_sem); struct timespec ts;
logs *buf = self->log; int rc;
if(self->log->next ==NULL)
self->log = self->rear = NULL; /* 计算绝对超时:当前 + 1000 s */
self->count--; if (clock_gettime(CLOCK_MONOTONIC, &ts) != 0)
return -1; /* 罕见失败 */
ts.tv_sec += LOG_SLEEP_LENGTH;
/* 纳秒部分无需处理1000 s 整不会溢出 */
pthread_mutex_lock(&self->mtx); /* 进入临界区 */
while (1) {
rc = pthread_cond_timedwait(&self->cond, &self->mtx, &ts);
if (rc == ETIMEDOUT) { /* 1000 s 到点 */
pthread_mutex_unlock(&self->mtx);
return 1; /* 正常超时 */
}
if (rc != 0) { /* 其他错误 */
pthread_mutex_unlock(&self->mtx);
return -1;
}
/* 被 signal / broadcast 提前唤醒,检查 stop */
if (self->stop == 1) {/* 主线程要求退出 */
pthread_mutex_unlock(&self->mtx);
return 0; /* 告诉调用者:该结束了 */
}
}
}
int cleanup(log_manager *self)
{
if(self->log ==NULL)
return 1;
logs *tobeclean,*loc;
void **tobeclean_p;
sem_wait(&self->log_sem);//获取信号量
void **loc_p = self->log;
self->log = NULL;
atomic_store(&self->count,0);//摘取log链
sem_post(&self->log_sem); sem_post(&self->log_sem);
buf->next =NULL; //释放信号量
return buf; loc = getbody(loc_p);
char logbuf[MAX_LOG_LENGTH];
size_t buf_length = 0;
int fd;
while(loc->next !=NULL)
{
tobeclean_p = loc_p;
tobeclean = getbody(tobeclean_p);
loc_p = loc->next;
loc = getbody(loc_p);
int eno = write_into_block(logbuf,tobeclean->info,&buf_length,MAX_LOG_LENGTH,"log.txt");
if(eno == -1)
perror("log");
eno = write_into_block(logbuf,":",&buf_length,MAX_LOG_LENGTH,"log.txt");
eno = write_into_block(logbuf,tobeclean->log,&buf_length,MAX_LOG_LENGTH,"log.txt");
if(eno == -1)
perror("log");//非业务逻辑只警告
self->mempool->FreeBlock(self->mempool,tobeclean_p);
}
write_into_block(logbuf,loc->info,&buf_length,MAX_LOG_LENGTH,"log.txt");
write_into_block(logbuf,":",&buf_length,MAX_LOG_LENGTH,"log.txt");
write_into_block(logbuf,loc->log,&buf_length,MAX_LOG_LENGTH,"log.txt");
self->mempool->FreeBlock(self,loc_p);
fd = open("log.txt",O_CREAT | O_WRONLY | O_APPEND, 0644);
if(fd == -1){
perror("log:");
}
int error_buf = write(fd,logbuf,strlen(logbuf));
if(error_buf==-1){
return -1;
}
else if(error_buf<strlen(logbuf)){
perror("file");
write(fd,"unknown error case log write cut down\n",38);
}
close(fd);
return 0;
}
void log_manager_stop(log_manager *self)
{
pthread_mutex_lock(&self->mtx);
if(self->stop == 1){
pthread_mutex_unlock(&self->mtx);
return ;
}
self->stop = 1;
/* 置退出标志 */
printf("SYS:stopping loger\n");
self->in_log(self,"stopping loger\n","SYS:");
printf("SYS:done\n");
self->in_log(self,"done","SYS:");
pthread_mutex_unlock(&self->mtx);
pthread_cond_broadcast(&self->cond); /* 唤醒所有等待线程 */
} }
//定期清理函数 //定期清理函数
@ -39,35 +194,55 @@ void *clear_log(void *self_p)
log_manager *self = (log_manager*)self_p; log_manager *self = (log_manager*)self_p;
for(;;) for(;;)
{ {
sleep(1000); sleep_with_signal(self);
sem_wait(&self->log_sem); sem_wait(&self->log_sem);
if(self->count<256){ if((self->count<MAX_LOG||self->log==NULL)&&self->stop !=1){
sem_post(&self->log_sem); sem_post(&self->log_sem);
continue; continue;
} }
logs* buf = self->log;
self->log = self->rear =NULL;
sem_post(&self->log_sem); sem_post(&self->log_sem);
logs* tobeclear; cleanup(self);
while(buf->next !=NULL) if(self->stop == 1){
{ return NULL;
tobeclear = buf;
buf = buf->next;
free(tobeclear);
} }
} }
} }
int init_loger(log_manager *self) int init_loger(log_manager *self,mem_ctl *mempool)
{ {
if(self == NULL) if(self == NULL)
{ {
perror("NULL\n"); perror("NULL\n");
return -1; return -1;
} }
sem_init(&self->log_sem, 0,1); if(sem_init(&self->log_sem, 0,1)==-1)
return -1;
if(pthread_mutex_init(&self->mtx,NULL)==-1)
{
if(sem_destroy(&self->log_sem)==-1)
{
perror("log:");
}
return -1;
}
if(pthread_cond_init(&self->cond,NULL)==-1)
{
if(sem_destroy(&self->log_sem)==-1)
{
perror("log:");
}
if(pthread_mutex_destroy(&self->mtx)==-1)
{
perror("log:");
}
return -1;
}
self->in_log = in_log; self->in_log = in_log;
self->out_log = out_log;
self->clear_log = clear_log; self->clear_log = clear_log;
self->log = NULL; self->log = NULL;
self->stop = 0;
self->cleanup = cleanup;
atomic_init(&self->count,0);
self->mempool = mempool;
return 0;
} }

25
c/tools/log/log.h Normal file → Executable file
View File

@ -1,27 +1,36 @@
#ifndef LOG #ifndef LOG
#define LOG #define LOG
#include "config.h"
#include "memctl/memctl.h"
#include <semaphore.h> #include <semaphore.h>
#include <pthread.h>
#define MAX_LOG 256
typedef struct logs typedef struct logs
{ {
char log[1024]; char log[MAX_LOG_LENGTH];
struct logs *next; void **next;
char info[INFO_LENGTH];
}logs; }logs;
typedef struct log_manager typedef struct log_manager
{ {
int (*in_log)(logs *,struct log_manager*); pthread_t pid;
logs* (*out_log)(struct log_manager*); mem_ctl *mempool;
int (*in_log)(struct log_manager*,const char *,const char *);
void *(*clear_log)(void*); void *(*clear_log)(void*);
int (*cleanup)(struct log_manager*);
sem_t log_sem; sem_t log_sem;
logs *log; void **log;
logs *rear; logs *rear;
int count; atomic_int count;
pthread_mutex_t mtx;
pthread_cond_t cond;
int stop;
}log_manager; }log_manager;
int init_loger(log_manager *self); void log_manager_stop(log_manager *self);
int init_loger(log_manager *self,mem_ctl *mempool);
#endif #endif

0
c/tools/pkgmanager/pkginstall.c Normal file → Executable file
View File

0
c/tools/pkgmanager/pkginstall.h Normal file → Executable file
View File

View File

View File

100
c/tools/quit/quit.c Normal file → Executable file
View File

@ -1,7 +1,105 @@
#define _GNU_SOURCE
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h>
#include<unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/epoll.h>
#include "quit.h"
#include "tem/ctl.h"
#include "tools/toml/toml.h"
void *quit_all(void *self_d)
int quit_server(netm *self)
{
if(self ==NULL)
return -1;
//关闭epoll监听
if(self->epoll_fd != -1)
{
epoll_ctl(self->epoll_fd,EPOLL_CTL_DEL,self->http_fd,NULL);
epoll_ctl(self->epoll_fd,EPOLL_CTL_DEL,self->fifo_fd[0],NULL);
self->epoll_fd = -1;
}
//关闭socket监听
if(self->http_fd != -1)
{
shutdown(self->http_fd, SHUT_RDWR);
if(close(self->http_fd)==-1)
perror("http");
self->http_fd =-1;
}
//关闭管道监听
if(self->fifo_fd[1] != -1)
{
if(close(self->fifo_fd[1])==-1)
return -1;
self->fifo_fd[1] = -1;
}
free(self->err_indictor);
self->statue = POOL_ON;
return 0;
}
int quit_mempool(mem_ctl *mem_ctler)
{ {
} }
void quit_all(int status,void *self_p)
{
alres *resouce =(alres*)self_p;
//转换参数
resouce->network->shutdown_pool(resouce->network);
if(resouce->network->statue == SERVER_ON)
{
quit_server(resouce->network);
}
if(resouce->network->statue == POOL_ON)
{
resouce->network->shutdown_pool(resouce->network);
}
resouce->loger->in_log(resouce->loger,"shutting down network pool","SYS:");
free(resouce->network);
//释放网络资源
if(resouce->tem->command !=NULL){
free_history(resouce->tem);
if(resouce->tem->command->arg != NULL)
{
args* arg = resouce->tem->command->arg;
if(arg->next !=NULL)
{
while(arg->next != NULL){
args* tobefree = arg;
arg = arg->next;
free(tobefree);
}
free(arg);
}
}
toml_free(resouce->tem->config);
free(resouce->tem->command);
}
//释放终端资源
//释放日志管理器
if(resouce->loger->pid != -1){
log_manager_stop(resouce->loger);
pthread_join(resouce->loger->pid,NULL);
}
pthread_mutex_destroy(&resouce->loger->mtx);
pthread_cond_destroy(&resouce->loger->cond);
log_manager_stop(resouce->loger);
sem_destroy(&resouce->loger->log_sem);
//销毁信号量
free(resouce->loger);
//清理日志
free(resouce);
}

23
c/tools/quit/quit.h Normal file → Executable file
View File

@ -1,6 +1,23 @@
#ifndef QUIT #ifndef QUIT_LIB
#define QUIT #define QUIT_LIB
#include "network/network.h"
#include "tem/ctl.h"
#include "tools/log/log.h"
#include "memctl/memctl.h"
typedef struct all_resources
{
Ctl *tem;
netm *network;
log_manager *loger;
mem_ctl *memctler;
}alres;
void quit_all(int status,void *self_p);
int quit_server(netm *self);
void *quitall(int status,void *arg);
#endif #endif

0
c/tools/toml/toml.c Normal file → Executable file
View File

0
c/tools/toml/toml.h Normal file → Executable file
View File

0
config/config.toml Normal file → Executable file
View File

0
src/file_store_api.py Normal file → Executable file
View File

0
src/modules/__init__.py Normal file → Executable file
View File

0
src/modules/plugin_modules.py Normal file → Executable file
View File

0
src/modules/user_modules.py Normal file → Executable file
View File

0
src/plugin_manager.py Normal file → Executable file
View File