Skip to content

Commit

Permalink
Merge pull request #48 from capcom6/feature/private-mode
Browse files Browse the repository at this point in the history
Private mode support
  • Loading branch information
capcom6 authored Mar 20, 2024
2 parents b202dd4 + a67b794 commit e3206cb
Show file tree
Hide file tree
Showing 17 changed files with 159 additions and 80 deletions.
9 changes: 4 additions & 5 deletions app/src/main/java/me/capcom/smsgateway/App.kt
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ class App: Application() {
notificationsModule,
messagesModule,
encryptionModule,
me.capcom.smsgateway.modules.gateway.gatewayModule,
)
}

Expand All @@ -36,12 +37,10 @@ class App: Application() {
EventsReceiver.register(this)
}

val gatewayModule by lazy {
GatewayModule(
get(),
get(),
)
val gatewayModule: GatewayModule by lazy {
get()
}

val localServerModule by lazy {
LocalServerModule(
get(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,21 @@ import io.ktor.client.request.post
import io.ktor.client.request.setBody
import io.ktor.http.ContentType
import io.ktor.http.HttpHeaders
import io.ktor.http.Url
import io.ktor.http.contentType
import io.ktor.http.hostWithPort
import io.ktor.serialization.gson.gson
import me.capcom.smsgateway.BuildConfig
import me.capcom.smsgateway.domain.MessageState
import java.util.Date

class GatewayApi() {
class GatewayApi(
private val baseUrl: String,
private val privateToken: String?
) {
val hostname: String
get() = Url(baseUrl).hostWithPort

private val client = HttpClient(OkHttp) {
install(UserAgent) {
agent = "me.capcom.smsgateway/" + BuildConfig.VERSION_NAME
Expand All @@ -30,36 +38,39 @@ class GatewayApi() {
expectSuccess = true
}

suspend fun deviceRegister(request: DeviceRegisterRequest): DeviceRegisterResponse {
return client.post("$BASE_URL/device") {
suspend fun deviceRegister(
request: DeviceRegisterRequest
): DeviceRegisterResponse {
return client.post("$baseUrl/device") {
privateToken?.let { auth(it) }
contentType(ContentType.Application.Json)
setBody(request)
}.body()
}

suspend fun devicePatch(token: String, request: DevicePatchRequest) {
client.patch("$BASE_URL/device") {
client.patch("$baseUrl/device") {
auth(token)
contentType(ContentType.Application.Json)
setBody(request)
}
}

suspend fun getMessages(token: String): List<Message> {
return client.get("$BASE_URL/message") {
return client.get("$baseUrl/message") {
auth(token)
}.body()
}

suspend fun patchMessages(token: String, request: List<MessagePatchRequest>) {
client.patch("$BASE_URL/message") {
client.patch("$baseUrl/message") {
auth(token)
contentType(ContentType.Application.Json)
setBody(request)
}
}

fun HttpRequestBuilder.auth(token: String) {
private fun HttpRequestBuilder.auth(token: String) {
header(HttpHeaders.Authorization, "Bearer $token")
}

Expand Down Expand Up @@ -101,8 +112,4 @@ class GatewayApi() {
val state: MessageState,
val error: String?,
)

companion object {
private const val BASE_URL = "https://sms.capcom.me/api/mobile/v1"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ package me.capcom.smsgateway.modules.gateway

import android.content.Context
import android.os.Build
import io.ktor.client.plugins.ClientRequestException
import io.ktor.http.HttpStatusCode
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.SupervisorJob
Expand All @@ -23,7 +25,12 @@ class GatewayModule(
private val messagesService: MessagesService,
private val settings: GatewaySettings,
) {
private val api = GatewayApi()
private var _api: GatewayApi? = null
private val api
get() = _api ?: GatewayApi(
settings.privateUrl ?: GatewaySettings.PUBLIC_URL,
settings.privateToken
).also { _api = it }

val events = EventBus()
var enabled: Boolean
Expand All @@ -34,6 +41,11 @@ class GatewayModule(

fun start(context: Context) {
if (!enabled) return
this._api = GatewayApi(
settings.privateUrl ?: GatewaySettings.PUBLIC_URL,
settings.privateToken
)

PushService.register(context)
PullMessagesWorker.start(context)

Expand All @@ -58,6 +70,7 @@ class GatewayModule(
fun stop(context: Context) {
scope.cancel()
PullMessagesWorker.stop(context)
this._api = null
}

private suspend fun sendState(
Expand Down Expand Up @@ -85,46 +98,53 @@ class GatewayModule(
}
}

suspend fun registerFcmToken(token: String) {
suspend fun registerFcmToken(pushToken: String) {
if (!enabled) return

val settings = settings.registrationInfo
settings?.token?.let {
withContext(Dispatchers.IO) {
val accessToken = settings?.token

if (accessToken != null) {
// if there's an access token, try to update push token
try {
api.devicePatch(
it,
accessToken,
GatewayApi.DevicePatchRequest(
settings.id,
token
pushToken
)
)
}

events.emitEvent(
DeviceRegisteredEvent(
settings.login,
settings.password,
)
)
}
?: kotlin.run {
val response = withContext(Dispatchers.IO) {
api.deviceRegister(
GatewayApi.DeviceRegisterRequest(
"${Build.MANUFACTURER}/${Build.PRODUCT}",
token
)
)
}
this.settings.registrationInfo = response

events.emitEvent(
DeviceRegisteredEvent(
response.login,
response.password,
api.hostname,
settings.login,
settings.password,
)
)
return
} catch (e: ClientRequestException) {
// if token is invalid, try to register new one
if (e.response.status != HttpStatusCode.Unauthorized) {
throw e
}
}
}

val response = api.deviceRegister(
GatewayApi.DeviceRegisterRequest(
"${Build.MANUFACTURER}/${Build.PRODUCT}",
pushToken
)
)
this.settings.registrationInfo = response

events.emitEvent(
DeviceRegisteredEvent(
api.hostname,
response.login,
response.password,
)
)
}

internal suspend fun getNewMessages() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import me.capcom.smsgateway.modules.settings.get
class GatewaySettings(
private val storage: KeyValueStorage,
) {

var enabled: Boolean
get() = storage.get<Boolean>(ENABLED) ?: false
set(value) = storage.set(ENABLED, value)
Expand All @@ -15,8 +14,18 @@ class GatewaySettings(
get() = storage.get(REGISTRATION_INFO)
set(value) = storage.set(REGISTRATION_INFO, value)

val privateUrl: String?
get() = storage.get<String?>(CLOUD_URL)
val privateToken: String?
get() = storage.get<String>(PRIVATE_TOKEN)

companion object {
private const val REGISTRATION_INFO = "REGISTRATION_INFO"
private const val ENABLED = "ENABLED"

private const val CLOUD_URL = "cloud_url"
private const val PRIVATE_TOKEN = "private_token"

const val PUBLIC_URL = "https://sms.capcom.me/api/mobile/v1"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package me.capcom.smsgateway.modules.gateway.events
import me.capcom.smsgateway.modules.events.AppEvent

class DeviceRegisteredEvent(
val server: String,
val login: String,
val password: String,
): AppEvent(NAME) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ class MessagesSettings(

val secondsBetweenMessages: Int
get() = storage.get<Int>(SECONDS_BETWEEN_MESSAGES) ?: 0
// set(value) = storage.set(SECONDS_BETWEEN_MESSAGES, value)

companion object {
private const val SECONDS_BETWEEN_MESSAGES = "SECONDS_BETWEEN_MESSAGES"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,18 +39,22 @@ class PreferencesStorage(
serializer.deserialize(it, typeOfT)
}
} catch (th: ClassCastException) {
when (typeOfT) {
java.lang.Long::class.java -> preferences.getLong("${prefix}.${key}", 0) as T
java.lang.Integer::class.java -> preferences.getInt("${prefix}.${key}", 0) as T
java.lang.String::class.java -> preferences.getString("${prefix}.${key}", "") as T
java.lang.Boolean::class.java -> preferences.getBoolean(
"${prefix}.${key}",
false
) as T

java.lang.Float::class.java -> preferences.getFloat("${prefix}.${key}", 0.0f) as T
else -> throw RuntimeException("Unknown type for key $key")
}
getFallback<T>(typeOfT, key)
} catch (th: com.google.gson.JsonParseException) {
getFallback<T>(typeOfT, key)
}
}

private fun <T> getFallback(typeOfT: Type, key: String) = when (typeOfT) {
java.lang.Long::class.java -> preferences.getLong("${prefix}.${key}", 0) as T
Integer::class.java -> preferences.getInt("${prefix}.${key}", 0) as T
java.lang.String::class.java -> preferences.getString("${prefix}.${key}", "") as T
java.lang.Boolean::class.java -> preferences.getBoolean(
"${prefix}.${key}",
false
) as T

java.lang.Float::class.java -> preferences.getFloat("${prefix}.${key}", 0.0f) as T
else -> throw RuntimeException("Unknown type for key $key")
}
}
19 changes: 2 additions & 17 deletions app/src/main/java/me/capcom/smsgateway/services/PushService.kt
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,6 @@ import com.google.android.gms.tasks.OnCompleteListener
import com.google.firebase.messaging.FirebaseMessaging
import com.google.firebase.messaging.FirebaseMessagingService
import com.google.firebase.messaging.RemoteMessage
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.launch
import me.capcom.smsgateway.helpers.SettingsHelper
import me.capcom.smsgateway.modules.gateway.PullMessagesWorker
import me.capcom.smsgateway.modules.gateway.RegistrationWorker
Expand All @@ -19,25 +16,15 @@ class PushService : FirebaseMessagingService() {
override fun onNewToken(token: String) {
settingsHelper.fcmToken = token

scope.launch {
RegistrationWorker.start(this@PushService, token)
}
RegistrationWorker.start(this@PushService, token)
}

override fun onMessageReceived(message: RemoteMessage) {
Log.d(this.javaClass.name, message.data.toString())
PullMessagesWorker.start(this)
}

override fun onDestroy() {
job.cancel()
super.onDestroy()
}

companion object {
private val job = SupervisorJob()
private val scope = CoroutineScope(job)

fun register(context: Context): Unit {
FirebaseMessaging.getInstance().token.addOnCompleteListener(OnCompleteListener { task ->
if (!task.isSuccessful) {
Expand All @@ -49,9 +36,7 @@ class PushService : FirebaseMessagingService() {
val token = task.result

// Log and toast
scope.launch {
RegistrationWorker.start(context, token)
}
RegistrationWorker.start(context, token)
})
}
}
Expand Down
1 change: 1 addition & 0 deletions app/src/main/java/me/capcom/smsgateway/ui/HomeFragment.kt
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ class HomeFragment : Fragment() {
App.instance.gatewayModule.events.events.collect { event ->
val event = event as? DeviceRegisteredEvent ?: return@collect

binding.textRemoteAddress.text = getString(R.string.address_is, event.server)
binding.textRemoteAuth.movementMethod = LinkMovementMethod.getInstance()
binding.textRemoteAuth.text = makeCopyableLink(
Html
Expand Down
Loading

0 comments on commit e3206cb

Please sign in to comment.