feat: 修改合并bug

This commit is contained in:
zerosaturation 2026-06-04 00:52:21 +08:00
parent f768613509
commit 456bf10352
5 changed files with 56 additions and 158 deletions

View File

@ -1,6 +0,0 @@
[mcp_servers.code-review-graph]
command = "uvx"
args = [
"code-review-graph",
"serve",
]

View File

@ -1,28 +0,0 @@
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write|Bash",
"hooks": [
{
"type": "command",
"command": "git rev-parse --git-dir >/dev/null 2>&1 && code-review-graph update --skip-flows --repo \"/Users/liulujian/Documents/code/TopFansByGithub\" || true",
"timeout": 30
}
]
}
],
"SessionStart": [
{
"matcher": "",
"hooks": [
{
"type": "command",
"command": "git rev-parse --git-dir >/dev/null 2>&1 && code-review-graph status --repo \"/Users/liulujian/Documents/code/TopFansByGithub\" || echo 'Not a git repo, skipping'",
"timeout": 10
}
]
}
]
}
}

View File

@ -1,70 +0,0 @@
---
name: "karpathy-guidelines"
description: "Karpathy 启发的编码行为指南,包含四大原则:编码前思考、简洁优先、精准修改、目标驱动执行。适用于所有编码任务,自动引导模型减少常见 LLM 编码错误。"
---
# Karpathy 编码行为指南
源自 [Andrej Karpathy 的观察](https://x.com/karpathy/status/2015883857489522876) 关于 LLM 编码陷阱的总结。
**权衡说明:** 这些指南倾向于谨慎而非速度。对于琐碎任务(简单拼写错误修复、显而易见的一行修改),请自行判断。
## 1. 编码前思考
**不要假设。不要隐藏困惑。呈现权衡。**
在实现之前:
- 明确陈述你的假设。如果不确定,询问。
- 如果存在多种解释,呈现它们 —— 不要默默选择。
- 如果存在更简单的方法,说出来。适时提出异议。
- 如果有不清楚的地方,停下来。指出困惑之处。询问。
## 2. 简洁优先
**用最少的代码解决问题。不要过度推测。**
- 不添加要求之外的功能。
- 不为一次性代码创建抽象。
- 不添加未要求的"灵活性"或"可配置性"。
- 不为不可能发生的场景做错误处理。
- 如果你写了 200 行代码,而 50 行就能搞定,重写它。
**自问:** "资深工程师会觉得这过于复杂吗?" 如果是,简化。
## 3. 精准修改
**只碰必须碰的。只清理自己造成的混乱。**
编辑现有代码时:
- 不要"改进"相邻的代码、注释或格式。
- 不要重构没坏的东西。
- 匹配现有风格,即使你更倾向于不同的写法。
- 如果注意到无关的死代码,提一下 —— 不要删除它。
当你的改动产生孤儿代码时:
- 删除因你的改动而变得无用的导入/变量/函数。
- 不要删除预先存在的死代码,除非被要求。
**检验标准:** 每一行修改都应该能直接追溯到用户的请求。
## 4. 目标驱动执行
**定义成功标准。循环验证直到达成。**
将指令式任务转化为可验证的目标:
- "添加验证" → "为无效输入编写测试,然后让它们通过"
- "修复 bug" → "编写重现 bug 的测试,然后让它通过"
- "重构 X" → "确保重构前后测试都能通过"
对于多步骤任务,说明一个简短的计划:
```
1. [步骤] → 验证: [检查]
2. [步骤] → 验证: [检查]
3. [步骤] → 验证: [检查]
```
强有力的成功标准让你能够独立循环执行。弱标准("让它工作")需要不断澄清。
---
**这些指南在起作用的标志:** diff 中不必要的改动更少、因过度复杂而导致的重写更少、澄清问题在实现之前提出而不是在犯错之后。

View File

@ -18,6 +18,7 @@ type Config struct {
LaserCompositor LaserCompositorConfig LaserCompositor LaserCompositorConfig
Redis RedisConfig Redis RedisConfig
DB DBConfig DB DBConfig
WebSocket WebSocketConfig
Root string Root string
} }
@ -36,13 +37,6 @@ type LaserCompositorConfig struct {
type DifyConfig struct { type DifyConfig struct {
APIBase string APIBase string
APIKey string APIKey string
Server ServerConfig
Dubbo DubboConfig
JWT JWTConfig
OSS OSSConfig
Redis RedisConfig
WebSocket WebSocketConfig
Root string
} }
// RedisConfig Redis 配置 // RedisConfig Redis 配置
@ -175,6 +169,15 @@ func Load() *Config {
Password: getEnv("REDIS_PASSWORD", ""), Password: getEnv("REDIS_PASSWORD", ""),
DB: getEnvInt("REDIS_DB", 0), DB: getEnvInt("REDIS_DB", 0),
}, },
DB: DBConfig{
Host: getEnv("DB_HOST", "localhost"),
Port: getEnvInt("DB_PORT", 5432),
User: getEnv("DB_USER", "postgres"),
Password: getEnv("DB_PASSWORD", ""),
DBName: getEnv("DB_NAME", "top-fans"),
SSLMode: getEnv("DB_SSLMODE", "disable"),
TimeZone: getEnv("DB_TIMEZONE", "Asia/Shanghai"),
},
WebSocket: WebSocketConfig{ WebSocket: WebSocketConfig{
AIChatPath: getEnv("WS_AI_CHAT_PATH", "/ws/ai-chat"), AIChatPath: getEnv("WS_AI_CHAT_PATH", "/ws/ai-chat"),
}, },

