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

com.github.sseserver.remote.RemoteConnectionServiceImpl Maven / Gradle / Ivy

package com.github.sseserver.remote;

import com.github.sseserver.local.LocalController.Response;
import com.github.sseserver.springboot.SseServerProperties;
import com.github.sseserver.util.*;
import com.github.sseserver.util.SpringUtil.AsyncRestTemplate;
import com.github.sseserver.util.SpringUtil.HttpEntity;

import java.io.Serializable;
import java.net.URL;
import java.nio.channels.ClosedChannelException;
import java.util.*;
import java.util.concurrent.Callable;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;

public class RemoteConnectionServiceImpl implements RemoteConnectionService {
    public static int connectTimeout = Integer.getInteger("sseserver.RemoteConnectionServiceImpl.connectTimeout",
            500);
    public static int readTimeout = Integer.getInteger("sseserver.RemoteConnectionServiceImpl.readTimeout",
            1000);
    public static int threadsIfAsyncRequest = Integer.getInteger("sseserver.RemoteConnectionServiceImpl.threadsIfAsyncRequest",
            1);
    public static int threadsIfBlockRequest = Integer.getInteger("sseserver.RemoteConnectionServiceImpl.threadsIfBlockRequest",
            Math.max(16, Runtime.getRuntime().availableProcessors() * 2));

    private final ThreadLocal scopeOnWriteableThreadLocal = new ThreadLocal<>();
    private final AsyncRestTemplate restTemplate;
    private final URL url;
    private final String urlConnectionQueryService;
    private final String urlSendService;
    private final String urlRemoteConnectionService;
    private final SseServerProperties.ClusterConfig.ConnectionService config;
    private final Set classNotFoundSet = Collections.newSetFromMap(new ConcurrentHashMap<>());
    private final String id;
    private boolean closeFlag = false;

    public RemoteConnectionServiceImpl(URL url, String account, String password,
                                       SseServerProperties.ClusterConfig.ConnectionService config) {
        this.url = url;
        this.id = account;
        this.urlConnectionQueryService = url + "/ConnectionQueryService";
        this.urlSendService = url + "/SendService";
        this.urlRemoteConnectionService = url + "/RemoteConnectionService";
        this.config = config;
        this.restTemplate = SpringUtil.newAsyncRestTemplate(
                connectTimeout, readTimeout,
                threadsIfAsyncRequest, threadsIfBlockRequest,
                account + "RemoteConnectionService", account, password);
    }

    @Override
    public String getId() {
        return id;
    }

    @Override
    public RemoteCompletableFuture isOnlineAsync(Serializable userId) {
        return asyncGetConnectionQueryService("/isOnline?userId={userId}", this::extract,
                userId);
    }

    @Override
    public  RemoteCompletableFuture getUserAsync(Serializable userId) {
        return asyncGetConnectionQueryService("/getUser?userId={userId}", this::extract,
                userId);
    }

    @Override
    public  RemoteCompletableFuture, RemoteConnectionService> getUsersAsync() {
        return getUsersAsync(null);
    }

    @Override
    public  RemoteCompletableFuture, RemoteConnectionService> getUsersAsync(SseServerProperties.AutoType autoType) {
        return asyncGetConnectionQueryService("/getUsers", (response) -> extract(response, autoType));
    }

    @Override
    public  RemoteCompletableFuture, RemoteConnectionService> getUsersByListeningAsync(String sseListenerName) {
        return asyncGetConnectionQueryService("/getUsersByListening?sseListenerName={sseListenerName}", this::extract,
                sseListenerName);
    }

    @Override
    public  RemoteCompletableFuture, RemoteConnectionService> getUsersByTenantIdListeningAsync(Serializable tenantId, String sseListenerName) {
        return asyncGetConnectionQueryService("/getUsersByTenantIdListening?tenantId={tenantId}&sseListenerName={sseListenerName}", this::extract,
                tenantId, sseListenerName);
    }

