Files
dudu/server/internal/httpapi/router.go
T
wangjia 40760aa884
ci / server (push) Failing after 14s
ci / design-tokens (push) Failing after 11s
dudu MVP:五端语音输入法初始提交
- server:Go 网关(WS 流式识别中继/计费配额/微信登录支付 mock/反馈/埋点),gummy provider 已真实联调
- desktop:Tauri 2(全局快捷键 push-to-talk/浮层/托盘/设置/登录购买/反馈/首启引导)
- android:Compose 主 App + IME(键盘内录音直传)
- ios:App + 键盘扩展(1A spike 实证键盘内不可录音,走 deep link 听写)
- design/design-pipeline:设计系统 + token 导出 iOS/Android 主题
- doc:前后端设计文档(HTML);web:官网宣传页;todo:任务看板

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-12 00:38:37 +08:00

101 lines
3.0 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// Package httpapi 路由装配。各业务模块在各自包内实现 handler,这里只负责挂载,
// 并按配置在真实外部依赖(微信/支付/OSS/ASR)与 mock 之间切换。
package httpapi
import (
"context"
"net/http"
"github.com/gin-gonic/gin"
"github.com/redis/go-redis/v9"
"gorm.io/gorm"
"dudu/server/internal/asr"
"dudu/server/internal/auth"
"dudu/server/internal/billing"
"dudu/server/internal/config"
"dudu/server/internal/feedback"
"dudu/server/internal/gateway"
"dudu/server/internal/quota"
"dudu/server/internal/telemetry"
"dudu/server/internal/user"
)
type Deps struct {
Cfg config.Config
DB *gorm.DB
RDB *redis.Client
JWT *auth.JWT
Quota *quota.Manager
}
// pickProvider 按配置选择 ASR Providergummy 在 6B 实现 + DASHSCOPE_API_KEY 就绪后接入)。
func pickProvider(cfg config.Config) asr.Provider {
switch cfg.ASRProvider {
default:
return asr.NewMock()
}
}
// pickWechat 微信凭证未配置(#2A 申请中)时使用 mock。
func pickWechat(cfg config.Config) auth.WechatClient {
if cfg.WechatWebAppID == "" {
return auth.MockWechat{}
}
return auth.MockWechat{} // TODO(5C-真实): 开放平台实现,凭证就绪后替换
}
// pickPay 商户号未配置(#2B 申请中)时使用 mock。
func pickPay(cfg config.Config) billing.PayClient {
if cfg.WxPayMchID == "" {
return billing.MockPay{}
}
return billing.MockPay{} // TODO(7D-真实): wechatpay-go 实现,商户号就绪后替换
}
// pickStorage OSS 未配置时图片落本地盘。
func pickStorage(cfg config.Config) feedback.Storage {
if cfg.OSSBucket == "" {
return feedback.LocalStorage{Dir: "var/uploads"}
}
return feedback.LocalStorage{Dir: "var/uploads"} // TODO(8C-真实): OSS 实现
}
func Register(r *gin.Engine, d *Deps) {
r.GET("/healthz", func(c *gin.Context) { c.JSON(http.StatusOK, gin.H{"ok": true}) })
authH := &auth.Handlers{DB: d.DB, RDB: d.RDB, JWT: d.JWT, Wechat: pickWechat(d.Cfg)}
billH := &billing.Handlers{DB: d.DB, Pay: pickPay(d.Cfg), Quota: d.Quota}
userH := &user.Handlers{DB: d.DB, Quota: d.Quota}
fbH := &feedback.Handlers{DB: d.DB, RDB: d.RDB, Storage: pickStorage(d.Cfg)}
telH := telemetry.New(d.DB, d.RDB)
gwH := &gateway.Handler{Provider: pickProvider(d.Cfg), Quota: d.Quota, RDB: d.RDB}
// 后台任务
bg := context.Background()
billH.StartWatchdog(bg)
d.Quota.StartDailyReconcile(bg)
telH.StartDailyAggregate(bg)
v1 := r.Group("/v1")
// 🔓 无需登录
v1.POST("/auth/qr", authH.CreateQr)
v1.GET("/auth/qr/:state", authH.PollQr)
v1.GET("/auth/wechat/callback", authH.QrCallback)
v1.POST("/auth/wechat", authH.MobileLogin)
v1.GET("/packs", billH.Packs)
v1.POST("/pay/notify", billH.Notify)
v1.POST("/metrics/batch", telH.Batch)
v1.GET("/app/latest", userH.AppLatest)
// 需登录
authed := v1.Group("", d.JWT.Middleware())
authed.POST("/auth/logout", authH.Logout)
authed.GET("/me", userH.Me)
authed.POST("/orders", billH.CreateOrder)
authed.GET("/orders/:id", billH.OrderStatus)
authed.POST("/feedback", fbH.Submit)
authed.GET("/asr/stream", gwH.HandleWS)
}