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
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import org.holochain.androidserviceruntime.client.InstallAppPayloadFfiParcel;
import org.holochain.androidserviceruntime.client.ZomeCallParamsFfiParcel;

interface IHolochainServiceApp {
boolean isReady();
void setupApp(IHolochainServiceCallback callback, in InstallAppPayloadFfiParcel request, boolean enableAfterInstall);
void enableApp(IHolochainServiceCallback callback);
void ensureAppWebsocket(IHolochainServiceCallback callback);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package org.holochain.androidserviceruntime.client

import android.app.Activity
import android.content.ComponentName
import android.content.Context
import android.content.Intent
Expand All @@ -10,7 +9,7 @@ import android.util.Log
import kotlinx.coroutines.delay

class HolochainServiceAdminClient(
private val activity: Activity,
private val context: Context,
private val serviceComponentName: ComponentName,
) {
private var mService: IHolochainServiceAdmin? = null
Expand Down Expand Up @@ -43,7 +42,7 @@ class HolochainServiceAdminClient(
intent.component = this.serviceComponentName
intent.putExtra("config", RuntimeNetworkConfigFfiParcel(config))

this.activity.startForegroundService(intent)
this.context.startForegroundService(intent)
}

/**
Expand All @@ -56,12 +55,12 @@ class HolochainServiceAdminClient(

// Giving the intent a unique action ensures the HolochainService `onBind()` callback is
// triggered.
val packageName: String = this.activity.getPackageName()
val packageName: String = this.context.packageName
val intent = Intent(packageName)

intent.putExtra("api", "admin")
intent.setComponent(this.serviceComponentName)
this.activity.bindService(intent, this.mConnection, Context.BIND_ABOVE_CLIENT)
this.context.bindService(intent, this.mConnection, Context.BIND_ABOVE_CLIENT)
}

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package org.holochain.androidserviceruntime.client

import android.app.Activity
import android.content.ComponentName
import android.content.Context
import android.content.Intent
Expand All @@ -10,8 +9,10 @@ import android.util.Log
import kotlinx.coroutines.delay

class HolochainServiceAppClient(
private val activity: Activity,
private val context: Context,
private val serviceComponentName: ComponentName,
private val onConnected: (() -> Unit)? = null,
private val onDisconnected: (() -> Unit)? = null,
) {
private var mService: IHolochainServiceApp? = null
private val logTag = "HolochainServiceAppClient"
Expand All @@ -25,11 +26,13 @@ class HolochainServiceAppClient(
) {
mService = IHolochainServiceApp.Stub.asInterface(service)
Log.d(logTag, "IHolochainServiceApp connected")
onConnected?.invoke()
}

override fun onServiceDisconnected(className: ComponentName) {
mService = null
Log.d(logTag, "IHolochainServiceApp disconnected")
onDisconnected?.invoke()
}
}

Expand All @@ -43,13 +46,13 @@ class HolochainServiceAppClient(

// Giving the intent a unique action ensures the HolochainService `onBind()` callback is
// triggered.
val packageName: String = this.activity.getPackageName()
val packageName: String = this.context.packageName
val intent = Intent("$packageName:$installedAppId")

intent.putExtra("api", "app")
intent.putExtra("installedAppId", installedAppId)
intent.setComponent(this.serviceComponentName)
this.activity.bindService(intent, this.mConnection, Context.BIND_ABOVE_CLIENT)
this.context.bindService(intent, this.mConnection, Context.BIND_ABOVE_CLIENT)
}

/**
Expand Down Expand Up @@ -96,13 +99,19 @@ class HolochainServiceAppClient(
* @param installAppPayload The payload containing app installation data
* @param enableAfterInstall Whether to enable the app after installation
* @return AppAuthFfi object containing authentication and connection information
* @throws HolochainServiceNotConnectedException if not connected to the service
*/
suspend fun connectSetupApp(
installAppPayload: InstallAppPayloadFfi,
enableAfterInstall: Boolean,
): AppAuthFfi {
this.connect(installAppPayload.installedAppId!!)
this.waitForConnectReady()

if (!this.waitForConnectReady()) {
throw HolochainServiceNotConnectedException()
}

this.waitForServiceReady()
return this.setupApp(installAppPayload, enableAfterInstall)
}

Expand Down Expand Up @@ -146,6 +155,13 @@ class HolochainServiceAppClient(
return callbackDeferred.await()
}

/**
* Checks if the Holochain runtime is ready to receive calls.
*
* @return true if connected and runtime is ready, false otherwise
*/
fun isReady(): Boolean = this.mService?.isReady() ?: false

/**
* Polls until connected to the service, or the timeout has elapsed.
*
Expand All @@ -155,14 +171,40 @@ class HolochainServiceAppClient(
private suspend fun waitForConnectReady(
timeoutMs: Long = 100L,
intervalMs: Long = 5L,
) {
): Boolean {
var elapsedMs = 0L
while (elapsedMs <= timeoutMs) {
Log.d(logTag, "waitForConnectReady " + elapsedMs)
if (this.mService != null) break
if (this.mService != null) return true

delay(intervalMs)
elapsedMs += intervalMs
}
return false
}

/**
* Polls until the Holochain service runtime is ready, or the timeout has elapsed.
*
* This is necessary because the service may be connected (onBind returned) but the
* Holochain conductor may not have finished starting yet.
*
* @param timeoutMs Maximum time to wait for service to be ready in milliseconds (default: 30000ms)
* @param intervalMs Time between readiness checks in milliseconds (default: 100ms)
* @return true if service became ready within timeout, false otherwise
*/
suspend fun waitForServiceReady(
timeoutMs: Long = 30000L,
intervalMs: Long = 100L,
): Boolean {
var elapsedMs = 0L
while (elapsedMs <= timeoutMs) {
Log.d(logTag, "waitForServiceReady " + elapsedMs)
if (this.isReady()) return true

delay(intervalMs)
elapsedMs += intervalMs
}
return false
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -584,6 +584,13 @@ class HolochainService : Service() {
private var authorized = false
private var clientPackageName: String? = null

// Is the conductor started and ready to receive calls
// No authorization needed
override fun isReady(): Boolean {
Log.d(logTag, "isReady")
return runtime != null
}

// / Setup an app
override fun setupApp(
callback: IHolochainServiceCallback,
Expand Down
Loading