    @Override
    public  RemoteCompletableFuture>, RemoteConnectionService> getConnectionDTOAllAsync(SseServerProperties.AutoType autoTypeEnum) {
        return asyncGetConnectionQueryService("/getConnectionDTOAll", (response) -> {
            List> list = extract(response, autoTypeEnum);
            SseServerProperties.AutoType autoType = autoTypeEnum == null ? config.getAutoType() : autoTypeEnum;
            for (ConnectionDTO item : list) {
                try {
                    ACCESS_USER cast = AutoTypeBean.cast(item.getAccessUser(),
                            item.getArrayClassName(), item.getObjectClassName(),
                            autoType, classNotFoundSet);
                    item.setAccessUser(cast);
                } catch (ClassNotFoundException e) {
                    LambdaUtil.sneakyThrows(e);
                }
            }
            return list;
        });
    }

    @Override
    public RemoteCompletableFuture, RemoteConnectionService> getConnectionDTOByUserIdAsync(Serializable userId) {
        return asyncGetConnectionQueryService("/getConnectionDTOByUserId?userId={userId}", this::extract, userId);
    }

    @Override
    public  RemoteCompletableFuture, RemoteConnectionService> getUserIdsAsync(Class type) {
        return asyncGetConnectionQueryService("/getUserIds", entity -> {
            Collection result = extract(entity);
            return castBasic(result, type);
        });
    }

    @Override
    public  RemoteCompletableFuture, RemoteConnectionService> getUserIdsByListeningAsync(String sseListenerName, Class type) {
        return asyncGetConnectionQueryService("/getUserIdsByListening?sseListenerName={sseListenerName}", entity -> {
            Collection result = extract(entity);
            return castBasic(result, type);
        }, sseListenerName);
    }

    @Override
    public  RemoteCompletableFuture, RemoteConnectionService> getUserIdsByTenantIdListeningAsync(Serializable tenantId, String sseListenerName, Class type) {
        return asyncGetConnectionQueryService("/getUserIdsByTenantIdListening?tenantId={tenantId}&sseListenerName={sseListenerName}", entity -> {
            Collection result = extract(entity);
            return castBasic(result, type);
        }, tenantId, sseListenerName);
    }

    @Override
    public RemoteCompletableFuture, RemoteConnectionService> getAccessTokensAsync() {
        return asyncGetConnectionQueryService("/getAccessTokens", this::extract);
    }

    @Override
    public  RemoteCompletableFuture, RemoteConnectionService> getTenantIdsAsync(Class type) {
        return asyncGetConnectionQueryService("/getTenantIds", entity -> {
            Collection result = extract(entity);
            return castBasic(result, type);
        });
    }

    @Override
    public RemoteCompletableFuture, RemoteConnectionService> getChannelsAsync() {
        return asyncGetConnectionQueryService("/getChannels", this::extract);
    }

    @Override
    public RemoteCompletableFuture getConnectionCountAsync() {
        return asyncGetConnectionQueryService("/getConnectionCount", this::extract);
    }

    @Override
    public boolean isOnline(Serializable userId) {
        RemoteCompletableFuture future = isOnlineAsync(userId);
        Boolean result = future.block();
        Objects.requireNonNull(result,
                "RemoteConnectionServiceImpl -> public boolean isOnline(userId) result is Null");
        return result;
    }

    @Override
    public  List> getConnectionDTOAll() {
        RemoteCompletableFuture>, RemoteConnectionService> future
                = getConnectionDTOAllAsync(null);
        return future.block();
    }

    @Override
    public List getConnectionDTOByUserId(Serializable userId) {
        RemoteCompletableFuture, RemoteConnectionService> future
                = getConnectionDTOByUserIdAsync(userId);
        return future.block();
    }

    @Override
    public  ACCESS_USER getUser(Serializable userId) {
        RemoteCompletableFuture future = getUserAsync(userId);
        return future.block();
    }

