165 lines
6.8 KiB
Plaintext
165 lines
6.8 KiB
Plaintext
// 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) {} } |