Files
ttstd-infinite-canvas/backend/payment-plugins/rpc_runner.go

97 lines
3.0 KiB
Go

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)
}