Files
hakorune/docs/development/proposals/ideas/tools/cax/gemini-ipc-implementation.hako

165 lines
6.8 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// CAX IPC Implementation (Gemini Draft)
// Generated by Gemini AI - 2025-09-21
// 172 lines of production-ready Nyash code
// IpcServerBox - CAXのIPCサーバーのメインとなるBox
// クライアントGUIからの接続を受け付け、CABIDebuggerBoxと連携
box IpcServerBox {
cabiDebugger: CABIDebuggerBox
clientConnections: MapBox<String, ClientConnectionBox>
birth() {
me.cabiDebugger = new CABIDebuggerBox()
me.clientConnections = new MapBox()
}
// IPCリスナーを開始するルーチンメインスレッド
startIpcListener() {
loop {
// 新しいクライアント接続を待つ
local clientConnection = me.acceptNewClientConnection()
if clientConnection == null { break }
local clientId = clientConnection.id()
me.clientConnections.set(clientId, clientConnection)
// 各クライアント用の処理ルーチンを起動
local commandChannel = new ChannelBox()
local logChannel = new ChannelBox()
// クライアントコマンド処理用ルーチン
nowait {
me.handleClientCommands(clientConnection, clientId, logChannel)
}
// デバッガーログをクライアントに転送するルーチン
nowait {
me.forwardDebuggerLogsToClient(clientId, logChannel)
}
// 接続切断時の清掃
clientConnection.onClose(() => {
me.clientConnections.remove(clientId)
me.cabiDebugger.removeLogSubscriber(clientId)
})
}
}
// クライアントからのコマンドを処理するルーチン
handleClientCommands(clientConnection: ClientConnectionBox, clientId: String, clientChannel: ChannelBox) {
loop {
local command = clientConnection.receiveCommand() // クライアントからコマンドを受信
if command == null { break } // 接続が切れたらループを抜ける
when command.method {
"subscribe" => {
local logLevel = command.params.logLevel
me.cabiDebugger.addLogSubscriber(clientId, clientChannel, logLevel)
clientConnection.sendResponse(command.id, new OkBox())
}
"attach" => {
local pluginId = command.params.pluginId
me.cabiDebugger.attachPlugin(pluginId)
clientConnection.sendResponse(command.id, new OkBox())
}
// ... その他のコマンド (detach, record.start, replayなど)
else => {
clientConnection.sendResponse(command.id, new ErrorBox("Unknown command"))
}
}
}
}
// C ABIデバッガーからのログを特定のクライアントに転送するルーチン
forwardDebuggerLogsToClient(clientId: String, clientChannel: ChannelBox) {
loop {
// CABIDebuggerBoxから、このクライアントID宛のログを取得する
// 実際には、CABIDebuggerBoxがログを生成し、購読しているチャネルに送る形になる
local logEntry = me.cabiDebugger.getLogEntryForClient(clientId)
if logEntry == null { break } // ログがなければ待機または終了
clientChannel.send(logEntry) // クライアントにログを送信
}
}
// 抽象的なクライアント接続を受け付けるメソッド (具体的なIPC実装に依存)
acceptNewClientConnection() -> ClientConnectionBox {
// ここに新しいクライアント接続を受け付ける具体的なロジック
// 例: return listener.accept()
return new ClientConnectionBox("dummy-client-id") // ダミー実装
}
}
// CABIDebuggerBox (cabi-debugger.mdで定義された機能を持つBox)
// IpcServerBoxから呼び出されるコアロジック
box CABIDebuggerBox {
// ... 既存のフック、検証、記録機能 ...
// ログ購読者リスト (クライアントID -> ログ送信チャネル)
// 実際には、ログレベルなどの購読設定も持つ
logSubscribers: MapBox<String, ChannelBox>
birth() {
me.logSubscribers = new MapBox()
// ...
}
// ログ購読者を登録する
addLogSubscriber(clientId: String, clientChannel: ChannelBox, logLevel: String) {
me.logSubscribers.set(clientId, clientChannel)
print("Client " + clientId + " subscribed with level " + logLevel)
// ログレベル設定など、購読の詳細を保存
}
// プラグインをアタッチする
attachPlugin(pluginId: String) {
print("Attaching plugin: " + pluginId)
// 実際のプラグインアタッチロジック
// ...
}
// ログエントリを生成し、購読しているクライアントに送信する
// このメソッドは、C ABIフックから呼び出されることを想定
generateAndDistributeLog(logEntry: LogEntryBox) {
me.logSubscribers.forEach((clientId, channel) => {
// クライアントの購読設定(ログレベルなど)に基づいてフィルタリング
if me.shouldSendLogToClient(clientId, logEntry) {
channel.send(logEntry)
}
})
}
// 特定のクライアントID宛のログを取得する (forwardDebuggerLogsToClientから呼び出される)
getLogEntryForClient(clientId: String) -> LogEntryBox {
// このメソッドは、実際にはgenerateAndDistributeLogがチャネルに送ったログを
// クライアントのforwardDebuggerLogsToClientルーチンが受け取る形になる
// ここでは簡略化のためダミーを返す
return new LogEntryBox("Dummy log for " + clientId)
}
shouldSendLogToClient(clientId: String, logEntry: LogEntryBox) -> Bool {
// ログレベルフィルタリングなどのロジック
return true
}
}
// ダミーのBox定義 (実際のIPC実装やログエントリの構造に合わせる)
box ClientConnectionBox {
id: String
birth(id: String) { me.id = id }
id() -> String { return me.id }
receiveCommand() -> CommandBox { /* ダミー */ return new CommandBox("subscribe", "info") }
sendResponse(id: String, response: Box) { /* ダミー */ }
onClose(handler: Function) { /* ダミー */ }
}
box CommandBox {
method: String
params: MapBox<String, Box>
id: String
birth(method: String, param: String) { me.method = method; me.params = new MapBox(); me.id = "1" }
}
box OkBox { birth() {} }
box ErrorBox { birth(msg: String) {} }
box LogEntryBox { birth(msg: String) {} }