Skip to content
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
14 changes: 14 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
root = true

# Apply to all files
[*]
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
max_line_length=120
indent_style = space
indent_size = 4

[*.md]
max_line_length = off
trim_trailing_whitespace = false
8 changes: 7 additions & 1 deletion app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -97,9 +97,11 @@ dependencies {
// Saved state module for ViewModel
implementation("androidx.lifecycle:lifecycle-viewmodel-savedstate:$lifecycleVersion")

// Compose Navigation
val composeNavigationVersion = "2.7.7"
implementation("androidx.navigation:navigation-compose:$composeNavigationVersion")
androidTestImplementation("androidx.navigation:navigation-testing:$composeNavigationVersion")
implementation("androidx.hilt:hilt-navigation-compose:1.2.0")

// Compose Tooling for Android Studio Preview
val composeToolingVersion = "1.6.8"
Expand All @@ -110,7 +112,11 @@ dependencies {
val hiltVersion = "2.51.1"
implementation("com.google.dagger:hilt-android:$hiltVersion")
ksp("com.google.dagger:hilt-android-compiler:$hiltVersion")
implementation("androidx.hilt:hilt-navigation-compose:1.2.0")
ksp("androidx.hilt:hilt-compiler:1.2.0")

// WorkManager
implementation("androidx.hilt:hilt-work:1.2.0")
implementation("androidx.work:work-runtime-ktx:2.9.0")

// Material Design
implementation("com.google.android.material:material:1.12.0")
Expand Down
9 changes: 8 additions & 1 deletion app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">

<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
<uses-permission android:name="android.permission.INTERNET" />
Expand Down Expand Up @@ -39,6 +40,12 @@
</intent-filter>
</service>

<provider
android:name="androidx.startup.InitializationProvider"
android:authorities="${applicationId}.androidx-startup"
android:exported="false"
tools:node="remove" />

<!-- Set custom default icon.
This is used when no icon is set for incoming notification messages.
See https://goo.gl/l4GJaQ -->
Expand Down
13 changes: 12 additions & 1 deletion app/src/main/java/to/bitkit/App.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,22 @@ import android.annotation.SuppressLint
import android.app.Activity
import android.app.Application
import android.os.Bundle
import androidx.hilt.work.HiltWorkerFactory
import androidx.work.Configuration
import dagger.hilt.android.HiltAndroidApp
import javax.inject.Inject
import kotlin.reflect.typeOf

@HiltAndroidApp
internal class App : Application() {
internal class App : Application(), Configuration.Provider {
@Inject
lateinit var workerFactory: HiltWorkerFactory

override val workManagerConfiguration
get() = Configuration.Builder()
.setWorkerFactory(workerFactory)
.build()

override fun onCreate() {
super.onCreate()
currentActivity = CurrentActivity().also { registerActivityLifecycleCallbacks(it) }
Expand Down
3 changes: 2 additions & 1 deletion app/src/main/java/to/bitkit/Constants.kt
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,5 @@ internal const val _FCM = "_FCM"
internal const val _LDK = "_LDK"
internal const val _BDK = "_BDK"

internal val NETWORK = Network.REGTEST
internal val BDK_NETWORK = Network.REGTEST
internal val LDK_NETWORK get() = org.ldk.enums.Network.LDKNetwork_Regtest
5 changes: 4 additions & 1 deletion app/src/main/java/to/bitkit/LauncherActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,15 @@ import to.bitkit.ldk.Ldk
import to.bitkit.ldk.init
import to.bitkit.ldk.ldkDir
import to.bitkit.ui.MainActivity
import to.bitkit.ui.initNotificationChannel
import to.bitkit.ui.logFcmToken
import java.io.File

class LauncherActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)

initNotificationChannel()
logFcmToken()
warmupNode(filesDir.absolutePath)
startActivity(Intent(this, MainActivity::class.java))
}
Expand Down
18 changes: 9 additions & 9 deletions app/src/main/java/to/bitkit/bdk/Bdk.kt
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import org.ldk.structs.Result_NoneAPIErrorZ
import org.ldk.structs.Result_ThirtyTwoBytesAPIErrorZ
import org.ldk.structs.UserConfig
import org.ldk.util.UInt128
import to.bitkit.NETWORK
import to.bitkit.BDK_NETWORK
import to.bitkit._BDK
import to.bitkit._LDK
import to.bitkit.bdk.Bdk.wallet
Expand All @@ -43,12 +43,12 @@ object Bdk {

private fun initWallet() {
val mnemonic = loadMnemonic()
val key = DescriptorSecretKey(NETWORK, Mnemonic.fromString(mnemonic), null)
val key = DescriptorSecretKey(BDK_NETWORK, Mnemonic.fromString(mnemonic), null)

wallet = Wallet(
Descriptor.newBip84(key, KeychainKind.INTERNAL, NETWORK),
Descriptor.newBip84(key, KeychainKind.EXTERNAL, NETWORK),
NETWORK,
Descriptor.newBip84(key, KeychainKind.INTERNAL, BDK_NETWORK),
Descriptor.newBip84(key, KeychainKind.EXTERNAL, BDK_NETWORK),
BDK_NETWORK,
DatabaseConfig.Memory,
)

Expand Down Expand Up @@ -86,7 +86,7 @@ object Bdk {
fun getLdkEntropy(): ByteArray {
val mnemonic = loadMnemonic()
val key = DescriptorSecretKey(
network = NETWORK,
network = BDK_NETWORK,
mnemonic = Mnemonic.fromString(mnemonic),
password = null,
)
Expand Down Expand Up @@ -141,9 +141,9 @@ object Bdk {
} catch (e: Throwable) {
// if mnemonic doesn't exist, generate one and save it
Log.d(_BDK, "No mnemonic backup, we'll create a new wallet")
val mnemonic = Mnemonic(WordCount.WORDS12)
mnemonicFile.writeText(mnemonic.asString())
mnemonic.asString()
val mnemonic = Mnemonic(WordCount.WORDS12).asString()
mnemonicFile.writeText(mnemonic)
mnemonic
}
}
}
Expand Down
1 change: 0 additions & 1 deletion app/src/main/java/to/bitkit/data/Syncer.kt
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,6 @@ class LdkSyncer @Inject constructor(
}

}

}

// Add confirmed Tx from filtered Transaction Ids
Expand Down
77 changes: 69 additions & 8 deletions app/src/main/java/to/bitkit/fcm/MessagingService.kt
Original file line number Diff line number Diff line change
@@ -1,10 +1,23 @@
package to.bitkit.fcm

import android.content.Context
import android.util.Log
import androidx.hilt.work.HiltWorker
import androidx.work.CoroutineWorker
import androidx.work.Data
import androidx.work.OneTimeWorkRequest
import androidx.work.WorkManager
import androidx.work.WorkerParameters
import com.google.firebase.messaging.FirebaseMessagingService
import com.google.firebase.messaging.RemoteMessage
import dagger.assisted.Assisted
import dagger.assisted.AssistedInject
import kotlinx.coroutines.delay
import to.bitkit._FCM
import to.bitkit.data.RestApi
import to.bitkit.data.Syncer
import to.bitkit.ui.payInvoice
import to.bitkit.warmupNode
import java.util.Date

internal class MessagingService : FirebaseMessagingService() {
Expand Down Expand Up @@ -33,7 +46,7 @@ internal class MessagingService : FirebaseMessagingService() {
Log.d(_FCM, "\n")

if (message.needsScheduling()) {
scheduleJob()
scheduleJob(message.data)
} else {
handleNow(message.data)
}
Expand All @@ -42,7 +55,7 @@ internal class MessagingService : FirebaseMessagingService() {
}

/**
* TODO Handle message within 10 seconds.
* Handle message within 10 seconds.
*/
private fun handleNow(data: Map<String, String>) {
val bolt11 = data["bolt11"].orEmpty()
Expand All @@ -54,19 +67,67 @@ internal class MessagingService : FirebaseMessagingService() {
}

/**
* TODO Schedule async work using WorkManager for long-running tasks (10 seconds or more)
* Schedule async work using WorkManager for tasks of 10+ seconds.
*/
private fun scheduleJob() {
TODO("Not yet implemented: scheduleJob")
private fun scheduleJob(messageData: Map<String, String>) {
val work = OneTimeWorkRequest.Builder(PayWorker::class.java)
.setInputData(
Data.Builder()
.putString("bolt11", messageData["bolt11"].orEmpty())
.build()
)
.build()
WorkManager.getInstance(this)
.beginWith(work)
.enqueue()
}

private fun RemoteMessage.needsScheduling(): Boolean {
// return notification == null && data.isNotEmpty()
return false
return notification == null &&
data.containsKey("bolt11")
}

override fun onNewToken(token: String) {
this.token = token
Log.d(_FCM, "onNewToken: $token")
}
}
}

@HiltWorker
class PayWorker @AssistedInject constructor(
@Assisted private val appContext: Context,
@Assisted private val workerParams: WorkerParameters,
private val syncer: Syncer,
private val restApi: RestApi,
) : CoroutineWorker(appContext, workerParams) {
override suspend fun doWork(): Result {
Log.d(_FCM, "Node waking up from notification…")
warmupNode(appContext.filesDir.absolutePath)
.let { Log.d(_FCM, "Node wakeup result: $it…") }

Log.d(_FCM, "Syncing BDK & LDK from notification…")
syncer.sync()

restApi.connectPeer()
.let { Log.d(_FCM, "Connect peer from notification result: $it") }

workerParams.inputData.getString("bolt11")?.let { bolt11 ->
delay(1500) // sleep on bg queue
val isSuccess = payInvoice(bolt11)
if (isSuccess) {
return Result.success()
} else {
return Result.failure(
Data.Builder()
.putString("reason:", "payment error")
.build()
)
}
}
return Result.failure(
Data.Builder()
.putString("reason:", "bolt11 field missing")
.build()
)
}
}
Loading