From 125df13976daec27a9df294e0b496093dc350235 Mon Sep 17 00:00:00 2001 From: moonrailgun Date: Tue, 7 May 2024 21:36:02 +0800 Subject: [PATCH] feat: add tianji script environment --- client/shared/hooks/useDataReady.ts | 27 ++++++++++++++++++ client/shared/index.tsx | 1 + client/shared/model/config.ts | 8 ++++++ client/shared/utils/consts.ts | 1 + client/web/src/App.tsx | 3 ++ client/web/src/hooks/useInjectTianjiScript.ts | 28 +++++++++++++++++++ server/.env.example | 4 +++ .../packages/sdk/src/services/lib/settings.ts | 7 +++++ server/services/core/config.service.ts | 1 + website/docs/deployment/environment.md | 2 ++ .../current/deployment/environment.md | 2 ++ 11 files changed, 84 insertions(+) create mode 100644 client/shared/hooks/useDataReady.ts create mode 100644 client/web/src/hooks/useInjectTianjiScript.ts diff --git a/client/shared/hooks/useDataReady.ts b/client/shared/hooks/useDataReady.ts new file mode 100644 index 00000000..56ca5b64 --- /dev/null +++ b/client/shared/hooks/useDataReady.ts @@ -0,0 +1,27 @@ +import { DependencyList, useLayoutEffect, useRef } from 'react'; +import { useEvent } from './useEvent'; + +/** + * Call once on data ready(validator return true) + */ +export function useDataReady( + validator: () => boolean, + cb: () => void, + deps?: DependencyList +) { + const isReadyRef = useRef(false); + + const _validator = useEvent(validator); + const _callback = useEvent(cb); + + useLayoutEffect(() => { + if (isReadyRef.current) { + return; + } + + if (_validator() === true) { + _callback(); + isReadyRef.current = true; + } + }, deps); +} diff --git a/client/shared/index.tsx b/client/shared/index.tsx index 0a4ba35e..12789960 100644 --- a/client/shared/index.tsx +++ b/client/shared/index.tsx @@ -74,6 +74,7 @@ export { useAsync } from './hooks/useAsync'; export { useAsyncFn } from './hooks/useAsyncFn'; export { useAsyncRefresh } from './hooks/useAsyncRefresh'; export { useAsyncRequest } from './hooks/useAsyncRequest'; +export { useDataReady } from './hooks/useDataReady'; export { useDebounce } from './hooks/useDebounce'; export { useEditValue } from './hooks/useEditValue'; export { useEvent } from './hooks/useEvent'; diff --git a/client/shared/model/config.ts b/client/shared/model/config.ts index c45805bd..37a623bc 100644 --- a/client/shared/model/config.ts +++ b/client/shared/model/config.ts @@ -6,6 +6,14 @@ import { defaultGlobalConfig } from '../utils/consts'; * 后端的全局设置 */ export interface GlobalConfig { + /** + * Tianji 配置 + */ + tianji: { + scriptUrl?: string; + websiteId?: string; + }; + /** * 上传文件体积 * 默认1m diff --git a/client/shared/utils/consts.ts b/client/shared/utils/consts.ts index acf5561e..ec1f4819 100644 --- a/client/shared/utils/consts.ts +++ b/client/shared/utils/consts.ts @@ -19,6 +19,7 @@ export const LANGUAGE_KEY = 'i18n:language'; export const SYSTEM_USERID = '000000000000000000000000'; export const defaultGlobalConfig: GlobalConfig = { + tianji: {}, uploadFileLimit: 1 * 1024 * 1024, emailVerification: false, serverName: 'Tailchat', diff --git a/client/web/src/App.tsx b/client/web/src/App.tsx index 0cc9a45a..d41aace6 100644 --- a/client/web/src/App.tsx +++ b/client/web/src/App.tsx @@ -32,6 +32,7 @@ import { HTML5Backend } from 'react-dnd-html5-backend'; import { ErrorBoundary } from './components/ErrorBoundary'; import enUS from 'antd/es/locale/en_US'; import type { Locale } from 'antd/es/locale-provider'; +import { useInjectTianjiScript } from './hooks/useInjectTianjiScript'; const AppRouter: any = isElectron() ? HashRouter : BrowserRouter; @@ -146,6 +147,8 @@ AppHeader.displayName = 'AppHeader'; export const App: React.FC = React.memo(() => { useRecordMeasure('appRenderStart'); + useInjectTianjiScript(); + useEffect(() => { sharedEvent.emit('appLoaded'); }, []); diff --git a/client/web/src/hooks/useInjectTianjiScript.ts b/client/web/src/hooks/useInjectTianjiScript.ts new file mode 100644 index 00000000..1c6c26bc --- /dev/null +++ b/client/web/src/hooks/useInjectTianjiScript.ts @@ -0,0 +1,28 @@ +import { useDataReady, useGlobalConfigStore } from 'tailchat-shared'; + +export function useInjectTianjiScript() { + const { tianji } = useGlobalConfigStore(); + + useDataReady( + () => + typeof tianji.scriptUrl === 'string' && + typeof tianji.websiteId === 'string' && + tianji.websiteId.length > 0, + () => { + if (!tianji.scriptUrl) { + console.error( + 'Cannot inject Tianji script because of scriptUrl not cool:', + tianji.scriptUrl + ); + return; + } + + const el = document.createElement('script'); + el.src = tianji.scriptUrl; + el.setAttribute('data-website-id', String(tianji.websiteId)); + el.setAttribute('async', 'async'); + el.setAttribute('defer', 'defer'); + document.head.append(el); + } + ); +} diff --git a/server/.env.example b/server/.env.example index f31c7b57..a6ff3f5a 100644 --- a/server/.env.example +++ b/server/.env.example @@ -33,3 +33,7 @@ ADMIN_PASS=com.msgbyte.tailchat GETUI_APPID= GETUI_APPKEY= GETUI_MASTERSECRET= + +# Tianji +TIANJI_SCRIPT_URL= +TIANJI_WEBSITE_ID= diff --git a/server/packages/sdk/src/services/lib/settings.ts b/server/packages/sdk/src/services/lib/settings.ts index a564e0bd..37732d6e 100644 --- a/server/packages/sdk/src/services/lib/settings.ts +++ b/server/packages/sdk/src/services/lib/settings.ts @@ -55,6 +55,13 @@ export const config = { runner: { requestTimeout, }, + /** + * 使用Tianji对网站进行监控 + */ + tianji: { + scriptUrl: process.env.TIANJI_SCRIPT_URL, + websiteId: process.env.TIANJI_WEBSITE_ID, + }, feature: { disableFileCheck: checkEnvTrusty(process.env.DISABLE_FILE_CHECK), disableLogger: checkEnvTrusty(process.env.DISABLE_LOGGER), // 是否关闭日志 diff --git a/server/services/core/config.service.ts b/server/services/core/config.service.ts index 258ea989..d703f311 100644 --- a/server/services/core/config.service.ts +++ b/server/services/core/config.service.ts @@ -77,6 +77,7 @@ class ConfigService extends TcService { const persistConfig = await this.adapter.model.getAllClientPersistConfig(); return { + tianji: config.tianji, uploadFileLimit: config.storage.limit, emailVerification: config.emailVerification, disableUserRegister: config.feature.disableUserRegister, diff --git a/website/docs/deployment/environment.md b/website/docs/deployment/environment.md index 446c6f3f..120997e2 100644 --- a/website/docs/deployment/environment.md +++ b/website/docs/deployment/environment.md @@ -25,6 +25,8 @@ title: Environment Variable | FILE_LIMIT | 1048576 | File/image upload size limit, the default is 1m, please enter a number(unit: byte) | | EMAIL_VERIFY | - | Whether to enable email verification, if it is "1" or "true", add email verification control when registering | | REQUEST_TIMEOUT | 10000 | Number of milliseconds to wait before reject a request with a RequestTimeout error. Disabled: 0 | +| TIANJI_SCRIPT_URL | - | Script Url of Tianji if you wanna monitor Tailchat user usage, you can get it in code modal in Tianji website (example: `https://tianji.example.com/tracker.js`) | +| TIANJI_WEBSITE_ID | - | Tianji website id | | DISABLE_LOGGER | - | Whether to disable the log output, if "1" or "true" turn off the log on the fly | | DISABLE_USER_REGISTER | - | Whether to disable the user register, if "1" or "true" turn off this method | | DISABLE_GUEST_LOGIN | - | Whether to disable the guest login, if "1" or "true" turn off this method | diff --git a/website/i18n/zh-Hans/docusaurus-plugin-content-docs/current/deployment/environment.md b/website/i18n/zh-Hans/docusaurus-plugin-content-docs/current/deployment/environment.md index 21de2e43..62167200 100644 --- a/website/i18n/zh-Hans/docusaurus-plugin-content-docs/current/deployment/environment.md +++ b/website/i18n/zh-Hans/docusaurus-plugin-content-docs/current/deployment/environment.md @@ -25,6 +25,8 @@ title: 环境变量 | FILE_LIMIT | 1048576 | 文件/图片上传的大小限制,默认为1m,请输入数字,(单位: 字节) | | EMAIL_VERIFY | - | 是否开启邮箱校验, 如果为 "1" 或者 "true" 则在注册时增加邮箱校验控制 | | REQUEST_TIMEOUT | 10000 | 请求超时毫秒数,请求超过该时间没有完成会抛出 `RequestTimeout` 错误。 如果需要禁用请求超时限制传:0 | +| TIANJI_SCRIPT_URL | - | Tianji 脚本 URL,如需监控 Tailchat 用户使用情况,可在天际网站代码模式中获取 (例如:`https://tianji.example.com/tracker.js`) | +| TIANJI_WEBSITE_ID | - | Tianji 网站 id | | DISABLE_LOGGER | - | 是否禁用日志输出, 如果为 "1" 或者 "true" 则在运行中关闭日志 | | DISABLE_USER_REGISTER | - | 是否关闭用户注册功能, 如果为 "1" 或者 "true" 则关闭该功能 | | DISABLE_GUEST_LOGIN | - | 是否关闭用户游客登录功能, 如果为 "1" 或者 "true" 则关闭该功能 |