Skip to content

Commit

Permalink
Use precomputed coturn values
Browse files Browse the repository at this point in the history
  • Loading branch information
Sheikah45 committed Jun 4, 2023
1 parent 550b34f commit 211f217
Show file tree
Hide file tree
Showing 10 changed files with 44 additions and 97 deletions.
2 changes: 1 addition & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -296,7 +296,7 @@ dependencies {

implementation("io.projectreactor.addons:reactor-extra")

def commonsVersion = "1a4afa332a"
def commonsVersion = "0423e0af13"

implementation("com.github.FAForever.faf-java-commons:faf-commons-data:${commonsVersion}") {
exclude module: 'guava'
Expand Down
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
version=unspecified
javafxPlatform=unspecified
iceAdapterVersion=v3.3.0
iceAdapterVersion=v3.3.2
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

import com.faforever.client.api.FafApiAccessor;
import com.faforever.client.mapstruct.IceServerMapper;
import com.faforever.client.preferences.CoturnHostPort;
import com.faforever.client.preferences.ForgedAlliancePrefs;
import com.faforever.commons.api.dto.CoturnServer;
import com.faforever.commons.api.elide.ElideNavigator;
Expand All @@ -12,8 +11,8 @@
import org.springframework.stereotype.Service;
import reactor.core.publisher.Flux;

import java.util.Collection;
import java.util.List;
import java.util.Set;
import java.util.concurrent.CompletableFuture;

@Lazy
Expand All @@ -36,9 +35,9 @@ public CompletableFuture<List<CoturnServer>> getSelectedCoturns() {
ElideNavigatorOnCollection<CoturnServer> navigator = ElideNavigator.of(CoturnServer.class).collection();
Flux<CoturnServer> coturnServerFlux = fafApiAccessor.getMany(navigator);

Collection<CoturnHostPort> preferredCoturnHosts = forgedAlliancePrefs.getPreferredCoturnServers();
Set<String> preferredCoturnRegions = forgedAlliancePrefs.getPreferredCoturnIds();

return coturnServerFlux.filter(coturnServer -> preferredCoturnHosts.contains(iceServerMapper.mapToHostPort(coturnServer)))
return coturnServerFlux.filter(coturnServer -> preferredCoturnRegions.contains(coturnServer.getId()))
.switchIfEmpty(coturnServerFlux)
.switchIfEmpty(Flux.error(new IllegalStateException("No Coturn Servers Available")))
.collectList()
Expand Down
48 changes: 7 additions & 41 deletions src/main/java/com/faforever/client/mapstruct/IceServerMapper.java
Original file line number Diff line number Diff line change
@@ -1,56 +1,22 @@
package com.faforever.client.mapstruct;

import com.faforever.client.domain.PlayerBean;
import com.faforever.client.player.PlayerService;
import com.faforever.client.preferences.CoturnHostPort;
import com.faforever.commons.api.dto.CoturnServer;
import org.apache.commons.codec.digest.HmacUtils;
import org.mapstruct.Mapper;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.ArrayList;
import java.util.Base64;
import java.net.URI;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Mapper(config = MapperConfiguration.class)
public abstract class IceServerMapper {
int TTL = 86400;

@Autowired
private PlayerService playerService;

public abstract CoturnHostPort mapToHostPort(CoturnServer coturnServer);

public Map<String, Object> map(CoturnServer coturnServer) {
Map<String, Object> map = new HashMap<>();

PlayerBean currentPlayer = playerService.getCurrentPlayer();

// Build hmac verification as described here:
// https://github.com/coturn/coturn/blob/f67326fe3585eafd664720b43c77e142d9bed73c/README.turnserver#L710
long timestamp = System.currentTimeMillis() / 1000 + TTL;
String tokenName = String.format("%d:%d", timestamp, currentPlayer.getId());

String token = Base64.getEncoder().encodeToString(new HmacUtils("HmacSHA1", coturnServer.getKey()).hmac(tokenName));

String host = coturnServer.getHost();
if (coturnServer.getPort() != null) {
host += ":" + coturnServer.getPort();
}

List<String> urls = new ArrayList<>();
urls.add(String.format("turn:%s?transport=tcp", host));
urls.add(String.format("turn:%s?transport=udp", host));
urls.add(String.format("turn:%s", host));

map.put("urls", urls);
map.put("credential", token);
map.put("credentialType", "token");
map.put("username", tokenName);
return map;
return Map.of(
"urls", coturnServer.getUrls().stream().map(URI::toString).toList(),
"credential", coturnServer.getCredential(),
"credentialType", coturnServer.getCredentialType(),
"username", coturnServer.getUsername()
);
}

public abstract List<Map<String, Object>> map(Collection<CoturnServer> coturnServers);
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ public class ForgedAlliancePrefs {
ObjectProperty<Path> executionDirectory = new SimpleObjectProperty<>();
BooleanProperty runFAWithDebugger = new SimpleBooleanProperty(false);
BooleanProperty showIceAdapterDebugWindow = new SimpleBooleanProperty(false);
ObservableSet<CoturnHostPort> preferredCoturnServers = FXCollections.observableSet();
ObservableSet<String> preferredCoturnIds = FXCollections.observableSet();

/**
* Whether the game process' priority should be set to high after launch. Enabling this may cause issues with some
Expand Down Expand Up @@ -176,8 +176,8 @@ public BooleanProperty showIceAdapterDebugWindow() {
return showIceAdapterDebugWindow;
}

public ObservableSet<CoturnHostPort> getPreferredCoturnServers() {
return preferredCoturnServers;
public ObservableSet<String> getPreferredCoturnIds() {
return preferredCoturnIds;
}

public boolean getWarnNonAsciiVaultPath() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@
import com.faforever.client.notification.Severity;
import com.faforever.client.notification.TransientNotification;
import com.faforever.client.preferences.ChatPrefs;
import com.faforever.client.preferences.CoturnHostPort;
import com.faforever.client.preferences.DataPrefs;
import com.faforever.client.preferences.DateInfo;
import com.faforever.client.preferences.ForgedAlliancePrefs;
Expand Down Expand Up @@ -86,6 +85,7 @@
import java.util.Locale;
import java.util.Map;
import java.util.Objects;
import java.util.function.Function;
import java.util.stream.Collectors;

import static com.faforever.client.fx.JavaFxUtil.PATH_STRING_CONVERTER;
Expand Down Expand Up @@ -340,11 +340,11 @@ private void initPreferredCoturnListView() {
preferredCoturnListView.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);
preferredCoturnListView.setItems(FXCollections.observableList(coturnServers));
preferredCoturnListView.setCellFactory(param -> new StringListCell<>(CoturnServer::getRegion, fxApplicationThreadExecutor));
ObservableSet<CoturnHostPort> preferredCoturnServers = preferences
ObservableSet<String> preferredCoturnServers = preferences
.getForgedAlliance()
.getPreferredCoturnServers();
Map<CoturnHostPort, CoturnServer> hostPortCoturnServerMap = coturnServers.stream()
.collect(Collectors.toMap(iceServerMapper::mapToHostPort, server -> server));
.getPreferredCoturnIds();
Map<String, CoturnServer> hostPortCoturnServerMap = coturnServers.stream()
.collect(Collectors.toMap(CoturnServer::getId, Function.identity()));

preferredCoturnServers.stream()
.filter(hostPortCoturnServerMap::containsKey)
Expand All @@ -355,7 +355,7 @@ private void initPreferredCoturnListView() {
.getSelectedItems(), (InvalidationListener) observable -> {
List<CoturnServer> selectedCoturns = preferredCoturnListView.getSelectionModel().getSelectedItems();
preferredCoturnServers.clear();
selectedCoturns.stream().map(iceServerMapper::mapToHostPort).forEach(preferredCoturnServers::add);
selectedCoturns.stream().map(CoturnServer::getId).forEach(preferredCoturnServers::add);
});
}, fxApplicationThreadExecutor);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
import com.faforever.client.api.FafApiAccessor;
import com.faforever.client.mapstruct.IceServerMapper;
import com.faforever.client.mapstruct.MapperSetup;
import com.faforever.client.preferences.CoturnHostPort;
import com.faforever.client.preferences.ForgedAlliancePrefs;
import com.faforever.client.test.ElideMatchers;
import com.faforever.client.test.ServiceTest;
Expand Down Expand Up @@ -50,46 +49,46 @@ public void testGetActiveCoturns() {

@Test
public void TestGetSelectedCoturnsNoActiveSelected() {
forgedAlliancePrefs.getPreferredCoturnServers().add(new CoturnHostPort("test", null));
forgedAlliancePrefs.getPreferredCoturnIds().add("1");

CoturnServer otherServer = new CoturnServer();
otherServer.setHost("other");
otherServer.setId("0");
when(fafApiAccessor.getMany(any())).thenReturn(Flux.just(otherServer));

List<CoturnServer> servers = instance.getSelectedCoturns().join();

assertEquals(1, servers.size());
assertEquals("other", servers.get(0).getHost());
assertEquals("0", servers.get(0).getId());
verify(fafApiAccessor).getMany(argThat(ElideMatchers.hasDtoClass(CoturnServer.class)));
}

@Test
public void testGetSelectedCoturnsNoneSelected() {
CoturnServer otherServer = new CoturnServer();
otherServer.setHost("other");
otherServer.setId("0");
when(fafApiAccessor.getMany(any())).thenReturn(Flux.just(otherServer));

List<CoturnServer> servers = instance.getSelectedCoturns().join();

assertEquals(1, servers.size());
assertEquals("other", servers.get(0).getHost());
assertEquals("0", servers.get(0).getId());
verify(fafApiAccessor).getMany(argThat(ElideMatchers.hasDtoClass(CoturnServer.class)));
}

@Test
public void testGetSelectedCoturnsActiveSelected() {
forgedAlliancePrefs.getPreferredCoturnServers().add(new CoturnHostPort("test", null));
forgedAlliancePrefs.getPreferredCoturnIds().add("1");

CoturnServer otherServer = new CoturnServer();
otherServer.setHost("other");
otherServer.setId("0");
CoturnServer selectedServer = new CoturnServer();
otherServer.setHost("test");
otherServer.setId("1");
when(fafApiAccessor.getMany(any())).thenReturn(Flux.just(otherServer, selectedServer));

List<CoturnServer> servers = instance.getSelectedCoturns().join();

assertEquals(1, servers.size());
assertEquals("test", servers.get(0).getHost());
assertEquals("1", servers.get(0).getId());
verify(fafApiAccessor).getMany(argThat(ElideMatchers.hasDtoClass(CoturnServer.class)));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@
import com.faforever.commons.lobby.GpgGameOutboundMessage;
import com.faforever.commons.lobby.MessageTarget;
import com.google.common.eventbus.EventBus;
import org.apache.commons.codec.digest.HmacUtils;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mapstruct.factory.Mappers;
Expand All @@ -32,10 +31,11 @@
import org.springframework.beans.factory.ObjectFactory;
import org.springframework.test.util.ReflectionTestUtils;

import java.net.URI;
import java.nio.file.Path;
import java.util.Base64;
import java.util.List;
import java.util.Map;
import java.util.Set;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
Expand Down Expand Up @@ -72,7 +72,6 @@ public class IceAdapterImplTest extends ServiceTest {
@BeforeEach
public void setUp() throws Exception {
MapperSetup.injectMappers(iceServerMapper);
ReflectionTestUtils.setField(iceServerMapper, "playerService", playerService, null);
ReflectionTestUtils.setField(instance, "iceAdapterProxy", iceAdapterApi, null);
}

Expand Down Expand Up @@ -180,12 +179,10 @@ public void testGameClosey() throws Exception {
@Test
public void testSetIceAdapters() throws Exception {
CoturnServer coturnServer = new CoturnServer();
coturnServer.setHost("test");
coturnServer.setPort(8000);
coturnServer.setKey("test");

PlayerBean currentPlayer = PlayerBeanBuilder.create().defaultValues().get();
when(playerService.getCurrentPlayer()).thenReturn(currentPlayer);
coturnServer.setCredential("test");
coturnServer.setCredentialType("token");
coturnServer.setUsername("0:1234");
coturnServer.setUrls(Set.of(URI.create("turn://test.coturn.com?transport=tcp")));

instance.setIceServers(List.of(coturnServer));

Expand All @@ -198,21 +195,10 @@ public void testSetIceAdapters() throws Exception {

Map<String, Object> iceMap = value.get(0);

String tokenName = (String) iceMap.get("username");
String[] nameParts = tokenName.split(":");
String userId = nameParts[1];
String timeString = nameParts[0];
String token = Base64.getEncoder().encodeToString(new HmacUtils("HmacSHA1", coturnServer.getKey()).hmac(tokenName));
List<String> urls = (List<String>) iceMap.get("urls");

assertEquals("1", userId);
assertEquals("token", iceMap.get("credentialType"));
assertEquals(token, iceMap.get("credential"));
assertTrue(Long.parseLong(timeString) > System.currentTimeMillis() / 1000);
assertEquals(3, urls.size());
assertEquals("turn:test:8000?transport=tcp", urls.get(0));
assertEquals("turn:test:8000?transport=udp", urls.get(1));
assertEquals("turn:test:8000", urls.get(2));
assertEquals(coturnServer.getUsername(), iceMap.get("username"));
assertEquals(coturnServer.getCredentialType(), iceMap.get("credentialType"));
assertEquals(coturnServer.getCredential(), iceMap.get("credential"));
assertEquals(List.of("turn://test.coturn.com?transport=tcp"), iceMap.get("urls"));
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
import com.faforever.client.notification.NotificationService;
import com.faforever.client.notification.PersistentNotification;
import com.faforever.client.preferences.ChatPrefs;
import com.faforever.client.preferences.CoturnHostPort;
import com.faforever.client.preferences.LanguageChannel;
import com.faforever.client.preferences.Preferences;
import com.faforever.client.preferences.PreferencesService;
Expand Down Expand Up @@ -124,7 +123,8 @@ public void setUp() throws Exception {
when(uiService.getCurrentTheme()).thenReturn(FIRST_THEME);
when(uiService.getAvailableThemes()).thenReturn(Arrays.asList(FIRST_THEME, SECOND_THEME));
CoturnServer coturnServer = new CoturnServer();
coturnServer.setHost("Test");
coturnServer.setId("0");
coturnServer.setRegion("Test");
when(coturnService.getActiveCoturns()).thenReturn(CompletableFuture.completedFuture(List.of(coturnServer)));
when(gameService.isGamePrefsPatchedToAllowMultiInstances()).thenReturn(CompletableFuture.completedFuture(true));

Expand Down Expand Up @@ -231,7 +231,7 @@ public void testLanguageChannels() throws Exception {

@Test
public void testCoturnSelected() throws Exception {
ObservableSet<CoturnHostPort> preferredCoturnServers = preferences.getForgedAlliance().getPreferredCoturnServers();
ObservableSet<String> preferredCoturnServers = preferences.getForgedAlliance().getPreferredCoturnIds();
preferredCoturnServers.clear();
runOnFxThreadAndWait(() -> instance.initialize());

Expand All @@ -240,7 +240,7 @@ public void testCoturnSelected() throws Exception {
runOnFxThreadAndWait(() -> instance.preferredCoturnListView.getSelectionModel().select(0));

assertEquals(1, preferredCoturnServers.size());
assertTrue(preferredCoturnServers.contains(new CoturnHostPort("Test", null)));
assertTrue(preferredCoturnServers.contains("0"));

runOnFxThreadAndWait(() -> instance.initialize());

Expand Down

0 comments on commit 211f217

Please sign in to comment.