Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
xian committed Jul 25, 2024
1 parent 75b1340 commit 39a36fb
Show file tree
Hide file tree
Showing 30 changed files with 417 additions and 321 deletions.
10 changes: 10 additions & 0 deletions rpc/src/commonMain/kotlin/baaahs/rpc/RpcClientId.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package baaahs.rpc

import kotlin.coroutines.CoroutineContext

public class RpcClientId(public val id: String) : CoroutineContext.Element {
override val key: CoroutineContext.Key<*>
get() = Key

public companion object Key : CoroutineContext.Key<RpcClientId>
}
8 changes: 7 additions & 1 deletion rpc/src/commonMain/kotlin/baaahs/rpc/RpcImpl.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package baaahs.rpc
import kotlinx.serialization.KSerializer
import kotlinx.serialization.json.Json
import kotlinx.serialization.modules.SerializersModule
import kotlin.coroutines.coroutineContext

public class CommandPort<C, R>(
public val name: String,
Expand Down Expand Up @@ -34,7 +35,12 @@ public interface RpcCommandChannel<C, R> {
public suspend fun send(command: C): R
}

public interface RpcClient : RpcEndpoint, RpcCommandRecipient
public interface RpcClient : RpcEndpoint, RpcCommandRecipient {
public companion object {
public suspend fun id(): String =
coroutineContext[RpcClientId]?.id ?: error("not in RPC call")
}
}

public interface RpcServer : RpcEndpoint

Expand Down
23 changes: 16 additions & 7 deletions src/commonMain/kotlin/baaahs/PubSub.kt
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import kotlinx.serialization.builtins.ListSerializer
import kotlinx.serialization.json.Json
import kotlinx.serialization.json.JsonElement
import kotlinx.serialization.modules.SerializersModule
import kotlin.coroutines.EmptyCoroutineContext
import kotlin.js.JsName
import kotlin.jvm.Synchronized
import kotlin.properties.ReadWriteProperty
Expand All @@ -33,7 +34,8 @@ abstract class PubSub {
val logger = Logger<PubSub>()
}

open class Origin(val id: String) {
open class Origin(val id: String, clientId: String?) {
val clientId = clientId?.let { RpcClientId(it) }
override fun toString(): String = "Origin($id)"
}

Expand Down Expand Up @@ -212,7 +214,9 @@ abstract class PubSub {
val name = commandPort.name
if (hasServerChannel(name)) error("Command channel $name already exists.")
putServerChannel(name,
ServerCommandChannel(commandPort) { command -> callback(command) })
ServerCommandChannel(commandPort) { command ->
callback(command)
})
}

class ServerCommandChannel<C, R>(
Expand All @@ -225,7 +229,7 @@ abstract class PubSub {
fromConnection: Connection,
handlerScope: CoroutineScope
) {
handlerScope.launch {
handlerScope.launch(fromConnection.clientId ?: EmptyCoroutineContext) {
try {
val command = commandPort.fromJson(commandJson)
val reply = callback.invoke(command)
Expand Down Expand Up @@ -271,7 +275,7 @@ abstract class PubSub {
private val topics: Topics,
private val commandChannels: CommandChannels,
private val handlerScope: CoroutineScope
) : Origin("connection $name"), Network.WebSocketListener {
) : Origin("connection $name", name), Network.WebSocketListener {
var isConnected: Boolean = false
var everConnected: Boolean = false

Expand Down Expand Up @@ -523,14 +527,19 @@ abstract class PubSub {
httpServer: Network.HttpServer,
private val handlerScope: CoroutineScope
) : Endpoint(), IServer, RpcEndpoint {
private val publisher = Origin("Server-side publisher")
private val publisher = Origin("Server-side publisher", null)
private val topics: Topics = Topics()
override val commandChannels: CommandChannels = CommandChannels()
private val connectionListeners: MutableList<(ConnectionFromClient) -> Unit> = mutableListOf()
private val connectionCountByHost = hashMapOf<String, Int>()

init {
httpServer.listenWebSocket("/sm/ws") { incomingConnection ->
val name = "server ${incomingConnection.toAddress} to ${incomingConnection.fromAddress}"
val fromAddress = incomingConnection.fromAddress.toString()
val number = connectionCountByHost[fromAddress] ?: 0
connectionCountByHost[fromAddress] = number + 1

val name = "${incomingConnection.fromAddress}${if (number > 0) "-$number" else ""}"
ConnectionFromClient(name, topics, commandChannels, handlerScope)
.also { connection -> connectionListeners.forEach { it.invoke(connection) } }
}
Expand Down Expand Up @@ -664,7 +673,7 @@ abstract class PubSub {

@JsName("subscribe")
fun <T> subscribe(topic: Topic<T>, onUpdateFn: (T) -> Unit): Channel<T> {
val subscriber = Origin("Client-side subscriber at ${link.myAddress}")
val subscriber = Origin("Client-side subscriber at ${link.myAddress}", link.myAddress.toString())

val topicName = topic.name

Expand Down
12 changes: 0 additions & 12 deletions src/commonMain/kotlin/baaahs/client/ClientStageManager.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package baaahs.client

import baaahs.*
import baaahs.gl.Toolchain
import baaahs.midi.MidiDevices
import baaahs.scene.OpenScene
import baaahs.scene.SceneProvider
import baaahs.show.Feed
Expand All @@ -22,7 +21,6 @@ class ClientStageManager(
toolchain: Toolchain,
private val pubSub: PubSub.Client,
sceneProvider: SceneProvider,
private val midiDevices: MidiDevices,
private val coroutineScope: CoroutineScope = GlobalScope
) : BaseShowPlayer(toolchain, SceneProviderWithFallback(sceneProvider)) {
private val gadgets: MutableMap<String, ClientGadget> = mutableMapOf()
Expand All @@ -34,16 +32,6 @@ class ClientStageManager(
private val showControlCommands = ShowControlCommands.IMPL
.createSender(pubSub)

init {
globalLaunch {
midiDevices.listTransmitters().forEach { midiTransmitter ->
midiTransmitter.listen { midiMessage ->
println("MIDI from ${midiTransmitter.id}: $midiMessage")
}
}
}
}

private fun checkForChanges() {
listeners.forEach { it.onPatchSetChanged() }
}
Expand Down
4 changes: 2 additions & 2 deletions src/commonMain/kotlin/baaahs/di/Modules.kt
Original file line number Diff line number Diff line change
Expand Up @@ -136,8 +136,8 @@ interface PinkyModule : KModule {
scoped { GadgetManager(get(), get(), get(Named.pinkyContext)) }
scoped<Toolchain> { RootToolchain(get()) }
scoped { PinkyConfigStore(get(), fs.resolve(".")) }
scoped { EventManager(get(), get(), get()) }
scoped { StageManager(get(), get(), get(), get(Named.dataDir), get(), get(), get(), get(), get(), get(), get()) }
scoped { EventManager(get(), get<PubSub.Server>(), get()) }
scoped { StageManager(get(), get(), get(), get(Named.dataDir), get(), get(), get(), get(), get(), get(), get(), get()) }
scoped { Pinky.NetworkStats() }
scoped { BrainManager(get(), get(), get(), get(), get(Named.pinkyContext)) }
scoped { SacnManager(get(), get(Named.pinkyContext), get(), get()) }
Expand Down
54 changes: 27 additions & 27 deletions src/commonMain/kotlin/baaahs/midi/MidiCommandPorts.kt
Original file line number Diff line number Diff line change
@@ -1,27 +1,27 @@
package baaahs.midi

import baaahs.PubSub
import baaahs.plugin.Plugins
import kotlinx.serialization.builtins.ListSerializer
import kotlinx.serialization.builtins.serializer

class MidiCommandPorts(plugins: Plugins) {
val listTransmittersCommandPort = PubSub.CommandPort(
"/midi/listTransmitters",
RemoteMidiDevices.ListTransmittersCommand.serializer(),
ListSerializer(RemoteMidiDevices.RemoteMidiDeviceInfo.serializer()),
plugins.serialModule
)
val listenToTransmitterCommandPort = PubSub.CommandPort(
"/midi/listenToTransmitter", RemoteMidiDevices.ListenToTransmitterCommand.serializer(), Unit.serializer(),
plugins.serialModule
)
val midiEventCommandPort = PubSub.CommandPort(
"/midi/event", RemoteMidiDevices.MidiEventCommand.serializer(), Unit.serializer(),
plugins.serialModule
)
val closeTransmitterCommandPort = PubSub.CommandPort(
"/midi/closeTransmitter", RemoteMidiDevices.CloseTransmitterCommand.serializer(), Unit.serializer(),
plugins.serialModule
)
}
//package baaahs.midi
//
//import baaahs.PubSub
//import baaahs.plugin.Plugins
//import kotlinx.serialization.builtins.ListSerializer
//import kotlinx.serialization.builtins.serializer
//
//class MidiCommandPorts(plugins: Plugins) {
// val listTransmittersCommandPort = PubSub.CommandPort(
// "/midi/listTransmitters",
// RemoteMidiDevices.ListTransmittersCommand.serializer(),
// ListSerializer(RemoteMidiDevices.RemoteMidiDeviceInfo.serializer()),
// plugins.serialModule
// )
// val listenToTransmitterCommandPort = PubSub.CommandPort(
// "/midi/listenToTransmitter", RemoteMidiDevices.ListenToTransmitterCommand.serializer(), Unit.serializer(),
// plugins.serialModule
// )
// val midiEventCommandPort = PubSub.CommandPort(
// "/midi/event", RemoteMidiDevices.MidiEventCommand.serializer(), Unit.serializer(),
// plugins.serialModule
// )
// val closeTransmitterCommandPort = PubSub.CommandPort(
// "/midi/closeTransmitter", RemoteMidiDevices.CloseTransmitterCommand.serializer(), Unit.serializer(),
// plugins.serialModule
// )
//}
20 changes: 18 additions & 2 deletions src/commonMain/kotlin/baaahs/midi/MidiDevices.kt
Original file line number Diff line number Diff line change
@@ -1,9 +1,25 @@
package baaahs.midi

import baaahs.rpc.Service

@Service
interface MidiDevices {
suspend fun listTransmitters(): List<MidiTransmitter>
suspend fun listTransmitters(): List<MidiPort>

companion object {
val IMPL by lazy { MidiDevices.getImpl("pinky/midiDevices") }
}
}

//class MidiManager(
// rpcEndpoint: RpcEndpoint
//) : MidiDevices {
// val midiDevicesService = MidiDevices.IMPL.createReceiver(rpcEndpoint, object : MidiDevices {
// override suspend fun listTransmitters(): List<MidiPort> {
// TODO("not implemented")
// }
// })
//}
class NullMidiDevices : MidiDevices {
override suspend fun listTransmitters(): List<MidiTransmitter> = emptyList()
override suspend fun listTransmitters(): List<MidiPort> = emptyList()
}
67 changes: 67 additions & 0 deletions src/commonMain/kotlin/baaahs/midi/MidiGateway.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
package baaahs.midi

import baaahs.rpc.Service
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch
import kotlinx.datetime.Instant
import kotlinx.serialization.Serializable

@Service
interface MidiGatewayApi {
suspend fun deviceOnline(midiDeviceId: Int, midiDevice: MidiDevice)
suspend fun receivedEvent(midiDeviceId: Int, midiEvent: MidiEvent)
suspend fun deviceOffline(midiDeviceId: Int)

companion object {
val IMPL by lazy { MidiGateway.getImpl("pinky/midiGateway") }
}
}

@Service
interface MidiGateway {
suspend fun receivedEvent(midiDevice: MidiDevice, midiEvent: MidiEvent)
suspend fun deviceOffline(midiDevice: MidiDevice)

companion object {
val IMPL by lazy { MidiGateway.getImpl("pinky/midiGateway") }
}
}

class MidiGatewayServer : MidiGateway {
override suspend fun receivedEvent(midiDevice: MidiDevice, midiEvent: MidiEvent) {
TODO("not implemented")
}

override suspend fun deviceOffline(midiDevice: MidiDevice) {
TODO("not implemented")
}
}

class MidiGatewayClient(
private val midiGateway: MidiGateway,
private val scope: CoroutineScope
) {
fun receivedEvent(midiDevice: MidiDevice, midiEvent: MidiEvent) {
scope.launch {
midiGateway.receivedEvent(midiDevice, midiEvent)
}
}
}

@Serializable
data class MidiDevice(
val id: String,
val name: String,
val vendor: String,
val description: String,
val version: String
)

@Serializable
data class MidiEvent(
val instant: Instant,
val channel: Int,
val command: Int,
val data1: Int,
val data2: Int
)
3 changes: 3 additions & 0 deletions src/commonMain/kotlin/baaahs/midi/MidiPort.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
package baaahs.midi

interface MidiPort
21 changes: 0 additions & 21 deletions src/commonMain/kotlin/baaahs/midi/MidiTransmitter.kt

This file was deleted.

Loading

0 comments on commit 39a36fb

Please sign in to comment.