refactor: restructure project directories for better modularity

- Delete llm/ dead code (3 files, zero references)
- Split mcp/ into sub-packages: mcp/provider/ (8 providers) and
  mcp/payment/ (4 payment clients) with registry pattern
- Export Client internal fields and ClientHooks interface for
  sub-package access
- Split api/server.go (3892 lines) into 8 domain-specific handler files
- Split trader/auto_trader.go (2296 lines) into 5 focused files
- Reorganize web/src/components/ flat files into auth/, charts/,
  trader/, common/, modals/, backtest/ subdirectories
- Update all consumer imports to use registry-based provider creation
This commit is contained in:
tinkle-community
2026-03-11 23:58:13 +08:00
parent 6a30e11ee5
commit 8e294a5eed
103 changed files with 6391 additions and 8984 deletions

View File

@@ -0,0 +1,161 @@
import { useCallback, useEffect, useState, type ReactNode } from 'react'
import { Loader2, ShieldAlert, ShieldCheck, ShieldMinus } from 'lucide-react'
import { CryptoService, diagnoseWebCryptoEnvironment } from '../../lib/crypto'
import { t, type Language } from '../../i18n/translations'
export type WebCryptoCheckStatus =
| 'idle'
| 'checking'
| 'secure'
| 'insecure'
| 'unsupported'
| 'disabled' // Transport encryption disabled
interface WebCryptoEnvironmentCheckProps {
language: Language
variant?: 'card' | 'compact'
onStatusChange?: (status: WebCryptoCheckStatus) => void
}
export function WebCryptoEnvironmentCheck({
language,
variant = 'card',
onStatusChange,
}: WebCryptoEnvironmentCheckProps) {
const [status, setStatus] = useState<WebCryptoCheckStatus>('idle')
const [summary, setSummary] = useState<string | null>(null)
useEffect(() => {
onStatusChange?.(status)
}, [onStatusChange, status])
const runCheck = useCallback(async () => {
setStatus('checking')
setSummary(null)
try {
// First check if transport encryption is enabled on the server
const config = await CryptoService.fetchCryptoConfig()
if (!config.transport_encryption) {
setStatus('disabled')
return
}
const result = diagnoseWebCryptoEnvironment()
setSummary(
t('environmentCheck.summary', language, {
origin: result.origin || 'N/A',
protocol: result.protocol || 'unknown',
})
)
if (!result.isBrowser || !result.hasSubtleCrypto) {
setStatus('unsupported')
return
}
if (!result.isSecureContext) {
setStatus('insecure')
return
}
setStatus('secure')
} catch {
// If we can't fetch config, assume encryption is disabled
setStatus('disabled')
}
}, [language])
useEffect(() => {
runCheck()
}, [runCheck])
const isCompact = variant === 'compact'
const containerClass = isCompact
? 'p-3 rounded border border-gray-700 bg-gray-900 space-y-3'
: 'p-4 rounded border border-[#2B3139] bg-[#0B0E11] space-y-4'
const descriptionColor = isCompact ? '#CBD5F5' : '#A1AEC8'
const showInfo = status !== 'idle'
const statusRendererMap: Record<WebCryptoCheckStatus, () => ReactNode> = {
secure: () => (
<div className="flex items-start gap-2 text-green-400 text-xs">
<ShieldCheck className="w-4 h-4 flex-shrink-0" />
<div>
<div className="font-semibold">
{t('environmentCheck.secureTitle', language)}
</div>
<div>{t('environmentCheck.secureDesc', language)}</div>
</div>
</div>
),
insecure: () => (
<div className="text-xs" style={{ color: '#F59E0B' }}>
<div className="flex items-start gap-2 mb-1">
<ShieldAlert className="w-4 h-4 flex-shrink-0" />
<div className="font-semibold">
{t('environmentCheck.insecureTitle', language)}
</div>
</div>
<div>{t('environmentCheck.insecureDesc', language)}</div>
<div className="mt-2 font-semibold">
{t('environmentCheck.tipsTitle', language)}
</div>
<ul className="list-disc pl-5 space-y-1 mt-1">
<li>{t('environmentCheck.tipHTTPS', language)}</li>
<li>{t('environmentCheck.tipLocalhost', language)}</li>
<li>{t('environmentCheck.tipIframe', language)}</li>
</ul>
</div>
),
unsupported: () => (
<div className="text-xs" style={{ color: '#F87171' }}>
<div className="flex items-start gap-2 mb-1">
<ShieldAlert className="w-4 h-4 flex-shrink-0" />
<div className="font-semibold">
{t('environmentCheck.unsupportedTitle', language)}
</div>
</div>
<div>{t('environmentCheck.unsupportedDesc', language)}</div>
</div>
),
disabled: () => (
<div className="flex items-start gap-2 text-gray-400 text-xs">
<ShieldMinus className="w-4 h-4 flex-shrink-0" />
<div>
<div className="font-semibold">
{t('environmentCheck.disabledTitle', language)}
</div>
<div>{t('environmentCheck.disabledDesc', language)}</div>
</div>
</div>
),
checking: () => (
<div
className="flex items-center gap-2 text-xs"
style={{ color: '#EAECEF' }}
>
<Loader2 className="w-4 h-4 animate-spin" />
<span>{t('environmentCheck.checking', language)}</span>
</div>
),
idle: () => null,
}
const renderStatus = () => statusRendererMap[status]()
return (
<div className={containerClass}>
<div className="flex flex-col gap-2 sm:flex-row sm:items-center sm:justify-between">
{showInfo && (
<div className="text-xs" style={{ color: descriptionColor }}>
{summary ?? t('environmentCheck.description', language)}
</div>
)}
</div>
{showInfo && <div className="min-h-[1.5rem]">{renderStatus()}</div>}
</div>
)
}