#!/bin/bash # Proto 文件编译脚本 # 用途:编译所有 proto 文件为 Go 代码 set -e # 进入项目根目录 SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" cd "$SCRIPT_DIR/.." # 添加 GOPATH/bin 到 PATH export PATH="$PATH:$(go env GOPATH)/bin" echo "======================================" echo "开始编译 Proto 文件" echo "======================================" # 检查 protoc 是否已安装 if ! command -v protoc &> /dev/null; then echo "❌ protoc 未安装!" echo "请安装 protoc:" echo " macOS: brew install protobuf" echo " Ubuntu: apt-get install protobuf-compiler" exit 1 fi echo "✅ protoc 版本: $(protoc --version)" # 检查必要的 Go 插件 MISSING_PLUGINS=false if ! command -v protoc-gen-go &> /dev/null; then echo "❌ protoc-gen-go 未安装" MISSING_PLUGINS=true fi if ! command -v protoc-gen-go-triple &> /dev/null; then echo "❌ protoc-gen-go-triple 未安装" MISSING_PLUGINS=true fi if [ "$MISSING_PLUGINS" = true ]; then echo "" echo "请安装缺失的插件:" echo " go install google.golang.org/protobuf/cmd/protoc-gen-go@latest" echo " go install github.com/dubbogo/protoc-gen-go-triple/v3@latest" exit 1 fi echo "✅ 所有必需插件已安装" echo "" # 辅助函数:移动 protoc-gen-go-triple v3 生成的文件到正确位置 # v3 插件根据 go_package 路径生成文件到 github.com/ 目录,需要手动移动 move_triple_files() { local module_path="$1" local target_dir="$2" local triple_file=$(basename "$module_path").triple.go local src_file="github.com/$module_path/$triple_file" if [ -f "$src_file" ]; then mv "$src_file" "$target_dir/" rm -rf "github.com/$module_path" echo " ✅ $triple_file 已移动到正确位置" fi } # 预先创建目标目录 echo "📁 创建目标目录..." for name in common user social asset gallery ranking activity task starbook ai_chat event statistic; do mkdir -p "pkg/proto/$name" done echo "" # 编译 common.proto(仅生成 pb.go;common.proto 没有 service,生成 triple.go 会导致未使用 import 编译失败) echo "📦 编译 common.proto ..." protoc --proto_path=proto \ --go_out=pkg/proto/common \ --go_opt=paths=source_relative \ common.proto echo "✅ common.proto 编译完成" echo "" # 编译 user.proto echo "📦 编译 user.proto ..." protoc --proto_path=proto \ --proto_path=. \ --go_out=pkg/proto/user \ --go_opt=paths=source_relative \ --go-triple_out=pkg/proto/user \ --go-triple_opt=paths=source_relative \ user.proto move_triple_files "topfans/backend/pkg/proto/user" "pkg/proto/user" echo "✅ user.proto 编译完成" echo "" # 编译 social.proto echo "📦 编译 social.proto ..." protoc --proto_path=proto \ --proto_path=. \ --go_out=pkg/proto/social \ --go_opt=paths=source_relative \ --go-triple_out=pkg/proto/social \ --go-triple_opt=paths=source_relative \ social.proto move_triple_files "topfans/backend/pkg/proto/social" "pkg/proto/social" echo "✅ social.proto 编译完成" echo "" # 编译 asset.proto echo "📦 编译 asset.proto ..." protoc --proto_path=proto \ --proto_path=. \ --go_out=pkg/proto/asset \ --go_opt=paths=source_relative \ --go-triple_out=pkg/proto/asset \ --go-triple_opt=paths=source_relative \ asset.proto move_triple_files "topfans/backend/pkg/proto/asset" "pkg/proto/asset" echo "✅ asset.proto 编译完成" echo "" # 编译 gallery.proto echo "📦 编译 gallery.proto ..." protoc --proto_path=proto \ --proto_path=. \ --go_out=pkg/proto/gallery \ --go_opt=paths=source_relative \ --go-triple_out=pkg/proto/gallery \ --go-triple_opt=paths=source_relative \ gallery.proto move_triple_files "topfans/backend/pkg/proto/gallery" "pkg/proto/gallery" echo "✅ gallery.proto 编译完成" echo "" # 编译 ranking.proto echo "📦 编译 ranking.proto ..." protoc --proto_path=proto \ --proto_path=. \ --go_out=pkg/proto/ranking \ --go_opt=paths=source_relative \ --go-triple_out=pkg/proto/ranking \ --go-triple_opt=paths=source_relative \ ranking.proto move_triple_files "topfans/backend/pkg/proto/ranking" "pkg/proto/ranking" echo "✅ ranking.proto 编译完成" echo "" # 编译 activity.proto echo "📦 编译 activity.proto ..." protoc --proto_path=proto \ --proto_path=. \ --go_out=pkg/proto/activity \ --go_opt=paths=source_relative \ --go-triple_out=pkg/proto/activity \ --go-triple_opt=paths=source_relative \ activity.proto move_triple_files "topfans/backend/pkg/proto/activity" "pkg/proto/activity" echo "✅ activity.proto 编译完成" echo "" # 编译 task.proto echo "📦 编译 task.proto ..." protoc --proto_path=proto \ --proto_path=. \ --go_out=pkg/proto/task \ --go_opt=paths=source_relative \ --go-triple_out=pkg/proto/task \ --go-triple_opt=paths=source_relative \ task.proto move_triple_files "topfans/backend/pkg/proto/task" "pkg/proto/task" echo "✅ task.proto 编译完成" echo "" # 编译 starbook.proto echo "📦 编译 starbook.proto ..." protoc --proto_path=proto \ --proto_path=. \ --go_out=pkg/proto/starbook \ --go_opt=paths=source_relative \ --go-triple_out=pkg/proto/starbook \ --go-triple_opt=paths=source_relative \ starbook.proto move_triple_files "topfans/backend/pkg/proto/starbook" "pkg/proto/starbook" echo "✅ starbook.proto 编译完成" echo "" # 编译 ai_chat.proto echo "📦 编译 ai_chat.proto ..." protoc --proto_path=proto \ --proto_path=. \ --go_out=pkg/proto/ai_chat \ --go_opt=paths=source_relative \ --go-triple_out=pkg/proto/ai_chat \ --go-triple_opt=paths=source_relative \ ai_chat.proto move_triple_files "topfans/backend/pkg/proto/ai_chat" "pkg/proto/ai_chat" echo "✅ ai_chat.proto 编译完成" echo "" # 编译 event.proto(仅生成 pb.go;event.proto 没有 service,生成 triple.go 会导致未使用 import 编译失败) echo "📦 编译 event.proto ..." protoc --proto_path=proto \ --proto_path=. \ --go_out=pkg/proto/event \ --go_opt=paths=source_relative \ event.proto echo "✅ event.proto 编译完成" echo "" # 编译 statistic.proto echo "📦 编译 statistic.proto ..." protoc --proto_path=proto \ --proto_path=. \ --go_out=pkg/proto/statistic \ --go_opt=paths=source_relative \ --go-triple_out=pkg/proto/statistic \ --go-triple_opt=paths=source_relative \ statistic.proto move_triple_files "topfans/backend/pkg/proto/statistic" "pkg/proto/statistic" # 后处理:protoc-gen-go-triple v3.0.0 在跨包类型作 RPC 参数时丢包前缀。 # statistic.proto 引用了 event.Event / event.BatchEventRequest, # triple 生成器把它们当作 statistic 包内类型(new(Event) / *Event), # 而未导入 event 包,导致编译失败。这里补回 event 包导入和类型前缀。 TRIPLE_FILE="pkg/proto/statistic/statistic.triple.go" if [ -f "$TRIPLE_FILE" ]; then if ! grep -q 'github.com/topfans/backend/pkg/proto/event"' "$TRIPLE_FILE"; then # 在第二个 import 块(dubbo 块)的最末 import 行后追加 event 包导入 # 用 awk 顺序扫描,找到第二个 "import (" 之后第一个 ")" 之前的最后一行 python3 -c " import re, sys with open('$TRIPLE_FILE', 'r') as f: src = f.read() # 找所有 import 块,定位第二个 import ( ... ) pattern = re.compile(r'(import\s*\([^)]*\))', re.MULTILINE) blocks = list(pattern.finditer(src)) if len(blocks) >= 2: second = blocks[1] block_text = second.group(1) if 'pkg/proto/event' not in block_text: new_block = block_text[:-1].rstrip() + '\n\tevent \"github.com/topfans/backend/pkg/proto/event\"\n)' src = src[:second.start()] + new_block + src[second.end():] with open('$TRIPLE_FILE', 'w') as f: f.write(src) " # 把 RPC 方法签名 / new() / 类型断言中的裸 Event / BatchEventRequest 加上 event. 前缀 # 注意:BSD sed(macOS)不支持 \b,改用 ([,)]) 等显式边界 sed -i '' \ -e 's/\*Event\([,)]\)/\*event.Event\1/g' \ -e 's/\*Event$/&XXX/g' \ -e 's/\*Event[^a-zA-Z._)/]/\*event.Event\&/g' \ -e 's/new(Event)/new(event.Event)/g' \ -e 's/\*BatchEventRequest\([,)]\)/\*event.BatchEventRequest\1/g' \ -e 's/new(BatchEventRequest)/new(event.BatchEventRequest)/g' \ "$TRIPLE_FILE" # 修复 args[0].(*Event) 类型断言 — 用单独的 sed 处理方括号 sed -i '' \ -e 's/(\*Event)/(\*event.Event)/g' \ -e 's/(\*BatchEventRequest)/(\*event.BatchEventRequest)/g' \ "$TRIPLE_FILE" echo " ✅ statistic.triple.go 已修复跨包类型引用(protoc-gen-go-triple v3.0.0 bug)" fi fi echo "✅ statistic.proto 编译完成" echo "" # 清理可能存在的冗余目录和文件 echo "🔄 清理冗余文件..." # 删除 github.com 目录(如果存在) if [ -d "github.com" ]; then rm -rf github.com echo " ✅ github.com 目录已清理" fi # 删除 proto 目录下的生成文件(如果存在) for name in common user social asset gallery ranking activity task starbook ai_chat event statistic; do if [ -f "proto/$name.pb.go" ]; then rm "proto/$name.pb.go" echo " ✅ proto/$name.pb.go 已清理" fi if [ -f "proto/$name.triple.go" ]; then rm "proto/$name.triple.go" echo " ✅ proto/$name.triple.go 已清理" fi # 清理 pkg/proto/$name/proto/ 子目录(如果存在) if [ -d "pkg/proto/$name/proto" ]; then rm -rf "pkg/proto/$name/proto" echo " ✅ pkg/proto/$name/proto/ 子目录已清理" fi done echo " ✅ 所有文件已整理完成" echo "" echo "生成的文件结构:" echo " pkg/proto/" echo " ├── common/" echo " │ ├── common.pb.go" echo " │ └── (no triple.go)" echo " ├── user/" echo " │ ├── user.pb.go" echo " │ └── user.triple.go" echo " ├── social/" echo " │ ├── social.pb.go" echo " │ └── social.triple.go" echo " ├── asset/" echo " │ ├── asset.pb.go" echo " │ └── asset.triple.go" echo " ├── gallery/" echo " │ ├── gallery.pb.go" echo " │ └── gallery.triple.go" echo " ├── ranking/" echo " │ ├── ranking.pb.go" echo " │ └── ranking.triple.go" echo " └── activity/" echo " ├── activity.pb.go" echo " └── activity.triple.go" echo "" # 统计生成的文件 GENERATED_FILES=$(find pkg/proto -name "*.pb.go" -o -name "*.triple.go" 2>/dev/null | wc -l) echo "======================================" echo "✅ 所有 Proto 文件编译完成!" echo "======================================" echo "生成文件总数: $GENERATED_FILES" echo "" echo "下一步:" echo " 1. 实现 RankingService 接口" echo " 2. 创建 Provider 层" echo " 3. 注册 Dubbo 服务" echo ""