All Downloads are FREE. Search and download functionalities are using the official Maven repository.

cn.felord.payment.wechat.v3.retrofit.TenpayCertificateService Maven / Gradle / Ivy

The newest version!
/*
 *  Copyright (c) 2023. felord.cn
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *       https://www.apache.org/licenses/LICENSE-2.0
 *  Website:
 *       https://felord.cn
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */

package cn.felord.payment.wechat.v3.retrofit;

import cn.felord.retrofit.json.JsonConverterFactory;
import cn.felord.payment.PayException;
import cn.felord.payment.wechat.v3.crypto.AppMerchant;
import cn.felord.payment.wechat.v3.crypto.TenpayKey;
import com.nimbusds.jose.jwk.JWK;
import okhttp3.ConnectionPool;
import okhttp3.OkHttpClient;
import okhttp3.Response;
import okhttp3.logging.HttpLoggingInterceptor;
import retrofit2.Retrofit;
import retrofit2.adapter.rxjava3.RxJava3CallAdapterFactory;

import java.util.Objects;
import java.util.concurrent.TimeUnit;

/**
 * 微信支付平台证书API
 *
 * @author dax
 * @since 2024/8/10 10:04
 */
class TenpayCertificateService {

    private final AppMerchant appMerchant;
    private final TenpayKeyCache tenpayKeyCache;
    private final InternalCertificateApi certificateApi;


    /**
     * Instantiates a new Tenpay certificate api.
     *
     * @param baseUrl        the base url
     * @param appMerchant    the app merchant
     * @param tenpayKeyCache the tenpay key cache
     */
    TenpayCertificateService(String baseUrl, AppMerchant appMerchant, TenpayKeyCache tenpayKeyCache) {
        this.appMerchant = appMerchant;
        this.tenpayKeyCache = tenpayKeyCache;
        this.certificateApi = new TenpayCertificateRetrofitFactory(baseUrl)
                .app(appMerchant)
                .create(InternalCertificateApi.class);
    }

    /**
     * 根据商户号和v3密钥获取平台证书列表
     *
     * @throws PayException the pay exception
     */
    public void certificates() throws PayException {
        synchronized (appMerchant) {
            certificateApi.certificates()
                    .getData()
                    .forEach(tenpayCertificate -> {
                        String merchantId = appMerchant.merchantId();
                        String serialNo = tenpayCertificate.getSerialNo();
                        JWK tenPayJwk = tenpayCertificate.getEncryptCertificate()
                                .toJwk(appMerchant.getApiV3Secret());
                        TenpayKey tenpayKey = new TenpayKey(merchantId, serialNo, tenPayJwk);
                        tenpayKeyCache.putTenpayKey(merchantId, serialNo, tenpayKey);
                    });
        }
    }

    /**
     * Gets tenpay key.
     *
     * @param serialNumber the serial number
     * @return the tenpay key
     */
    public TenpayKey getTenpayKey(String serialNumber) {
        TenpayKey tenpayKey = tenpayKeyCache.getTenpayKey(appMerchant.merchantId(), serialNumber);
        if (Objects.isNull(tenpayKey)) {
            this.certificates();
            tenpayKey = tenpayKeyCache.getTenpayKey(appMerchant.merchantId(), serialNumber);
            if (Objects.isNull(tenpayKey)) {
                throw new PayException("Fail to load tenpayKey");
            }
        }
        return tenpayKey;
    }


    /**
     * The type Tenpay certificate retrofit factory.
     */
    static class TenpayCertificateRetrofitFactory {
        private static final String DEFAULT_BASE_URL = "https://api.mch.weixin.qq.com/";
        private final String baseUrl;
        private final ConnectionPool connectionPool;
        private final HttpLoggingInterceptor.Level level;

        /**
         * Instantiates a new Wechat pay retrofit factory.
         */
        public TenpayCertificateRetrofitFactory() {
            this(DEFAULT_BASE_URL);
        }

        /**
         * Instantiates a new Wechat pay retrofit factory.
         *
         * @param baseUrl the base url
         */
        public TenpayCertificateRetrofitFactory(String baseUrl) {
            this(baseUrl, new ConnectionPool(), HttpLoggingInterceptor.Level.NONE);
        }

        /**
         * Instantiates a new Wechat pay retrofit factory.
         *
         * @param baseUrl        the base url
         * @param connectionPool the connection pool
         * @param level          the level
         */
        public TenpayCertificateRetrofitFactory(String baseUrl, ConnectionPool connectionPool, HttpLoggingInterceptor.Level level) {
            this.baseUrl = baseUrl;
            this.connectionPool = connectionPool;
            this.level = level;
        }

        /**
         * 带拦截器的Retrofit客户端
         *
         * @param appMerchant the app merchant
         * @return the retrofit
         */
        public Retrofit app(AppMerchant appMerchant) {
            return new Retrofit.Builder()
                    .baseUrl(baseUrl)
                    .client(okHttpClient(appMerchant, connectionPool, level))
                    .addCallAdapterFactory(RxJava3CallAdapterFactory.create())
                    .addCallAdapterFactory(new ResponseBodyCallAdapterFactory())
                    .addConverterFactory(JsonConverterFactory.create())
                    .build();
        }

        private static OkHttpClient okHttpClient(AppMerchant appMerchant,
                                                 ConnectionPool connectionPool,
                                                 HttpLoggingInterceptor.Level level) {
            HttpLoggingInterceptor httpLoggingInterceptor = new HttpLoggingInterceptor();
            httpLoggingInterceptor.level(level);
            TenpayCertificateAuthorizationInterceptor authorizationInterceptor = new TenpayCertificateAuthorizationInterceptor(appMerchant);
            return new OkHttpClient.Builder()
                    .connectionPool(connectionPool)
                    .addInterceptor(authorizationInterceptor)
                    .addInterceptor(httpLoggingInterceptor)
                    .retryOnConnectionFailure(true)
                    .connectTimeout(20, TimeUnit.SECONDS)
                    .readTimeout(20, TimeUnit.SECONDS)
                    .writeTimeout(20, TimeUnit.SECONDS)
                    .build();
        }
    }

    /**
     * The type Wechat authorization interceptor.
     */
    static class TenpayCertificateAuthorizationInterceptor extends AbstractAuthorizationInterceptor {
        /**
         * Instantiates a new Tenpay certificate authorization interceptor.
         *
         * @param appMerchant the app merchant
         */
        public TenpayCertificateAuthorizationInterceptor(AppMerchant appMerchant) {
            super(appMerchant);
        }

        @Override
        protected void verifyResponse(Response response) throws PayException {
            // do nothing
        }

    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy