feat: 重构基础模块

This commit is contained in:
kuaifan 2025-07-31 14:26:06 +08:00
parent 625648c908
commit 8746caab06
6 changed files with 551 additions and 293 deletions

View File

@ -775,7 +775,8 @@ class ApproveController extends AbstractController
}
$dialog = WebSocketDialog::checkUserDialog($botUser, $user->userid);
//
go(function () use ($data, $user, $botUser, $dialog) {
$doo = Doo::load();
go(function () use ($doo, $data, $user, $botUser, $dialog) {
Coroutine::sleep(1);
//
$content = [];
@ -802,30 +803,30 @@ class ApproveController extends AbstractController
$res = Base::arrayKeyToUnderline($process['data']);
//
$headings = [];
$headings[] = Doo::translate('申请编号');
$headings[] = Doo::translate('标题');
$headings[] = Doo::translate('申请状态');
$headings[] = Doo::translate('发起时间');
$headings[] = Doo::translate('完成时间');
$headings[] = Doo::translate('发起人工号');
$headings[] = Doo::translate('发起人User ID');
$headings[] = Doo::translate('发起人姓名');
$headings[] = Doo::translate('发起人部门');
$headings[] = Doo::translate('发起人部门ID');
$headings[] = Doo::translate('部门负责人');
$headings[] = Doo::translate('历史审批人');
$headings[] = Doo::translate('历史办理人');
$headings[] = Doo::translate('审批记录');
$headings[] = Doo::translate('当前处理人');
$headings[] = Doo::translate('审批节点');
$headings[] = Doo::translate('审批人数');
$headings[] = Doo::translate('审批耗时');
$headings[] = Doo::translate('假期类型');
$headings[] = Doo::translate('开始时间');
$headings[] = Doo::translate('结束时间');
$headings[] = Doo::translate('时长');
$headings[] = Doo::translate('请假事由');
$headings[] = Doo::translate('请假单位');
$headings[] = $doo->translate('申请编号');
$headings[] = $doo->translate('标题');
$headings[] = $doo->translate('申请状态');
$headings[] = $doo->translate('发起时间');
$headings[] = $doo->translate('完成时间');
$headings[] = $doo->translate('发起人工号');
$headings[] = $doo->translate('发起人User ID');
$headings[] = $doo->translate('发起人姓名');
$headings[] = $doo->translate('发起人部门');
$headings[] = $doo->translate('发起人部门ID');
$headings[] = $doo->translate('部门负责人');
$headings[] = $doo->translate('历史审批人');
$headings[] = $doo->translate('历史办理人');
$headings[] = $doo->translate('审批记录');
$headings[] = $doo->translate('当前处理人');
$headings[] = $doo->translate('审批节点');
$headings[] = $doo->translate('审批人数');
$headings[] = $doo->translate('审批耗时');
$headings[] = $doo->translate('假期类型');
$headings[] = $doo->translate('开始时间');
$headings[] = $doo->translate('结束时间');
$headings[] = $doo->translate('时长');
$headings[] = $doo->translate('请假事由');
$headings[] = $doo->translate('请假单位');
//
$datas = [];
foreach ($res as $val) {
@ -845,12 +846,12 @@ class ApproveController extends AbstractController
// 计算审批耗时
$startTime = Carbon::parse($val['start_time'])->timestamp;
$endTime = $val['end_time'] ? Carbon::parse($val['end_time'])->timestamp : time();
$approval_time = Doo::translate(Timer::timeDiff($startTime, $endTime)); // 审批耗时
$approval_time = $doo->translate(Timer::timeDiff($startTime, $endTime)); // 审批耗时
// 计算时长
$varStartTime = Carbon::parse($val['var']['start_time']);
$varEndTime = Carbon::parse($val['var']['end_time']);
$duration = $varEndTime->floatDiffInHours($varStartTime);
$duration_unit = Doo::translate('小时'); // 时长单位
$duration_unit = $doo->translate('小时'); // 时长单位
$datas[] = [
$val['id'], // 申请编号
$val['proc_def_name'], // 标题
@ -891,7 +892,7 @@ class ApproveController extends AbstractController
return;
}
//
$title = Doo::translate("审批记录");
$title = $doo->translate("审批记录");
$sheets = [
BillExport::create()->setTitle($title)->setHeadings($headings)->setData($datas)->setStyles(["A1:Y1" => ["font" => ["bold" => true]]])
];

View File

@ -1258,26 +1258,27 @@ class ProjectController extends AbstractController
}
$dialog = WebSocketDialog::checkUserDialog($botUser, $user->userid);
//
go(function () use ($user, $userid, $time, $type, $botUser, $dialog) {
$doo = Doo::load();
go(function () use ($doo, $user, $userid, $time, $type, $botUser, $dialog) {
Coroutine::sleep(1);
$headings = [];
$headings[] = Doo::translate('任务ID');
$headings[] = Doo::translate('父级任务ID');
$headings[] = Doo::translate('所属项目');
$headings[] = Doo::translate('任务标题');
$headings[] = Doo::translate('任务标签');
$headings[] = Doo::translate('任务开始时间');
$headings[] = Doo::translate('任务结束时间');
$headings[] = Doo::translate('完成时间');
$headings[] = Doo::translate('归档时间');
$headings[] = Doo::translate('任务计划用时');
$headings[] = Doo::translate('实际完成用时');
$headings[] = Doo::translate('超时时间');
$headings[] = Doo::translate('开发用时');
$headings[] = Doo::translate('验收/测试用时');
$headings[] = Doo::translate('负责人');
$headings[] = Doo::translate('创建人');
$headings[] = Doo::translate('状态');
$headings[] = $doo->translate('任务ID');
$headings[] = $doo->translate('父级任务ID');
$headings[] = $doo->translate('所属项目');
$headings[] = $doo->translate('任务标题');
$headings[] = $doo->translate('任务标签');
$headings[] = $doo->translate('任务开始时间');
$headings[] = $doo->translate('任务结束时间');
$headings[] = $doo->translate('完成时间');
$headings[] = $doo->translate('归档时间');
$headings[] = $doo->translate('任务计划用时');
$headings[] = $doo->translate('实际完成用时');
$headings[] = $doo->translate('超时时间');
$headings[] = $doo->translate('开发用时');
$headings[] = $doo->translate('验收/测试用时');
$headings[] = $doo->translate('负责人');
$headings[] = $doo->translate('创建人');
$headings[] = $doo->translate('状态');
$datas = [];
//
$content = [];
@ -1330,9 +1331,9 @@ class ProjectController extends AbstractController
$planTotalTime = $endTime - $startTime;
$residueTime = $planTotalTime - $totalTime;
if ($residueTime < 0) {
$overTime = Doo::translate(Timer::timeFormat(abs($residueTime)));
$overTime = $doo->translate(Timer::timeFormat(abs($residueTime)));
}
$planTime = Doo::translate(Timer::timeDiff($startTime, $endTime));
$planTime = $doo->translate(Timer::timeDiff($startTime, $endTime));
}
$actualTime = $task->complete_at ? $totalTime : 0; // 实际完成用时
$statusText = '未完成';
@ -1376,13 +1377,13 @@ class ProjectController extends AbstractController
$task->complete_at ?: '-',
$task->archived_at ?: '-',
$planTime,
$actualTime ? Doo::translate(Timer::timeFormat($actualTime)) : '-',
$actualTime ? $doo->translate(Timer::timeFormat($actualTime)) : '-',
$overTime,
$developTime > 0 ? Doo::translate(Timer::timeFormat($developTime)) : '-',
$testTime > 0 ? Doo::translate(Timer::timeFormat($testTime)) : '-',
$developTime > 0 ? $doo->translate(Timer::timeFormat($developTime)) : '-',
$testTime > 0 ? $doo->translate(Timer::timeFormat($testTime)) : '-',
Base::filterEmoji(User::userid2nickname($task->ownerid)) . " (ID: {$task->ownerid})",
Base::filterEmoji(User::userid2nickname($task->userid)) . " (ID: {$task->userid})",
Doo::translate($statusText),
$doo->translate($statusText),
];
}
});
@ -1416,7 +1417,7 @@ class ProjectController extends AbstractController
} else {
$fileName .= '的任务统计';
}
$fileName = Doo::translate($fileName) . '_' . Timer::time() . '.xls';
$fileName = $doo->translate($fileName) . '_' . Timer::time() . '.xls';
$filePath = "temp/task/export/" . date("Ym", Timer::time());
$export = new BillMultipleExport($sheets);
$res = $export->store($filePath . "/" . $fileName);
@ -1500,21 +1501,22 @@ class ProjectController extends AbstractController
}
$dialog = WebSocketDialog::checkUserDialog($botUser, $user->userid);
//
go(function () use ($botUser, $dialog, $user) {
$doo = Doo::load();
go(function () use ($doo, $botUser, $dialog, $user) {
Coroutine::sleep(1);
//
$headings = [];
$headings[] = Doo::translate('任务ID');
$headings[] = Doo::translate('父级任务ID');
$headings[] = Doo::translate('所属项目');
$headings[] = Doo::translate('任务标题');
$headings[] = Doo::translate('任务标签');
$headings[] = Doo::translate('任务开始时间');
$headings[] = Doo::translate('任务结束时间');
$headings[] = Doo::translate('任务计划用时');
$headings[] = Doo::translate('超时时间');
$headings[] = Doo::translate('负责人');
$headings[] = Doo::translate('创建人');
$headings[] = $doo->translate('任务ID');
$headings[] = $doo->translate('父级任务ID');
$headings[] = $doo->translate('所属项目');
$headings[] = $doo->translate('任务标题');
$headings[] = $doo->translate('任务标签');
$headings[] = $doo->translate('任务开始时间');
$headings[] = $doo->translate('任务结束时间');
$headings[] = $doo->translate('任务计划用时');
$headings[] = $doo->translate('超时时间');
$headings[] = $doo->translate('负责人');
$headings[] = $doo->translate('创建人');
$data = [];
//
$content = [];
@ -1541,9 +1543,9 @@ class ProjectController extends AbstractController
$planTotalTime = $endTime - $startTime;
$residueTime = $planTotalTime - $totalTime;
if ($residueTime < 0) {
$overTime = Doo::translate(Timer::timeFormat(abs($residueTime)));
$overTime = $doo->translate(Timer::timeFormat(abs($residueTime)));
}
$planTime = Doo::translate(Timer::timeDiff($startTime, $endTime));
$planTime = $doo->translate(Timer::timeDiff($startTime, $endTime));
}
$ownerIds = $task->taskUser->where('owner', 1)->pluck('userid')->toArray();
$ownerNames = [];
@ -1580,7 +1582,7 @@ class ProjectController extends AbstractController
return;
}
//
$title = Doo::translate('超期任务');
$title = $doo->translate('超期任务');
$sheets = [
BillExport::create()->setTitle($title)->setHeadings($headings)->setData($data)->setStyles(["A1:J1" => ["font" => ["bold" => true]]])
];

View File

@ -1328,18 +1328,19 @@ class SystemController extends AbstractController
}
$dialog = WebSocketDialog::checkUserDialog($botUser, $user->userid);
//
go(function () use ($secondStart, $secondEnd, $time, $userid, $date, $user, $botUser, $dialog) {
$doo = Doo::load();
go(function () use ($doo, $secondStart, $secondEnd, $time, $userid, $date, $user, $botUser, $dialog) {
Coroutine::sleep(1);
//
$headings = [];
$headings[] = Doo::translate('签到人');
$headings[] = Doo::translate('签到日期');
$headings[] = Doo::translate('班次时间');
$headings[] = Doo::translate('首次签到时间');
$headings[] = Doo::translate('首次签到结果');
$headings[] = Doo::translate('最后签到时间');
$headings[] = Doo::translate('最后签到结果');
$headings[] = Doo::translate('参数数据');
$headings[] = $doo->translate('签到人');
$headings[] = $doo->translate('签到日期');
$headings[] = $doo->translate('班次时间');
$headings[] = $doo->translate('首次签到时间');
$headings[] = $doo->translate('首次签到结果');
$headings[] = $doo->translate('最后签到时间');
$headings[] = $doo->translate('最后签到结果');
$headings[] = $doo->translate('参数数据');
//
$content = [];
$content[] = [
@ -1375,12 +1376,12 @@ class SystemController extends AbstractController
if (Timer::time() < $startT + $secondStart) {
$firstResult = "-";
} else {
$firstResult = Doo::translate("正常");
$firstResult = $doo->translate("正常");
if (empty($firstTimestamp)) {
$firstResult = Doo::translate("缺卡");
$firstResult = $doo->translate("缺卡");
$styles["E{$index}"] = ["font" => ["color" => ["rgb" => "ff0000"]]];
} elseif ($firstTimestamp > $startT + $secondStart) {
$firstResult = Doo::translate("迟到");
$firstResult = $doo->translate("迟到");
$styles["E{$index}"] = ["font" => ["color" => ["rgb" => "436FF6"]]];
}
}
@ -1388,12 +1389,12 @@ class SystemController extends AbstractController
$lastResult = "-";
$lastTimestamp = 0;
} else {
$lastResult = Doo::translate("正常");
$lastResult = $doo->translate("正常");
if (empty($lastTimestamp) || $lastTimestamp === $firstTimestamp) {
$lastResult = Doo::translate("缺卡");
$lastResult = $doo->translate("缺卡");
$styles["G{$index}"] = ["font" => ["color" => ["rgb" => "ff0000"]]];
} elseif ($lastTimestamp < $startT + $secondEnd) {
$lastResult = Doo::translate("早退");
$lastResult = $doo->translate("早退");
$styles["G{$index}"] = ["font" => ["color" => ["rgb" => "436FF6"]]];
}
}
@ -1436,7 +1437,7 @@ class SystemController extends AbstractController
} else {
$fileName .= '的签到记录';
}
$fileName = Doo::translate($fileName) . '_' . Timer::time() . '.xlsx';
$fileName = $doo->translate($fileName) . '_' . Timer::time() . '.xlsx';
$filePath = "temp/checkin/export/" . date("Ym", Timer::time());
$export = new BillMultipleExport($sheets);
$res = $export->store($filePath . "/" . $fileName);

View File

@ -2,14 +2,9 @@
namespace App\Module;
use App\Exceptions\ApiException;
use App\Models\User;
use App\Module\Interface\DooSo;
use App\Services\RequestContext;
use Cache;
use Carbon\Carbon;
use FFI;
use FFI\CData;
use FFI\Exception;
class Doo
{
@ -17,56 +12,22 @@ class Doo
private const DOO_LANGUAGE = 'doo_language';
/**
* char转为字符串
* @param $text
* @return string
*/
private static function string($text): string
{
if (!($text instanceof CData)) {
return "";
}
try {
return FFI::string($text);
} catch (Exception) {
return "";
}
}
/**
* 装载
* 加载Doo实例
* - 如果已经存在,则直接返回
* - 否则创建一个新的FFI实例并初始化
* @param $token
* @param $language
* @return FFI
* @return DooSo
*/
public static function load($token = null, $language = null)
public static function load($token = null, $language = null): DooSo
{
$instance = FFI::cdef(<<<EOF
void initialize(char* work, char* token, char* lang);
char* license();
char* licenseDecode(char* license);
char* licenseSave(char* license);
int userId();
char* userExpiredAt();
char* userEmail();
char* userEncrypt();
char* userToken();
char* userCreate(char* email, char* password);
char* tokenEncode(int userid, char* email, char* encrypt, int days);
char* tokenDecode(char* val);
char* translate(char* val, char* val);
char* md5s(char* text, char* password);
char* macs();
char* dooSN();
char* version();
char* pgpGenerateKeyPair(char* name, char* email, char* passphrase);
char* pgpEncrypt(char* plainText, char* publicKey);
char* pgpDecrypt(char* cipherText, char* privateKey, char* passphrase);
EOF, "/usr/lib/doo/doo.so");
if (RequestContext::has(self::DOO_INSTANCE)) {
return RequestContext::get(self::DOO_INSTANCE);
}
$token = $token ?: Base::token();
$language = $language ?: Base::headerOrInput('language');
$instance->initialize("/var/www", $token, $language);
$instance = new DooSo($token, $language);
RequestContext::set(self::DOO_INSTANCE, $instance);
RequestContext::set(self::DOO_LANGUAGE, $language);
@ -74,62 +35,13 @@ class Doo
return $instance;
}
/**
* 获取实例
* @param $token
* @param $language
* @return mixed
*/
public static function doo($token = null, $language = null)
{
$instance = RequestContext::get(self::DOO_INSTANCE);
if ($instance === null) {
$instance = self::load($token, $language);
}
return $instance;
}
/**
* License
* @return array
*/
public static function license(): array
{
$array = Base::json2array(self::string(self::doo()->license()));
$ips = explode(",", $array['ip']);
$array['ip'] = [];
foreach ($ips as $ip) {
if (Base::is_ipv4($ip)) {
$array['ip'][] = $ip;
}
}
$domains = explode(",", $array['domain']);
$array['domain'] = [];
foreach ($domains as $domain) {
if (Base::is_domain($domain)) {
$array['domain'][] = $domain;
}
}
$macs = explode(",", $array['mac']);
$array['mac'] = [];
foreach ($macs as $mac) {
if (Base::isMac($mac)) {
$array['mac'][] = $mac;
}
}
$emails = explode(",", $array['email']);
$array['email'] = [];
foreach ($emails as $email) {
if (Base::isEmail($email)) {
$array['email'][] = $email;
}
}
return $array;
return self::load()->license();
}
/**
@ -157,26 +69,13 @@ class Doo
return $content;
}
/**
* 解析License
* @param $license
* @return array
*/
public static function licenseDecode($license): array
{
return Base::json2array(self::string(self::doo()->licenseDecode($license)));
}
/**
* 保存License
* @param $license
*/
public static function licenseSave($license): void
{
$res = self::string(self::doo()->licenseSave($license));
if ($res != 'success') {
throw new ApiException($res ?: 'LICENSE 保存失败');
}
self::load()->licenseSave($license);
}
/**
@ -185,7 +84,7 @@ class Doo
*/
public static function userId(): int
{
return intval(self::doo()->userId());
return self::load()->userId();
}
/**
@ -194,8 +93,7 @@ class Doo
*/
public static function userExpired(): bool
{
$expiredAt = self::userExpiredAt();
return $expiredAt && Carbon::parse($expiredAt)->isBefore(Carbon::now());
return self::load()->userExpired();
}
/**
@ -204,8 +102,7 @@ class Doo
*/
public static function userExpiredAt(): ?string
{
$expiredAt = self::string(self::doo()->userExpiredAt());
return $expiredAt === 'forever' ? null : $expiredAt;
return self::load()->userExpiredAt();
}
/**
@ -214,7 +111,7 @@ class Doo
*/
public static function userEmail(): string
{
return self::string(self::doo()->userEmail());
return self::load()->userEmail();
}
/**
@ -223,7 +120,7 @@ class Doo
*/
public static function userEncrypt(): string
{
return self::string(self::doo()->userEncrypt());
return self::load()->userEncrypt();
}
/**
@ -232,7 +129,7 @@ class Doo
*/
public static function userToken(): string
{
return self::string(self::doo()->userToken());
return self::load()->userToken();
}
/**
@ -243,23 +140,7 @@ class Doo
*/
public static function userCreate($email, $password): User|null
{
$data = Base::json2array(self::string(self::doo()->userCreate($email, $password)));
if (Base::isError($data)) {
throw new ApiException($data['msg'] ?: '注册失败');
}
if (\DB::transactionLevel() > 0) {
try {
\DB::commit();
\DB::beginTransaction();
} catch (\Throwable) {
// do nothing
}
}
$user = User::whereEmail($email)->first();
if (empty($user)) {
throw new ApiException('注册失败');
}
return $user;
return self::load()->userCreate($email, $password);
}
/**
@ -272,7 +153,7 @@ class Doo
*/
public static function tokenEncode($userid, $email, $encrypt, int $days = 15): string
{
return self::string(self::doo()->tokenEncode($userid, $email, $encrypt, $days));
return self::load()->tokenEncode($userid, $email, $encrypt, $days);
}
/**
@ -282,34 +163,30 @@ class Doo
*/
public static function tokenDecode($token): array
{
$array = Base::json2array(self::string(self::doo()->tokenDecode($token)));
$array['expired_at'] = $array['expired_at'] === 'forever' ? null : $array['expired_at'];
return $array;
return self::load()->tokenDecode($token);
}
/**
* 翻译
* @param $text
* @param string $lang
* @param ?string $lang
* @return string
*/
public static function translate($text, string $lang = ""): string
public static function translate($text, ?string $lang = ""): string
{
if (empty($text)) {
return "";
}
if (empty($lang)) {
$lang = RequestContext::get(self::DOO_LANGUAGE);
}
return self::string(self::doo()->translate($text, $lang));
return self::load()->translate($text, $lang);
}
/**
* 设置语言
* @param string|int $lang 语言 会员ID
* @param int|string $lang 语言 会员ID
* @return void
*/
public static function setLanguage($lang) {
public static function setLanguage(int|string $lang): void
{
if (Base::isNumber($lang)) {
$lang = User::find(intval($lang))?->lang ?: "";
}
@ -318,10 +195,10 @@ class Doo
/**
* 获取语言列表 语言名称
* @param string|false $lang
* @param bool|string $lang
* @return string|string[]
*/
public static function getLanguages($lang = false)
public static function getLanguages(bool|string $lang = false): array|string
{
$array = [
"zh" => "简体中文",
@ -358,7 +235,7 @@ class Doo
*/
public static function md5s($text, string $password = ""): string
{
return self::string(self::doo()->md5s($text, $password));
return self::load()->md5s($text, $password);
}
/**
@ -367,14 +244,7 @@ class Doo
*/
public static function macs(): array
{
$macs = explode(",", self::string(self::doo()->macs()));
$array = [];
foreach ($macs as $mac) {
if (Base::isMac($mac)) {
$array[] = $mac;
}
}
return $array;
return self::load()->macs();
}
/**
@ -383,7 +253,7 @@ class Doo
*/
public static function dooSN(): string
{
return self::string(self::doo()->dooSN());
return self::load()->dooSN();
}
/**
@ -392,7 +262,7 @@ class Doo
*/
public static function dooVersion(): string
{
return self::string(self::doo()->version());
return self::load()->dooVersion();
}
/**
@ -404,7 +274,7 @@ class Doo
*/
public static function pgpGenerateKeyPair($name, $email, string $passphrase = ""): array
{
return Base::json2array(self::string(self::doo()->pgpGenerateKeyPair($name, $email, $passphrase)));
return self::load()->pgpGenerateKeyPair($name, $email, $passphrase);
}
/**
@ -415,11 +285,7 @@ class Doo
*/
public static function pgpEncrypt($plaintext, $publicKey): string
{
if (strlen($publicKey) < 50) {
$keyCache = Base::json2array(Cache::get("KeyPair::" . $publicKey));
$publicKey = $keyCache['public_key'];
}
return self::string(self::doo()->pgpEncrypt($plaintext, $publicKey));
return self::load()->pgpEncrypt($plaintext, $publicKey);
}
/**
@ -431,12 +297,7 @@ class Doo
*/
public static function pgpDecrypt($encryptedText, $privateKey, $passphrase = null): string
{
if (strlen($privateKey) < 50) {
$keyCache = Base::json2array(Cache::get("KeyPair::" . $privateKey));
$privateKey = $keyCache['private_key'];
$passphrase = $keyCache['passphrase'];
}
return self::string(self::doo()->pgpDecrypt($encryptedText, $privateKey, $passphrase));
return self::load()->pgpDecrypt($encryptedText, $privateKey, $passphrase);
}
/**
@ -447,9 +308,7 @@ class Doo
*/
public static function pgpEncryptApi($plaintext, $publicKey): string
{
$content = Base::array2json($plaintext);
$content = self::pgpEncrypt($content, $publicKey);
return preg_replace("/\s*-----(BEGIN|END) PGP MESSAGE-----\s*/i", "", $content);
return self::load()->pgpEncryptApi($plaintext, $publicKey);
}
/**
@ -461,9 +320,7 @@ class Doo
*/
public static function pgpDecryptApi($encryptedText, $privateKey, $passphrase = null): array
{
$content = "-----BEGIN PGP MESSAGE-----\n\n" . $encryptedText . "\n-----END PGP MESSAGE-----";
$content = self::pgpDecrypt($content, $privateKey, $passphrase);
return Base::json2array($content);
return self::load()->pgpDecryptApi($encryptedText, $privateKey, $passphrase);
}
/**
@ -473,24 +330,7 @@ class Doo
*/
public static function pgpParseStr($string): array
{
$array = [
'encrypt_type' => '',
'encrypt_id' => '',
'client_type' => '',
'client_key' => '',
];
$string = str_replace(";", "&", $string);
parse_str($string, $params);
foreach ($params as $key => $value) {
$key = strtolower(trim($key));
if ($key) {
$array[$key] = trim($value);
}
}
if ($array['client_type'] === 'pgp' && $array['client_key']) {
$array['client_key'] = self::pgpPublicFormat($array['client_key']);
}
return $array;
return self::load()->pgpParseStr($string);
}
/**
@ -500,10 +340,6 @@ class Doo
*/
public static function pgpPublicFormat($key): string
{
$key = str_replace(["-", "_", "$"], ["+", "/", "\n"], $key);
if (!str_contains($key, '-----BEGIN PGP PUBLIC KEY BLOCK-----')) {
$key = "-----BEGIN PGP PUBLIC KEY BLOCK-----\n\n" . $key . "\n-----END PGP PUBLIC KEY BLOCK-----";
}
return $key;
return self::load()->pgpPublicFormat($key);
}
}

View File

@ -0,0 +1,412 @@
<?php
namespace App\Module\Interface;
use App\Exceptions\ApiException;
use App\Module\Base;
use App\Models\User;
use Cache;
use Carbon\Carbon;
use DB;
use FFI;
use FFI\CData;
use FFI\Exception;
use Throwable;
class DooSo
{
private mixed $so;
public function __construct($token = null, $language = null)
{
$this->so = FFI::cdef(<<<EOF
void initialize(char* work, char* token, char* lang);
char* license();
char* licenseDecode(char* license);
char* licenseSave(char* license);
int userId();
char* userExpiredAt();
char* userEmail();
char* userEncrypt();
char* userToken();
char* userCreate(char* email, char* password);
char* tokenEncode(int userid, char* email, char* encrypt, int days);
char* tokenDecode(char* val);
char* translate(char* val, char* val);
char* md5s(char* text, char* password);
char* macs();
char* dooSN();
char* version();
char* pgpGenerateKeyPair(char* name, char* email, char* passphrase);
char* pgpEncrypt(char* plainText, char* publicKey);
char* pgpDecrypt(char* cipherText, char* privateKey, char* passphrase);
EOF, "/usr/lib/doo/doo.so");
$this->so->initialize("/var/www", $token, $language);
return $this->so;
}
/**
* char转为字符串
* @param $text
* @return string
*/
private static function string($text): string
{
if (!($text instanceof CData)) {
return "";
}
try {
return FFI::string($text);
} catch (Exception) {
return "";
}
}
/**
* License
* @return array
*/
public function license(): array
{
$array = Base::json2array(self::string($this->so->license()));
$ips = explode(",", $array['ip']);
$array['ip'] = [];
foreach ($ips as $ip) {
if (Base::is_ipv4($ip)) {
$array['ip'][] = $ip;
}
}
$domains = explode(",", $array['domain']);
$array['domain'] = [];
foreach ($domains as $domain) {
if (Base::is_domain($domain)) {
$array['domain'][] = $domain;
}
}
$macs = explode(",", $array['mac']);
$array['mac'] = [];
foreach ($macs as $mac) {
if (Base::isMac($mac)) {
$array['mac'][] = $mac;
}
}
$emails = explode(",", $array['email']);
$array['email'] = [];
foreach ($emails as $email) {
if (Base::isEmail($email)) {
$array['email'][] = $email;
}
}
return $array;
}
/**
* 解析License
* @param $license
* @return array
*/
public function licenseDecode($license): array
{
return Base::json2array(self::string($this->so->licenseDecode($license)));
}
/**
* 保存License
* @param $license
*/
public function licenseSave($license): void
{
$res = self::string($this->so->licenseSave($license));
if ($res != 'success') {
throw new ApiException($res ?: 'LICENSE 保存失败');
}
}
/**
* 当前会员ID来自请求的token
* @return int
*/
public function userId(): int
{
return intval($this->so->userId());
}
/**
* token是否过期来自请求的token
* @return bool
*/
public function userExpired(): bool
{
$expiredAt = $this->userExpiredAt();
return $expiredAt && Carbon::parse($expiredAt)->isBefore(Carbon::now());
}
/**
* token过期时间来自请求的token
* @return string|null
*/
public function userExpiredAt(): ?string
{
$expiredAt = self::string($this->so->userExpiredAt());
return $expiredAt === 'forever' ? null : $expiredAt;
}
/**
* 当前会员邮箱地址来自请求的token
* @return string
*/
public function userEmail(): string
{
return self::string($this->so->userEmail());
}
/**
* 当前会员Encrypt来自请求的token
* @return string
*/
public function userEncrypt(): string
{
return self::string($this->so->userEncrypt());
}
/**
* 当前会员token来自请求的token
* @return string
*/
public function userToken(): string
{
return self::string($this->so->userToken());
}
/**
* 创建帐号
* @param $email
* @param $password
* @return User|null
*/
public function userCreate($email, $password): User|null
{
$data = Base::json2array(self::string($this->so->userCreate($email, $password)));
if (Base::isError($data)) {
throw new ApiException($data['msg'] ?: '注册失败');
}
if (DB::transactionLevel() > 0) {
try {
DB::commit();
DB::beginTransaction();
} catch (Throwable) {
// do nothing
}
}
$user = User::whereEmail($email)->first();
if (empty($user)) {
throw new ApiException('注册失败');
}
return $user;
}
/**
* 生成token编码token
* @param $userid
* @param $email
* @param $encrypt
* @param int $days 有效时间(天)
* @return string
*/
public function tokenEncode($userid, $email, $encrypt, int $days = 15): string
{
return self::string($this->so->tokenEncode($userid, $email, $encrypt, $days));
}
/**
* 解码token
* @param $token
* @return array
*/
public function tokenDecode($token): array
{
$array = Base::json2array(self::string($this->so->tokenDecode($token)));
$array['expired_at'] = $array['expired_at'] === 'forever' ? null : $array['expired_at'];
return $array;
}
/**
* 翻译
* @param $text
* @param ?string $lang
* @return string
*/
public function translate($text, ?string $lang = ""): string
{
if (empty($text)) {
return "";
}
if (empty($lang)) {
$lang = "";
}
return self::string($this->so->translate($text, $lang));
}
/**
* md5防破解
* @param $text
* @param string $password
* @return string
*/
public function md5s($text, string $password = ""): string
{
return self::string($this->so->md5s($text, $password));
}
/**
* 获取php容器mac地址组
* @return array
*/
public function macs(): array
{
$macs = explode(",", self::string($this->so->macs()));
$array = [];
foreach ($macs as $mac) {
if (Base::isMac($mac)) {
$array[] = $mac;
}
}
return $array;
}
/**
* 获取当前SN
* @return string
*/
public function dooSN(): string
{
return self::string($this->so->dooSN());
}
/**
* 获取当前版本
* @return string
*/
public function dooVersion(): string
{
return self::string($this->so->version());
}
/**
* 生成PGP密钥对
* @param $name
* @param $email
* @param string $passphrase
* @return array
*/
public function pgpGenerateKeyPair($name, $email, string $passphrase = ""): array
{
return Base::json2array(self::string($this->so->pgpGenerateKeyPair($name, $email, $passphrase)));
}
/**
* PGP加密
* @param $plaintext
* @param $publicKey
* @return string
*/
public function pgpEncrypt($plaintext, $publicKey): string
{
if (strlen($publicKey) < 50) {
$keyCache = Base::json2array(Cache::get("KeyPair::" . $publicKey));
$publicKey = $keyCache['public_key'];
}
return self::string($this->so->pgpEncrypt($plaintext, $publicKey));
}
/**
* PGP解密
* @param $encryptedText
* @param $privateKey
* @param null $passphrase
* @return string
*/
public function pgpDecrypt($encryptedText, $privateKey, $passphrase = null): string
{
if (strlen($privateKey) < 50) {
$keyCache = Base::json2array(Cache::get("KeyPair::" . $privateKey));
$privateKey = $keyCache['private_key'];
$passphrase = $keyCache['passphrase'];
}
return self::string($this->so->pgpDecrypt($encryptedText, $privateKey, $passphrase));
}
/**
* PGP加密API
* @param $plaintext
* @param $publicKey
* @return string
*/
public function pgpEncryptApi($plaintext, $publicKey): string
{
$content = Base::array2json($plaintext);
$content = $this->pgpEncrypt($content, $publicKey);
return preg_replace("/\s*-----(BEGIN|END) PGP MESSAGE-----\s*/i", "", $content);
}
/**
* PGP解密API
* @param $encryptedText
* @param null $privateKey
* @param null $passphrase
* @return array
*/
public function pgpDecryptApi($encryptedText, $privateKey, $passphrase = null): array
{
$content = "-----BEGIN PGP MESSAGE-----\n\n" . $encryptedText . "\n-----END PGP MESSAGE-----";
$content = $this->pgpDecrypt($content, $privateKey, $passphrase);
return Base::json2array($content);
}
/**
* 解析PGP参数
* @param $string
* @return string[]
*/
public function pgpParseStr($string): array
{
$array = [
'encrypt_type' => '',
'encrypt_id' => '',
'client_type' => '',
'client_key' => '',
];
$string = str_replace(";", "&", $string);
parse_str($string, $params);
foreach ($params as $key => $value) {
$key = strtolower(trim($key));
if ($key) {
$array[$key] = trim($value);
}
}
if ($array['client_type'] === 'pgp' && $array['client_key']) {
$array['client_key'] = $this->pgpPublicFormat($array['client_key']);
}
return $array;
}
/**
* 还原公钥格式
* @param $key
* @return string
*/
public function pgpPublicFormat($key): string
{
$key = str_replace(["-", "_", "$"], ["+", "/", "\n"], $key);
if (!str_contains($key, '-----BEGIN PGP PUBLIC KEY BLOCK-----')) {
$key = "-----BEGIN PGP PUBLIC KEY BLOCK-----\n\n" . $key . "\n-----END PGP PUBLIC KEY BLOCK-----";
}
return $key;
}
}

View File

@ -39,16 +39,22 @@ class RequestContext
*/
public static function getCurrentRequestId($requestId = null): ?string
{
if (str_starts_with($requestId, self::REQUEST_ID_PREFIX)) {
// 如果提供了有效的请求ID直接返回
if ($requestId && str_starts_with($requestId, self::REQUEST_ID_PREFIX)) {
return $requestId;
}
// 尝试从当前请求获取
$request = request();
if (!$request->attributes->has(static::CONTEXT_KEY)) {
$request->attributes->set(static::CONTEXT_KEY, self::generateRequestId());
if ($request && method_exists($request, 'attributes') && $request->attributes) {
if (!$request->attributes->has(static::CONTEXT_KEY)) {
$request->attributes->set(static::CONTEXT_KEY, self::generateRequestId());
}
return $request->attributes->get(static::CONTEXT_KEY);
}
return $request->attributes->get(static::CONTEXT_KEY);
// 如果没有请求上下文生成一个新的请求ID
return self::generateRequestId();
}
/**