Skip to content

Commit

Permalink
feat(get-domain-from-backend) Use new Helium API to fetch backend domain
Browse files Browse the repository at this point in the history
* Update Helium to 1.4.1
* Add assertions to major tests
* Remove Consts.java from tests
* Add call to get api version and default domain
  • Loading branch information
alexandreferris committed Oct 1, 2024
1 parent 7f59827 commit a051559
Show file tree
Hide file tree
Showing 9 changed files with 93 additions and 108 deletions.
80 changes: 25 additions & 55 deletions src/main/java/com/wire/bots/hold/NotificationProcessor.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,39 +3,34 @@
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.wire.bots.hold.DAO.AccessDAO;
import com.wire.bots.hold.model.Config;
import com.wire.bots.hold.model.LHAccess;
import com.wire.bots.hold.model.Notification;
import com.wire.bots.hold.model.NotificationList;
import com.wire.helium.API;
import com.wire.helium.LoginClient;
import com.wire.helium.models.Access;
import com.wire.helium.models.Event;
import com.wire.helium.models.NotificationList;
import com.wire.xenon.backend.models.Payload;
import com.wire.xenon.exceptions.AuthException;
import com.wire.xenon.exceptions.HttpException;
import com.wire.xenon.tools.Logger;

import javax.ws.rs.client.Client;
import javax.ws.rs.client.WebTarget;
import javax.ws.rs.core.Cookie;
import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import java.util.List;
import java.util.UUID;
import java.util.logging.Level;

