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

Private mode support #48

Merged
merged 4 commits into from
Mar 20, 2024
Merged
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
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
Loading