golang协议脚本

This commit is contained in:
hahwu 2026-04-09 17:37:58 +08:00
parent 7a3429206e
commit 1d4baca598
9 changed files with 110240 additions and 6 deletions

2
.gitignore vendored
View File

@ -1,3 +1,5 @@
.vs .vs
compiler/cpp/compiler/Debug compiler/cpp/compiler/Debug
generated generated
tmp_go_check/meowmentnet/*
.vscode/*

View File

@ -0,0 +1,37 @@
# Go 包生成工具
这个工具会批量读取 thrift-files/meowment-network 下的所有 thrift 文件,并生成一个统一的 Go 包目录。
默认输出位置:
- compiled_output/golang/meowmentnet
默认行为:
- 自动优先使用仓库内的 compiler/exe/thrift.exe
- 如果仓库内编译器不可用,则回退到系统 PATH 中的 thrift
- 将全部 thrift 文件生成到同一个 Go package: meowmentnet
- 启用 ignore_initialisms保留 Id、Uid 这类字段写法,不自动改成 ID、UID
- 生成完成后自动运行 gofmt
- 使用 --module 时会自动执行 go mod tidy
直接运行:
```bat
PythonWorkSpace\IntegratedTool\启动Go包生成工具.bat
```
常见参数:
```bat
PythonWorkSpace\IntegratedTool\启动Go包生成工具.bat --output-dir D:\temp\meowmentnet
PythonWorkSpace\IntegratedTool\启动Go包生成工具.bat --package-name netpkg
PythonWorkSpace\IntegratedTool\启动Go包生成工具.bat --module github.com/yourname/meowmentnet
PythonWorkSpace\IntegratedTool\启动Go包生成工具.bat --compiler F:\Github\thrift\thrift.exe
```
如果你想把生成结果直接作为一个独立 Go module 使用,建议同时传入:
```bat
PythonWorkSpace\IntegratedTool\启动Go包生成工具.bat --module github.com/yourname/meowmentnet --output-dir D:\work\meowmentnet
```

View File

@ -0,0 +1,302 @@
"""Generate a Go package from thrift-files/meowment-network."""
from __future__ import annotations
import argparse
import os
import shutil
import subprocess
import sys
import tempfile
from pathlib import Path
from typing import Iterable, Sequence
REPO_ROOT = Path(__file__).resolve().parents[2]
DEFAULT_SOURCE_DIR = REPO_ROOT / "thrift-files" / "meowment-network"
DEFAULT_OUTPUT_DIR = REPO_ROOT / "compiled_output" / "golang" / "meowmentnet"
DEFAULT_PACKAGE_NAME = "meowmentnet"
DEFAULT_THRIFT_IMPORT = "github.com/apache/thrift/lib/go/thrift"
class ToolError(RuntimeError):
pass
def parse_args() -> argparse.Namespace:
parser = argparse.ArgumentParser(
description="Generate a Go package from meowment-network thrift files.",
)
parser.add_argument(
"--source-dir",
type=Path,
default=DEFAULT_SOURCE_DIR,
help="Directory containing .thrift files.",
)
parser.add_argument(
"--output-dir",
type=Path,
default=DEFAULT_OUTPUT_DIR,
help="Destination directory of the generated Go package.",
)
parser.add_argument(
"--package-name",
default=DEFAULT_PACKAGE_NAME,
help="Generated Go package name.",
)
parser.add_argument(
"--compiler",
type=Path,
help="Explicit thrift compiler executable path.",
)
parser.add_argument(
"--package-prefix",
default="",
help="Optional value passed to go:package_prefix=...",
)
parser.add_argument(
"--thrift-import",
default=DEFAULT_THRIFT_IMPORT,
help="Import path of the Go thrift runtime.",
)
parser.add_argument(
"--module",
default="",
help="If set, write a go.mod file with this module path.",
)
parser.add_argument(
"--no-clean",
action="store_true",
help="Do not delete the existing output directory before copying files.",
)
parser.add_argument(
"--skip-gofmt",
action="store_true",
help="Do not run gofmt after generation.",
)
parser.add_argument(
"--skip-go-mod-tidy",
action="store_true",
help="Do not run go mod tidy after writing go.mod.",
)
return parser.parse_args()
def candidate_compilers(explicit: Path | None) -> Iterable[Path]:
seen: set[str] = set()
def emit(path: Path | None) -> Iterable[Path]:
if path is None:
return ()
resolved = str(path)
if resolved in seen:
return ()
seen.add(resolved)
return (path,)
if explicit is not None:
yield from emit(explicit)
env_compiler = Path(os.environ["THRIFT_COMPILER"]) if "THRIFT_COMPILER" in os.environ else None
yield from emit(env_compiler)
yield from emit(REPO_ROOT / "compiler" / "exe" / "thrift-go.exe")
system_compiler = shutil.which("thrift")
if system_compiler:
yield from emit(Path(system_compiler))
def probe_compiler(executable: Path) -> bool:
try:
completed = subprocess.run(
[str(executable), "-version"],
check=False,
capture_output=True,
text=True,
timeout=10,
)
except OSError:
return False
except subprocess.TimeoutExpired:
return False
return completed.returncode == 0
def resolve_compiler(explicit: Path | None) -> Path:
for compiler in candidate_compilers(explicit):
if probe_compiler(compiler):
return compiler
raise ToolError(
"No working thrift compiler was found. Use --compiler or set THRIFT_COMPILER."
)
def find_thrift_files(source_dir: Path) -> list[Path]:
if not source_dir.exists():
raise ToolError(f"Source directory does not exist: {source_dir}")
thrift_files = sorted(source_dir.glob("*.thrift"))
if not thrift_files:
raise ToolError(f"No .thrift files were found in: {source_dir}")
return thrift_files
def build_generator_option(args: argparse.Namespace) -> str:
options = [f"package={args.package_name}"]
options.append("ignore_initialisms")
if args.package_prefix:
options.append(f"package_prefix={normalize_package_prefix(args.package_prefix)}")
if args.thrift_import:
options.append(f"thrift_import={args.thrift_import}")
options.append("skip_remote")
return "go:" + ",".join(options)
def normalize_package_prefix(prefix: str) -> str:
normalized = prefix.strip()
if not normalized:
return normalized
return normalized if normalized.endswith("/") else normalized + "/"
def run_command(command: Sequence[str], cwd: Path) -> None:
completed = subprocess.run(
list(command),
cwd=str(cwd),
check=False,
capture_output=True,
text=True,
)
if completed.returncode == 0:
return
stdout = completed.stdout.strip()
stderr = completed.stderr.strip()
details = "\n".join(part for part in (stdout, stderr) if part)
if not details:
details = "The command exited with a non-zero status and produced no output."
raise ToolError(details)
def generate_go_sources(
compiler: Path,
source_dir: Path,
thrift_files: Sequence[Path],
package_name: str,
generator_option: str,
staging_root: Path,
) -> Path:
for thrift_file in thrift_files:
command = [
str(compiler),
"-o",
str(staging_root),
"-strict",
"--gen",
generator_option,
str(thrift_file),
]
try:
run_command(command, cwd=source_dir)
except ToolError as exc:
raise ToolError(f"Failed to generate {thrift_file.name}:\n{exc}") from exc
package_dir = staging_root / "gen-go" / package_name
if not package_dir.exists():
raise ToolError(f"Generated package directory not found: {package_dir}")
return package_dir
def write_go_mod(output_dir: Path, module_name: str) -> None:
go_mod = output_dir / "go.mod"
go_mod.write_text(
"\n".join(
[
f"module {module_name}",
"",
"go 1.22",
"",
"require github.com/apache/thrift v0.22.0",
"",
]
),
encoding="utf-8",
)
def copy_output(staged_package_dir: Path, output_dir: Path, clean: bool) -> None:
if clean and output_dir.exists():
shutil.rmtree(output_dir)
output_dir.parent.mkdir(parents=True, exist_ok=True)
shutil.copytree(staged_package_dir, output_dir, dirs_exist_ok=not clean)
def run_gofmt(output_dir: Path) -> None:
gofmt = shutil.which("gofmt")
if not gofmt:
print("[warn] gofmt was not found in PATH. Skipping formatting.")
return
go_files = sorted(output_dir.glob("*.go"))
if not go_files:
return
for go_file in go_files:
run_command([gofmt, "-w", str(go_file)], cwd=output_dir)
def run_go_mod_tidy(output_dir: Path) -> None:
go = shutil.which("go")
if not go:
print("[warn] go was not found in PATH. Skipping go mod tidy.")
return
run_command([go, "mod", "tidy"], cwd=output_dir)
def validate_args(args: argparse.Namespace) -> None:
if not args.package_name.strip():
raise ToolError("--package-name cannot be empty.")
def main() -> int:
args = parse_args()
try:
validate_args(args)
source_dir = args.source_dir.resolve()
output_dir = args.output_dir.resolve()
thrift_files = find_thrift_files(source_dir)
compiler = resolve_compiler(args.compiler.resolve() if args.compiler else None)
generator_option = build_generator_option(args)
with tempfile.TemporaryDirectory(prefix="thrift_go_") as tmp_dir:
staged_package_dir = generate_go_sources(
compiler=compiler,
source_dir=source_dir,
thrift_files=thrift_files,
package_name=args.package_name,
generator_option=generator_option,
staging_root=Path(tmp_dir),
)
copy_output(staged_package_dir, output_dir, clean=not args.no_clean)
if args.module:
write_go_mod(output_dir, args.module)
if not args.skip_go_mod_tidy:
run_go_mod_tidy(output_dir)
if not args.skip_gofmt:
run_gofmt(output_dir)
print(f"Compiler: {compiler}")
print(f"Source directory: {source_dir}")
print(f"Output directory: {output_dir}")
print(f"Package name: {args.package_name}")
print(f"Thrift files: {len(thrift_files)}")
if args.module:
print(f"go.mod: {args.module}")
return 0
except ToolError as exc:
print(f"[error] {exc}", file=sys.stderr)
return 1
if __name__ == "__main__":
raise SystemExit(main())

View File

@ -0,0 +1,13 @@
@echo off
setlocal
set SCRIPT_DIR=%~dp0
set PYTHON_EXE=%SCRIPT_DIR%..\..\.venv\Scripts\python.exe
if exist "%PYTHON_EXE%" (
"%PYTHON_EXE%" "%SCRIPT_DIR%generate_go_package.py" %*
) else (
python "%SCRIPT_DIR%generate_go_package.py" %*
)
endlocal

View File

@ -0,0 +1,5 @@
// Code generated by Thrift Compiler (0.22.0). DO NOT EDIT.
package meowmentnet
var GoUnusedProtection__ int

View File

@ -0,0 +1,33 @@
// Code generated by Thrift Compiler (0.22.0). DO NOT EDIT.
package meowmentnet
import (
"bytes"
"context"
"errors"
"fmt"
thrift "github.com/apache/thrift/lib/go/thrift"
"iter"
"log/slog"
"regexp"
"strings"
"time"
)
// (needed to ensure safety because of naive import list construction.)
var _ = bytes.Equal
var _ = context.Background
var _ = errors.New
var _ = fmt.Printf
var _ = iter.Pull[int]
var _ = slog.Log
var _ = time.Now
var _ = thrift.ZERO
// (needed by validator.)
var _ = strings.Contains
var _ = regexp.MatchString
func init() {
}

File diff suppressed because it is too large Load Diff

BIN
compiler/exe/thrift-go.exe Normal file

Binary file not shown.

View File

@ -919,7 +919,7 @@ struct ReqCatReturnGiftReward {
} }
struct ReqCatReturnGiftRewardGfit { struct ReqCatReturnGiftRewardGift {
1: i32 Id, 1: i32 Id,
} }
@ -1544,7 +1544,7 @@ struct ReqPlayroomWork {
} }
struct ReqPlayroomWrokOutline { struct ReqPlayroomWorkOutline {
} }
@ -2002,7 +2002,7 @@ struct ResCatReturnGiftReward {
} }
struct ResCatReturnGiftRewardGfit { struct ResCatReturnGiftRewardGift {
1: RES_CODE Code, 1: RES_CODE Code,
2: string Msg, 2: string Msg,
} }
@ -2942,11 +2942,12 @@ struct ResPlayerRank {
5: i32 Level, 5: i32 Level,
6: double score, 6: double score,
7: i32 type, 7: i32 type,
8: map<i32, i32> PlayroomSet 8: map<i32, i32> PlayroomSet,
9: map<i32, i32> DressSet 9: map<i32, i32> DressSet,
10: i32 FurSet, 10: i32 FurSet,
11: ActLog Last, 11: ActLog Last,
12: string PetName, 12: string PetName,
13: i32 Rank,
} }
@ -3166,7 +3167,7 @@ struct ResPlayroomWork {
} }
struct ResPlayroomWrokOutline { struct ResPlayroomWorkOutline {
1: RES_CODE Code, 1: RES_CODE Code,
2: string Msg, 2: string Msg,
} }