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

io.irain.reactor.limit.aspect.LimitAspect Maven / Gradle / Ivy

package io.irain.reactor.limit.aspect;

import io.irain.reactor.commons.enums.TimeUnitMessageKey;
import io.irain.reactor.commons.exception.ServerException;
import io.irain.reactor.limit.annotation.Limit;
import io.irain.reactor.limit.provider.LimitProvider;
import io.irain.reactor.limit.support.LimitSupport;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.context.MessageSource;
import org.springframework.context.NoSuchMessageException;
import org.springframework.core.annotation.Order;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.lang.reflect.Method;
import java.text.MessageFormat;
import java.util.concurrent.TimeUnit;

/**
 * @author youta
 **/
@Slf4j
@Aspect
@RequiredArgsConstructor
@Order(2)
public class LimitAspect {

    private final ObjectProvider provider;

    /**
     * Handler object.
     *
     * @param point the point
     * @param limit the limit
     * @return the object
     * @throws Throwable the throwable
     */
    @Around("@annotation(limit)")
    @SuppressWarnings("all")
    public Object handler(ProceedingJoinPoint point, Limit limit) throws Throwable {
        Signature signature = point.getSignature();
        if (!(signature instanceof MethodSignature methodSignature)) {
            return point.proceed();
        }
        Method method = methodSignature.getMethod();
        Object[] args = point.getArgs();
        LimitSupport limitSupport = LimitSupport.of(provider.getIfAvailable());
        var msg = "Do not repeat the request, please wait for {0} {1} and try again";
        msg = MessageFormat.format(msg, limit.expire(), getTimeUnitName(limit.unit()));
        return limitSupport.exec(limit, method, args)
                .filter(allowed -> allowed)
                .switchIfEmpty(Mono.error(new ServerException(429, msg)))
                .flatMap(allowed -> result(point));

    }

    private static Mono result(ProceedingJoinPoint point) {
        try {
            Object result = point.proceed();
            if (result instanceof Mono mono) {
                return mono;
            } else if (result instanceof Flux flux) {
                return flux.collectList();
            } else {
                return Mono.just(result);
            }
        } catch (Throwable throwable) {
            return Mono.error(throwable);
        }
    }


    /**
     * The Message source.
     */
    protected final MessageSource messageSource;

    /**
     * 获取加锁时间单位显示名称.
     *
     * @param timeUnit 分布式锁注解
     * @return 加锁时间单位显示名称
     */
    protected String getTimeUnitName(TimeUnit timeUnit) {
        try {
            return TimeUnitMessageKey.getKey(timeUnit);
        } catch (NoSuchMessageException ignore) {
            return "";
        }
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy