97 lines
3.0 KiB
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)
|
|
}
|