Skip to content
This repository has been archived by the owner on Oct 14, 2023. It is now read-only.

Start of a basic implementation #1

Merged
merged 27 commits into from
Dec 9, 2022
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
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
8 changes: 8 additions & 0 deletions src/androidMain/kotlin/com/liftric/persisted/queue/UUID.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package com.liftric.persisted.queue

import java.util.UUID
import kotlin.reflect.KClass

actual typealias UUID = UUID

actual fun KClass<UUID>.instance(): UUID = UUID.randomUUID()
7 changes: 7 additions & 0 deletions src/commonMain/kotlin/com/liftric/persisted/queue/Job.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.liftric.persisted.queue

abstract class Job {
val id: UUID = UUID::class.instance()
abstract val params: Map<String, Any>
abstract suspend fun body(context: Context<Job>)
}
32 changes: 32 additions & 0 deletions src/commonMain/kotlin/com/liftric/persisted/queue/JobDelegate.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package com.liftric.persisted.queue

interface Context<T: Job> {
val name: String
suspend fun done()
suspend fun fail(exception: Exception)
suspend fun cancel()
}

class Delegate<T: Job>(job: T): Context<T> {
override val name: String = job::class.simpleName!!

sealed class Event {
object DidEnd: Event()
object DidCancel: Event()
data class DidFail(val throwable: Throwable): Event()
}

var onEvent: ((Event) -> Unit)? = null

override suspend fun done() {
onEvent?.invoke(Event.DidEnd)
}

override suspend fun fail(exception: Exception) {
onEvent?.invoke(Event.DidFail(exception))
}

override suspend fun cancel() {
onEvent?.invoke(Event.DidCancel)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.liftric.persisted.queue

import kotlin.reflect.KClass

interface JobFactory {
fun <T: Job> create(type: KClass<T>, params: Map<String, Any>): Job
}
58 changes: 58 additions & 0 deletions src/commonMain/kotlin/com/liftric/persisted/queue/JobManager.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package com.liftric.persisted.queue

import kotlinx.coroutines.*

class JobManager(val factory: JobFactory) {
val queue = Queue()

suspend inline fun <reified T: Job> schedule(rules: List<JobRule>, params: Map<String, Any>) {
try {
val job = factory.create(T::class, params)

val operation = rules.fold(Operation(rules, job)) { operation, rule ->
rule.mapping(operation)
}

rules.forEach {
it.willSchedule(queue, operation)
}

queue.operations.add(operation)
} catch (e: Exception) {
println(e.message)
}
}

suspend inline fun next() {
val operation = queue.operations.removeFirst()

val event: Deferred<Delegate.Event> = withContext(Dispatchers.Default) {
val result = CompletableDeferred<Delegate.Event>()

val delegate = Delegate(operation.job)
delegate.onEvent = { event ->
result.complete(event)
}

operation.rules.forEach { it.willRun(queue, operation) }

operation.job.body(delegate)

result
}

when(event.await()) {
is Delegate.Event.DidEnd -> {
println("Delegate.Event.DidEnd")
}
is Delegate.Event.DidCancel -> {
println("Delegate.Event.DidCancel")
}
is Delegate.Event.DidFail -> {
println("Delegate.Event.DidFail")
}
}

operation.rules.forEach { it.willRemove(operation) }
}
}
9 changes: 9 additions & 0 deletions src/commonMain/kotlin/com/liftric/persisted/queue/JobRule.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package com.liftric.persisted.queue

abstract class JobRule {
open suspend fun mapping(operation: Operation): Operation { return operation }
@Throws(Exception::class)
open suspend fun willSchedule(queue: Queue, operation: Operation) {}
open suspend fun willRun(queue: Queue, operation: Operation) {}
open suspend fun willRemove(operation: Operation) {}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.liftric.persisted.queue

data class Operation(
val rules: List<JobRule>,
val job: Job,
var tag: String? = null
)
5 changes: 5 additions & 0 deletions src/commonMain/kotlin/com/liftric/persisted/queue/Queue.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package com.liftric.persisted.queue

class Queue {
val operations: MutableList<Operation> = mutableListOf()
}
7 changes: 7 additions & 0 deletions src/commonMain/kotlin/com/liftric/persisted/queue/UUID.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.liftric.persisted.queue

import kotlin.reflect.KClass

expect class UUID

expect fun KClass<UUID>.instance(): UUID
16 changes: 16 additions & 0 deletions src/commonMain/kotlin/com/liftric/persisted/queue/UniqueJob.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package com.liftric.persisted.queue

class UniqueRule(private val id: String): JobRule() {
override suspend fun mapping(operation: Operation): Operation {
return operation.apply { tag = id }
}

@Throws(Exception::class)
override suspend fun willSchedule(queue: Queue, operation: Operation) {
for (item in queue.operations) {
if (item.tag == id) {
throw Exception("Should be unique")
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package com.liftric.persisted.queue

import kotlinx.coroutines.runBlocking
import kotlin.test.Test
import kotlin.test.assertEquals

class JobManagerTests {
@Test
fun testSchedule() = runBlocking {
val jobManager = JobManager(TestFactory())
val id = UUID::class.instance().toString()

jobManager.schedule<TestJob>(
rules = listOf(UniqueRule(id)),
gaebel marked this conversation as resolved.
Show resolved Hide resolved
params = mapOf(
"testResultId" to id
)
)

jobManager.schedule<TestJob>(
rules = listOf(UniqueRule(id)),
params = mapOf(
"testResultId" to id
)
)

assertEquals(1, jobManager.queue.operations.count())

jobManager.next()

assertEquals(0, jobManager.queue.operations.count())
}
}
10 changes: 10 additions & 0 deletions src/commonTest/kotlin/com/liftric/persisted/queue/TestFactory.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.liftric.persisted.queue

import kotlin.reflect.KClass

class TestFactory: JobFactory {
override fun <T : Job> create(type: KClass<T>, params: Map<String, Any>): Job = when(type) {
TestJob::class -> TestJob(params)
else -> throw Exception("Unknown job!")
}
}
12 changes: 12 additions & 0 deletions src/commonTest/kotlin/com/liftric/persisted/queue/TestJob.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.liftric.persisted.queue

class TestJob(override val params: Map<String, Any>): Job() {
private val testResultId: String by params

override suspend fun body(context: Context<Job>) = try {
println(testResultId)
context.done()
} catch (e: Exception) {
context.cancel()
}
}
8 changes: 8 additions & 0 deletions src/iosMain/kotlin/com/liftric/persisted/queue/UUID.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package com.liftric.persisted.queue

import platform.Foundation.NSUUID
import kotlin.reflect.KClass

actual typealias UUID = NSUUID

actual fun KClass<UUID>.instance(): UUID = NSUUID()