diff --git a/app/Http/Controllers/Api/ProjectController.php b/app/Http/Controllers/Api/ProjectController.php index cffbba6a3..82878556b 100755 --- a/app/Http/Controllers/Api/ProjectController.php +++ b/app/Http/Controllers/Api/ProjectController.php @@ -22,6 +22,7 @@ use App\Models\WebSocketDialog; use App\Module\Base; use App\Module\BillExport; use App\Module\BillMultipleExport; +use App\Module\Doo; use App\Module\TimeRange; use Carbon\Carbon; use Illuminate\Support\Arr; @@ -2082,12 +2083,12 @@ class ProjectController extends AbstractController if ($task_id === 0) { $log->projectTask?->cancelAppend(); } - $log->detail = Base::Lang($log->detail); + $log->detail = Doo::translate($log->detail); $log->time = [ 'ymd' => date(date("Y", $timestamp) == date("Y", Base::time()) ? "m-d" : "Y-m-d", $timestamp), 'hi' => date("h:i", $timestamp) , - 'week' => Base::Lang("周" . Base::getTimeWeek($timestamp)), - 'segment' => Base::Lang(Base::getTimeDayeSegment($timestamp)), + 'week' => Doo::translate("周" . Base::getTimeWeek($timestamp)), + 'segment' => Doo::translate(Base::getTimeDayeSegment($timestamp)), ]; return $log; }); diff --git a/app/Http/Controllers/Api/ReportController.php b/app/Http/Controllers/Api/ReportController.php index db479bbb5..ec1e9c1de 100755 --- a/app/Http/Controllers/Api/ReportController.php +++ b/app/Http/Controllers/Api/ReportController.php @@ -9,6 +9,7 @@ use App\Models\Report; use App\Models\ReportReceive; use App\Models\User; use App\Module\Base; +use App\Module\Doo; use App\Tasks\PushTask; use Carbon\Carbon; use Hhxsv5\LaravelS\Swoole\Task\Task; @@ -306,7 +307,7 @@ class ReportController extends AbstractController if ($complete_task->isNotEmpty()) { foreach ($complete_task as $task) { $complete_at = Carbon::parse($task->complete_at); - $pre = $type == Report::WEEKLY ? ('[' . Base::Lang('周' . ['日', '一', '二', '三', '四', '五', '六'][$complete_at->dayOfWeek]) . '] ') : ''; + $pre = $type == Report::WEEKLY ? ('[' . Doo::translate('周' . ['日', '一', '二', '三', '四', '五', '六'][$complete_at->dayOfWeek]) . '] ') : ''; $completeContent .= "
  • {$pre}[{$task->project->name}] {$task->name}
  • "; } } else { @@ -327,7 +328,7 @@ class ReportController extends AbstractController if ($unfinished_task->isNotEmpty()) { foreach ($unfinished_task as $task) { empty($task->end_at) || $end_at = Carbon::parse($task->end_at); - $pre = (!empty($end_at) && $end_at->lt($now_dt)) ? '[' . Base::Lang('超期') . '] ' : ''; + $pre = (!empty($end_at) && $end_at->lt($now_dt)) ? '[' . Doo::translate('超期') . '] ' : ''; $unfinishedContent .= "
  • {$pre}[{$task->project->name}] {$task->name}
  • "; } } else { @@ -341,12 +342,12 @@ class ReportController extends AbstractController $title = $user->nickname . "的日报[" . $start_time->format("Y/m/d") . "]"; } // 生成内容 - $content = '

    ' . Base::Lang('已完成工作') . '

      ' . + $content = '

      ' . Doo::translate('已完成工作') . '

        ' . $completeContent . '

      ' . - Base::Lang('未完成的工作') . '

        ' . + Doo::translate('未完成的工作') . '
          ' . $unfinishedContent . '
        '; if ($type === Report::WEEKLY) { - $content .= "

        " . Base::Lang("下周拟定计划") . "[" . $start_time->addWeek()->format("m/d") . "-" . $end_time->addWeek()->format("m/d") . "]

        1.  
        "; + $content .= "

        " . Doo::translate("下周拟定计划") . "[" . $start_time->addWeek()->format("m/d") . "-" . $end_time->addWeek()->format("m/d") . "]

        1.  
        "; } $data = [ "time" => $start_time->toDateTimeString(), diff --git a/app/Http/Controllers/Api/UsersController.php b/app/Http/Controllers/Api/UsersController.php index dc157a311..95a860f9c 100755 --- a/app/Http/Controllers/Api/UsersController.php +++ b/app/Http/Controllers/Api/UsersController.php @@ -19,6 +19,7 @@ use App\Models\WebSocketDialog; use App\Models\WebSocketDialogMsg; use App\Module\AgoraIO\AgoraTokenGenerator; use App\Module\Base; +use App\Module\Doo; use Arr; use Cache; use Captcha; @@ -135,8 +136,8 @@ class UsersController extends AbstractController // if (!Project::withTrashed()->whereUserid($user->userid)->wherePersonal(1)->exists()) { Project::createProject([ - 'name' => Base::Lang('个人项目'), - 'desc' => Base::Lang('注册时系统自动创建项目,你可以自由删除。'), + 'name' => Doo::translate('个人项目'), + 'desc' => Doo::translate('注册时系统自动创建项目,你可以自由删除。'), 'personal' => 1, ], $user->userid); } @@ -530,13 +531,13 @@ class UsersController extends AbstractController return preg_match("/\(M\)$/", $item); }); if ($dep) { - $tags[] = preg_replace("/\(M\)$/", "", trim($dep[0])) . Base::Lang("负责人"); + $tags[] = preg_replace("/\(M\)$/", "", trim($dep[0])) . Doo::translate("负责人"); } if ($userInfo->isAdmin()) { - $tags[] = Base::Lang("系统管理员"); + $tags[] = Doo::translate("系统管理员"); } if ($userInfo->isTemp()) { - $tags[] = Base::Lang("临时帐号"); + $tags[] = Doo::translate("临时帐号"); } $userInfo->tags = $tags; // diff --git a/app/Http/Middleware/WebApi.php b/app/Http/Middleware/WebApi.php index 77168c009..cc6083e53 100644 --- a/app/Http/Middleware/WebApi.php +++ b/app/Http/Middleware/WebApi.php @@ -4,6 +4,7 @@ namespace App\Http\Middleware; @error_reporting(E_ALL & ~E_NOTICE & ~E_WARNING); +use App\Module\Doo; use Closure; use Request; @@ -31,6 +32,7 @@ class WebApi if (in_array(strtolower($APP_SCHEME), ['https', 'on', 'ssl', '1', 'true', 'yes'], true)) { $request->setTrustedProxies([$request->getClientIp()], $request::HEADER_X_FORWARDED_PROTO); } + Doo::init(); return $next($request); } diff --git a/app/Models/UserBot.php b/app/Models/UserBot.php index 520b7bdfe..9444711fc 100644 --- a/app/Models/UserBot.php +++ b/app/Models/UserBot.php @@ -2,7 +2,7 @@ namespace App\Models; -use App\Module\Base; +use App\Module\Doo; use App\Module\Extranet; use Cache; use Carbon\Carbon; @@ -47,43 +47,43 @@ class UserBot extends AbstractModel 'check-in@bot.system' => [ [ 'key' => 'checkin', - 'label' => Base::Lang('我要签到') + 'label' => Doo::translate('我要签到') ], [ 'key' => 'it', - 'label' => Base::Lang('IT资讯') + 'label' => Doo::translate('IT资讯') ], [ 'key' => '36ke', - 'label' => Base::Lang('36氪') + 'label' => Doo::translate('36氪') ], [ 'key' => '60s', - 'label' => Base::Lang('60s读世界') + 'label' => Doo::translate('60s读世界') ], [ 'key' => 'joke', - 'label' => Base::Lang('开心笑话') + 'label' => Doo::translate('开心笑话') ], [ 'key' => 'soup', - 'label' => Base::Lang('心灵鸡汤') + 'label' => Doo::translate('心灵鸡汤') ] ], 'anon-msg@bot.system' => [ [ 'key' => 'help', - 'label' => Base::Lang('使用说明') + 'label' => Doo::translate('使用说明') ], [ 'key' => 'privacy', - 'label' => Base::Lang('隐私说明') + 'label' => Doo::translate('隐私说明') ], ], 'bot-manager@bot.system' => [ [ 'key' => '/help', - 'label' => Base::Lang('帮助指令') + 'label' => Doo::translate('帮助指令') ], [ 'key' => '/api', - 'label' => Base::Lang('Api接口文档') + 'label' => Doo::translate('Api接口文档') ], [ 'key' => '/list', - 'label' => Base::Lang('我的机器人') + 'label' => Doo::translate('我的机器人') ], ], default => [], diff --git a/app/Models/WebSocketDialog.php b/app/Models/WebSocketDialog.php index 337934209..38be79c03 100644 --- a/app/Models/WebSocketDialog.php +++ b/app/Models/WebSocketDialog.php @@ -4,6 +4,7 @@ namespace App\Models; use App\Exceptions\ApiException; use App\Module\Base; +use App\Module\Doo; use App\Tasks\PushTask; use Cache; use Carbon\Carbon; @@ -147,7 +148,7 @@ class WebSocketDialog extends AbstractModel } break; case 'all': - $this->name = Base::Lang('全体成员'); + $this->name = Doo::translate('全体成员'); $this->all_group_mute = Base::settingFind('system', 'all_group_mute'); break; } @@ -181,7 +182,7 @@ class WebSocketDialog extends AbstractModel && $mention_id = intval($builder->clone()->whereMention(1)->orderByDesc('msg_id')->value('msg_id'))) { $array[] = [ 'msg_id' => $mention_id, - 'label' => Base::Lang('@我的消息'), + 'label' => Doo::translate('@我的消息'), ]; } // 最早一条未读消息 @@ -374,7 +375,7 @@ class WebSocketDialog extends AbstractModel $name = \DB::table('project_tasks')->where('dialog_id', $this->id)->value('name'); break; case 'all': - $name = Base::Lang('全体成员'); + $name = Doo::translate('全体成员'); break; } } diff --git a/app/Module/Base.php b/app/Module/Base.php index 3f2f86f71..9961a4682 100755 --- a/app/Module/Base.php +++ b/app/Module/Base.php @@ -1458,73 +1458,6 @@ class Base } } - /** - * 国际化(替换国际语言) - * @param $val - * @return mixed - */ - public static function Lang($val) - { - $data = self::langData(); - if (isset($data[$val])) { - return $data[$val] ?: $val; - } - foreach ($data as $key => $item) { - if (str_contains($key, "(*)")) { - $regex = str_replace("(*)", "~%~", $key); - $regex = preg_quote($regex); - $regex = str_replace("~%~", "(.*?)", $regex); - $regex = "/^" . $regex . "$/"; - if (preg_match($regex, $val)) { - $r = $item ?: $key; - return preg_replace_callback($regex, function($m) use ($r) { - $i = 0; - foreach ($m as $v) { - if ($i > 0) { - $r = preg_replace("/\(\*\)/", $v, $r, 1); - } - $i++; - } - return $r; - }, $val); - } - } - } - // - $undefinedPath = base_path('language/undefined-api.txt'); - if (self::$undefinedLang === null) { - self::$undefinedLang = []; - if (file_exists($undefinedPath)) { - self::$undefinedLang = explode("\n", file_get_contents($undefinedPath)); - self::$undefinedLang = array_values(array_filter(array_unique(self::$undefinedLang))); - } - } - if (!in_array($val, self::$undefinedLang)) { - self::$undefinedLang[] = $val; - @file_put_contents(base_path('language/undefined-api.txt'), "$val\n", FILE_APPEND); - } - return $val; - } - private static $undefinedLang = null; - - /** - * 加载语言数据 - * @return array - */ - public static function langData() - { - global $_A; - $language = trim(self::headerOrInput('language')); - if (!isset($_A["__static_langdata_" . $language])) { - $_A["__static_langdata_" . $language] = []; - $langpath = public_path('language/api/' . $language . '.json'); - if (file_exists($langpath) && $data = Base::json2array(file_get_contents($langpath))) { - $_A["__static_langdata_" . $language] = $data; - } - } - return $_A["__static_langdata_" . $language]; - } - /** * JSON返回 * @param $param @@ -1552,7 +1485,7 @@ class Base { return [ 'ret' => $ret, - 'msg' => self::Lang($msg), + 'msg' => Doo::translate($msg), 'data' => $data ]; } @@ -1568,7 +1501,7 @@ class Base { return [ 'ret' => $ret, - 'msg' => self::Lang($msg), + 'msg' => Doo::translate($msg), 'data' => $data ]; } diff --git a/app/Module/Doo.php b/app/Module/Doo.php new file mode 100644 index 000000000..ba826b26d --- /dev/null +++ b/app/Module/Doo.php @@ -0,0 +1,170 @@ +initialize(); + $doo->setWorkDir("/var/www"); + $doo->setDefaultLanguage(Base::headerOrInput('language')); + $doo->setUserToken(Base::getToken()); + self::$doo = $doo; + } + return self::$doo; + } + + /** + * char转为字符串 + * @param $text + * @return string + */ + public static function string($text) + { + return FFI::string($text); + } + + /** + * License + * @return array + */ + public static function license() + { + $array = Base::json2array(self::string(self::init()->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; + } + } + + $emails = explode(",", $array['email']); + $array['email'] = []; + foreach ($emails as $email) { + if (Base::isEmail($email)) { + $array['email'][] = $email; + } + } + + return $array; + } + + /** + * 当前会员ID(来自请求的token) + * @return int + */ + public static function userId() + { + return self::init()->userId(); + } + + /** + * token是否过期(来自请求的token) + * @return bool + */ + public static function userExpired() + { + return Carbon::parse(self::string(self::init()->userExpiredAt()))->isBefore(Carbon::now()); + } + + /** + * 当前会员邮箱地址(来自请求的token) + * @return string + */ + public static function userEmail() + { + return self::string(self::init()->userEmail()); + } + + /** + * 当前会员token(来自请求的token) + * @return string + */ + public static function userToken() + { + return self::string(self::init()->userToken()); + } + + /** + * 生成token(编码token) + * @param $userid + * @param $email + * @param $encrypt + * @param int $days 有效时间(天) + * @return string + */ + public static function tokenEncode($userid, $email, $encrypt, $days = 7) + { + return self::string(self::init()->tokenEncode($userid, $email, $encrypt, $days)); + } + + /** + * 解码token + * @param $token + * @return array + */ + public static function tokenDecode($token) + { + $array = Base::json2array(self::string(self::init()->tokenDecode($token))); + $array['is_expired'] = Carbon::parse($array['expired_at'])->isBefore(Carbon::now()); + return $array; + } + + + /** + * 翻译 + * @param string $text + * @param string|null $type + * @return string + */ + public static function translate($text, $type = null) + { + if ($type) { + $test = self::init()->translateSpecified($text, $type); + } else { + $test = self::init()->translate($text); + } + return self::string($test); + } +} diff --git a/app/Module/Lib/doo.h b/app/Module/Lib/doo.h new file mode 100644 index 000000000..f5e9f49d4 --- /dev/null +++ b/app/Module/Lib/doo.h @@ -0,0 +1,93 @@ +/* Code generated by cmd/cgo; DO NOT EDIT. */ + +/* package command-line-arguments */ + + +#line 1 "cgo-builtin-export-prolog" + +#include + +#ifndef GO_CGO_EXPORT_PROLOGUE_H +#define GO_CGO_EXPORT_PROLOGUE_H + +#ifndef GO_CGO_GOSTRING_TYPEDEF +typedef struct { const char *p; ptrdiff_t n; } _GoString_; +#endif + +#endif + +/* Start of preamble from import "C" comments. */ + + + + +/* End of preamble from import "C" comments. */ + + +/* Start of boilerplate cgo prologue. */ +#line 1 "cgo-gcc-export-header-prolog" + +#ifndef GO_CGO_PROLOGUE_H +#define GO_CGO_PROLOGUE_H + +typedef signed char GoInt8; +typedef unsigned char GoUint8; +typedef short GoInt16; +typedef unsigned short GoUint16; +typedef int GoInt32; +typedef unsigned int GoUint32; +typedef long long GoInt64; +typedef unsigned long long GoUint64; +typedef GoInt64 GoInt; +typedef GoUint64 GoUint; +typedef size_t GoUintptr; +typedef float GoFloat32; +typedef double GoFloat64; +#ifdef _MSC_VER +#include +typedef _Fcomplex GoComplex64; +typedef _Dcomplex GoComplex128; +#else +typedef float _Complex GoComplex64; +typedef double _Complex GoComplex128; +#endif + +/* + static assertion to make sure the file is being used on architecture + at least with matching size of GoInt. +*/ +typedef char _check_for_64_bit_pointer_matching_GoInt[sizeof(void*)==64/8 ? 1:-1]; + +#ifndef GO_CGO_GOSTRING_TYPEDEF +typedef _GoString_ GoString; +#endif +typedef void *GoMap; +typedef void *GoChan; +typedef struct { void *t; void *v; } GoInterface; +typedef struct { void *data; GoInt len; GoInt cap; } GoSlice; + +#endif + +/* End of boilerplate cgo prologue. */ + +#ifdef __cplusplus +extern "C" { +#endif + +extern void initialize(); +extern void setWorkDir(char* val); +extern void setDefaultLanguage(char* val); +extern void setUserToken(char* token); +extern char* license(); +extern int userId(); +extern char* userExpiredAt(); +extern char* userEmail(); +extern char* userToken(); +extern char* tokenEncode(int userid, char* email, char* encrypt, int days); +extern char* tokenDecode(char* token); +extern char* translate(char* text); +extern char* translateSpecified(char* text, char* langType); + +#ifdef __cplusplus +} +#endif diff --git a/app/Module/Lib/doo.so b/app/Module/Lib/doo.so new file mode 100644 index 000000000..537e9ce3e Binary files /dev/null and b/app/Module/Lib/doo.so differ diff --git a/docker-compose.yml b/docker-compose.yml index 0e11ff1fc..7c530ec6e 100755 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -3,7 +3,7 @@ version: '3' services: php: container_name: "dootask-php-${APP_ID}" - image: "kuaifan/php:swoole-8.0.rc2" + image: "kuaifan/php:swoole-8.0.rc3" shm_size: "1024m" volumes: - ./docker/crontab/crontab.conf:/etc/supervisor/conf.d/crontab.conf