View File

@ -1046,16 +1046,10 @@ func (ctrl *AssetController) generateOSSPolicyTokenWithKey(
date := utcTime.Format("20060102") date := utcTime.Format("20060102")
expiration := utcTime.Add(time.Duration(ossConfig.TokenExpireTime) * time.Second) expiration := utcTime.Add(time.Duration(ossConfig.TokenExpireTime) * time.Second)
baseDir := ossConfig.GetUploadDir(uploadType) // 尝试 STS AssumeRole失败则降级到永久 AccessKey 直连
uploadDir := baseDir
if userID != nil && starID != nil {
uploadDir = fmt.Sprintf("%s%d/%d/", baseDir, userID, starID)
}
var accessKeyID, accessKeySecret, securityToken string var accessKeyID, accessKeySecret, securityToken string
useSTS := false useSTS := false
// 尝试 STS AssumeRole失败则降级到永久 AccessKey 直连
// 1. 创建 STS 凭证提供器 // 1. 创建 STS 凭证提供器
credConfig := new(credentials.Config). credConfig := new(credentials.Config).
SetType("ram_role_arn"). SetType("ram_role_arn").
@ -1079,32 +1073,23 @@ func (ctrl *AssetController) generateOSSPolicyTokenWithKey(
logger.Logger.Warn("STS credential provider failed, falling back to direct AK/SK", zap.Error(err)) logger.Logger.Warn("STS credential provider failed, falling back to direct AK/SK", zap.Error(err))
} }
if !useSTS { if !useSTS {
accessKeyID = ossConfig.AccessKeyID accessKeyID = ossConfig.AccessKeyID
accessKeySecret = ossConfig.AccessKeySecret accessKeySecret = ossConfig.AccessKeySecret
} }
// 2. 获取临时凭证
cred, err := provider.GetCredential()
if err != nil {
return nil, fmt.Errorf("获取临时凭证失败: %w", err)
}
// 3. 构建 Policy // 2. 构建 Policy 条件
utcTime := time.Now().UTC()
date := utcTime.Format("20060102")
expiration := utcTime.Add(time.Duration(ossConfig.TokenExpireTime) * time.Second)
// 构建 Policy 条件
conditions := []interface{}{ conditions := []interface{}{
map[string]string{"bucket": ossConfig.BucketName}, map[string]string{"bucket": ossConfig.BucketName},
// 限制 key 必须等于指定完整 key更严前端只能写到该路径 // 限制 key 必须等于指定完整 key更严前端只能写到该路径
[]interface{}{"eq", "$key", uploadKey}, []interface{}{"eq", "$key", uploadKey},
map[string]string{"x-oss-signature-version": "OSS4-HMAC-SHA256"}, map[string]string{"x-oss-signature-version": "OSS4-HMAC-SHA256"},
map[string]string{"x-oss-credential": fmt.Sprintf("%s/%s/%s/%s/aliyun_v4_request", map[string]string{"x-oss-credential": fmt.Sprintf("%s/%s/%s/%s/aliyun_v4_request",
*cred.AccessKeyId, date, ossConfig.Region, "oss")}, accessKeyID, date, ossConfig.Region, "oss")},
map[string]string{"x-oss-date": utcTime.Format("20060102T150405Z")}, map[string]string{"x-oss-date": utcTime.Format("20060102T150405Z")},
map[string]string{"x-oss-security-token": *cred.SecurityToken}, }
if useSTS && securityToken != "" {
conditions = append(conditions, map[string]string{"x-oss-security-token": securityToken})
} }
policyMap := map[string]interface{}{ policyMap := map[string]interface{}{
@ -1112,33 +1097,36 @@ func (ctrl *AssetController) generateOSSPolicyTokenWithKey(
"conditions": conditions, "conditions": conditions,
} }
// 4. 生成 Policy 的 Base64 编码 // 3. 生成 Policy 的 Base64 编码
policyJSON, err := json.Marshal(policyMap) policyJSON, err := json.Marshal(policyMap)
if err != nil { if err != nil {
return nil, fmt.Errorf("序列化 policy 失败: %w", err) return nil, fmt.Errorf("序列化 policy 失败: %w", err)
} }
policyBase64 := base64.StdEncoding.EncodeToString(policyJSON) policyBase64 := base64.StdEncoding.EncodeToString(policyJSON)
// 5. 计算签名 // 4. 计算签名
signingKey := buildSigningKey(*cred.AccessKeySecret, date, ossConfig.Region, "oss") signingKey := buildSigningKey(accessKeySecret, date, ossConfig.Region, "oss")
signature := calculateSignature(signingKey, policyBase64) signature := calculateSignature(signingKey, policyBase64)
// 6. 构建返回数据 // 5. 构建返回数据
host := fmt.Sprintf("https://%s.oss-%s.aliyuncs.com", ossConfig.BucketName, ossConfig.Region) host := fmt.Sprintf("https://%s.oss-%s.aliyuncs.com", ossConfig.BucketName, ossConfig.Region)
return map[string]interface{}{ result := map[string]interface{}{
"policy": policyBase64, "policy": policyBase64,
"security_token": *cred.SecurityToken,
"x_oss_signature_version": "OSS4-HMAC-SHA256", "x_oss_signature_version": "OSS4-HMAC-SHA256",
"x_oss_credential": fmt.Sprintf("%s/%s/%s/%s/aliyun_v4_request", "x_oss_credential": fmt.Sprintf("%s/%s/%s/%s/aliyun_v4_request",
*cred.AccessKeyId, date, ossConfig.Region, "oss"), accessKeyID, date, ossConfig.Region, "oss"),
"x_oss_date": utcTime.Format("20060102T150405Z"), "x_oss_date": utcTime.Format("20060102T150405Z"),
"signature": signature, "signature": signature,
"host": host, "host": host,
"dir": dirFromKey(uploadKey), "dir": dirFromKey(uploadKey),
"key": uploadKey, "key": uploadKey,
"expire_time": expiration.Unix(), "expire_time": expiration.Unix(),
}, nil }
if useSTS && securityToken != "" {
result["security_token"] = securityToken
}
return result, nil
} }
// generateOSSPolicyTokenWithDir 按显式目录生成 OSS 上传策略和签名 // generateOSSPolicyTokenWithDir 按显式目录生成 OSS 上传策略和签名
@ -1157,15 +1145,26 @@ func (ctrl *AssetController) generateOSSPolicyTokenWithDir(
SetPolicy(""). SetPolicy("").
SetRoleSessionExpiration(ossConfig.TokenExpireTime) SetRoleSessionExpiration(ossConfig.TokenExpireTime)
provider, err := credentials.NewCredential(credConfig) // 尝试 STS AssumeRole失败则降级到永久 AccessKey 直连
if err != nil { var accessKeyID, accessKeySecret, securityToken string
return nil, fmt.Errorf("创建凭证提供器失败: %w", err) useSTS := false
if provider, err := credentials.NewCredential(credConfig); err == nil {
if cred, err := provider.GetCredential(); err == nil {
accessKeyID = *cred.AccessKeyId
accessKeySecret = *cred.AccessKeySecret
securityToken = *cred.SecurityToken
useSTS = true
} else {
logger.Logger.Warn("STS AssumeRole failed for WithDir, falling back to direct AK/SK", zap.Error(err))
}
} else {
logger.Logger.Warn("STS credential provider failed for WithDir, falling back to direct AK/SK", zap.Error(err))
} }
// 2. 获取临时凭证 if !useSTS {
cred, err := provider.GetCredential() accessKeyID = ossConfig.AccessKeyID
if err != nil { accessKeySecret = ossConfig.AccessKeySecret
return nil, fmt.Errorf("获取临时凭证失败: %w", err)
} }
// 3. 构建 Policy // 3. 构建 Policy