fix(payment): 支付插件 - 修复跨平台构建与运行时缓存 (#402)

This commit is contained in:
MasterChiefCN
2026-09-03 11:05:29 +08:00
committed by GitHub
parent f8e87bcc4c
commit 367a0933cf
18 changed files with 795 additions and 33 deletions

View File

@@ -2,21 +2,69 @@
set -eu
root_dir=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)
repo_dir=$(CDPATH= cd -- "$root_dir/.." && pwd)
payment_plugins="official-payment-wechat-native official-payment-alipay-page"
payments_only=false
node "$root_dir/embed-documentation.mjs"
if [ "${1:-}" = "--payments-only" ]; then
payments_only=true
shift
fi
if [ "$#" -ne 0 ]; then
echo "usage: $0 [--payments-only]" >&2
exit 2
fi
if [ "$payments_only" = true ]; then
node "$root_dir/embed-documentation.mjs" $payment_plugins
else
node "$root_dir/embed-documentation.mjs"
fi
# Payment backends are executable plugin payloads. They are compiled outside
# the host binary and then included under backend/provider in the package.
repo_dir=$(CDPATH= cd -- "$root_dir/.." && pwd)
for payment_plugin in official-payment-wechat-native official-payment-alipay-page; do
mkdir -p "$root_dir/$payment_plugin/backend"
done
(cd "$repo_dir/backend" && go build -trimpath -ldflags='-s -w' -o "$root_dir/official-payment-wechat-native/backend/provider" ./cmd/payment-wechat)
(cd "$repo_dir/backend" && go build -trimpath -ldflags='-s -w' -o "$root_dir/official-payment-alipay-page/backend/provider" ./cmd/payment-alipay)
payment_goos=${PAYMENT_PLUGIN_GOOS:-$(go env GOOS)}
payment_goarch=${PAYMENT_PLUGIN_GOARCH:-$(go env GOARCH)}
payment_cgo=${PAYMENT_PLUGIN_CGO_ENABLED:-0}
for manifest in "$root_dir"/*/manifest.json; do
package_dir=${manifest%/manifest.json}
package_id=${package_dir##*/}
case "$payment_cgo" in
0|1) ;;
*)
echo "PAYMENT_PLUGIN_CGO_ENABLED must be 0 or 1" >&2
exit 2
;;
esac
build_payment_provider() {
package_id=$1
command_path=$2
output_file="$root_dir/$package_id/backend/provider"
temporary_file="$output_file.tmp"
mkdir -p "$(dirname -- "$output_file")"
rm -f "$temporary_file"
(
cd "$repo_dir/backend"
CGO_ENABLED="$payment_cgo" \
GOOS="$payment_goos" \
GOARCH="$payment_goarch" \
go build -trimpath -ldflags='-s -w' -o "$temporary_file" "$command_path"
)
mv "$temporary_file" "$output_file"
chmod 0755 "$output_file"
build_info=$(go version -m "$output_file")
printf '%s\n' "$build_info" | grep -F "GOOS=$payment_goos" >/dev/null
printf '%s\n' "$build_info" | grep -F "GOARCH=$payment_goarch" >/dev/null
printf '%s\n' "$build_info" | grep -F "CGO_ENABLED=$payment_cgo" >/dev/null
}
build_payment_provider official-payment-wechat-native ./cmd/payment-wechat
build_payment_provider official-payment-alipay-page ./cmd/payment-alipay
package_plugin() {
package_id=$1
package_dir="$root_dir/$package_id"
output_file="$root_dir/$package_id.yingce-plugin"
temporary_file="$root_dir/.$package_id.yingce-plugin.tmp"
rm -f "$temporary_file"
@@ -25,4 +73,21 @@ for manifest in "$root_dir"/*/manifest.json; do
find manifest.json README.md docs assets web backend LICENSE -type f 2>/dev/null | LC_ALL=C sort | zip -X -q "$temporary_file" -@
)
mv "$temporary_file" "$output_file"
}
if [ "$payments_only" = true ]; then
for payment_plugin in $payment_plugins; do
package_plugin "$payment_plugin"
done
exit 0
fi
for payment_plugin in $payment_plugins; do
mkdir -p "$root_dir/$payment_plugin/backend"
done
for manifest in "$root_dir"/*/manifest.json; do
package_dir=${manifest%/manifest.json}
package_id=${package_dir##*/}
package_plugin "$package_id"
done

View File

@@ -8,6 +8,10 @@ const contractEnd = "<!-- YINGCE_MANIFEST_CONTRACT_END -->";
const recursiveDocumentationPlaceholder =
"<当前插件的完整 documentation,由 README.md 与 docs/interface.md 拼接而成;为避免 JSON 递归,此处不重复展开正文。>";
function normalizeNewlines(document) {
return document.replace(/\r\n?/g, "\n");
}
function withoutGeneratedContract(document) {
const start = document.indexOf(contractStart);
if (start < 0) return document.trimEnd();
@@ -45,19 +49,21 @@ for (const packageID of packageDirectories) {
const packageRoot = join(root, packageID);
let manifestSource;
try {
manifestSource = await readFile(join(packageRoot, "manifest.json"), "utf8");
manifestSource = normalizeNewlines(await readFile(join(packageRoot, "manifest.json"), "utf8"));
} catch (error) {
if (error?.code === "ENOENT") continue;
throw error;
}
const manifest = JSON.parse(manifestSource);
const readme = (await readFile(join(packageRoot, "README.md"), "utf8")).trim();
const readmePath = join(packageRoot, "README.md");
const readme = normalizeNewlines(await readFile(readmePath, "utf8")).trim();
const interfacePath = join(packageRoot, "docs", "interface.md");
const interfaceSource = await readFile(interfacePath, "utf8");
const interfaceSource = normalizeNewlines(await readFile(interfacePath, "utf8"));
const interfaceDocument = `${withoutGeneratedContract(interfaceSource)}\n\n${renderContract(manifest)}\n`;
manifest.documentation = `${readme}\n\n---\n\n${interfaceDocument.trim()}\n`;
await writeFile(readmePath, `${readme}\n`);
await writeFile(interfacePath, interfaceDocument);
await writeFile(join(packageRoot, "manifest.json"), `${JSON.stringify(manifest, null, 2)}\n`);
updated += 1;

View File

@@ -0,0 +1,65 @@
#!/bin/sh
set -eu
root_dir=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)
expected_goos=${1:-}
expected_goarch=${2:-}
if [ "$expected_goos" != "linux" ]; then
echo "payment package verification currently requires expected GOOS linux" >&2
exit 2
fi
case "$expected_goarch" in
amd64) expected_machine=3e00 ;;
arm64) expected_machine=b700 ;;
*)
echo "unsupported payment package architecture: $expected_goarch" >&2
exit 2
;;
esac
temporary_dir=$(mktemp -d)
trap 'rm -rf "$temporary_dir"' EXIT HUP INT TERM
for package_id in official-payment-wechat-native official-payment-alipay-page; do
provider="$root_dir/$package_id/backend/provider"
package_file="$root_dir/$package_id.yingce-plugin"
archived_provider="$temporary_dir/$package_id-provider"
test -f "$provider"
if [ "$(uname -s)" = "Linux" ]; then
test -x "$provider"
fi
test -f "$package_file"
magic=$(od -An -tx1 -N4 "$provider" | tr -d '[:space:]')
if [ "$magic" != "7f454c46" ]; then
echo "$package_id provider is not an ELF executable (magic=$magic)" >&2
exit 1
fi
class=$(od -An -tx1 -j4 -N1 "$provider" | tr -d '[:space:]')
byte_order=$(od -An -tx1 -j5 -N1 "$provider" | tr -d '[:space:]')
if [ "$class" != "02" ] || [ "$byte_order" != "01" ]; then
echo "$package_id provider is not a 64-bit little-endian ELF executable" >&2
exit 1
fi
machine=$(od -An -tx1 -j18 -N2 "$provider" | tr -d '[:space:]')
if [ "$machine" != "$expected_machine" ]; then
echo "$package_id provider architecture does not match linux/$expected_goarch (ELF machine=$machine)" >&2
exit 1
fi
unzip -p "$package_file" backend/provider >"$archived_provider"
if ! cmp -s "$provider" "$archived_provider"; then
echo "$package_id directory provider and packaged provider differ" >&2
exit 1
fi
if [ "${PAYMENT_PLUGIN_SMOKE_TEST:-0}" = "1" ]; then
response=$(printf 'invalid-json\n' | "$provider")
printf '%s\n' "$response" | grep -F '"code":"invalid_request"' >/dev/null
fi
done