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
2 changes: 1 addition & 1 deletion .githooks/pre-commit
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,5 @@ echo "Running Spotless..."
echo "Running Detekt..."
./gradlew -q detekt
echo "Running unit tests (JVM modules)..."
./gradlew -q :ports:test :runtime-actor:test :fakes:test
./gradlew -q :ports:test :core-domain:check :core-runtime:check :fakes:test
echo "OK"
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ jobs:
run: ./gradlew --no-daemon :adapters-android:lint :app-demo:lint

- name: Unit tests (JVM)
run: ./gradlew --no-daemon :ports:test :runtime-actor:test :fakes:test
run: ./gradlew --no-daemon :ports:test :core-domain:check :core-runtime:check :fakes:test

- name: Assemble app
run: ./gradlew --no-daemon :app-demo:assembleDebug
Expand Down
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,5 @@ build

local.properties
/.idea

.DS_Store
3 changes: 2 additions & 1 deletion app-demo/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,8 @@ android {

dependencies {
// SDK modules
implementation(project(":runtime-actor"))
implementation(project(":core-domain"))
implementation(project(":core-runtime"))
implementation(project(":ports"))
implementation(project(":fakes"))

Expand Down
61 changes: 54 additions & 7 deletions app-demo/src/main/java/com/hailie/demo/di/RuntimeModule.kt
Original file line number Diff line number Diff line change
@@ -1,17 +1,64 @@
package com.hailie.demo.di

import com.hailie.runtimeactor.BleSyncActor
import com.hailie.domain.DeviceId
import com.hailie.domain.model.initialSyncAggregate
import com.hailie.domain.policy.AdaptivePageSizingPolicy
import com.hailie.domain.policy.ExponentialRetryPolicy
import com.hailie.domain.policy.SimpleBreakerPolicy
import com.hailie.domain.saga.DefaultSaga
import com.hailie.domain.saga.Saga
import com.hailie.runtime.actor.SyncActor
import com.hailie.runtime.ports.BlePort
import com.hailie.runtime.ports.ClockPort
import com.hailie.runtime.ports.DeliveryPort
import com.hailie.runtime.ports.StateStorePort
import com.hailie.runtime.ports.TelemetryPort
import org.koin.dsl.module

val runtimeModule =
module {
// Policies (provide here, or reuse existing beans if you already have them)
single { AdaptivePageSizingPolicy(minPage = 20, maxPage = 200, growStep = 20, shrinkStep = 20) }
// connect
single { SimpleBreakerPolicy(failuresToOpen = 1, coolDownMs = 300) }
// read
single { SimpleBreakerPolicy() }
// deliver
single { SimpleBreakerPolicy() }
// ack
single { SimpleBreakerPolicy() }
single {
BleSyncActor(
// ble = get<BlePort>(),
// delivery = get<DeliveryPort>(),
// store = get<StateStorePort>(),
// telemetry = get<TelemetryPort>(),
// clock = get<ClockPort>(),
ExponentialRetryPolicy(
maxAttempts = 3,
minBackoffMs = 100,
maxBackoffMs = 1_000,
jitterRatio = 0.0,
)
}

// Saga
single<Saga> {
DefaultSaga(
retryPolicy = get(),
// if you need distinct instances per stage, name them
breakerForConnect = get(),
breakerForRead = get(),
breakerForDeliver = get(),
breakerForAck = get(),
pageSizingPolicy = get(),
)
}

// SyncActor factory – takes a DeviceId at creation time
factory { (deviceId: DeviceId) ->
SyncActor(
initialState = initialSyncAggregate(deviceId = deviceId, initialPageSize = 50),
saga = get<Saga>(),
clock = get<ClockPort>(),
ble = get<BlePort>(),
delivery = get<DeliveryPort>(),
store = get<StateStorePort>(),
telemetry = get<TelemetryPort>(),
)
}
}
4 changes: 2 additions & 2 deletions app-demo/src/main/java/com/hailie/demo/ui/DemoApp.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,13 @@ import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import com.hailie.runtimeactor.BleSyncActor
import com.hailie.runtime.actor.SyncActor
import org.koin.compose.koinInject

@Composable
fun demoApp() {
// This is the symbol that needs the Koin Compose dependency AND the correct import
val actor = koinInject<BleSyncActor>()
val actor = koinInject<SyncActor>()

MaterialTheme {
Surface {
Expand Down
2 changes: 1 addition & 1 deletion build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,6 @@ tasks.register("depsUpdate") {
dependsOn("dependencyUpdates")
}

configure(listOf(project(":core-domain"), project(":ports"), project(":runtime-actor"), project(":adapters-android"))) {
configure(listOf(project(":core-domain"), project(":ports"), project(":core-runtime"), project(":adapters-android"))) {
pluginManager.apply("org.jetbrains.kotlinx.binary-compatibility-validator")
}
108 changes: 108 additions & 0 deletions core-runtime/api/core-runtime.api
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
public abstract interface class com/hailie/runtime/actor/Message {
}

public final class com/hailie/runtime/actor/Message$DomainEvent : com/hailie/runtime/actor/Message {
public fun <init> (Lcom/hailie/domain/events/Event;)V
public final fun component1 ()Lcom/hailie/domain/events/Event;
public final fun copy (Lcom/hailie/domain/events/Event;)Lcom/hailie/runtime/actor/Message$DomainEvent;
public static synthetic fun copy$default (Lcom/hailie/runtime/actor/Message$DomainEvent;Lcom/hailie/domain/events/Event;ILjava/lang/Object;)Lcom/hailie/runtime/actor/Message$DomainEvent;
public fun equals (Ljava/lang/Object;)Z
public final fun getEvent ()Lcom/hailie/domain/events/Event;
public fun hashCode ()I
public fun toString ()Ljava/lang/String;
}

public final class com/hailie/runtime/actor/Message$Start : com/hailie/runtime/actor/Message {
public static final field INSTANCE Lcom/hailie/runtime/actor/Message$Start;
public fun equals (Ljava/lang/Object;)Z
public fun hashCode ()I
public fun toString ()Ljava/lang/String;
}

public final class com/hailie/runtime/actor/Message$Stop : com/hailie/runtime/actor/Message {
public static final field INSTANCE Lcom/hailie/runtime/actor/Message$Stop;
public fun equals (Ljava/lang/Object;)Z
public fun hashCode ()I
public fun toString ()Ljava/lang/String;
}

public final class com/hailie/runtime/actor/Message$TimerFired : com/hailie/runtime/actor/Message {
public static final field INSTANCE Lcom/hailie/runtime/actor/Message$TimerFired;
public fun equals (Ljava/lang/Object;)Z
public fun hashCode ()I
public fun toString ()Ljava/lang/String;
}

public final class com/hailie/runtime/actor/SyncActor {
public fun <init> (Lcom/hailie/domain/model/SyncAggregate;Lcom/hailie/domain/saga/Saga;Lcom/hailie/runtime/ports/ClockPort;Lcom/hailie/runtime/ports/BlePort;Lcom/hailie/runtime/ports/DeliveryPort;Lcom/hailie/runtime/ports/StateStorePort;Lcom/hailie/runtime/ports/TelemetryPort;)V
public final fun offer (Lcom/hailie/runtime/actor/Message;)V
public final fun start ()V
public final fun stop ()V
}

public abstract interface class com/hailie/runtime/ports/BlePort {
public abstract fun ack-y0BiGhE (Ljava/lang/String;J)Lcom/hailie/domain/events/Event;
public abstract fun bond-6Qdsz-o (Ljava/lang/String;)Lcom/hailie/domain/events/Event;
public abstract fun connect-6Qdsz-o (Ljava/lang/String;)Lcom/hailie/domain/events/Event;
public abstract fun disconnect-6Qdsz-o (Ljava/lang/String;)Lcom/hailie/domain/events/Event;
public abstract fun readCount-6Qdsz-o (Ljava/lang/String;)Lcom/hailie/domain/events/Event;
public abstract fun readPage-vSBjs1w (Ljava/lang/String;JI)Lcom/hailie/domain/events/Event;
}

public abstract interface class com/hailie/runtime/ports/ClockPort {
public abstract fun cancel (Lcom/hailie/runtime/ports/TimerToken;)V
public abstract fun now-l8VicOg ()J
public abstract fun schedule-1_AN8L0 (JLkotlin/jvm/functions/Function0;)Lcom/hailie/runtime/ports/TimerToken;
}

public abstract interface class com/hailie/runtime/ports/DeliveryPort {
public abstract fun deliver-T4xMTfM (Ljava/lang/String;Lcom/hailie/domain/EventRange;)Lcom/hailie/domain/events/Event;
}

public abstract interface class com/hailie/runtime/ports/StateStorePort {
public abstract fun read-6Qdsz-o (Ljava/lang/String;)Lcom/hailie/runtime/ports/SyncSnapshot;
public abstract fun write (Lcom/hailie/runtime/ports/SyncSnapshot;)V
}

public final class com/hailie/runtime/ports/SyncSnapshot {
public synthetic fun <init> (Ljava/lang/String;JILjava/lang/String;Lkotlin/jvm/internal/DefaultConstructorMarker;)V
public final fun component1-Q1XiGFY ()Ljava/lang/String;
public final fun component2-lXtqNcE ()J
public final fun component3-OV6LaTU ()I
public final fun component4-fZOzdw0 ()Ljava/lang/String;
public final fun copy-DYWvGkc (Ljava/lang/String;JILjava/lang/String;)Lcom/hailie/runtime/ports/SyncSnapshot;
public static synthetic fun copy-DYWvGkc$default (Lcom/hailie/runtime/ports/SyncSnapshot;Ljava/lang/String;JILjava/lang/String;ILjava/lang/Object;)Lcom/hailie/runtime/ports/SyncSnapshot;
public fun equals (Ljava/lang/Object;)Z
public final fun getDeviceId-Q1XiGFY ()Ljava/lang/String;
public final fun getLastAckedExclusive-lXtqNcE ()J
public final fun getPageSize-OV6LaTU ()I
public final fun getSagaCursor-fZOzdw0 ()Ljava/lang/String;
public fun hashCode ()I
public fun toString ()Ljava/lang/String;
}

public final class com/hailie/runtime/ports/TelemetryEvent {
public synthetic fun <init> (Ljava/lang/String;JLjava/lang/String;Ljava/util/Map;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
public synthetic fun <init> (Ljava/lang/String;JLjava/lang/String;Ljava/util/Map;Lkotlin/jvm/internal/DefaultConstructorMarker;)V
public final fun component1 ()Ljava/lang/String;
public final fun component2-l8VicOg ()J
public final fun component3 ()Ljava/lang/String;
public final fun component4 ()Ljava/util/Map;
public final fun copy-phg6an8 (Ljava/lang/String;JLjava/lang/String;Ljava/util/Map;)Lcom/hailie/runtime/ports/TelemetryEvent;
public static synthetic fun copy-phg6an8$default (Lcom/hailie/runtime/ports/TelemetryEvent;Ljava/lang/String;JLjava/lang/String;Ljava/util/Map;ILjava/lang/Object;)Lcom/hailie/runtime/ports/TelemetryEvent;
public fun equals (Ljava/lang/Object;)Z
public final fun getAt-l8VicOg ()J
public final fun getData ()Ljava/util/Map;
public final fun getDeviceId ()Ljava/lang/String;
public final fun getName ()Ljava/lang/String;
public fun hashCode ()I
public fun toString ()Ljava/lang/String;
}

public abstract interface class com/hailie/runtime/ports/TelemetryPort {
public abstract fun emit (Lcom/hailie/runtime/ports/TelemetryEvent;)V
}

public abstract interface class com/hailie/runtime/ports/TimerToken {
}

27 changes: 27 additions & 0 deletions core-runtime/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
plugins {
kotlin("multiplatform")
}

kotlin {
jvm() // JVM target so we can run tests now; iOS targets can be added later

sourceSets {
val commonMain by getting {
dependencies {
implementation(kotlin("stdlib"))
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3")
implementation(project(":core-domain"))
}
}
val commonTest by getting {
dependencies {
implementation(kotlin("test"))
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-test:1.7.3")
implementation("io.kotest:kotest-assertions-core:5.8.0")
implementation("io.kotest:kotest-property:5.8.0")
}
}
val jvmMain by getting
val jvmTest by getting
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.hailie.runtime.actor

import com.hailie.domain.events.Event

sealed interface Message {
data object Start : Message

data class DomainEvent(val event: Event) : Message

data object TimerFired : Message

data object Stop : Message
}
Loading