    @Override
    public  List getUsers() {
        RemoteCompletableFuture, RemoteConnectionService> future = getUsersAsync();
        return future.block();
    }

    @Override
    public  List getUsersByListening(String sseListenerName) {
        RemoteCompletableFuture, RemoteConnectionService> future = getUsersByListeningAsync(sseListenerName);
        return future.block();
    }

    @Override
    public  List getUsersByTenantIdListening(Serializable tenantId, String sseListenerName) {
        RemoteCompletableFuture, RemoteConnectionService> future = getUsersByTenantIdListeningAsync(tenantId, sseListenerName);
        return future.block();
    }

    @Override
    public  Collection getUserIds(Class type) {
        RemoteCompletableFuture, RemoteConnectionService> future = getUserIdsAsync(type);
        return future.block();
    }

    @Override
    public  List getUserIdsByListening(String sseListenerName, Class type) {
        RemoteCompletableFuture, RemoteConnectionService> future = getUserIdsByListeningAsync(sseListenerName, type);
        return future.block();
    }

    @Override
    public  List getUserIdsByTenantIdListening(Serializable tenantId, String sseListenerName, Class type) {
        RemoteCompletableFuture, RemoteConnectionService> future = getUserIdsByTenantIdListeningAsync(tenantId, sseListenerName, type);
        return future.block();
    }

    @Override
    public Collection getAccessTokens() {
        RemoteCompletableFuture, RemoteConnectionService> future = getAccessTokensAsync();
        return future.block();
    }

    @Override
    public  List getTenantIds(Class type) {
        RemoteCompletableFuture, RemoteConnectionService> future = getTenantIdsAsync(type);
        return future.block();
    }

    @Override
    public List getChannels() {
        RemoteCompletableFuture, RemoteConnectionService> future = getChannelsAsync();
        return future.block();
    }

    @Override
    public int getAccessTokenCount() {
        RemoteCompletableFuture future = asyncGetConnectionQueryService("/getAccessTokenCount", this::extract);
        Integer result = future.block();
        Objects.requireNonNull(result,
                "RemoteConnectionServiceImpl -> public int getAccessTokenCount() result is Null");
        return result;
    }

    @Override
    public int getUserCount() {
        RemoteCompletableFuture future = asyncGetConnectionQueryService("/getUserCount", this::extract);
        Integer result = future.block();
        Objects.requireNonNull(result,
                "RemoteConnectionServiceImpl -> public int getUserCount() result is Null");
        return result;
    }

    @Override
    public int getConnectionCount() {
        RemoteCompletableFuture future = asyncGetConnectionQueryService("/getConnectionCount", this::extract);
        Integer result = future.block();
        Objects.requireNonNull(result,
                "RemoteConnectionServiceImpl -> public boolean getConnectionCount() result is Null");
        return result;
    }

    @Override
    public  T scopeOnWriteable(Callable runnable) {
        scopeOnWriteableThreadLocal.set(true);
        try {
            return runnable.call();
        } catch (Exception e) {
            LambdaUtil.sneakyThrows(e);
            return null;
        } finally {
            scopeOnWriteableThreadLocal.remove();
        }
    }

    @Override
    public RemoteCompletableFuture sendAll(String eventName, Object body) {
        Map request = new HashMap<>(2);
        request.put("eventName", eventName);
        request.put("body", body);
        return asyncPostSendService("/sendAll", this::extract, request);
    }

    @Override
    public RemoteCompletableFuture sendAllListening(String eventName, Object body) {
        Map request = new HashMap<>(2);
        request.put("eventName", eventName);
        request.put("body", body);
        return asyncPostSendService("/sendAllListening", this::extract, request);
    }

    @Override
    public RemoteCompletableFuture sendByChannel(Collection channels, String eventName, Object body) {
        Map request = new HashMap<>(3);
        request.put("channels", channels);
        request.put("eventName", eventName);
        request.put("body", body);
        return asyncPostSendService("/sendByChannel", this::extract, request);
    }

