-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Showing
15 changed files
with
468 additions
and
13 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
88 changes: 88 additions & 0 deletions
88
src/main/java/ca/levimiller/smsbridge/data/dto/TwilioSmsDtoConverter.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
package ca.levimiller.smsbridge.data.dto; | ||
|
||
import java.io.IOException; | ||
import java.nio.charset.StandardCharsets; | ||
import java.util.ArrayList; | ||
import java.util.Collections; | ||
import java.util.List; | ||
import java.util.Map; | ||
import javax.inject.Inject; | ||
import org.springframework.http.HttpInputMessage; | ||
import org.springframework.http.HttpOutputMessage; | ||
import org.springframework.http.MediaType; | ||
import org.springframework.http.converter.AbstractHttpMessageConverter; | ||
import org.springframework.http.converter.FormHttpMessageConverter; | ||
import org.springframework.http.converter.HttpMessageNotReadableException; | ||
import org.springframework.http.converter.HttpMessageNotWritableException; | ||
import org.springframework.stereotype.Component; | ||
|
||
@Component | ||
public class TwilioSmsDtoConverter extends AbstractHttpMessageConverter<TwilioSmsDto> { | ||
private final FormHttpMessageConverter formHttpMessageConverter; | ||
|
||
@Inject | ||
public TwilioSmsDtoConverter(FormHttpMessageConverter formHttpMessageConverter) { | ||
super(new MediaType("application","x-www-form-urlencoded", StandardCharsets.UTF_8)); | ||
this.formHttpMessageConverter = formHttpMessageConverter; | ||
} | ||
|
||
@Override | ||
protected boolean supports(Class<?> clazz) { | ||
return TwilioSmsDto.class == clazz; | ||
} | ||
|
||
@Override | ||
protected TwilioSmsDto readInternal(Class<? extends TwilioSmsDto> clazz, | ||
HttpInputMessage inputMessage) throws IOException, HttpMessageNotReadableException { | ||
Map<String, String> vals = formHttpMessageConverter.read(null, inputMessage).toSingleValueMap(); | ||
|
||
Integer numMedia = getInteger(vals, "NumMedia"); | ||
|
||
return TwilioSmsDto.builder() | ||
.messageSid(vals.get("MessageSid")) | ||
.messageSid(vals.get("MessageSid")) | ||
.accountSid(vals.get("AccountSid")) | ||
.from(vals.get("From")) | ||
.to(vals.get("To")) | ||
.body(vals.get("Body")) | ||
.numSegments(getInteger(vals, "NumSegments")) | ||
.numMedia(numMedia) | ||
.mediaContentTypes(getList(vals, "MediaContentType", numMedia)) | ||
.mediaUrls(getList(vals, "MediaUrl", numMedia)) | ||
.messagingServiceSid(vals.get("MessagingServiceSid")) | ||
.fromCity(vals.get("FromCity")) | ||
.fromState(vals.get("FromState")) | ||
.fromZip(vals.get("FromZip")) | ||
.fromCountry(vals.get("FromCountry")) | ||
.toCity(vals.get("ToCity")) | ||
.toState(vals.get("ToState")) | ||
.toZip(vals.get("ToZip")) | ||
.toCountry(vals.get("ToCountry")) | ||
.build(); | ||
} | ||
|
||
@Override | ||
protected void writeInternal(TwilioSmsDto twilioSmsDto, HttpOutputMessage httpOutputMessage) | ||
throws HttpMessageNotWritableException { | ||
// TwilioSmsDto is currently only for incoming requests. | ||
} | ||
|
||
private Integer getInteger(Map<String, String> vals, String key) { | ||
try { | ||
return Integer.parseInt(vals.get(key)); | ||
} catch (NumberFormatException e) { | ||
return null; | ||
} | ||
} | ||
|
||
private List<String> getList(Map<String, String> vals, String key, Integer size) { | ||
if (size == null) { | ||
return Collections.emptyList(); | ||
} | ||
List<String> result = new ArrayList<>(size); | ||
for (int i = 0; i < size; i++) { | ||
result.add(vals.get(key + i)); | ||
} | ||
return result; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
20 changes: 20 additions & 0 deletions
20
src/main/java/ca/levimiller/smsbridge/service/AttachmentService.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
package ca.levimiller.smsbridge.service; | ||
|
||
import ca.levimiller.smsbridge.data.model.ChatUser; | ||
import ca.levimiller.smsbridge.data.model.Media; | ||
|
||
public interface AttachmentService { | ||
|
||
/** | ||
* Sends the given attachment. | ||
* @param attachment - attachment to send | ||
*/ | ||
void sendAttachment(ChatUser user, String roomId, Media attachment); | ||
|
||
/** | ||
* Returns true if the given content type is supported by the attachment service. | ||
* @param contentType - content type to check | ||
* @return - true if supported | ||
*/ | ||
boolean supportsType(String contentType); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
80 changes: 80 additions & 0 deletions
80
...ava/ca/levimiller/smsbridge/service/impl/matrix/attachment/AbstractAttachmentService.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
package ca.levimiller.smsbridge.service.impl.matrix.attachment; | ||
|
||
import ca.levimiller.smsbridge.data.model.ChatUser; | ||
import ca.levimiller.smsbridge.data.model.Media; | ||
import ca.levimiller.smsbridge.service.AttachmentService; | ||
import io.github.ma1uta.matrix.client.AppServiceClient; | ||
import io.github.ma1uta.matrix.event.content.EventContent; | ||
import java.io.IOException; | ||
import java.io.InputStream; | ||
import java.net.URISyntaxException; | ||
import java.net.URL; | ||
import java.util.concurrent.CancellationException; | ||
import java.util.concurrent.CompletionException; | ||
import lombok.extern.slf4j.Slf4j; | ||
import org.apache.http.HttpResponse; | ||
import org.apache.http.client.methods.HttpGet; | ||
import org.apache.http.impl.client.CloseableHttpClient; | ||
import org.apache.http.impl.client.HttpClients; | ||
import org.apache.http.impl.client.LaxRedirectStrategy; | ||
|
||
@Slf4j | ||
public abstract class AbstractAttachmentService implements AttachmentService { | ||
protected final AppServiceClient matrixClient; | ||
|
||
public AbstractAttachmentService(AppServiceClient matrixClient) { | ||
this.matrixClient = matrixClient; | ||
} | ||
|
||
/** | ||
* Builds the event content from the attachment. | ||
* @param attachment - attachment to send | ||
* @return - event content for attachment | ||
*/ | ||
protected abstract EventContent getContent(ChatUser user, Media attachment); | ||
|
||
@Override | ||
public void sendAttachment(ChatUser user, String roomId, Media attachment) { | ||
matrixClient.userId(user.getOwnerId()).event() | ||
.sendEvent(roomId, "m.room.message", getContent(user, attachment)) | ||
.exceptionally(throwable -> { | ||
log.error( | ||
String.format("Error sending attachment to matrix (%s): ", getClass()), | ||
throwable); | ||
return null; | ||
}); | ||
} | ||
|
||
/** | ||
* Tries to upload the file at the given url to the matrix homeserver. | ||
* <p></p> | ||
* If an exception occurs during the upload, the original url is returned. | ||
* @param user - user uploading the file | ||
* @param media - file to upload | ||
* @return - new url from matrix | ||
*/ | ||
protected String uploadFileToMatrix(ChatUser user, Media media) { | ||
try { | ||
String fileName = media.getUrl().substring(media.getUrl().lastIndexOf("/") + 1); | ||
|
||
// Download file | ||
URL url = new URL(media.getUrl()); | ||
CloseableHttpClient httpclient = HttpClients.custom() | ||
.setRedirectStrategy(new LaxRedirectStrategy()) | ||
.build(); | ||
HttpGet get = new HttpGet(url.toURI()); | ||
HttpResponse response = httpclient.execute(get); | ||
InputStream source = response.getEntity().getContent(); | ||
|
||
return matrixClient.userId(user.getOwnerId()).content() | ||
.upload(source, fileName, media.getContentType()) | ||
.join(); | ||
} catch (IOException | URISyntaxException | CancellationException | CompletionException error) { | ||
log.error( | ||
String.format("Error uploading file to matrix homeserver (%s): ", getClass()), | ||
error); | ||
// Fallback to initial url, so matrix message is sent instead of just a twilio error. | ||
return media.getUrl(); | ||
} | ||
} | ||
} |
36 changes: 36 additions & 0 deletions
36
...n/java/ca/levimiller/smsbridge/service/impl/matrix/attachment/AudioAttachmentService.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
package ca.levimiller.smsbridge.service.impl.matrix.attachment; | ||
|
||
import ca.levimiller.smsbridge.data.model.ChatUser; | ||
import ca.levimiller.smsbridge.data.model.Media; | ||
import io.github.ma1uta.matrix.client.AppServiceClient; | ||
import io.github.ma1uta.matrix.event.content.EventContent; | ||
import io.github.ma1uta.matrix.event.message.Audio; | ||
import io.github.ma1uta.matrix.event.nested.AudioInfo; | ||
import javax.inject.Inject; | ||
import org.springframework.stereotype.Service; | ||
|
||
@Service | ||
public class AudioAttachmentService extends AbstractAttachmentService { | ||
|
||
@Inject | ||
public AudioAttachmentService(AppServiceClient matrixClient) { | ||
super(matrixClient); | ||
} | ||
|
||
@Override | ||
protected EventContent getContent(ChatUser user, Media attachment) { | ||
Audio audio = new Audio(); | ||
audio.setBody("audio attachment"); | ||
audio.setUrl(uploadFileToMatrix(user, attachment)); | ||
|
||
AudioInfo info = new AudioInfo(); | ||
info.setMimetype(attachment.getContentType()); | ||
audio.setInfo(info); | ||
return audio; | ||
} | ||
|
||
@Override | ||
public boolean supportsType(String contentType) { | ||
return contentType.startsWith("audio"); | ||
} | ||
} |
Oops, something went wrong.