Skip to content

Commit

Permalink
fixed many bugs, updated dependencies
Browse files Browse the repository at this point in the history
  • Loading branch information
benkuly committed Jul 8, 2020
1 parent 70fabe9 commit fb21fd9
Show file tree
Hide file tree
Showing 19 changed files with 646 additions and 385 deletions.
2 changes: 1 addition & 1 deletion buildSrc/src/main/kotlin/Versions.kt
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ object Versions {
const val springBoot = "2.3.1.RELEASE"
const val springDependencyManagement = "1.0.9.RELEASE"
const val springMockk = "2.0.1"
const val matrixSDK = "0.3.0.RELEASE"
const val matrixSDK = "0.3.1.RELEASE"
const val clikt = "2.7.1"
const val ant = "1.10.8"
const val libphonenumber = "8.12.5"
Expand Down
2 changes: 1 addition & 1 deletion examples/gammu/config/application.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ matrix:
provider:
gammu:
enabled: true
defaultRoomId: "!qbEsipeNUMCYjFYaUA:matrix-local"
defaultRoomId: "!tRraLABExGeUDmOWvF:matrix-local"
defaultRegion: DE
bot:
serverName: matrix-local
Expand Down
29 changes: 17 additions & 12 deletions examples/gammu/synapse/matrix-kotlin-sdk-it-synapse.log.config
Original file line number Diff line number Diff line change
@@ -1,28 +1,33 @@

version: 1

formatters:
precise:
format: '%(asctime)s - %(name)s - %(lineno)d - %(levelname)s - %(request)s - %(message)s'
precise:
format: '%(asctime)s - %(name)s - %(lineno)d - %(levelname)s - %(request)s - %(message)s'

filters:
context:
(): synapse.logging.context.LoggingContextFilter
request: ""
context:
(): synapse.util.logcontext.LoggingContextFilter
request: ""

handlers:
console:
class: logging.StreamHandler
formatter: precise
filters: [context]
console:
class: logging.StreamHandler
formatter: precise
filters: [context]

loggers:
synapse:
level: WARNING

synapse.storage.SQL:
# beware: increasing this to DEBUG will make synapse log sensitive
# information such as access tokens.
level: WARNING

rest_auth_provider:
level: INFO

root:
level: INFO
level: WARNING
handlers: [console]

disable_existing_loggers: false
Original file line number Diff line number Diff line change
Expand Up @@ -6,26 +6,24 @@ import com.github.ajalt.clikt.parameters.arguments.optional
import com.github.ajalt.clikt.parameters.options.*
import com.github.ajalt.clikt.parameters.types.enum
import com.google.i18n.phonenumbers.NumberParseException
import com.google.i18n.phonenumbers.NumberParseException.ErrorType.NOT_A_NUMBER
import com.google.i18n.phonenumbers.PhoneNumberUtil
import kotlinx.coroutines.runBlocking
import net.folivo.matrix.bridge.sms.SmsBridgeProperties
import net.folivo.matrix.bridge.sms.handler.SendSmsCommandHelper.RoomCreationMode
import net.folivo.matrix.bridge.sms.handler.SendSmsCommandHelper.RoomCreationMode.AUTO
import net.folivo.matrix.bridge.sms.provider.PhoneNumberService
import org.slf4j.LoggerFactory

class SendSmsCommand(
private val sender: String,
private val helper: SendSmsCommandHelper,
private val phoneNumberService: PhoneNumberService,
private val smsBridgeProperties: SmsBridgeProperties
) : CliktCommand(name = "send") {

companion object {
private val LOG = LoggerFactory.getLogger(this::class.java)
}

private val phoneNumberUtil = PhoneNumberUtil.getInstance()

private val body by argument().optional()

private val telephoneNumbers by option("-t", "--telephoneNumber").multiple(required = true).unique()
Expand All @@ -35,16 +33,7 @@ class SendSmsCommand(

override fun run() {
try {
val receiverNumbers = telephoneNumbers.map { rawNumber ->
phoneNumberUtil.parse(rawNumber, smsBridgeProperties.defaultRegion)
.let {
if (!phoneNumberUtil.isValidNumber(it)) throw NumberParseException(
NOT_A_NUMBER,
"not a valid number"
)
"+${it.countryCode}${it.nationalNumber}"
}
}
val receiverNumbers = telephoneNumbers.map { phoneNumberService.parseToInternationalNumber(it) }
if (useGroup) {
LOG.debug("use group and send message")
echo(runBlocking {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,8 @@ class SendSmsCommandHelper(
): String {
val receiverIds = receiverNumbers.map { "@sms_${it.removePrefix("+")}:${botProperties.serverName}" }
val membersWithoutBot = setOf(sender, *receiverIds.toTypedArray())
val members = setOf(*membersWithoutBot.toTypedArray())

val rooms = roomService.getRoomsWithUsers(members)
val rooms = roomService.getRoomsWithUsers(membersWithoutBot)
.take(2)
.toList()

Expand All @@ -69,31 +68,42 @@ class SendSmsCommandHelper(
smsBridgeProperties.templates.botSmsSendCreatedRoomAndSendMessage
} else if (rooms.size == 1) {
LOG.debug("only send message")
val room = roomService.getRoom(rooms[0].roomId)
val room = roomService.getOrCreateRoom(rooms[0].roomId)
if (body.isNullOrBlank()) {
smsBridgeProperties.templates.botSmsSendNoMessage
} else {
val botIsMember = room.members.keys.find { it.userId == "@${botProperties.username}:${botProperties.serverName}" } != null
val expectedManagedMemberSize = if (botIsMember) receiverIds.size + 1 else receiverIds.size
val membersMatch = room.members.keys.count { it.isManaged } == expectedManagedMemberSize
if (membersMatch) {
if (!botIsMember) {
LOG.debug("try to invite sms bot user to room ${room.roomId}")
LOG.debug("send message to room ${room.roomId}")
if (botIsMember) {
matrixClient.roomsApi.sendRoomEvent(
roomId = rooms[0].roomId,
eventContent = TextMessageEventContent(
smsBridgeProperties.templates.botSmsSendNewRoomMessage
.replace("{sender}", sender)
.replace("{body}", body)
)
)
} else {
LOG.debug("try to invite sms bot user to room ${room.roomId} and send message later")
matrixClient.roomsApi.inviteUser(
roomId = room.roomId,
userId = "@${botProperties.username}:${botProperties.serverName}",
asUserId = receiverIds.first()
)
roomService.sendMessageLater(
RoomMessage(
roomId = room.roomId,
body = smsBridgeProperties.templates.botSmsSendNewRoomMessage
.replace("{sender}", sender)
.replace("{body}", body),
requiredReceiverIds = receiverIds.toSet()
)
)
}
LOG.debug("send message to room ${room.roomId}")
matrixClient.roomsApi.sendRoomEvent(
roomId = rooms[0].roomId,
eventContent = TextMessageEventContent(
smsBridgeProperties.templates.botSmsSendNewRoomMessage
.replace("{sender}", sender)
.replace("{body}", body)
)
)

smsBridgeProperties.templates.botSmsSendSendMessage
} else {
smsBridgeProperties.templates.botSmsSendDisabledRoomCreation
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ class SmsAppserviceMessageHandler(
LOG.debug("ignored message to default room")
return
} else {
val room = roomService.getRoom(roomId, sender)
val room = roomService.getOrCreateRoom(roomId)
val wasForBot = if (content is TextMessageEventContent && room.members.keys.find { it.userId == "@${botProperties.username}:${botProperties.serverName}" } != null) {
smsBotMessageHandler.handleMessageToSmsBot(
room = room,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
package net.folivo.matrix.bridge.sms.handler

import com.github.ajalt.clikt.core.*
import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import net.folivo.matrix.bot.handler.MessageContext
import net.folivo.matrix.bridge.sms.SmsBridgeProperties
import net.folivo.matrix.bridge.sms.provider.PhoneNumberService
import net.folivo.matrix.bridge.sms.room.AppserviceRoom
import net.folivo.matrix.core.model.events.m.room.message.NoticeMessageEventContent
import org.apache.tools.ant.types.Commandline
Expand All @@ -14,6 +15,7 @@ import org.springframework.stereotype.Component
@Component
class SmsBotMessageHandler(
private val helper: SendSmsCommandHelper,
private val phoneNumberService: PhoneNumberService,
private val smsBridgeProperties: SmsBridgeProperties
) {
companion object {
Expand All @@ -25,9 +27,9 @@ class SmsBotMessageHandler(
body: String,
sender: String,
context: MessageContext
): Boolean = coroutineScope {
if (room.members.keys.find { it.userId == sender && !it.isManaged } == null) {
LOG.debug("ignore message from not managed user")
): Boolean {
return if (room.members.keys.find { it.userId == sender }?.isManaged != false) {
LOG.debug("ignore message from managed (or unknown) user")
false
} else if (body.startsWith("sms")) {
if (room.members.size > 2) {
Expand All @@ -40,11 +42,11 @@ class SmsBotMessageHandler(
val args = Commandline.translateCommandline(body.removePrefix("sms"))

//TODO test
launch {
GlobalScope.launch {
val answerConsole = SmsBotConsole(context)
try {
SmsCommand().context { console = answerConsole }
.subcommands(SendSmsCommand(sender, helper, smsBridgeProperties))
.subcommands(SendSmsCommand(sender, helper, phoneNumberService, smsBridgeProperties))
.parse(args)
} catch (e: PrintHelpMessage) {
answerConsole.print(e.command.getFormattedHelp(), false)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package net.folivo.matrix.bridge.sms.provider

import com.google.i18n.phonenumbers.NumberParseException
import com.google.i18n.phonenumbers.NumberParseException.ErrorType.NOT_A_NUMBER
import com.google.i18n.phonenumbers.PhoneNumberUtil
import net.folivo.matrix.bridge.sms.SmsBridgeProperties
import org.springframework.stereotype.Service

@Service
class PhoneNumberService(private val smsBridgeProperties: SmsBridgeProperties) {

private val phoneNumberUtil = PhoneNumberUtil.getInstance()

fun parseToInternationalNumber(raw: String): String {
return phoneNumberUtil.parse(raw, smsBridgeProperties.defaultRegion)
.let {
if (!phoneNumberUtil.isValidNumber(it)) throw NumberParseException(
NOT_A_NUMBER,
"not a valid number"
)
"+${it.countryCode}${it.nationalNumber}"
}
}
}
Original file line number Diff line number Diff line change
@@ -1,14 +1,8 @@
package net.folivo.matrix.bridge.sms.provider.gammu

import com.google.i18n.phonenumbers.PhoneNumberUtil
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.asFlow
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.launch
import kotlinx.coroutines.reactive.awaitFirst
import net.folivo.matrix.bridge.sms.SmsBridgeProperties
import kotlinx.coroutines.reactor.mono
import net.folivo.matrix.bridge.sms.handler.ReceiveSmsService
import net.folivo.matrix.bridge.sms.provider.PhoneNumberService
import net.folivo.matrix.bridge.sms.provider.SmsProvider
import net.folivo.matrix.core.api.ErrorResponse
import net.folivo.matrix.core.api.MatrixServerException
Expand All @@ -21,11 +15,14 @@ import org.springframework.core.Ordered
import org.springframework.core.annotation.Order
import org.springframework.http.HttpStatus.INTERNAL_SERVER_ERROR
import org.springframework.stereotype.Component
import reactor.core.Disposable
import reactor.core.publisher.Flux
import reactor.core.publisher.Mono
import java.io.File
import java.nio.file.Files
import java.nio.file.Path
import java.nio.file.StandardCopyOption
import java.time.Duration
import java.util.concurrent.TimeUnit
import kotlin.text.Charsets.UTF_8

Expand All @@ -38,7 +35,7 @@ import kotlin.text.Charsets.UTF_8
class GammuSmsProvider(
private val properties: GammuSmsProviderProperties,
private val receiveSmsService: ReceiveSmsService,
private val smsBridgeProperties: SmsBridgeProperties
private val phoneNumberService: PhoneNumberService
) : SmsProvider {

companion object {
Expand All @@ -49,38 +46,38 @@ class GammuSmsProvider(
LOG.info("Using Gammu as SmsProvider.")
}

private val phoneNumberUtil = PhoneNumberUtil.getInstance()
private var disposable: Disposable? = null

@EventListener(ContextRefreshedEvent::class)
suspend fun startNewMessageLookupLoop() {
GlobalScope.launch {
while (true) {
try {
Path.of(properties.inboxPath).toFile().walkTopDown().asFlow()
.collect { file ->
val sender = file.name.substringBeforeLast('_').substringAfterLast('_')
val message = Flux.fromStream(Files.lines(file.toPath(), UTF_8))
.skipUntil { it.startsWith("[SMSBackup000]") }
.filter { it.startsWith("; ") }
.map { it.removePrefix("; ") }
.collectList()
.map { it.joinToString(separator = "") }
.doOnSuccess {
Files.move(
file.toPath(),
Path.of(properties.inboxProcessedPath, file.name),
StandardCopyOption.REPLACE_EXISTING
)
}.awaitFirst()
receiveSms(sender, message)
fun startNewMessageLookupLoop() {
disposable = Mono.just(true) // TODO is there a less hacky way? Without that line, repeat does not work
.flatMapMany { Flux.fromStream(Files.list(Path.of(properties.inboxPath))) }
.map { it.toFile() }
.flatMap { file ->
val name = file.name
val sender = name.substringBeforeLast('_').substringAfterLast('_')
Flux.fromStream(Files.lines(file.toPath(), UTF_8))
.skipUntil { it.startsWith("[SMSBackup000]") }
.filter { it.startsWith("; ") }
.map { it.removePrefix("; ") }
.collectList()
.map { Pair(sender, it.joinToString(separator = "")) }
.doOnSuccess {
Files.move(
file.toPath(),
Path.of(properties.inboxProcessedPath, file.name),
StandardCopyOption.REPLACE_EXISTING
)
}
LOG.debug("read inbox")
} catch (error: Throwable) {
LOG.error("something unexpected happened while scanning directories for new sms", error)
}.flatMap { message ->
receiveSms(message.first, message.second)
}
delay(10000)
}
}
.doOnComplete { LOG.debug("read inbox") }
.doOnError { LOG.error("something happened while scanning directories for new sms", it) }
.delaySubscription(Duration.ofSeconds(10))
.repeat()
.retry()
.subscribe()
}

override suspend fun sendSms(receiver: String, body: String) {
Expand Down Expand Up @@ -127,15 +124,14 @@ class GammuSmsProvider(

}

//FIXME test
suspend fun receiveSms(
fun receiveSms(
sender: String,
body: String
) {
val phoneNumber = phoneNumberUtil.parse(sender, smsBridgeProperties.defaultRegion).let {
"+${it.countryCode}${it.nationalNumber}"
}
receiveSmsService.receiveSms(body = body, sender = phoneNumber)
?.also { sendSms(receiver = phoneNumber, body = it) }
): Mono<Void> {
return mono {
val phoneNumber = phoneNumberService.parseToInternationalNumber(sender)
receiveSmsService.receiveSms(body = body, sender = phoneNumber)
?.also { sendSms(receiver = phoneNumber, body = it) }
}.then()
}
}
Loading

0 comments on commit fb21fd9

Please sign in to comment.