    @Override
    public RemoteCompletableFuture sendByChannelListening(Collection channels, String eventName, Object body) {
        Map request = new HashMap<>(3);
        request.put("channels", channels);
        request.put("eventName", eventName);
        request.put("body", body);
        return asyncPostSendService("/sendByChannelListening", this::extract, request);
    }

    @Override
    public RemoteCompletableFuture sendByAccessToken(Collection accessTokens, String eventName, Object body) {
        Map request = new HashMap<>(3);
        request.put("accessTokens", accessTokens);
        request.put("eventName", eventName);
        request.put("body", body);
        return asyncPostSendService("/sendByAccessToken", this::extract, request);
    }

    @Override
    public RemoteCompletableFuture sendByAccessTokenListening(Collection accessTokens, String eventName, Object body) {
        Map request = new HashMap<>(3);
        request.put("accessTokens", accessTokens);
        request.put("eventName", eventName);
        request.put("body", body);
        return asyncPostSendService("/sendByAccessTokenListening", this::extract, request);
    }

    @Override
    public RemoteCompletableFuture sendByUserId(Collection userIds, String eventName, Object body) {
        Map request = new HashMap<>(3);
        request.put("userIds", userIds);
        request.put("eventName", eventName);
        request.put("body", body);
        return asyncPostSendService("/sendByUserId", this::extract, request);
    }

    @Override
    public RemoteCompletableFuture sendByUserIdListening(Collection userIds, String eventName, Object body) {
        Map request = new HashMap<>(3);
        request.put("userIds", userIds);
        request.put("eventName", eventName);
        request.put("body", body);
        return asyncPostSendService("/sendByUserIdListening", this::extract, request);
    }

    @Override
    public RemoteCompletableFuture sendByTenantId(Collection tenantIds, String eventName, Object body) {
        Map request = new HashMap<>(3);
        request.put("tenantIds", tenantIds);
        request.put("eventName", eventName);
        request.put("body", body);
        return asyncPostSendService("/sendByTenantId", this::extract, request);
    }

    @Override
    public RemoteCompletableFuture sendByTenantIdListening(Collection tenantIds, String eventName, Object body) {
        Map request = new HashMap<>(3);
        request.put("tenantIds", tenantIds);
        request.put("eventName", eventName);
        request.put("body", body);
        return asyncPostSendService("/sendByTenantIdListening", this::extract, request);
    }

    @Override
    public RemoteCompletableFuture disconnectByUserId(Serializable userId) {
        Map request = new HashMap<>(1);
        request.put("userId", userId);
        return asyncPostRemoteConnectionService("/disconnectByUserId", this::extract, request);
    }

    @Override
    public RemoteCompletableFuture disconnectByAccessToken(String accessToken) {
        Map request = new HashMap<>(1);
        request.put("accessToken", accessToken);
        return asyncPostRemoteConnectionService("/disconnectByAccessToken", this::extract, request);
    }

    @Override
    public RemoteCompletableFuture disconnectByConnectionId(Long connectionId) {
        Map request = new HashMap<>(1);
        request.put("connectionId", connectionId);
        return asyncPostRemoteConnectionService("/disconnectByConnectionId", this::extract, request);
    }

    @Override
    public RemoteCompletableFuture disconnectByConnectionId(Long connectionId, Long duration, Long sessionDuration) {
        Map request = new HashMap<>(1);
        request.put("connectionId", connectionId);
        request.put("duration", duration);
        request.put("sessionDuration", sessionDuration);
        return asyncPostRemoteConnectionService("/disconnectByConnectionId", this::extract, request);
    }

    @Override
    public RemoteCompletableFuture disconnectByConnectionIds(Collection connectionIds) {
        Map request = new HashMap<>(1);
        request.put("connectionIds", connectionIds);
        return asyncPostRemoteConnectionService("/disconnectByConnectionIds", this::extract, request);
    }

