Skip to content

Commit 981f6e2

Browse files
committed
[wip] migrate legacy integrations to node-based system
1 parent 25f3b31 commit 981f6e2

File tree

81 files changed

+902
-895
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

81 files changed

+902
-895
lines changed

api/src/main/kotlin/me/snoty/backend/database/mongo/BsonUtils.kt

+12
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import org.bson.codecs.DecoderContext
99
import org.bson.codecs.DocumentCodec
1010
import org.bson.codecs.EncoderContext
1111
import org.bson.codecs.configuration.CodecRegistry
12+
import kotlin.reflect.KClass
1213

1314
// the joys of mongodb
1415
fun <T : Any> CodecRegistry.encode(value: T): Document {
@@ -22,3 +23,14 @@ fun <T : Any> CodecRegistry.encode(value: T): Document {
2223

2324
return documentCodec.decode(BsonDocumentReader(document), DecoderContext.builder().build())
2425
}
26+
27+
28+
// must be inlined to correctly create the context
29+
@Suppress("NOTHING_TO_INLINE")
30+
inline fun <T : Any> CodecRegistry.decode(clazz: KClass<T>, document: Document): T {
31+
return get(clazz.java)
32+
.decode(
33+
BsonDocumentReader(document.toBsonDocument()),
34+
DecoderContext.builder().build()
35+
)
36+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
package me.snoty.backend.errors
2+
3+
import io.ktor.http.*
4+
5+
open class ServiceResult(
6+
val httpCode: Int,
7+
val message: String,
8+
val details: String? = null
9+
) {
10+
constructor(httpCode: HttpStatusCode, message: String, details: String? = null) : this(httpCode.value, message, details)
11+
}

api/src/main/kotlin/me/snoty/backend/integration/config/ConfigId.kt

-23
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,23 @@
11
package me.snoty.backend.integration.config.flow
22

3+
import kotlinx.serialization.KSerializer
4+
import kotlinx.serialization.Serializable
5+
import kotlinx.serialization.descriptors.SerialDescriptor
6+
import kotlinx.serialization.descriptors.serialDescriptor
7+
import kotlinx.serialization.encoding.Decoder
8+
import kotlinx.serialization.encoding.Encoder
39
import org.bson.types.ObjectId
410

5-
typealias NodeId = ObjectId
11+
typealias NodeId = @Serializable(NodeIdSerializer::class) ObjectId
12+
13+
object NodeIdSerializer : KSerializer<NodeId> {
14+
override val descriptor: SerialDescriptor = serialDescriptor<String>()
15+
16+
override fun deserialize(decoder: Decoder): NodeId {
17+
return NodeId(decoder.decodeString())
18+
}
19+
20+
override fun serialize(encoder: Encoder, value: NodeId) {
21+
encoder.encodeString(value.toString())
22+
}
23+
}
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,17 @@
11
package me.snoty.backend.utils
22

3+
import kotlinx.coroutines.flow.Flow
4+
import kotlinx.coroutines.flow.transform
5+
36
fun <T, C : Collection<T>> C.orNull() = ifEmpty { null }
7+
8+
inline fun <T> T.contextual(block: T.() -> Unit) {
9+
block()
10+
}
11+
12+
fun <T, R> Flow<T>.listAsElements(block: suspend (T) -> Collection<R>): Flow<R> = this.transform { item ->
13+
val result = block(item)
14+
result.forEach {
15+
emit(it)
16+
}
17+
}

build.gradle.kts

+1
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ allprojects {
3232
kotlin {
3333
compilerOptions {
3434
freeCompilerArgs.add("-Xcontext-receivers")
35+
optIn.add("kotlinx.coroutines.ExperimentalCoroutinesApi")
3536
}
3637
}
3738
}

integrations/api/src/main/kotlin/me/snoty/integration/common/AbstractIntegration.kt

-74
This file was deleted.

integrations/api/src/main/kotlin/me/snoty/integration/common/IntegrationConfig.kt

-5
This file was deleted.

integrations/api/src/main/kotlin/me/snoty/integration/common/IntegrationDescriptor.kt

-5
This file was deleted.

integrations/api/src/main/kotlin/me/snoty/integration/common/IntegrationSettings.kt

-20
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,17 @@
11
package me.snoty.integration.common
22

33
import me.snoty.backend.scheduling.Scheduler
4-
import me.snoty.integration.common.config.IntegrationConfigService
4+
import me.snoty.integration.common.config.NodeService
55
import me.snoty.integration.common.diff.EntityStateService
6+
import me.snoty.integration.common.wiring.flow.FlowService
67
import me.snoty.integration.common.utils.calendar.CalendarService
8+
import org.bson.codecs.configuration.CodecRegistry
79

8-
data class IntegrationContext(
10+
data class NodeContext(
911
val entityStateService: EntityStateService,
10-
val integrationConfigService: IntegrationConfigService,
12+
val nodeService: NodeService,
13+
val flowService: FlowService,
14+
val codecRegistry: CodecRegistry,
1115
val calendarService: CalendarService,
1216
val scheduler: Scheduler
1317
)

integrations/api/src/main/kotlin/me/snoty/integration/common/config/IntegrationConfigService.kt

-22
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
package me.snoty.integration.common.config
2+
3+
import io.ktor.http.*
4+
import kotlinx.coroutines.flow.Flow
5+
import me.snoty.backend.errors.ServiceResult
6+
import me.snoty.backend.integration.config.flow.NodeId
7+
import me.snoty.integration.common.wiring.IFlowNode
8+
import me.snoty.integration.common.wiring.node.NodeDescriptor
9+
import me.snoty.integration.common.wiring.node.NodePosition
10+
import me.snoty.integration.common.wiring.node.NodeSettings
11+
import java.util.*
12+
13+
interface NodeService {
14+
fun getByUser(userID: UUID, position: NodePosition?): Flow<IFlowNode>
15+
16+
fun getAll(integrationType: String): Flow<IFlowNode>
17+
18+
suspend fun get(id: NodeId): IFlowNode?
19+
20+
/**
21+
* @return ID of the newly created entry
22+
*/
23+
suspend fun <S : NodeSettings> create(userID: UUID, descriptor: NodeDescriptor, settings: S): NodeId
24+
25+
/**
26+
* Connects two nodes together
27+
*/
28+
suspend fun connect(from: NodeId, to: NodeId): ServiceResult
29+
}
30+
31+
object NodeServiceResults {
32+
class NodeNotFoundError(val id: NodeId) : ServiceResult(HttpStatusCode.NotFound, "Node with ID $id not found")
33+
class NodeConnected(from: NodeId, to: NodeId) : ServiceResult(HttpStatusCode.OK, "Connected $from to $to")
34+
}
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,13 @@
11
package me.snoty.integration.common.diff
22

33
import kotlinx.coroutines.flow.Flow
4-
import me.snoty.integration.common.InstanceId
54
import me.snoty.integration.common.diff.state.EntityState
6-
import java.util.UUID
5+
import me.snoty.integration.common.wiring.IFlowNode
76

87
interface EntityStateService {
98
fun scheduleMetricsTask()
109

11-
suspend fun updateStates(userID: UUID, instanceId: InstanceId, entities: List<IUpdatableEntity<out Any>>)
10+
suspend fun updateStates(node: IFlowNode, entities: List<IUpdatableEntity<out Any>>)
1211

13-
fun getEntities(userID: UUID, instanceId: InstanceId, type: String): Flow<EntityState>
12+
fun getStates(node: IFlowNode): Flow<EntityState>
1413
}

integrations/api/src/main/kotlin/me/snoty/integration/common/diff/UserEntityChanges.kt

+2-4
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,14 @@ package me.snoty.integration.common.diff
33
import com.mongodb.kotlin.client.coroutine.MongoCollection
44
import kotlinx.datetime.Clock
55
import kotlinx.datetime.Instant
6-
import me.snoty.integration.common.InstanceId
6+
import me.snoty.backend.integration.config.flow.NodeId
77
import org.bson.codecs.pojo.annotations.BsonId
88
import org.bson.types.ObjectId
9-
import java.util.*
109

1110
data class EntityDescriptor(
12-
val instanceId: InstanceId,
11+
val nodeId: NodeId,
1312
val entityType: String,
1413
val entityId: String,
15-
val userId: UUID
1614
)
1715

1816
data class UserEntityChanges(
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
11
package me.snoty.integration.common.diff.state
22

33
import com.mongodb.kotlin.client.coroutine.MongoCollection
4-
import me.snoty.integration.common.InstanceId
4+
import me.snoty.backend.integration.config.flow.NodeId
55
import me.snoty.integration.common.diff.Fields
66
import org.bson.codecs.pojo.annotations.BsonId
7-
import java.util.*
87

98
data class EntityState(
109
val id: String,
@@ -13,10 +12,10 @@ data class EntityState(
1312
val checksum: Long
1413
)
1514

16-
data class UserEntityStates(
15+
data class NodeEntityStates(
1716
@BsonId
18-
val userId: UUID,
19-
val entities: Map<InstanceId, Set<EntityState>>
17+
val nodeId: NodeId,
18+
val entities: Set<EntityState>
2019
)
2120

22-
typealias EntityStateCollection = MongoCollection<UserEntityStates>
21+
typealias EntityStateCollection = MongoCollection<NodeEntityStates>
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,22 @@
11
package me.snoty.integration.common.diff.state
22

33
import com.mongodb.client.model.Filters
4-
import com.mongodb.client.model.Updates
5-
import me.snoty.integration.common.InstanceId
4+
import me.snoty.backend.integration.config.flow.NodeId
65
import me.snoty.integration.common.diff.IUpdatableEntity
6+
import me.snoty.integration.common.wiring.IFlowNode
77
import java.util.*
88

9-
suspend fun EntityStateCollection.updateStates(userId: UUID, instanceId: InstanceId, entities: List<IUpdatableEntity<out Any>>) {
9+
suspend fun EntityStateCollection.updateStates(node: IFlowNode, entities: List<IUpdatableEntity<out Any>>) {
1010
val mapped = entities.mapTo(HashSet()) {
1111
EntityState(it.id.toString(), it.type, it.fields, it.checksum)
1212
}
13-
updateStates(userId, instanceId, mapped)
13+
updateStates(node._id, mapped)
1414
}
1515

16-
suspend fun EntityStateCollection.updateStates(userId: UUID, instanceId: InstanceId, entities: Set<EntityState>) {
17-
val update = Updates.set("${UserEntityStates::entities.name}.$instanceId", entities)
18-
val result = updateOne(Filters.eq("_id", userId), update)
16+
suspend fun EntityStateCollection.updateStates(nodeId: NodeId, entities: Set<EntityState>) {
17+
val states = NodeEntityStates(nodeId, entities)
18+
val result = replaceOne(Filters.eq(nodeId), states)
1919
if (result.matchedCount == 0L) {
20-
insertOne(UserEntityStates(userId, mapOf(instanceId to entities)))
20+
insertOne(states)
2121
}
2222
}

0 commit comments

Comments
 (0)