selfhost(pyvm): MiniVmPrints – prefer JSON route early-return (ok==1) to avoid fallback loops; keep default behavior unchanged elsewhere
This commit is contained in:
165
docs/ideas/tools/cax/gemini-ipc-implementation.nyash
Normal file
165
docs/ideas/tools/cax/gemini-ipc-implementation.nyash
Normal file
@ -0,0 +1,165 @@
|
||||
// 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) {} }
|
||||
Reference in New Issue
Block a user