public class NotificationProcessor implements Runnable {
private static final int DEFAULT_NOTIFICATION_SIZE = 100;

private final Client client;
private final AccessDAO accessDAO;
private final HoldMessageResource messageResource;
private final WebTarget api;

NotificationProcessor(Client client, AccessDAO accessDAO, Config config, HoldMessageResource messageResource) {
NotificationProcessor(Client client, AccessDAO accessDAO, HoldMessageResource messageResource) {
this.client = client;
this.accessDAO = accessDAO;
this.messageResource = messageResource;

api = client.target(config.apiHost);
}

@Override
Expand All @@ -59,7 +54,11 @@ private Access getAccess(Cookie cookie) throws HttpException {

private void process(LHAccess device) {
UUID userId = device.userId;

try {
// todo get exception
final API api = new API(client, null, device.token);

Logger.debug("`GET /notifications`: user: %s, last: %s", userId, device.last);

String cookieValue = device.cookie;
Expand All @@ -77,10 +76,13 @@ private void process(LHAccess device) {

device.token = access.getAccessToken();

NotificationList notificationList = retrieveNotifications(device);
NotificationList notificationList = api.retrieveNotifications(
device.clientId,
device.last,
DEFAULT_NOTIFICATION_SIZE
);

process(userId, notificationList);

} catch (AuthException e) {
accessDAO.disable(userId);
Logger.info("Disabled LH device for user: %s, error: %s", userId, e.getMessage());
Expand All @@ -89,27 +91,21 @@ private void process(LHAccess device) {
}
}

private static String bearer(String token) {
return token == null ? null : String.format("Bearer %s", token);
}

private void process(UUID userId, NotificationList notificationList) {

for (Notification notif : notificationList.notifications) {
for (Payload payload : notif.payload) {
if (!process(userId, payload, notif.id)) {
Logger.error("Failed to process: user: %s, notif: %s", userId, notif.id);
//return;
for (Event event : notificationList.notifications) {
for (Payload payload : event.payload) {
if (!process(userId, payload, event.id)) {
Logger.error("Failed to process: user: %s, event: %s", userId, event.id);
} else {
Logger.debug("Processed: `%s` conv: %s, user: %s, notifId: %s",
Logger.debug("Processed: `%s` conv: %s, user: %s, eventId: %s",
payload.type,
payload.conversation,
userId,
notif.id);
event.id);
}
}

accessDAO.updateLast(userId, notif.id);
accessDAO.updateLast(userId, event.id);
}
}

Expand All @@ -123,13 +119,13 @@ private boolean process(UUID userId, Payload payload, UUID id) {

if (payload.from == null || payload.data == null) return true;

final boolean b = messageResource.onNewMessage(userId, id, payload);
final boolean wasMessageSent = messageResource.onNewMessage(userId, id, payload);

if (!b) {
if (!wasMessageSent) {
Logger.error("process: `%s` user: %s, from: %s:%s, error: %s", payload.type, userId, payload.from, payload.data.sender);
}

return b;
return wasMessageSent;
}

private void trace(Payload payload) {
Expand All @@ -142,30 +138,4 @@ private void trace(Payload payload) {
}
}
}

//TODO remove this and use retrieveNotifications provided by Helium
private NotificationList retrieveNotifications(LHAccess access) throws HttpException {
Response response = api.path("notifications").queryParam("client", access.clientId).queryParam("since", access.last).queryParam("size", 100).request(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON).header(HttpHeaders.AUTHORIZATION, bearer(access.token)).get();

int status = response.getStatus();

if (status == 200) {
return response.readEntity(NotificationList.class);
}

if (status == 404) { //todo what???
return response.readEntity(NotificationList.class);
}

if (status == 401) { //todo nginx returns text/html for 401. Cannot deserialize as json
response.readEntity(String.class);
throw new AuthException(status);
}

if (status == 403) {
throw response.readEntity(AuthException.class);
}

throw response.readEntity(HttpException.class);
}
}
11 changes: 5 additions & 6 deletions src/main/java/com/wire/bots/hold/Service.java
Original file line number Diff line number Diff line change
Expand Up @@ -27,14 +27,18 @@
import com.wire.bots.hold.monitoring.RequestMdcFactoryFilter;
import com.wire.bots.hold.monitoring.StatusResource;
import com.wire.bots.hold.resource.*;
import com.wire.bots.hold.utils.Cache;
import com.wire.bots.hold.utils.HoldClientRepo;
import com.wire.bots.hold.utils.ImagesBundle;
import com.wire.helium.LoginClient;
import com.wire.helium.models.BackendConfiguration;
import com.wire.xenon.Const;
import com.wire.xenon.backend.models.QualifiedId;
import com.wire.xenon.crypto.CryptoDatabase;
import com.wire.xenon.crypto.storage.JdbiStorage;
import com.wire.xenon.exceptions.HttpException;
import com.wire.xenon.factories.CryptoFactory;
import com.wire.xenon.tools.Logger;
import io.dropwizard.Application;
import io.dropwizard.assets.AssetsBundle;
import io.dropwizard.client.JerseyClientBuilder;
Expand Down Expand Up @@ -131,10 +135,9 @@ public void run(Config config, Environment environment) {
environment.healthChecks().register("SanityCheck", new SanityCheck(accessDAO, httpClient));

final HoldClientRepo repo = new HoldClientRepo(jdbi, cf, httpClient);
final LoginClient loginClient = new LoginClient(httpClient);

final HoldMessageResource holdMessageResource = new HoldMessageResource(new MessageHandler(jdbi), repo);
final NotificationProcessor notificationProcessor = new NotificationProcessor(httpClient, accessDAO, config, holdMessageResource);
final NotificationProcessor notificationProcessor = new NotificationProcessor(httpClient, accessDAO, holdMessageResource);

environment.lifecycle()
.scheduledExecutorService("notifications")
Expand All @@ -144,10 +147,6 @@ public void run(Config config, Environment environment) {
CollectorRegistry.defaultRegistry.register(new DropwizardExports(metrics));

environment.getApplicationContext().addServlet(MetricsServlet.class, "/metrics");

// todo here
// String res = loginClient.getBackendConfiguration();
// handle res ^
}

public Config getConfig() {
Expand Down
21 changes: 20 additions & 1 deletion src/main/java/com/wire/bots/hold/healthchecks/SanityCheck.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,11 @@
import com.codahale.metrics.health.HealthCheck;
import com.wire.bots.hold.DAO.AccessDAO;
import com.wire.bots.hold.model.LHAccess;
import com.wire.bots.hold.utils.Cache;
import com.wire.helium.API;
import com.wire.helium.models.BackendConfiguration;
import com.wire.xenon.backend.models.QualifiedId;
import com.wire.xenon.exceptions.HttpException;
import com.wire.xenon.tools.Logger;

import javax.ws.rs.client.Client;
Expand All @@ -30,14 +33,18 @@ protected Result check() {

API api = new API(client, null, single.token);

fetchAndStoreApiVersion(api);

String created = single.created;
List<LHAccess> accessList = accessDAO.list(100, created);

while (!accessList.isEmpty()) {
Logger.info("SanityCheck: checking %d devices, created: %s", accessList.size(), created);
for (LHAccess access : accessList) {
// TODO(WPB-11287): Use user domain if exists, otherwise default
// TODO: String domain = (access.domain != null) ? access.domain : Cache.DEFAULT_DOMAIN;
boolean hasDevice = api.hasDevice(
new QualifiedId(access.userId, null), // TODO(WPB-11287): Change null to default domain
new QualifiedId(access.userId, Cache.getDefaultDomain()), // TODO(WPB-11287): Change null to default domain
access.clientId
);

Expand All @@ -61,4 +68,16 @@ protected Result check() {
Logger.debug("Finished SanityCheck");
}
}

private void fetchAndStoreApiVersion(API api) {
if (Cache.getDefaultDomain() != null) { return; }

try {
BackendConfiguration apiVersionResponse = api.getBackendConfiguration();

Cache.setDefaultDomain(apiVersionResponse.domain);
} catch (HttpException exception) {
Logger.exception(exception, "Service.getApiVersion, exception: %s", exception.getMessage());
}
}
}
20 changes: 0 additions & 20 deletions src/main/java/com/wire/bots/hold/model/Notification.java

This file was deleted.

18 changes: 0 additions & 18 deletions src/main/java/com/wire/bots/hold/model/NotificationList.java

This file was deleted.

10 changes: 7 additions & 3 deletions src/main/java/com/wire/bots/hold/resource/ConfirmResource.java
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,13 @@ public ConfirmResource(AccessDAO accessDAO) {
@ApiResponse(code = 200, message = "Legal Hold Device enabled")})
public Response confirm(@ApiParam @Valid @NotNull ConfirmPayload payload) {
try {
int insert = accessDAO.insert(payload.userId,
payload.clientId,
payload.refreshToken);
int insert = accessDAO.insert(
// TODO(WPB-11287): Add new column in DB for domain
// TODO(WPB-11287): + Use default domain for v0
payload.userId,
payload.clientId,
payload.refreshToken
);

if (0 == insert) {
Logger.error("ConfirmResource: Failed to insert Access %s:%s",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,8 @@ public Response list(@ApiParam @PathParam("conversationId") UUID conversationId,
try {
List<Event> events = eventsDAO.listAllAsc(conversationId);

// TODO(WPB-11287) Verify default domain

testAPI();

Cache cache = new Cache(api, assetsDAO);
Expand Down
20 changes: 15 additions & 5 deletions src/main/java/com/wire/bots/hold/utils/Cache.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,11 @@
import java.util.concurrent.ConcurrentHashMap;

public class Cache {
// TODO(WPB-11287): Add default domain here
private static final ConcurrentHashMap<UUID, File> assets = new ConcurrentHashMap<>();//<messageId, File>
private static final ConcurrentHashMap<QualifiedId, User> users = new ConcurrentHashMap<>();//<userId, User>
private static final ConcurrentHashMap<QualifiedId, File> profiles = new ConcurrentHashMap<>();//<userId, Picture>
private static String DEFAULT_DOMAIN = null;

private static final ConcurrentHashMap<UUID, File> assets = new ConcurrentHashMap<>(); // <messageId, File>
private static final ConcurrentHashMap<QualifiedId, User> users = new ConcurrentHashMap<>(); // <QualifiedId, User>
private static final ConcurrentHashMap<QualifiedId, File> profiles = new ConcurrentHashMap<>(); // <QualifiedId, Picture>
private final API api;
private final AssetsDAO assetsDAO;

Expand All @@ -25,6 +26,16 @@ public Cache(API api, AssetsDAO assetsDAO) {
this.assetsDAO = assetsDAO;
}

public static void setDefaultDomain(String domain) {
if (DEFAULT_DOMAIN == null) {
DEFAULT_DOMAIN = domain;
}
}

public static String getDefaultDomain() {
return DEFAULT_DOMAIN;
}

@Nullable
public File getAssetFile(UUID messageId) {

Expand Down Expand Up @@ -57,7 +68,6 @@ public File getProfileImage(User user) {
}

public User getUser(QualifiedId userId) {
// TODO(WPB-11287): Fetch first in map then check API
return users.computeIfAbsent(userId, k -> {
try {
return api.getUser(userId);
Expand Down
19 changes: 19 additions & 0 deletions src/test/java/com/wire/bots/hold/utils/TestCache.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import com.wire.xenon.backend.models.QualifiedId;
import com.wire.xenon.backend.models.User;
import org.junit.Test;

import java.io.File;
import java.util.UUID;
Expand Down Expand Up @@ -32,4 +33,22 @@ public User getUser(QualifiedId userId) {

return dummyUser;
}

@Test
public void verifyDefaultDomainIsSetCorrectly() {
String firstDomain = Cache.getDefaultDomain();
assert firstDomain == null;

Cache.setDefaultDomain("dummy_domain");
String secondDomain = Cache.getDefaultDomain();

assert secondDomain != null;
assert secondDomain.equals("dummy_domain");

Cache.setDefaultDomain("dummy_domain_3");
String thirdDomain = Cache.getDefaultDomain();

assert thirdDomain != null;
assert thirdDomain.equals("dummy_domain");
}
}

0 comments on commit a051559

Please sign in to comment.