feat(history): establish Telegram SaaS platform foundation
This commit is contained in:
@@ -0,0 +1,79 @@
|
||||
const base = () => (process.env.TELEGRAM_GATEWAY_URL || 'http://host.docker.internal:3000/api').replace(/\/$/, '')
|
||||
|
||||
let gatewayToken = process.env.TELEGRAM_GATEWAY_TOKEN || ''
|
||||
let refreshPromise
|
||||
|
||||
function tokenExpiresSoon(token) {
|
||||
try {
|
||||
const payload = JSON.parse(Buffer.from(token.split('.')[1], 'base64url').toString('utf8'))
|
||||
return !payload.exp || payload.exp * 1000 < Date.now() + 5 * 60 * 1000
|
||||
} catch {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
async function refreshGatewayToken() {
|
||||
if (refreshPromise) return refreshPromise
|
||||
refreshPromise = (async () => {
|
||||
const email = process.env.TELEGRAM_GATEWAY_SERVICE_EMAIL
|
||||
const password = process.env.TELEGRAM_GATEWAY_SERVICE_PASSWORD
|
||||
const tenantId = process.env.TELEGRAM_GATEWAY_TENANT_ID
|
||||
if (!email || !password || !tenantId) {
|
||||
throw Object.assign(new Error('Telegram 网关服务账号凭据尚未配置'), { status: 503 })
|
||||
}
|
||||
const response = await fetch(`${base()}/auth/login`, {
|
||||
method: 'POST',
|
||||
headers: { 'content-type': 'application/json' },
|
||||
body: JSON.stringify({ email, password, tenantId }),
|
||||
})
|
||||
const raw = await response.text()
|
||||
let result
|
||||
try { result = raw ? JSON.parse(raw) : null } catch { result = raw }
|
||||
const token = result?.data?.token || result?.token
|
||||
if (!response.ok || !token) {
|
||||
throw Object.assign(new Error(result?.message || 'Telegram 网关服务账号续签失败'), { status: response.status || 503 })
|
||||
}
|
||||
gatewayToken = token
|
||||
return token
|
||||
})().finally(() => { refreshPromise = undefined })
|
||||
return refreshPromise
|
||||
}
|
||||
|
||||
export async function gatewayRequest(path, options = {}) {
|
||||
const tenantId = process.env.TELEGRAM_GATEWAY_TENANT_ID
|
||||
if (!tenantId) throw Object.assign(new Error('Telegram 网关租户尚未配置'), { status: 503 })
|
||||
if (!gatewayToken || tokenExpiresSoon(gatewayToken)) await refreshGatewayToken()
|
||||
const send = () => fetch(`${base()}${path}`, {
|
||||
...options,
|
||||
headers: {
|
||||
...(options.body instanceof FormData ? {} : { 'content-type': 'application/json' }),
|
||||
authorization: `Bearer ${gatewayToken}`,
|
||||
'x-tenant-id': tenantId,
|
||||
...(options.headers || {}),
|
||||
},
|
||||
})
|
||||
let response = await send()
|
||||
if (response.status === 401) {
|
||||
await refreshGatewayToken()
|
||||
response = await send()
|
||||
}
|
||||
const raw = await response.text()
|
||||
let result
|
||||
try { result = raw ? JSON.parse(raw) : null } catch { result = raw }
|
||||
if (!response.ok) {
|
||||
throw Object.assign(new Error(result?.message || `Telegram 网关请求失败 (${response.status})`), { status: response.status })
|
||||
}
|
||||
return result?.data ?? result
|
||||
}
|
||||
|
||||
export function postGateway(path, body) {
|
||||
return gatewayRequest(path, { method: 'POST', body: JSON.stringify(body) })
|
||||
}
|
||||
|
||||
export function putGateway(path, body) {
|
||||
return gatewayRequest(path, { method: 'PUT', body: JSON.stringify(body) })
|
||||
}
|
||||
|
||||
export function uploadGateway(path, formData) {
|
||||
return gatewayRequest(path, { method: 'POST', body: formData })
|
||||
}
|
||||
Reference in New Issue
Block a user