refactor(payment): 支付插件 - 宿主仅通过 RPC 包加载并保护订单版本
This commit is contained in:
96
backend/payment-plugins/rpc_runner.go
Normal file
96
backend/payment-plugins/rpc_runner.go
Normal file
@@ -0,0 +1,96 @@
|
||||
package paymentplugins
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
const rpcVersion = "yingce.payment/v1"
|
||||
|
||||
type rpcRequest struct {
|
||||
Version string `json:"version"`
|
||||
Operation string `json:"operation"`
|
||||
Config Config `json:"config,omitempty"`
|
||||
Request json.RawMessage `json:"request,omitempty"`
|
||||
Headers map[string][]string `json:"headers,omitempty"`
|
||||
Body string `json:"bodyBase64,omitempty"`
|
||||
BillDate string `json:"billDate,omitempty"`
|
||||
}
|
||||
|
||||
type rpcResponse struct {
|
||||
OK bool `json:"ok"`
|
||||
Code string `json:"code,omitempty"`
|
||||
Message string `json:"message,omitempty"`
|
||||
Data any `json:"data,omitempty"`
|
||||
}
|
||||
|
||||
func RunRPC(provider Provider, input io.Reader, output io.Writer) error {
|
||||
decoder := json.NewDecoder(io.LimitReader(input, 2<<20))
|
||||
var request rpcRequest
|
||||
if err := decoder.Decode(&request); err != nil {
|
||||
return writeRPC(output, rpcResponse{Code: "invalid_request", Message: "请求不是有效 JSON"})
|
||||
}
|
||||
if request.Version != rpcVersion {
|
||||
return writeRPC(output, rpcResponse{Code: "unsupported_version", Message: "不支持的支付插件协议版本"})
|
||||
}
|
||||
if provider == nil {
|
||||
return writeRPC(output, rpcResponse{Code: "provider_unavailable", Message: "支付插件未配置"})
|
||||
}
|
||||
ctx := context.Background()
|
||||
var value any
|
||||
var err error
|
||||
switch request.Operation {
|
||||
case "validate_config":
|
||||
err = provider.ValidateConfig(request.Config)
|
||||
case "create_order":
|
||||
var valueRequest CreateRequest
|
||||
err = json.Unmarshal(request.Request, &valueRequest)
|
||||
if err == nil {
|
||||
value, err = provider.CreateOrder(ctx, request.Config, valueRequest)
|
||||
}
|
||||
case "query_order":
|
||||
var valueRequest QueryRequest
|
||||
err = json.Unmarshal(request.Request, &valueRequest)
|
||||
if err == nil {
|
||||
value, err = provider.QueryOrder(ctx, request.Config, valueRequest)
|
||||
}
|
||||
case "close_order":
|
||||
var valueRequest CloseRequest
|
||||
err = json.Unmarshal(request.Request, &valueRequest)
|
||||
if err == nil {
|
||||
value, err = provider.CloseOrder(ctx, request.Config, valueRequest)
|
||||
}
|
||||
case "verify_notification":
|
||||
body, decodeErr := base64.StdEncoding.DecodeString(request.Body)
|
||||
err = decodeErr
|
||||
if err == nil {
|
||||
value, err = provider.VerifyNotification(ctx, request.Config, http.Header(request.Headers), body)
|
||||
}
|
||||
case "download_trade_bill":
|
||||
billDate, parseErr := time.Parse("2006-01-02", request.BillDate)
|
||||
err = parseErr
|
||||
if err == nil {
|
||||
value, err = provider.DownloadTradeBill(ctx, request.Config, billDate)
|
||||
}
|
||||
default:
|
||||
err = fmt.Errorf("unknown payment operation %q", request.Operation)
|
||||
}
|
||||
if err != nil {
|
||||
response := rpcResponse{Code: "provider_error", Message: err.Error()}
|
||||
if providerErr, ok := err.(*ProviderError); ok && strings.TrimSpace(providerErr.Code) != "" {
|
||||
response.Code = providerErr.Code
|
||||
}
|
||||
return writeRPC(output, response)
|
||||
}
|
||||
return writeRPC(output, rpcResponse{OK: true, Data: value})
|
||||
}
|
||||
|
||||
func writeRPC(output io.Writer, response rpcResponse) error {
|
||||
return json.NewEncoder(output).Encode(response)
|
||||
}
|
||||
Reference in New Issue
Block a user