init
This commit is contained in:
commit
70d467d052
97 files changed
+10386
No files matched your search
@@ -0,0 +1,177 @@
|
||||
|
||||
//作者:简单
|
||||
//修改:qing
|
||||
/*
|
||||
* C++17支持了中文变量名,配合define预编译指令可以将代码中文化。
|
||||
*
|
||||
* 在C语言中,变量名只能由字母、数字或是下划线组成。
|
||||
* 由于C++语言兼容C语言,最开始的C++是不能够使用多字节变量名的。
|
||||
*
|
||||
* */
|
||||
#ifndef __中文模式
|
||||
#define __中文模式
|
||||
#include <stdint.h>
|
||||
/*保留字*/
|
||||
#define 使用 using
|
||||
#define 命名空间 namespace
|
||||
#define 取别名 typedef
|
||||
#define 覆盖 override
|
||||
#define 取内存大小 sizeof
|
||||
#define 返回 return
|
||||
#define 如果 if
|
||||
#define 否则 else
|
||||
#define 又或者 else if
|
||||
#define 真 true
|
||||
#define 假 false
|
||||
//#define 且 and
|
||||
//#define 或 or
|
||||
#define 空类型 void
|
||||
#define 常量 const
|
||||
#define 有符号 signed
|
||||
#define 无符号 unsigned
|
||||
#define 文件 FILE
|
||||
#define 文件结束 EOF
|
||||
#define 类 class
|
||||
#define 结构体 struct
|
||||
#define 枚举类型 enum
|
||||
#define 对象 this
|
||||
#define 抛出异常 throw
|
||||
#define 新建 new
|
||||
//#define 新的 new
|
||||
#define 删除 delete
|
||||
#define 跳出 break
|
||||
#define 继续 continue
|
||||
#define 判断循环 while
|
||||
#define 循环判断 do
|
||||
#define 循环判断尾 while
|
||||
#define 分支选择 switch
|
||||
#define 支系 case
|
||||
#define 缺省 default
|
||||
#define 计次循环 for
|
||||
#define 尝试 try
|
||||
#define 获取异常 catch
|
||||
#define 捕获异常 catch
|
||||
#define 退出 exit
|
||||
#define 公开的 public
|
||||
#define 受保护的 protected
|
||||
#define 私有的 private
|
||||
#define 外部的 extern
|
||||
#define 静态的 static
|
||||
#define 虚拟的 virtual
|
||||
|
||||
#define 有号8位整 int8_t
|
||||
#define 无号8位整 uint8_t
|
||||
#define 有号16位整 int16_t
|
||||
#define 无号16位整 uint16_t
|
||||
#define 有号32位整 int32_t
|
||||
#define 无号32位整 uint32_t
|
||||
#define 有号64位整 int64_t
|
||||
#define 无号64位整 uint64_t
|
||||
|
||||
#define 空的 NULL
|
||||
#define 空指针 nullptr
|
||||
#define 整数 int
|
||||
#define 字符 char
|
||||
#define 短整数 short
|
||||
#define 长型 long
|
||||
#define 超长型 long long
|
||||
#define 单精度小数 float
|
||||
#define 双精度小数 double
|
||||
#define 长度单位 size_t
|
||||
#define 布尔 bool
|
||||
#define 逻辑型 bool
|
||||
#define 可变类型 auto
|
||||
#define 自动的 auto
|
||||
#define 适应 auto
|
||||
#define _文件 FILE
|
||||
#define _文件结束 EOF
|
||||
#define _读模式 "r"
|
||||
#define _写模式 "w"
|
||||
#define 模板 template
|
||||
#define 类型名 typename
|
||||
#define 默认的 default
|
||||
#define 被删除 delete
|
||||
#define 入口 main
|
||||
#define 主函数 main
|
||||
#define 或 ||
|
||||
#define 或者 ||
|
||||
#define 而且 &&
|
||||
#define 且 &&
|
||||
#define 等于 ==
|
||||
#define 大于等于 >=
|
||||
#define 小于等于 <=
|
||||
#define 大于 >
|
||||
#define 小于 <
|
||||
#define 不报错的 noexcept
|
||||
#define 不转换的 explicit
|
||||
#define 纯函数的 consteval
|
||||
#define 预求值的 constexpr
|
||||
|
||||
#define _加法重载 operator+
|
||||
#define _取下标重载 operator[]
|
||||
#define _开始 begin
|
||||
#define _结束 end
|
||||
//-----------------------------------------------------------
|
||||
//-----------------------------------------------------------
|
||||
//基本单元
|
||||
#ifdef __cplusplus
|
||||
#include <iostream>
|
||||
|
||||
命名空间 中文标准{
|
||||
|
||||
类 字符串 {
|
||||
公开的:
|
||||
/* 初始化为空字符串 */
|
||||
字符串() {
|
||||
对象->s = "";
|
||||
}
|
||||
/* 以字面量初始化 */
|
||||
字符串(常量 字符* 源) {
|
||||
对象->s = 源;
|
||||
}
|
||||
/* 访问器 */
|
||||
常量 字符* 取值() {
|
||||
返回 s.c_str();
|
||||
}
|
||||
/* */
|
||||
字符串& _加法重载(常量 字符* 乙方) {
|
||||
对象->s += 乙方;
|
||||
返回 *对象;
|
||||
}
|
||||
/* 字符串之间的连接 */
|
||||
字符串& _加法重载(字符串& 乙) {
|
||||
对象->s += 乙.取值();
|
||||
返回 *对象;
|
||||
}
|
||||
私有的:
|
||||
std::string s;
|
||||
};
|
||||
|
||||
类 标准输出{
|
||||
公开的:
|
||||
空类型 调试输出(常量 字符* 消息) {
|
||||
std::cout << 消息;
|
||||
}
|
||||
空类型 调试输出(字符串& 信) {
|
||||
std::cout<< 信.取值();
|
||||
}
|
||||
};
|
||||
|
||||
类 标准输入{
|
||||
公开的:
|
||||
字符串 取字符串(){
|
||||
std::string s;
|
||||
std::cin >> s;
|
||||
返回 字符串(s.c_str());
|
||||
}
|
||||
整数 取整数() {
|
||||
整数 数;
|
||||
std::cin >> 数;
|
||||
返回 数;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
#endif //__cplusplus
|
||||
#endif //__中文模式
|
||||
@@ -0,0 +1,129 @@
|
||||
#pragma once
|
||||
#include "中文化.hpp"
|
||||
#include "异常.hpp"
|
||||
命名空间 中文标准 {
|
||||
模板 <类型名 类型1>
|
||||
类 向量{
|
||||
公开的:
|
||||
|
||||
/* 注意:当长度单位为0时,内部指针是空的 */
|
||||
向量() {
|
||||
对象->指针 = 空指针;
|
||||
对象->容量 = 0;
|
||||
}
|
||||
/* 专门用于处理花括号初始化列表 */
|
||||
向量(常量 std::initializer_list<类型1>& init = {}) {
|
||||
对象->指针 = 新建 类型1[init.size()] {空的};
|
||||
对象->容量 = init.size();
|
||||
长度单位 计数 = 0;
|
||||
计次循环(适应 & 东西: init) {
|
||||
对象->指针[计数++] = 东西;
|
||||
}
|
||||
}
|
||||
|
||||
~向量() {
|
||||
删除 对象->指针;
|
||||
对象->指针 = 空指针;
|
||||
对象->容量 = 0;
|
||||
}
|
||||
/*----------访问器----------*/
|
||||
长度单位 取容量() {
|
||||
返回 对象->容量;
|
||||
}
|
||||
|
||||
布尔 是否为空() {
|
||||
返回 对象->容量 等于 0;
|
||||
}
|
||||
|
||||
/*--------运算符重载--------*/
|
||||
向量& _取下标重载( 常量 长度单位 下标 ) {
|
||||
如果(下标 < 0 或 下标 >= 对象->容量)
|
||||
抛出异常 下标越界{"向量", 对象->容量, 下标};
|
||||
返回 对象->指针[下标];
|
||||
}
|
||||
|
||||
/*--------可范围遍历--------*/
|
||||
类型1* _开始() {
|
||||
返回 对象->指针;
|
||||
}
|
||||
|
||||
类型1* _结束() {
|
||||
返回 对象->指针 + 对象->容量;
|
||||
}
|
||||
|
||||
/*----------变异器----------*/
|
||||
空类型 插入元素(常量 长度单位 位置, 常量 向量& 媒介) {
|
||||
|
||||
/* 越界检查 */
|
||||
如果(位置 < 0 或 位置 > 对象->容量)
|
||||
抛出异常 下标越界{"向量元素插入", 对象->容量+1, 位置};
|
||||
|
||||
适应 长度 = 取容量();
|
||||
适应 新的 = 新建 类型1[长度 + 1] { 空的 };
|
||||
|
||||
/* 插入位置之前 */
|
||||
计次循环(适应 计数 = 0; 计数 < 位置; ++计数)
|
||||
新的[计数] = 对象->指针[计数];
|
||||
|
||||
/* 执行插入 */
|
||||
新的[位置] = 媒介;
|
||||
|
||||
/* 插入位置之后 */
|
||||
计次循环(适应 计数 = 位置 + 1; 计数 <= 长度; ++计数)
|
||||
新的[计数] = 对象->指针[计数 - 1];
|
||||
|
||||
如果(对象->指针) 删除[] 对象->指针; /* 可能为空 */
|
||||
对象->指针 = 新的;
|
||||
}
|
||||
|
||||
空类型 追加元素(常量 向量& 媒介) {
|
||||
适应 长度 = 取容量();
|
||||
适应 新的 = 新建 类型1[长度 +1] {空的};
|
||||
计次循环(适应 计数 = 0; 计数 < 长度; ++计数)
|
||||
新的[计数] = 对象->指针[计数];
|
||||
新的[长度] = 媒介;
|
||||
如果(对象->指针) 删除[] 指针; /* 可能为空 */
|
||||
对象->指针 = 新的;
|
||||
}
|
||||
|
||||
空类型 删除元素(常量 长度单位 位置) {
|
||||
|
||||
/* 越界检查 */
|
||||
如果(位置 < 0 或 位置 >= 对象->容量)
|
||||
抛出异常 下标越界{"向量元素插入", 对象->容量 + 1, 位置};
|
||||
|
||||
适应 长度 = 取容量();
|
||||
适应 新的 = (长度 等于 1)
|
||||
? 空指针 : 新建 类型1[长度 - 1] { 空的 };
|
||||
|
||||
/* 目标位置之前 */
|
||||
计次循环(适应 计数 = 0; 计数 < 位置; ++计数)
|
||||
新的[计数] = 对象->指针[计数];
|
||||
|
||||
/* 目标位置之后 */
|
||||
计次循环(适应 计数 = 位置; 计数 < 长度; ++计数)
|
||||
新的[计数] = 对象->指针[计数 + 1];
|
||||
|
||||
删除[] 对象->指针;
|
||||
对象->指针 = 新的;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*----------------*/
|
||||
//类 迭代器{
|
||||
//公开的:
|
||||
// 迭代器(常量 std::vector<类型1>::iterator& it) {
|
||||
// this->it = it;
|
||||
// }
|
||||
//私有的:
|
||||
// std::vector<类型1>::iterator it;
|
||||
//};
|
||||
/*----------------*/
|
||||
|
||||
|
||||
私有的:
|
||||
类型1 *指针;
|
||||
长度单位 容量;
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
#pragma once
|
||||
#include "中文化.hpp"
|
||||
命名空间 中文标准 {
|
||||
类 标准异常 : 公开的 std::exception {
|
||||
公开的:
|
||||
不转换的 标准异常(常量 字符* 信息): 信息(信息) {}
|
||||
常量 字符* what() 常量 不报错的 覆盖 {
|
||||
返回 信息;
|
||||
}
|
||||
私有的:
|
||||
常量 字符* 信息;
|
||||
};
|
||||
|
||||
类 下标越界 : 公开的 标准异常{
|
||||
公开的:
|
||||
下标越界(常量 字符 * 提示, 常量 长度单位 标准值, 常量 长度单位 目前值)
|
||||
: 标准异常(提示), 标准值(标准值), 目前值(目前值) {
|
||||
};
|
||||
长度单位 取标准值() { 返回 标准值; }
|
||||
长度单位 取目前值() { 返回 目前值; }
|
||||
私有的:
|
||||
长度单位 标准值, 目前值;
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
#pragma once
|
||||
#include "中文化.hpp"
|
||||
#include "异常.hpp"
|
||||
#include "顺序表.hpp"
|
||||
命名空间 中文标准 {
|
||||
模板 <类型名 类型1, 长度单位 节点大小 = 64>
|
||||
类 链串 {
|
||||
公开的:
|
||||
/* 初始化为空链串 */
|
||||
链串() {
|
||||
对象->长度 = 0;
|
||||
对象->下一个 = 空指针;
|
||||
对象->上一个 = 空指针;
|
||||
对象->头 = 对象; /* 每一个子节点都记录同一个头结点 */
|
||||
对象->尾 = 对象; /* 为了方便,只有头结点记录尾节点 */
|
||||
}
|
||||
|
||||
链串 (常量 std::initializer_list<类型1>& init = {})
|
||||
{
|
||||
计次循环(适应 & 东西: init) {
|
||||
插入(东西);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* 链式析构
|
||||
*
|
||||
* 析构时,会递归析构所有节点。
|
||||
*/
|
||||
~链串() {
|
||||
删除[] 对象->下一个;
|
||||
}
|
||||
|
||||
空类型 插入(常量 类型1& 元素) {
|
||||
链串 *暂时 = 对象->尾;
|
||||
如果(暂时->长度 等于 节点大小)
|
||||
_推();
|
||||
暂时->存储[暂时->长度++] = 元素;
|
||||
}
|
||||
|
||||
长度单位 统计() {
|
||||
长度单位 总数 = 0;
|
||||
链串 *暂时 = 对象->头;
|
||||
判断循环(暂时 != 空指针) {
|
||||
总数 += 暂时->长度;
|
||||
暂时 = 暂时->下一个;
|
||||
}
|
||||
返回 总数;
|
||||
}
|
||||
|
||||
/*
|
||||
* 链串重组
|
||||
*
|
||||
* 将链串重组为顺序表W
|
||||
*/
|
||||
顺序表<类型1> 重组() {
|
||||
顺序表<类型1> 结果(统计());
|
||||
链串 *暂时 = 对象->头;
|
||||
长度单位 计数 = 0;
|
||||
判断循环(暂时 != 空指针) {
|
||||
计次循环(适应 索引 = 0; 索引 < 暂时->长度; ++索引) {
|
||||
结果[计数++] = 暂时->存储[索引];
|
||||
}
|
||||
暂时 = 暂时->下一个;
|
||||
}
|
||||
返回 结果;
|
||||
}
|
||||
|
||||
类 链串异常: 公开的 标准异常{
|
||||
公开的:
|
||||
链串异常(常量 字符* 消息) : 标准异常(消息) {}
|
||||
};
|
||||
私有的:
|
||||
类型1 存储[节点大小];
|
||||
长度单位 长度; /* 存储中的元素数量 */
|
||||
链串 *下一个;
|
||||
链串 *上一个;
|
||||
链串 *头;
|
||||
链串 *尾;
|
||||
|
||||
空类型 _推() {
|
||||
链串*新的;
|
||||
尝试{ 新的 = 新建 链串(); }
|
||||
捕获异常 (std::exception& exp){
|
||||
抛出异常 链串异常{"链串推失败"};
|
||||
}
|
||||
_拼接节点(新的);
|
||||
}
|
||||
|
||||
空类型 _拼接节点(链串* 新的) {
|
||||
对象->尾->下一个 = 新的;
|
||||
新的->上一个 = 对象->尾;
|
||||
对象->尾 = 新的;
|
||||
新的->头 = 对象;
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
#pragma once
|
||||
#include "中文化.hpp"
|
||||
#include "异常.hpp"
|
||||
命名空间 中文标准 {
|
||||
模板<类型名 类型1>
|
||||
类 顺序表 {
|
||||
公开的:
|
||||
顺序表(长度单位 大小) {
|
||||
存储 = 新建 类型1[大小];
|
||||
长度 = 大小;
|
||||
}
|
||||
~顺序表() {
|
||||
删除[] 存储;
|
||||
}
|
||||
类型1 _取下标重载(长度单位 下标) {
|
||||
如果(下标 >= 长度)
|
||||
抛出异常 顺序表异常{"下标超出范围"};
|
||||
返回 存储[下标];
|
||||
}
|
||||
类 顺序表异常: 公开的 标准异常{
|
||||
公开的:
|
||||
顺序表异常(常量 字符* 消息) : 标准异常(消息) {}
|
||||
};
|
||||
私有的:
|
||||
类型1 *存储;
|
||||
长度单位 长度;
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
/* 日志 */
|
||||
#pragma once
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <mutex>
|
||||
#include <chrono>
|
||||
#include <iomanip>
|
||||
#include <sstream>
|
||||
#include <ctime>
|
||||
|
||||
enum class LogLevel {
|
||||
DEBUG,
|
||||
INFO,
|
||||
WARNING,
|
||||
ERROR,
|
||||
CRITICAL
|
||||
};
|
||||
|
||||
namespace qing {
|
||||
/*
|
||||
* 这是由Deepseek创作的,用于记录日志的类模块
|
||||
* 简化版本,只输出到控制台
|
||||
*
|
||||
* 优化意见:改为存储日志文件
|
||||
*/
|
||||
class Logger {
|
||||
public:
|
||||
//获取日志实例(单例模式)
|
||||
static Logger& getInstance() {
|
||||
static Logger instance;
|
||||
return instance;
|
||||
}
|
||||
|
||||
//初始化日志系统
|
||||
void init(LogLevel minLogLevel = LogLevel::INFO,
|
||||
bool consoleOutput = true) {
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
|
||||
if (initialized_) {
|
||||
return;
|
||||
}
|
||||
|
||||
minLogLevel_ = minLogLevel;
|
||||
consoleOutput_ = consoleOutput;
|
||||
initialized_ = true;
|
||||
}
|
||||
|
||||
// 设置最低日志级别
|
||||
void setMinLogLevel(LogLevel level) {
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
minLogLevel_ = level;
|
||||
}
|
||||
|
||||
// 日志输出方法
|
||||
void log(LogLevel level, const std::string& message) {
|
||||
if (level < minLogLevel_ || !consoleOutput_) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto now = std::chrono::system_clock::now();
|
||||
auto in_time_t = std::chrono::system_clock::to_time_t(now);
|
||||
auto ms = std::chrono::duration_cast<std::chrono::milliseconds>(
|
||||
now.time_since_epoch()) % 1000;
|
||||
|
||||
std::tm tm;
|
||||
localtime_r(&in_time_t, &tm);
|
||||
|
||||
std::stringstream ss;
|
||||
ss << std::put_time(&tm, "%Y-%m-%d %H:%M:%S")
|
||||
<< "." << std::setfill('0') << std::setw(3) << ms.count()
|
||||
<< " [" << logLevelToString(level) << "] "
|
||||
<< message;
|
||||
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
std::cout << ss.str() << std::endl;
|
||||
}
|
||||
|
||||
Logger(const Logger&) = delete;
|
||||
Logger& operator=(const Logger&) = delete;
|
||||
|
||||
private:
|
||||
Logger() = default;
|
||||
~Logger() = default;
|
||||
|
||||
std::string logLevelToString(LogLevel level) {
|
||||
switch (level) {
|
||||
case LogLevel::DEBUG: return "DEBUG";
|
||||
case LogLevel::INFO: return "INFO";
|
||||
case LogLevel::WARNING: return "WARNING";
|
||||
case LogLevel::ERROR: return "ERROR";
|
||||
case LogLevel::CRITICAL: return "CRITICAL";
|
||||
default: return "UNKNOWN";
|
||||
}
|
||||
}
|
||||
|
||||
std::mutex mutex_;
|
||||
LogLevel minLogLevel_ = LogLevel::INFO;
|
||||
bool consoleOutput_ = true;
|
||||
bool initialized_ = false;
|
||||
};
|
||||
}
|
||||
|
||||
#define LOG_DEBUG(message) qing::Logger::getInstance().log(LogLevel::DEBUG, message)
|
||||
#define LOG_INFO(message) qing::Logger::getInstance().log(LogLevel::INFO, message)
|
||||
#define LOG_WARNING(message) qing::Logger::getInstance().log(LogLevel::WARNING, message)
|
||||
#define LOG_ERROR(message) qing::Logger::getInstance().log(LogLevel::ERROR, message)
|
||||
#define LOG_CRITICAL(message) qing::Logger::getInstance().log(LogLevel::CRITICAL, message)
|
||||
@@ -0,0 +1,110 @@
|
||||
#pragma once
|
||||
#include <us/Thread.hpp>
|
||||
#include <us/ITask.hpp>
|
||||
#include <us/HttpServer.hpp>
|
||||
namespace qing {
|
||||
namespace http = boost::beast::http;
|
||||
/* ----------------
|
||||
* HttpTask类 - 超文本服务器任务 */
|
||||
class HttpTask: public ITask {
|
||||
public:
|
||||
|
||||
/* 接受一个回调函数,其接受pmc::net::HttpServer对象的引用,在回调函数中对服务器进行配置 */
|
||||
HttpTask(int port, std::function<void(pmc::net::HttpServer& server)> handler);
|
||||
|
||||
/* 在一个线程中判断线程是否正在有效运行 */
|
||||
bool isRunning() override;
|
||||
|
||||
/* 启动该项任务 */
|
||||
void start() override;
|
||||
|
||||
/* 停止该项任务 */
|
||||
void stop() override;
|
||||
|
||||
private:
|
||||
int port;
|
||||
std::function<void(pmc::net::HttpServer& server)> handler;
|
||||
std::unique_ptr<Thread> th; /* ---- 可控线程指针 */
|
||||
std::unique_ptr<pmc::net::HttpServer> server; /* ---- HTTP服务器的指针 ---- */
|
||||
|
||||
/* 初始化线程,定义线程的行为(Http服务器) */
|
||||
void init_thread();
|
||||
};
|
||||
|
||||
/*-----------------------------------------------------------------------------*/
|
||||
|
||||
|
||||
|
||||
/* ================
|
||||
* 进程托管http服务器
|
||||
* ================
|
||||
* 对操作进程列表的http服务器进行配置,即是输入回调函数 */
|
||||
namespace process_http_server {
|
||||
|
||||
/* ---- 注册POST路由 ---- */
|
||||
void registerRoutes(pmc::net::HttpServer& server);
|
||||
|
||||
/**
|
||||
* @brief 解析请求体中的JSON数据
|
||||
* @param body 请求体字符串
|
||||
* @return JSON解析后的属性树
|
||||
*/
|
||||
boost::property_tree::ptree parseJsonBody(const std::string& body);
|
||||
|
||||
/**
|
||||
* @brief 构建JSON响应
|
||||
* @param success 是否成功
|
||||
* @param message 消息
|
||||
* @param data 附加数据
|
||||
* @return JSON字符串
|
||||
*/
|
||||
std::string buildJsonResponse(bool success, const std::string& message,
|
||||
const boost::property_tree::ptree& data = boost::property_tree::ptree());
|
||||
|
||||
/**
|
||||
* @brief 从请求中提取target参数
|
||||
* @param params 查询参数
|
||||
* @return target值(空字符串表示本机)
|
||||
*/
|
||||
std::string getTarget(const std::unordered_map<std::string, std::string>& params);
|
||||
|
||||
/**
|
||||
* @brief 从请求中提取exec参数
|
||||
* @param params 查询参数
|
||||
* @return 要执行的指令
|
||||
*/
|
||||
std::string getExecCommand(const std::unordered_map<std::string, std::string>& params);
|
||||
|
||||
/**
|
||||
* @brief 从请求中提取kill参数
|
||||
* @param params 查询参数
|
||||
* @return 目标进程号
|
||||
*/
|
||||
int getPid(const std::unordered_map<std::string, std::string>& params);
|
||||
|
||||
/* POST方法处理器 */
|
||||
http::response<http::string_body> handleList(
|
||||
const http::request<http::string_body>& req,
|
||||
const std::unordered_map<std::string, std::string>& params);
|
||||
|
||||
http::response<http::string_body> handleExec(
|
||||
const http::request<http::string_body>& req,
|
||||
const std::unordered_map<std::string, std::string>& params);
|
||||
|
||||
http::response<http::string_body> handleKill(
|
||||
const http::request<http::string_body>& req,
|
||||
const std::unordered_map<std::string, std::string>& params);
|
||||
|
||||
/** 内部实现函数 */
|
||||
std::string listProcesses(const std::string& target);
|
||||
std::string execCommand(const std::string& command, const std::string& target);
|
||||
bool killProcess(int pid, const std::string& target);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
#pragma once
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
#include <list>
|
||||
#include "main/ProcessTask.hh"
|
||||
|
||||
namespace qing {
|
||||
|
||||
|
||||
|
||||
/* -----------------
|
||||
* subprocess pool 子进程池
|
||||
* ----------------
|
||||
* FIXME: 将列表(序列化)功能放到这里来 */
|
||||
class PPool {
|
||||
public:
|
||||
|
||||
/* CREATE PROCESS - 创建进程
|
||||
*
|
||||
* cmd: 启动命令 */
|
||||
void crtp(const std::string& cmd);
|
||||
|
||||
|
||||
/* CLEAR 清理 - 删除所有已经停下的进程 */
|
||||
void clr();
|
||||
|
||||
|
||||
/* 获取进程池的大小 */
|
||||
size_t size() { return pool.size(); }
|
||||
|
||||
|
||||
/* 删除一个进程,需要输入进程的下标。
|
||||
*
|
||||
* FIXME: 输入进程下标似乎不太自然 */
|
||||
void kill(int idx);
|
||||
|
||||
/* 取下标运算符重载 - 取元素对象 */
|
||||
ProcessTask& operator[](const size_t idx);
|
||||
|
||||
|
||||
/* TODO: 实现迭代器和begin()、end()
|
||||
* ...... */
|
||||
|
||||
private:
|
||||
|
||||
/* 进程任务的shared指针的容器 */
|
||||
std::list<std::shared_ptr<ProcessTask>> pool{};
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
#pragma once
|
||||
#include <boost/process.hpp>
|
||||
#include <us/ITask.hpp>
|
||||
|
||||
namespace qing {
|
||||
|
||||
/* ----------------
|
||||
* 【子进程任务】
|
||||
* ----------------
|
||||
* 输入要执行的命令,构造子进程任务
|
||||
* TODO: 我们可以重定向子进程的输入和输出,实时交互 */
|
||||
class ProcessTask: public ITask {
|
||||
public:
|
||||
|
||||
/* 输入一个字符串(要执行的命令)(但是并没有执行起来) */
|
||||
ProcessTask(std::string cmd): cmd(cmd) {}
|
||||
|
||||
/* 任务是否在运行中 */
|
||||
bool isRunning() override { return p && p->running(); }
|
||||
|
||||
/* 启动任务 */
|
||||
void start() override {
|
||||
if (!isRunning())
|
||||
this->p = std::make_unique<boost::process::child>(cmd); }
|
||||
|
||||
/* 终止该任务(并且重置子进程指针) */
|
||||
void stop() override {
|
||||
if (isRunning()) p->terminate();
|
||||
p.reset();
|
||||
}
|
||||
|
||||
/* 获取该任务(子进程)的命令 */
|
||||
std::string check() { return this->cmd; }
|
||||
|
||||
/* 获取该子进程的pid(进程编号) */
|
||||
pid_t pid() { return p->id(); }
|
||||
|
||||
private:
|
||||
std::unique_ptr<boost::process::child> p; /* 子进程指针 */
|
||||
std::string cmd; /* 该进程执行的命令 */
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
|
||||
#ifdef __NEW_VER
|
||||
/* ---- [子进程任务]boost.process库升级到了v2 ---- */
|
||||
class ProcessTask: public ITask {
|
||||
public:
|
||||
ProcessTask(std::string cmd): cmd(cmd) {}
|
||||
bool isRunning() override;
|
||||
int getExitCode();
|
||||
void start() override;
|
||||
/* ---- NOTE(202606025-qing): 杀死进程失败只是打印错误信息 ---- */
|
||||
void stop() override;
|
||||
std::string check() {
|
||||
return this->cmd;
|
||||
}
|
||||
pid_t pid() {
|
||||
return p->id();
|
||||
}
|
||||
|
||||
private:
|
||||
boost::asio::io_context ctx; /* 异步上下文 */
|
||||
std::unique_ptr<boost::process::v2::process> p; /* 子进程指针 */
|
||||
boost::system::error_code exit_code; /* 进程退出的代码 */
|
||||
std::string cmd; /* 要执行的命令 */
|
||||
};
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,58 @@
|
||||
#pragma onces
|
||||
#include "tt/Mq.h"
|
||||
namespace qing {
|
||||
|
||||
|
||||
/*
|
||||
* TRANSMIT TASK 通信任务
|
||||
* (创建一个通信伺服器,它收到消息就执行回调)
|
||||
* (长时间伺服运行会不会有问题)
|
||||
*/
|
||||
class Tttask: public ITask {
|
||||
public:
|
||||
|
||||
/* 构造【通信任务】
|
||||
* msglen: 单条消息的长度
|
||||
* msgcnt: 消息伺服长度
|
||||
* callback: 回调函数 */
|
||||
Tttask(const size_t msglen, size_t msgcnt, const sf_t callback);
|
||||
|
||||
/* 启动该通信伺服任务 */
|
||||
void start() override;
|
||||
|
||||
/* 终止这个通信伺服任务
|
||||
*
|
||||
* TODO: 研究一下要不要释放一些资源
|
||||
* TODO: 增加超时 */
|
||||
void stop() override {
|
||||
if (this->isRunning())
|
||||
th->WaitClose();
|
||||
}
|
||||
|
||||
|
||||
/* 该任务是否在运行
|
||||
*
|
||||
* FIXME: 对START状态的处理还应该考虑
|
||||
* FIXME: 如果在STOP状态而没有stop()任务,可能会造成线程未关闭,一直占用资源? */
|
||||
bool isRunning() override;
|
||||
|
||||
|
||||
private:
|
||||
std::unique_ptr<Thread> th; /* 可控线程指针 */
|
||||
std::unique_ptr<sf_t> callback; /* 回调行为(接收之后)指针 */
|
||||
std::unique_ptr<Mq> mq; /* 消息队列指针 */
|
||||
size_t msglen=0, msgcnt=0; /* 消息的缓存规格 */
|
||||
std::string name; /* 消息队列名(进程号) */
|
||||
|
||||
|
||||
|
||||
|
||||
/* 初始化通信伺服线程,
|
||||
* 初始化方法就是通过传入一些函数,
|
||||
* 构建线程 */
|
||||
void init_thread();
|
||||
|
||||
|
||||
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
#pragma once
|
||||
#include <iostream>
|
||||
namespace qing {
|
||||
/* ----------------
|
||||
* 进程托管服务方法集
|
||||
* ----------------
|
||||
* 直接对进程组列表进行操作
|
||||
*
|
||||
*/
|
||||
namespace pmc_mtd
|
||||
{
|
||||
auto list() -> std::string; /* 列出所有的进程 */
|
||||
auto kill(const int pid) -> bool; /* 杀死一个进程,需提供PID */
|
||||
auto exec(const std::string& cmd) -> bool; /* 执行一个进程,输入要执行的命令行 */
|
||||
auto parse_self_init_list(std::string &path) -> void; /* 解析自启动脚本 */
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
#pragma once
|
||||
namespace qing {
|
||||
|
||||
/* ----------------
|
||||
* 子系统调用
|
||||
* ----------------
|
||||
* 通过进程间通信与子系统进行通讯,调用不同的功能
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
namespace subsys_call
|
||||
{
|
||||
std::string send_list_and_recv_pipe(const std::string& name_mq);
|
||||
std::string send_start_and_recv_pipe(const std::string& name_mq, const std::string& exec);
|
||||
std::string send_kill_and_recv_pipe(const std::string& name_mq, const int kill);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
* 目前是Message Queue 的发送端(不涉及创建消息队列)
|
||||
*
|
||||
* FIXME: 集成发送、接收和创建
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include <iostream>
|
||||
#include <cstring>
|
||||
#include <memory>
|
||||
#include <boost/interprocess/ipc/message_queue.hpp>
|
||||
|
||||
namespace qing {
|
||||
namespace bip = boost::interprocess;
|
||||
using sf_t = std::function<void(const char*)>; /* 通信成功的回调函数 success */
|
||||
using ef_t = std::function<void(void)>; /* 通信失败的回调函数 error */
|
||||
class Mq {
|
||||
public:
|
||||
enum {CREATOR=0, USER=1};
|
||||
Mq(const std::string& name, int msglen, size_t msgcnt, int mode = USER) {
|
||||
this->name = std::string("/") + name;
|
||||
this->msglen = msglen;
|
||||
this->msgcnt = msgcnt;
|
||||
this->mode = mode;
|
||||
switch (mode) {
|
||||
case USER:
|
||||
mqp = std::make_unique<bip::message_queue>(bip::open_only, this->name.c_str());
|
||||
break;
|
||||
case CREATOR: /* 由创建者创建消息队列 */
|
||||
bip::message_queue::remove(this->name.c_str());
|
||||
mqp = std::make_unique<bip::message_queue>(
|
||||
bip::create_only, this->name.c_str(),
|
||||
msgcnt, msglen * sizeof(char)
|
||||
);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* 创建者负责清理 */
|
||||
~Mq() {
|
||||
if (mode == CREATOR)
|
||||
bip::message_queue::remove(name.c_str());
|
||||
}
|
||||
|
||||
/* */
|
||||
Mq(const Mq&) = delete;
|
||||
Mq& operator=(const Mq&) = delete;
|
||||
|
||||
|
||||
/* 发送消息 */
|
||||
void send(std::string &msg)
|
||||
{
|
||||
if (msg.size() + 1 > msglen) /* over the len */
|
||||
throw std::length_error("Message queue Send Length over");
|
||||
|
||||
mqp->send(msg.c_str(), msg.size() + 1, 0); /* include \0 */
|
||||
}
|
||||
|
||||
/* 尝试接收消息 */
|
||||
void recv(sf_t success, ef_t notyet) {
|
||||
|
||||
auto data = std::make_unique<char[]>(msglen); /* 接收缓冲区 */
|
||||
unsigned int priority; /* 优先级 */
|
||||
bip::message_queue::size_type recvd_size;
|
||||
|
||||
try { /* try_receive()返回bool类型 */
|
||||
auto r = mqp->try_receive(
|
||||
data.get(), msglen*sizeof(char),
|
||||
recvd_size, priority
|
||||
);
|
||||
|
||||
if (r) /* 成功接收到数据 */
|
||||
success(data.get());
|
||||
|
||||
else /* 没有收到数据 */
|
||||
notyet();
|
||||
}
|
||||
|
||||
catch (std::exception &exp) {
|
||||
std::cerr << "exception type: " << typeid(exp).name() << std::endl;
|
||||
std::cerr << "exception message: " << exp.what() << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
/* */
|
||||
std::unique_ptr<bip::message_queue> mqp;
|
||||
std::string name;
|
||||
size_t msglen=0, msgcnt=0;
|
||||
int mode;
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,157 @@
|
||||
#pragma once
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h> /* open() */
|
||||
#include <sys/stat.h> /* mkfifo() */
|
||||
#include <sys/select.h>
|
||||
|
||||
namespace qing {
|
||||
|
||||
/* 20260309(qing): 该类不会抛出异常 */
|
||||
class Pipe{
|
||||
public:
|
||||
static const int CREATOR = 1;
|
||||
static const int USER =2;
|
||||
static const ssize_t PIPE_MAX_LEN = 2048;
|
||||
Pipe(const std::string& path, int mode)
|
||||
: fd(-1), isCreator(mode == CREATOR) {
|
||||
std::string real_path = "/tmp/pst-";
|
||||
real_path += path;
|
||||
fifo_path = real_path;
|
||||
if (isCreator && mkfifo(fifo_path.c_str(), 0666) == -1 && errno != EEXIST) /* wr_wr_wr */
|
||||
perror("mkfifo"); /* 文件已存在是正常情况,其他错误才需要处理 */
|
||||
}
|
||||
|
||||
~Pipe() {
|
||||
/* 如果打开了文件,则关闭文件 */
|
||||
if (fd != -1) close(fd);
|
||||
/**********************/
|
||||
/* 如果管道由该对象创建,就要负责清理 */
|
||||
if (isCreator) unlink(fifo_path.c_str()); /* 创建者负责清理 */
|
||||
}
|
||||
Pipe(const Pipe&) = delete;
|
||||
Pipe& operator=(const Pipe&) = delete;
|
||||
|
||||
/* 这里才是打开文件的指令 - 以读模式打开,可以非阻塞 */
|
||||
bool openForRead(bool nonblock = false) {
|
||||
|
||||
/* 设置是否以非阻塞方式打开文件 */
|
||||
int flags = O_RDONLY;
|
||||
if (nonblock) {
|
||||
flags |= O_NONBLOCK;
|
||||
}
|
||||
|
||||
fd = open(fifo_path.c_str(), flags);
|
||||
|
||||
if (fd == -1) {
|
||||
perror("open for read");
|
||||
return false;
|
||||
}
|
||||
|
||||
else {
|
||||
FD_ZERO(&read_fds);
|
||||
FD_SET(fd, &read_fds);
|
||||
if (fd > max_fd) max_fd = fd;
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* 以写模式打开文件 */
|
||||
bool openForWrite(/*bool nonblock = falsei*/) {
|
||||
|
||||
/* 写入管道是不需要阻塞/非阻塞的? */
|
||||
int flags = O_WRONLY;
|
||||
//if (nonblock) {
|
||||
// flags |= O_NONBLOCK;
|
||||
//}
|
||||
fd = open(fifo_path.c_str(), flags);
|
||||
if (fd == -1) {
|
||||
perror("open for write");
|
||||
return false;
|
||||
}
|
||||
|
||||
else {
|
||||
FD_ZERO(&write_fds);
|
||||
FD_SET(fd, &write_fds);
|
||||
if (fd > max_fd) max_fd = fd;
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* 写入管道,如果失败返回-1。成功返回写入的字符数。 */
|
||||
ssize_t writePipe(const std::string &data) {
|
||||
if (fd == -1) {
|
||||
std::cerr << "Pipe not opened for writing" << std::endl;
|
||||
return -1;
|
||||
}
|
||||
else {
|
||||
return write(fd, data.c_str(), data.size());
|
||||
}
|
||||
}
|
||||
|
||||
/* 将探测与读取解耦,使用者可以自行决定要不要阻塞 */
|
||||
bool waitForRead(int timeout_sec = 0, int timeout_usec = 0) {
|
||||
|
||||
/* 如果文件没打开,等待是失败的 */
|
||||
if (fd == -1) return false;
|
||||
|
||||
fd_set temp_fds = read_fds;
|
||||
struct timeval timeout = {timeout_sec, timeout_usec};
|
||||
|
||||
int ret = select(max_fd + 1, &temp_fds, nullptr, nullptr, &timeout);
|
||||
|
||||
if (ret == -1) {
|
||||
perror("select");
|
||||
return false;
|
||||
}
|
||||
|
||||
else {
|
||||
return ret > 0 && FD_ISSET(fd, &temp_fds);
|
||||
}
|
||||
}
|
||||
|
||||
/* 读取数据到字符串,返回实际读取的字节数 */
|
||||
ssize_t readPipe(std::string *output) {
|
||||
|
||||
if (fd == -1) {
|
||||
std::cerr << "Pipe not opened for reading" << std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
else
|
||||
|
||||
{
|
||||
|
||||
char buffer[PIPE_MAX_LEN];
|
||||
ssize_t n = read(fd, buffer, sizeof(buffer) - 1);
|
||||
if (n >0) {
|
||||
buffer[n] = '\0';
|
||||
*output = buffer;
|
||||
}
|
||||
|
||||
else if (n == 0) {
|
||||
/* 管道写入端关闭 */
|
||||
*output = "";
|
||||
}
|
||||
|
||||
else {
|
||||
perror("read");
|
||||
}
|
||||
|
||||
return n;
|
||||
|
||||
}
|
||||
}
|
||||
private:
|
||||
std::string fifo_path;
|
||||
int fd;
|
||||
bool isCreator;
|
||||
fd_set read_fds;
|
||||
fd_set write_fds;
|
||||
fd_set except_fds;
|
||||
int max_fd;
|
||||
};
|
||||
}
|
||||
Reference in new issue
Block a user