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); $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); Coroutine::sleep(1);
// //
$content = []; $content = [];
@ -802,30 +803,30 @@ class ApproveController extends AbstractController
$res = Base::arrayKeyToUnderline($process['data']); $res = Base::arrayKeyToUnderline($process['data']);
// //
$headings = []; $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('发起人User ID'); $headings[] = $doo->translate('发起人User ID');
$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('审批耗时'); $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 = []; $datas = [];
foreach ($res as $val) { foreach ($res as $val) {
@ -845,12 +846,12 @@ class ApproveController extends AbstractController
// 计算审批耗时 // 计算审批耗时
$startTime = Carbon::parse($val['start_time'])->timestamp; $startTime = Carbon::parse($val['start_time'])->timestamp;
$endTime = $val['end_time'] ? Carbon::parse($val['end_time'])->timestamp : time(); $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']); $varStartTime = Carbon::parse($val['var']['start_time']);
$varEndTime = Carbon::parse($val['var']['end_time']); $varEndTime = Carbon::parse($val['var']['end_time']);
$duration = $varEndTime->floatDiffInHours($varStartTime); $duration = $varEndTime->floatDiffInHours($varStartTime);
$duration_unit = Doo::translate('小时'); // 时长单位 $duration_unit = $doo->translate('小时'); // 时长单位
$datas[] = [ $datas[] = [
$val['id'], // 申请编号 $val['id'], // 申请编号
$val['proc_def_name'], // 标题 $val['proc_def_name'], // 标题
@ -891,7 +892,7 @@ class ApproveController extends AbstractController
return; return;
} }
// //
$title = Doo::translate("审批记录"); $title = $doo->translate("审批记录");
$sheets = [ $sheets = [
BillExport::create()->setTitle($title)->setHeadings($headings)->setData($datas)->setStyles(["A1:Y1" => ["font" => ["bold" => true]]]) 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); $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); Coroutine::sleep(1);
$headings = []; $headings = [];
$headings[] = Doo::translate('任务ID'); $headings[] = $doo->translate('任务ID');
$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('任务计划用时');
$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 = []; $datas = [];
// //
$content = []; $content = [];
@ -1330,9 +1331,9 @@ class ProjectController extends AbstractController
$planTotalTime = $endTime - $startTime; $planTotalTime = $endTime - $startTime;
$residueTime = $planTotalTime - $totalTime; $residueTime = $planTotalTime - $totalTime;
if ($residueTime < 0) { 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; // 实际完成用时 $actualTime = $task->complete_at ? $totalTime : 0; // 实际完成用时
$statusText = '未完成'; $statusText = '未完成';
@ -1376,13 +1377,13 @@ class ProjectController extends AbstractController
$task->complete_at ?: '-', $task->complete_at ?: '-',
$task->archived_at ?: '-', $task->archived_at ?: '-',
$planTime, $planTime,
$actualTime ? Doo::translate(Timer::timeFormat($actualTime)) : '-', $actualTime ? $doo->translate(Timer::timeFormat($actualTime)) : '-',
$overTime, $overTime,
$developTime > 0 ? Doo::translate(Timer::timeFormat($developTime)) : '-', $developTime > 0 ? $doo->translate(Timer::timeFormat($developTime)) : '-',
$testTime > 0 ? Doo::translate(Timer::timeFormat($testTime)) : '-', $testTime > 0 ? $doo->translate(Timer::timeFormat($testTime)) : '-',
Base::filterEmoji(User::userid2nickname($task->ownerid)) . " (ID: {$task->ownerid})", Base::filterEmoji(User::userid2nickname($task->ownerid)) . " (ID: {$task->ownerid})",
Base::filterEmoji(User::userid2nickname($task->userid)) . " (ID: {$task->userid})", Base::filterEmoji(User::userid2nickname($task->userid)) . " (ID: {$task->userid})",
Doo::translate($statusText), $doo->translate($statusText),
]; ];
} }
}); });
@ -1416,7 +1417,7 @@ class ProjectController extends AbstractController
} else { } else {
$fileName .= '的任务统计'; $fileName .= '的任务统计';
} }
$fileName = Doo::translate($fileName) . '_' . Timer::time() . '.xls'; $fileName = $doo->translate($fileName) . '_' . Timer::time() . '.xls';
$filePath = "temp/task/export/" . date("Ym", Timer::time()); $filePath = "temp/task/export/" . date("Ym", Timer::time());
$export = new BillMultipleExport($sheets); $export = new BillMultipleExport($sheets);
$res = $export->store($filePath . "/" . $fileName); $res = $export->store($filePath . "/" . $fileName);
@ -1500,21 +1501,22 @@ class ProjectController extends AbstractController
} }
$dialog = WebSocketDialog::checkUserDialog($botUser, $user->userid); $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); Coroutine::sleep(1);
// //
$headings = []; $headings = [];
$headings[] = Doo::translate('任务ID'); $headings[] = $doo->translate('任务ID');
$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('负责人');
$headings[] = Doo::translate('创建人'); $headings[] = $doo->translate('创建人');
$data = []; $data = [];
// //
$content = []; $content = [];
@ -1541,9 +1543,9 @@ class ProjectController extends AbstractController
$planTotalTime = $endTime - $startTime; $planTotalTime = $endTime - $startTime;
$residueTime = $planTotalTime - $totalTime; $residueTime = $planTotalTime - $totalTime;
if ($residueTime < 0) { 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(); $ownerIds = $task->taskUser->where('owner', 1)->pluck('userid')->toArray();
$ownerNames = []; $ownerNames = [];
@ -1580,7 +1582,7 @@ class ProjectController extends AbstractController
return; return;
} }
// //
$title = Doo::translate('超期任务'); $title = $doo->translate('超期任务');
$sheets = [ $sheets = [
BillExport::create()->setTitle($title)->setHeadings($headings)->setData($data)->setStyles(["A1:J1" => ["font" => ["bold" => true]]]) 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); $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); Coroutine::sleep(1);
// //
$headings = []; $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 = [];
$content[] = [ $content[] = [
@ -1375,12 +1376,12 @@ class SystemController extends AbstractController
if (Timer::time() < $startT + $secondStart) { if (Timer::time() < $startT + $secondStart) {
$firstResult = "-"; $firstResult = "-";
} else { } else {
$firstResult = Doo::translate("正常"); $firstResult = $doo->translate("正常");
if (empty($firstTimestamp)) { if (empty($firstTimestamp)) {
$firstResult = Doo::translate("缺卡"); $firstResult = $doo->translate("缺卡");
$styles["E{$index}"] = ["font" => ["color" => ["rgb" => "ff0000"]]]; $styles["E{$index}"] = ["font" => ["color" => ["rgb" => "ff0000"]]];
} elseif ($firstTimestamp > $startT + $secondStart) { } elseif ($firstTimestamp > $startT + $secondStart) {
$firstResult = Doo::translate("迟到"); $firstResult = $doo->translate("迟到");
$styles["E{$index}"] = ["font" => ["color" => ["rgb" => "436FF6"]]]; $styles["E{$index}"] = ["font" => ["color" => ["rgb" => "436FF6"]]];
} }
} }
@ -1388,12 +1389,12 @@ class SystemController extends AbstractController
$lastResult = "-"; $lastResult = "-";
$lastTimestamp = 0; $lastTimestamp = 0;
} else { } else {
$lastResult = Doo::translate("正常"); $lastResult = $doo->translate("正常");
if (empty($lastTimestamp) || $lastTimestamp === $firstTimestamp) { if (empty($lastTimestamp) || $lastTimestamp === $firstTimestamp) {
$lastResult = Doo::translate("缺卡"); $lastResult = $doo->translate("缺卡");
$styles["G{$index}"] = ["font" => ["color" => ["rgb" => "ff0000"]]]; $styles["G{$index}"] = ["font" => ["color" => ["rgb" => "ff0000"]]];
} elseif ($lastTimestamp < $startT + $secondEnd) { } elseif ($lastTimestamp < $startT + $secondEnd) {
$lastResult = Doo::translate("早退"); $lastResult = $doo->translate("早退");
$styles["G{$index}"] = ["font" => ["color" => ["rgb" => "436FF6"]]]; $styles["G{$index}"] = ["font" => ["color" => ["rgb" => "436FF6"]]];
} }
} }
@ -1436,7 +1437,7 @@ class SystemController extends AbstractController
} else { } else {
$fileName .= '的签到记录'; $fileName .= '的签到记录';
} }
$fileName = Doo::translate($fileName) . '_' . Timer::time() . '.xlsx'; $fileName = $doo->translate($fileName) . '_' . Timer::time() . '.xlsx';
$filePath = "temp/checkin/export/" . date("Ym", Timer::time()); $filePath = "temp/checkin/export/" . date("Ym", Timer::time());
$export = new BillMultipleExport($sheets); $export = new BillMultipleExport($sheets);
$res = $export->store($filePath . "/" . $fileName); $res = $export->store($filePath . "/" . $fileName);