    @Override
    public RemoteCompletableFuture setDurationByUserId(Serializable userId, long durationSecond) {
        Map request = new HashMap<>(2);
        request.put("userId", userId);
        request.put("durationSecond", durationSecond);
        return asyncPostRemoteConnectionService("/setDurationByUserId", this::extract, request);
    }

    @Override
    public RemoteCompletableFuture setDurationByAccessToken(String accessToken, long durationSecond) {
        Map request = new HashMap<>(2);
        request.put("accessToken", accessToken);
        request.put("durationSecond", durationSecond);
        return asyncPostRemoteConnectionService("/setDurationByAccessToken", this::extract, request);
    }

    @Override
    public RemoteCompletableFuture active(List> activeList) {
        Map request = new HashMap<>(1);
        request.put("activeList", activeList);
        return asyncPostRemoteConnectionService("/active", this::extract, request);
    }

    protected  RemoteCompletableFuture asyncGetConnectionQueryService(String uri, Function, T> extract, Object... uriVariables) {
        return asyncGet(urlConnectionQueryService + uri, extract, uriVariables);
    }

    protected  RemoteCompletableFuture asyncPostSendService(String uri, Function, T> extract, Map request) {
        Boolean scopeOnWriteable = scopeOnWriteableThreadLocal.get();
        if (scopeOnWriteable != null && scopeOnWriteable) {
            request.put("scopeOnWriteable", true);
        }
        return asyncPost(urlSendService + uri, extract, request);
    }

    protected  RemoteCompletableFuture asyncPostRemoteConnectionService(String uri, Function, T> extract, Map request) {
        return asyncPost(urlRemoteConnectionService + uri, extract, request);
    }

    protected  RemoteCompletableFuture asyncGet(String url, Function, T> extract, Object... uriVariables) {
        checkClose();
        CompletableFuture> future = restTemplate.getForEntity(url, Response.class, uriVariables);
        return completable(future, extract);
    }

    protected  RemoteCompletableFuture asyncPost(String url, Function, T> extract, Map request) {
        checkClose();
        CompletableFuture> future = restTemplate.postForEntity(
                url, request, Response.class);
        return completable(future, extract);
    }

    protected  RemoteCompletableFuture completable(CompletableFuture> future, Function, T> extract) {
        RemoteCompletableFuture result = new RemoteCompletableFuture<>();
        result.setClient(this);
        future.whenComplete((response, throwable) -> {
            if (throwable != null) {
                result.completeExceptionally(throwable);
            } else {
                T data;
                try {
                    data = extract.apply(response);
                } catch (Throwable e) {
                    result.completeExceptionally(e);
                    return;
                }
                result.complete(data);
            }
        });
        return result;
    }

    protected  T extract(HttpEntity response) {
        return extract(response, null);
    }

    protected  T extract(HttpEntity response, SseServerProperties.AutoType autoTypeEnum) {
        if (autoTypeEnum == null) {
            autoTypeEnum = config.getAutoType();
        }
        Response body = response.getBody();
        try {
            return AutoTypeBean.cast(body.getData(),
                    body.getArrayClassName(), body.getObjectClassName(),
                    autoTypeEnum, classNotFoundSet);
        } catch (ClassNotFoundException e) {
            LambdaUtil.sneakyThrows(e);
            return null;
        }
    }

    protected , T> List castBasic(SOURCE source, Class type) {
        return TypeUtil.castBasic(source, type);
    }

    @Override
    public URL getRemoteUrl() {
        return url;
    }

    @Override
    public String toString() {
        return url == null ? "null" : url.toString();
    }

    @Override
    public void close() {
        restTemplate.close();
        this.closeFlag = true;
    }

    protected void checkClose() {
        if (closeFlag) {
            LambdaUtil.sneakyThrows(new ClosedChannelException());
        }
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy