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) {} }
|