TTSOptions / TTSTimeout / TTSConfigErr / Auth.APIKeys / CORS 在运行期会被
LoadRuntimeConfig(PUT /api/settings 触发)整体替换,struct 整体赋值不是原子的,
若 TTS 请求正并发读,可能拿到半写状态。单用户场景概率低,属正确性隐患。
改动:
- setting/config.go: 把可变运行时配置迁到包内私有变量,新增 ttsMu
(sync.RWMutex) 统一保护,提供 Get*/Set* 访问器
- GetTTSOptions/SetTTSOptions: 值类型快照,读端无锁开销
- GetTTSTimeout/SetTTSTimeout
- GetTTSConfigErr/SetTTSConfigErr
- GetAuthAPIKeys/SetAuthAPIKeys: 拷贝进出,防止外部持有底层 slice
- GetCORSAllowAll/GetCORSOrigins/SetCORS: AllowAll 和 Origins 拆开,
避免热路径 CORSConfig 整体读时锁粒度过粗
- 删除导出可变全局 var TTSOptions/TTSTimeout/TTSConfigErr/Auth/CORS,
编译期强制所有读写走 Get*/Set*
- Server.Port/TrustedProxyHops/SetupToken 仅启动期写,运行期无并发修改,
保持原状不加锁
- LoadRuntimeConfig/InitAuthConfig/InitCORSConfig 全切到 Set*
- CheckEnvironmentVariables/LogStartupSummary 一次性拿快照,
缩短锁占用窗口,避免多次 log.Printf 之间数据被替换
调用点:
- controller/tts.go: 热路径 opts := setting.GetTTSOptions(),
context 超时走 GetTTSTimeout(),/health 块用 GetTTSConfigErr
- controller/settings.go: 写改 SetAuthAPIKeys/SetCORS
- controller/setup.go: 写改 SetAuthAPIKeys
- middleware/auth.go: 鉴权改 GetAuthAPIKeys()(在 RLock 下拿拷贝)
- middleware/admin_auth.go: 同上
- middleware/cors.go: matchOrigin 改 GetCORSAllowAll/GetCORSOrigins
读多写少,RWMutex 读路径不互斥,不会拖慢热路径。
47 lines
946 B
Go
47 lines
946 B
Go
package middleware
|
|
|
|
import (
|
|
"crypto/subtle"
|
|
"encoding/json"
|
|
"net/http"
|
|
"strings"
|
|
|
|
"github.com/volcano-tts/tts-api/setting"
|
|
)
|
|
|
|
func ValidateAPIKey(r *http.Request) bool {
|
|
keys := setting.GetAuthAPIKeys()
|
|
if len(keys) == 0 {
|
|
return true
|
|
}
|
|
|
|
authHeader := r.Header.Get("Authorization")
|
|
if authHeader == "" {
|
|
return false
|
|
}
|
|
|
|
if !strings.HasPrefix(authHeader, "Bearer ") {
|
|
return false
|
|
}
|
|
|
|
token := strings.TrimPrefix(authHeader, "Bearer ")
|
|
for _, validKey := range keys {
|
|
if subtle.ConstantTimeCompare([]byte(token), []byte(validKey)) == 1 {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
func SendJSONError(w http.ResponseWriter, statusCode int, message string, errType string, code string) {
|
|
w.Header().Set("Content-Type", "application/json")
|
|
w.WriteHeader(statusCode)
|
|
json.NewEncoder(w).Encode(map[string]interface{}{
|
|
"error": map[string]interface{}{
|
|
"message": message,
|
|
"type": errType,
|
|
"code": code,
|
|
},
|
|
})
|
|
}
|