View File

@ -2,14 +2,9 @@
namespace App\Module; namespace App\Module;
use App\Exceptions\ApiException;
use App\Models\User; use App\Models\User;
use App\Module\Interface\DooSo;
use App\Services\RequestContext; use App\Services\RequestContext;
use Cache;
use Carbon\Carbon;
use FFI;
use FFI\CData;
use FFI\Exception;
class Doo class Doo
{ {
@ -17,56 +12,22 @@ class Doo
private const DOO_LANGUAGE = 'doo_language'; private const DOO_LANGUAGE = 'doo_language';
/** /**
* char转为字符串 * 加载Doo实例
* @param $text * - 如果已经存在,则直接返回
* @return string * - 否则创建一个新的FFI实例并初始化
*/
private static function string($text): string
{
if (!($text instanceof CData)) {
return "";
}
try {
return FFI::string($text);
} catch (Exception) {
return "";
}
}
/**
* 装载
* @param $token * @param $token
* @param $language * @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 if (RequestContext::has(self::DOO_INSTANCE)) {
void initialize(char* work, char* token, char* lang); return RequestContext::get(self::DOO_INSTANCE);
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");
$token = $token ?: Base::token(); $token = $token ?: Base::token();
$language = $language ?: Base::headerOrInput('language'); $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_INSTANCE, $instance);
RequestContext::set(self::DOO_LANGUAGE, $language); RequestContext::set(self::DOO_LANGUAGE, $language);
@ -74,62 +35,13 @@ class Doo
return $instance; 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 * License
* @return array * @return array
*/ */
public static function license(): array public static function license(): array
{ {
$array = Base::json2array(self::string(self::doo()->license())); return self::load()->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;
} }
/** /**
@ -157,26 +69,13 @@ class Doo
return $content; return $content;
} }
/**
* 解析License
* @param $license
* @return array
*/
public static function licenseDecode($license): array
{
return Base::json2array(self::string(self::doo()->licenseDecode($license)));
}
/** /**
* 保存License * 保存License
* @param $license * @param $license
*/ */
public static function licenseSave($license): void public static function licenseSave($license): void
{ {
$res = self::string(self::doo()->licenseSave($license)); self::load()->licenseSave($license);
if ($res != 'success') {
throw new ApiException($res ?: 'LICENSE 保存失败');
}
} }
/** /**
@ -185,7 +84,7 @@ class Doo
*/ */
public static function userId(): int 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 public static function userExpired(): bool
{ {
$expiredAt = self::userExpiredAt(); return self::load()->userExpired();
return $expiredAt && Carbon::parse($expiredAt)->isBefore(Carbon::now());
} }
/** /**
@ -204,8 +102,7 @@ class Doo
*/ */
public static function userExpiredAt(): ?string public static function userExpiredAt(): ?string
{ {
$expiredAt = self::string(self::doo()->userExpiredAt()); return self::load()->userExpiredAt();
return $expiredAt === 'forever' ? null : $expiredAt;
} }
/** /**
@ -214,7 +111,7 @@ class Doo
*/ */
public static function userEmail(): string 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 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 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 public static function userCreate($email, $password): User|null
{ {
$data = Base::json2array(self::string(self::doo()->userCreate($email, $password))); return self::load()->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;
} }
/** /**
@ -272,7 +153,7 @@ class Doo
*/ */
public static function tokenEncode($userid, $email, $encrypt, int $days = 15): string 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 public static function tokenDecode($token): array
{ {
$array = Base::json2array(self::string(self::doo()->tokenDecode($token))); return self::load()->tokenDecode($token);
$array['expired_at'] = $array['expired_at'] === 'forever' ? null : $array['expired_at'];
return $array;
} }
/** /**
* 翻译 * 翻译
* @param $text * @param $text
* @param string $lang * @param ?string $lang
* @return string * @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)) { if (empty($lang)) {
$lang = RequestContext::get(self::DOO_LANGUAGE); $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 * @return void
*/ */
public static function setLanguage($lang) { public static function setLanguage(int|string $lang): void
{
if (Base::isNumber($lang)) { if (Base::isNumber($lang)) {
$lang = User::find(intval($lang))?->lang ?: ""; $lang = User::find(intval($lang))?->lang ?: "";
} }
@ -318,10 +195,10 @@ class Doo
/** /**
* 获取语言列表 语言名称 * 获取语言列表 语言名称
* @param string|false $lang * @param bool|string $lang
* @return string|string[] * @return string|string[]
*/ */
public static function getLanguages($lang = false) public static function getLanguages(bool|string $lang = false): array|string
{ {
$array = [ $array = [
"zh" => "简体中文", "zh" => "简体中文",
@ -358,7 +235,7 @@ class Doo
*/ */
public static function md5s($text, string $password = ""): string 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 public static function macs(): array
{ {
$macs = explode(",", self::string(self::doo()->macs())); return self::load()->macs();
$array = [];
foreach ($macs as $mac) {
if (Base::isMac($mac)) {
$array[] = $mac;
}
}
return $array;
} }
/** /**
@ -383,7 +253,7 @@ class Doo
*/ */
public static function dooSN(): string 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 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 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 public static function pgpEncrypt($plaintext, $publicKey): string
{ {
if (strlen($publicKey) < 50) { return self::load()->pgpEncrypt($plaintext, $publicKey);
$keyCache = Base::json2array(Cache::get("KeyPair::" . $publicKey));
$publicKey = $keyCache['public_key'];
}
return self::string(self::doo()->pgpEncrypt($plaintext, $publicKey));
} }
/** /**
@ -431,12 +297,7 @@ class Doo
*/ */
public static function pgpDecrypt($encryptedText, $privateKey, $passphrase = null): string public static function pgpDecrypt($encryptedText, $privateKey, $passphrase = null): string
{ {
if (strlen($privateKey) < 50) { return self::load()->pgpDecrypt($encryptedText, $privateKey, $passphrase);
$keyCache = Base::json2array(Cache::get("KeyPair::" . $privateKey));
$privateKey = $keyCache['private_key'];
$passphrase = $keyCache['passphrase'];
}
return self::string(self::doo()->pgpDecrypt($encryptedText, $privateKey, $passphrase));
} }
/** /**
@ -447,9 +308,7 @@ class Doo
*/ */
public static function pgpEncryptApi($plaintext, $publicKey): string public static function pgpEncryptApi($plaintext, $publicKey): string
{ {
$content = Base::array2json($plaintext); return self::load()->pgpEncryptApi($plaintext, $publicKey);
$content = self::pgpEncrypt($content, $publicKey);
return preg_replace("/\s*-----(BEGIN|END) PGP MESSAGE-----\s*/i", "", $content);
} }
/** /**
@ -461,9 +320,7 @@ class Doo
*/ */
public static function pgpDecryptApi($encryptedText, $privateKey, $passphrase = null): array public static function pgpDecryptApi($encryptedText, $privateKey, $passphrase = null): array
{ {
$content = "-----BEGIN PGP MESSAGE-----\n\n" . $encryptedText . "\n-----END PGP MESSAGE-----"; return self::load()->pgpDecryptApi($encryptedText, $privateKey, $passphrase);
$content = self::pgpDecrypt($content, $privateKey, $passphrase);
return Base::json2array($content);
} }
/** /**
@ -473,24 +330,7 @@ class Doo
*/ */
public static function pgpParseStr($string): array public static function pgpParseStr($string): array
{ {
$array = [ return self::load()->pgpParseStr($string);
'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;
} }
/** /**
@ -500,10 +340,6 @@ class Doo
*/ */
public static function pgpPublicFormat($key): string public static function pgpPublicFormat($key): string
{ {
$key = str_replace(["-", "_", "$"], ["+", "/", "\n"], $key); return self::load()->pgpPublicFormat($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

@ -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,18 +39,24 @@ class RequestContext
*/ */
public static function getCurrentRequestId($requestId = null): ?string 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; return $requestId;
} }
// 尝试从当前请求获取
$request = request(); $request = request();
if ($request && method_exists($request, 'attributes') && $request->attributes) {
if (!$request->attributes->has(static::CONTEXT_KEY)) { if (!$request->attributes->has(static::CONTEXT_KEY)) {
$request->attributes->set(static::CONTEXT_KEY, self::generateRequestId()); $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();
}
/** /**
* 获取当前请求的上下文示例 * 获取当前请求的上下文示例
*/ */