Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dropyacht: dynamic source page #23

Draft
wants to merge 2 commits into
base: multiservice_endpoints
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 15 additions & 2 deletions src/main/java/com/meta/cp4m/message/FBMessage.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,25 @@

import com.meta.cp4m.Identifier;
import java.time.Instant;
import org.checkerframework.checker.nullness.qual.Nullable;

public record FBMessage(
Instant timestamp,
Identifier instanceId,
Identifier senderId,
Identifier recipientId,
String message,
Role role)
implements Message {}
Role role,
@Nullable String accessToken)
implements Message {

public FBMessage(
Instant timestamp,
Identifier instanceId,
Identifier senderId,
Identifier recipientId,
String message,
Role role) {
this(timestamp, instanceId, senderId, recipientId, message, role, null);
}
}
31 changes: 11 additions & 20 deletions src/main/java/com/meta/cp4m/message/FBMessageHandler.java
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ public class FBMessageHandler implements MessageHandler<FBMessage> {
private final String appSecret;

private final String accessToken;
private final @Nullable String connectedFacebookPageForInstagram;
private final boolean instagramMode;

private final Deduplicator<Identifier> messageDeduplicator = new Deduplicator<>(10_000);
private Function<Identifier, URI> baseURLFactory =
Expand All @@ -64,31 +64,25 @@ public class FBMessageHandler implements MessageHandler<FBMessage> {
};

public FBMessageHandler(
String verifyToken,
String pageAccessToken,
String appSecret,
@Nullable String connectedFacebookPageForInstagram) {
String verifyToken, String pageAccessToken, String appSecret, boolean instagramMode) {
this.verifyToken = verifyToken;
this.appSecret = appSecret;
this.accessToken = pageAccessToken;
this.connectedFacebookPageForInstagram = connectedFacebookPageForInstagram;
this.instagramMode = instagramMode;
}

public FBMessageHandler(String verifyToken, String pageAccessToken, String appSecret) {
this.verifyToken = verifyToken;
this.appSecret = appSecret;
this.accessToken = pageAccessToken;
this.connectedFacebookPageForInstagram = null;
this.instagramMode = false;
}

FBMessageHandler(FBMessengerConfig config) {
this.verifyToken = config.verifyToken();
this.appSecret = config.appSecret();
this.accessToken = config.pageAccessToken();
this.connectedFacebookPageForInstagram =
config.connectedFacebookPageForInstagram().isPresent()
? config.connectedFacebookPageForInstagram().get()
: null;
this.instagramMode = config.instagramMode();
}

@TestOnly
Expand Down Expand Up @@ -164,12 +158,14 @@ private List<FBMessage> postHandler(Context ctx, JsonNode body) {
@Override
public void respond(FBMessage message) throws IOException {
List<String> chunkedText = CHUNKER.chunks(message.message()).toList();
String accessToken = message.accessToken() == null ? this.accessToken : message.accessToken();
for (String text : chunkedText) {
send(text, message.recipientId(), message.senderId());
send(text, message.recipientId(), message.senderId(), accessToken);
}
}

private void send(String message, Identifier recipient, Identifier sender) throws IOException {
private void send(String message, Identifier recipient, Identifier sender, String accessToken)
throws IOException {
URI url;
ObjectNode body = MAPPER.createObjectNode();
body.put("messaging_type", "RESPONSE").putObject("recipient").put("id", recipient.toString());
Expand All @@ -178,11 +174,7 @@ private void send(String message, Identifier recipient, Identifier sender) throw
try {
bodyString = MAPPER.writeValueAsString(body);
url =
new URIBuilder(
baseURLFactory.apply(
connectedFacebookPageForInstagram == null
? sender
: Identifier.from(connectedFacebookPageForInstagram)))
new URIBuilder(baseURLFactory.apply(sender))
.addParameter("access_token", accessToken)
.build();
} catch (JsonProcessingException | URISyntaxException e) {
Expand Down Expand Up @@ -226,8 +218,7 @@ public List<RouteDetails<?, FBMessage>> routeDetails() {
throw new BadRequestResponse("unable to parse body");
}
// TODO: need better validation
String expectedObjectValue =
connectedFacebookPageForInstagram == null ? "page" : "instagram";
String expectedObjectValue = instagramMode ? "instagram" : "page";
@Nullable JsonNode objectNode = body.get("object");
if (objectNode != null && objectNode.textValue().equals(expectedObjectValue)) {
return Optional.of(body);
Expand Down
41 changes: 20 additions & 21 deletions src/main/java/com/meta/cp4m/message/FBMessengerConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,25 +10,23 @@

import com.fasterxml.jackson.annotation.JsonProperty;
import com.google.common.base.Preconditions;
import org.checkerframework.checker.nullness.qual.Nullable;

import java.util.Optional;
import java.util.UUID;
import org.checkerframework.checker.nullness.qual.Nullable;

public class FBMessengerConfig implements HandlerConfig {

private final String name;
private final String verifyToken;
private final String appSecret;
private final String pageAccessToken;
private final @Nullable String connectedFacebookPageForInstagram;
private final boolean instagramMode;

private FBMessengerConfig(
@JsonProperty("name") String name,
@JsonProperty("verify_token") String verifyToken,
@JsonProperty("app_secret") String appSecret,
@JsonProperty("page_access_token") String pageAccessToken,
@JsonProperty("connected_facebook_page_for_instagram") @Nullable String connectedFacebookPageForInstagram) {
private FBMessengerConfig(
@JsonProperty("name") String name,
@JsonProperty("verify_token") String verifyToken,
@JsonProperty("app_secret") String appSecret,
@JsonProperty("page_access_token") String pageAccessToken,
@JsonProperty("instagram_mode") @Nullable Boolean instagramMode) {

Preconditions.checkArgument(name != null && !name.isBlank(), "name cannot be blank");
Preconditions.checkArgument(
Expand All @@ -42,19 +40,20 @@ private FBMessengerConfig(
this.verifyToken = verifyToken;
this.appSecret = appSecret;
this.pageAccessToken = pageAccessToken;
this.connectedFacebookPageForInstagram = connectedFacebookPageForInstagram;
this.instagramMode = instagramMode != null && instagramMode;
}

public static FBMessengerConfig of(String verifyToken, String appSecret, String pageAccessToken, @Nullable String connectedFacebookPageForInstagram) {
// human readability of the name only matters when it's coming from a config
return new FBMessengerConfig(
UUID.randomUUID().toString(), verifyToken, appSecret, pageAccessToken, connectedFacebookPageForInstagram);
public static FBMessengerConfig of(
String verifyToken, String appSecret, String pageAccessToken, boolean instagramMode) {
// human readability of the name only matters when it's coming from a config
return new FBMessengerConfig(
UUID.randomUUID().toString(), verifyToken, appSecret, pageAccessToken, instagramMode);
}

public static FBMessengerConfig of(String verifyToken, String appSecret, String pageAccessToken) {
// human readability of the name only matters when it's coming from a config
return new FBMessengerConfig(
UUID.randomUUID().toString(), verifyToken, appSecret, pageAccessToken, null);
// human readability of the name only matters when it's coming from a config
return new FBMessengerConfig(
UUID.randomUUID().toString(), verifyToken, appSecret, pageAccessToken, false);
}

@Override
Expand All @@ -79,7 +78,7 @@ public String pageAccessToken() {
return pageAccessToken;
}

public Optional<String> connectedFacebookPageForInstagram() {
return Optional.ofNullable(connectedFacebookPageForInstagram);
public boolean instagramMode() {
return instagramMode;
}
}
}
4 changes: 2 additions & 2 deletions src/test/java/com/meta/cp4m/message/FBMessageHandlerTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -330,9 +330,9 @@ void invalidMessage(

FBMessageHandler messageHandler;
if (isInstagram) {
messageHandler = new FBMessageHandler("0", token, secret, pageId.toString());
messageHandler = new FBMessageHandler("0", token, secret, true);
} else {
messageHandler = new FBMessageHandler("0", token, secret);
messageHandler = new FBMessageHandler("0", token, secret, false);
}
DummyLLMPlugin<FBMessage> llmHandler = new DummyLLMPlugin<>("this is a dummy message");
MemoryStore<FBMessage> memoryStore = MemoryStoreConfig.of(1, 1).toStore();
Expand Down
13 changes: 12 additions & 1 deletion src/test/java/com/meta/cp4m/message/FBMessengerConfigTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,12 @@ class FBMessengerConfigTest {
.required(true)
.validValues("123")
.invalidValues("", " ")
.getter(FBMessengerConfig::pageAccessToken));
.getter(FBMessengerConfig::pageAccessToken),
ConfigParamTestSpec.of(FBMessengerConfig.class, "instagram_mode")
.required(false)
.validValues(true, false)
.invalidValues("anything that's not a boolean", 3.14)
.getter(FBMessengerConfig::instagramMode));

static Stream<Named<ConfigParamTestSpec<FBMessengerConfig>>> required() {
return PARAMS.stream().filter(ConfigParamTestSpec::required).map(p -> Named.of(p.name(), p));
Expand Down Expand Up @@ -94,6 +99,12 @@ void allInvalid(ConfigParamTestSpec<FBMessengerConfig> param) {
for (JsonNode invalidValue : param.invalidValues()) {
config.set(param.name(), invalidValue);
assertThatThrownBy(() -> mapper.convertValue(config, FBMessengerConfig.class))
.withFailMessage(
"expecting the value of '"
+ invalidValue
+ "' to be invalid for field '"
+ param.name()
+ "'")
.isInstanceOf(IllegalArgumentException.class);
}
}
Expand Down