private Mono<UserSession> addOnlineDeviceIfAbsent(
            int version,
            @NotNull Set<TurmsRequest.KindCase> permissions,
            @NotNull ByteArrayWrapper ip,
            @NotNull Long userId,
            @NotNull DeviceType deviceType,
            @Nullable Map<String, String> deviceDetails,
            @Nullable UserStatus userStatus,
            @Nullable Location location,
            @Nullable String expectedNodeId,
            @Nullable Long expectedDeviceTimestamp) {
        // TODO: Add extension point https://github.com/turms-im/turms/issues/1187
        Map<String, String> details;
        List<DeviceDetailsItemProperties> itemPropertiesList = deviceDetailsItemPropertiesList;
        if (itemPropertiesList.isEmpty() || CollectionUtil.isEmpty(deviceDetails)) {
            details = null;
        } else {
            details = CollectionUtil.newMapWithExpectedSize(itemPropertiesList.size());
            for (DeviceDetailsItemProperties itemProperties : itemPropertiesList) {
                String value = deviceDetails.get(itemProperties.getFieldName());
                if (value != null) {
                    details.put(itemProperties.getRedisFieldName(), value);
                }
            }
        }
        // Try to update the global user status
        return userStatusService
                .addOnlineDeviceIfAbsent(userId,
                        deviceType,
                        details,
                        userStatus,
                        closeIdleSessionAfterSeconds,
                        expectedNodeId,
                        expectedDeviceTimestamp)
                .flatMap(wasSuccessful -> {
                    if (!wasSuccessful) {
                        return Mono.error(ResponseException
                                .get(ResponseStatusCode.SESSION_SIMULTANEOUS_CONFLICTS_DECLINE));
                    }
                    UserStatus finalUserStatus = null == userStatus
                            ? UserStatus.AVAILABLE
                            : userStatus;
                    UserSessionsManager manager = userIdToSessionsManager.computeIfAbsent(userId,
                            key -> new UserSessionsManager(key, finalUserStatus));
                    UserSession session = manager.addSessionIfAbsent(version,
                            permissions,
                            deviceType,
                            deviceDetails,
                            location);
                    // This should never happen
                    if (null == session) {
                        manager.closeSession(deviceType,
                                CloseReason.get(SessionCloseStatus.DISCONNECTED_BY_OTHER_DEVICE));
                        ipToSessions.computeIfPresent(ip, (key, sessions) -> {
                            boolean removed =
                                    sessions.removeIf(userSession -> userSession.getUserId()
                                            .equals(userId)
                                            && userSession.getDeviceType()
                                                    .equals(deviceType));
                            return removed
                                    ? (sessions.isEmpty()
                                            ? null
                                            : sessions)
                                    : sessions;
                        });
                        session = manager.addSessionIfAbsent(version,
                                permissions,
                                deviceType,
                                deviceDetails,
                                location);
                        if (null == session) {
                            return Mono.error(ResponseException
                                    .get(ResponseStatusCode.SERVER_INTERNAL_ERROR));
                        }
                    }
                    ipToSessions.computeIfAbsent(ip, key -> new ConcurrentLinkedQueue<>())
                            .add(session);
                    Date now = new Date();
                    if (null != location && sessionLocationService.isLocationEnabled()) {
                        return sessionLocationService
                                .upsertUserLocation(userId,
                                        deviceType,
                                        now,
                                        location.longitude(),
                                        location.latitude())
                                .thenReturn(session);
                    }
                    return Mono.just(session);
                });
    }
For the case that the client recovers from UDP to TCP/WebSocket: Return the local session if
the client connects to the machine that owns the existing session; Return a new session and
disconnect the remote session if the existing session is on a different machine.
turms-gateway/src/main/java/im/turms/gateway/domain/session/service/SessionService.java