debug msg

This commit is contained in:
Egor Aristov 2026-03-28 17:13:21 +03:00
parent c374bb9784
commit 96d4a5015c
10 changed files with 59 additions and 26 deletions

View File

@ -47,7 +47,7 @@ func main() {
cmd := exec.Command("node", path.Join(cwd, "ts/dist/index.js"))
ipc, err := kittenipc.NewParent(cmd, &localApi)
ipc, err := kittenipc.NewParent(cmd, nil, &localApi)
if err != nil {
log.Panic(err)
}

View File

@ -28,7 +28,7 @@ class TsIpcApi {
async function main() {
const localApi = new TsIpcApi();
const ipc = new ChildIPC(localApi);
const ipc = new ChildIPC(undefined, localApi);
const remoteApi = new GoIpcApi(ipc);
await ipc.start();

View File

@ -11,13 +11,17 @@ type ChildIPC struct {
*ipcCommon
}
func NewChild(localApis ...any) (*ChildIPC, error) {
func NewChild(opts *Options, localApis ...any) (*ChildIPC, error) {
if opts == nil {
opts = &Options{}
}
c := ChildIPC{
ipcCommon: &ipcCommon{
localApis: mapTypeNames(localApis),
pendingCalls: make(map[int64]*pendingCall),
errCh: make(chan error, 1),
ctx: context.Background(),
localApis: mapTypeNames(localApis),
pendingCalls: make(map[int64]*pendingCall),
errCh: make(chan error, 1),
ctx: context.Background(),
debugMessages: opts.DebugMessages,
},
}

View File

@ -5,6 +5,7 @@ import (
"context"
"encoding/json"
"fmt"
"log"
"net"
"reflect"
"strings"
@ -26,6 +27,10 @@ type pendingCall struct {
resultChan chan callResult
}
type Options struct {
DebugMessages bool
}
type ipcCommon struct {
localApis map[string]any
socketPath string
@ -38,6 +43,7 @@ type ipcCommon struct {
mu sync.Mutex
writeMu sync.Mutex
ctx context.Context
debugMessages bool
}
func (ipc *ipcCommon) readConn() {
@ -46,6 +52,9 @@ func (ipc *ipcCommon) readConn() {
for scn.Scan() {
var msg Message
msgBytes := scn.Bytes()
if ipc.debugMessages {
log.Printf("[ipc recv] %s", string(msgBytes))
}
if err := json.Unmarshal(msgBytes, &msg); err != nil {
ipc.raiseErr(fmt.Errorf("unmarshal message: %w", err))
break
@ -71,6 +80,9 @@ func (ipc *ipcCommon) sendMsg(msg Message) error {
if err != nil {
return fmt.Errorf("marshal message: %w", err)
}
if ipc.debugMessages {
log.Printf("[ipc send] %s", string(data))
}
data = append(data, '\n')
ipc.writeMu.Lock()

View File

@ -11,27 +11,27 @@ import (
func TestNewParent(t *testing.T) {
t.Run("socket argument in command", func(t *testing.T) {
cmd := exec.Command("/bin/sh", ipcSocketArg, "/tmp/kek")
_, err := NewParent(cmd)
_, err := NewParent(cmd, nil)
assert.Error(t, err)
})
t.Run("nonexistent binary", func(t *testing.T) {
cmd := exec.Command("/nonexistent/binary")
p, err := NewParent(cmd)
p, err := NewParent(cmd, nil)
assert.NoError(t, err)
assert.Error(t, p.Start())
})
t.Run("connection timeout", func(t *testing.T) {
cmd := exec.Command("../testdata/sleep15.sh")
p, err := NewParent(cmd)
p, err := NewParent(cmd, nil)
assert.NoError(t, err)
assert.Error(t, p.Start())
})
t.Run("child finished before accepting connection", func(t *testing.T) {
cmd := exec.Command("../testdata/sleep3.sh")
p, err := NewParent(cmd)
p, err := NewParent(cmd, nil)
assert.NoError(t, err)
start := time.Now()
assert.Error(t, p.Start())

View File

@ -22,18 +22,22 @@ type ParentIPC struct {
cmdErr error
}
func NewParent(cmd *exec.Cmd, localApis ...any) (*ParentIPC, error) {
return NewParentWithContext(context.Background(), cmd, localApis...)
func NewParent(cmd *exec.Cmd, opts *Options, localApis ...any) (*ParentIPC, error) {
return NewParentWithContext(context.Background(), cmd, opts, localApis...)
}
func NewParentWithContext(ctx context.Context, cmd *exec.Cmd, localApis ...any) (*ParentIPC, error) {
func NewParentWithContext(ctx context.Context, cmd *exec.Cmd, opts *Options, localApis ...any) (*ParentIPC, error) {
if opts == nil {
opts = &Options{}
}
p := ParentIPC{
ipcCommon: &ipcCommon{
localApis: mapTypeNames(localApis),
pendingCalls: make(map[int64]*pendingCall),
errCh: make(chan error, 1),
socketPath: filepath.Join(os.TempDir(), fmt.Sprintf("kitten-ipc-%d-%d.sock", os.Getpid(), rand.Int63())),
ctx: ctx,
localApis: mapTypeNames(localApis),
pendingCalls: make(map[int64]*pendingCall),
errCh: make(chan error, 1),
socketPath: filepath.Join(os.TempDir(), fmt.Sprintf("kitten-ipc-%d-%d.sock", os.Getpid(), rand.Int63())),
ctx: ctx,
debugMessages: opts.DebugMessages,
},
cmd: cmd,
}

View File

@ -1,10 +1,10 @@
import * as net from 'node:net';
import {IPCCommon} from './common.js';
import {IPCCommon, type IPCOptions} from './common.js';
import {socketPathFromArgs} from './util.js';
export class ChildIPC extends IPCCommon {
constructor(...localApis: object[]) {
super(localApis, socketPathFromArgs());
constructor(opts?: IPCOptions, ...localApis: object[]) {
super(localApis, socketPathFromArgs(), opts);
}
async start(): Promise<void> {

View File

@ -4,6 +4,10 @@ import {AsyncQueue} from './asyncqueue.js';
import type {CallMessage, CallResult, Message, ResponseMessage, Vals} from './protocol.js';
import {MsgType} from './protocol.js';
export interface IPCOptions {
debugMessages?: boolean;
}
export abstract class IPCCommon {
protected localApis: Record<string, any>;
protected socketPath: string;
@ -13,12 +17,14 @@ export abstract class IPCCommon {
protected stopRequested: boolean = false;
protected processingCalls: number = 0;
protected ready = false;
protected debugMessages: boolean;
protected errorQueue = new AsyncQueue<Error>();
protected onClose?: () => void;
protected constructor(localApis: object[], socketPath: string) {
protected constructor(localApis: object[], socketPath: string, opts?: IPCOptions) {
this.socketPath = socketPath;
this.debugMessages = opts?.debugMessages ?? false;
this.localApis = {};
for (const localApi of localApis) {
@ -47,6 +53,9 @@ export abstract class IPCCommon {
rl.on('line', (line) => {
try {
if (this.debugMessages) {
console.log(`[ipc recv] ${line}`);
}
const msg: Message = JSON.parse(line);
this.processMsg(msg);
} catch (e) {
@ -73,6 +82,9 @@ export abstract class IPCCommon {
try {
const data = JSON.stringify(msg) + '\n';
if (this.debugMessages) {
console.log(`[ipc send] ${JSON.stringify(msg)}`);
}
this.conn.write(data);
} catch (e) {
this.raiseErr(new Error(`send response for ${ msg.id }: ${ e }`));

View File

@ -1,2 +1,3 @@
export {ParentIPC} from './parent.js';
export {ChildIPC} from './child.js';
export type {IPCOptions} from './common.js';

View File

@ -4,7 +4,7 @@ import * as path from 'node:path';
import * as fs from 'node:fs';
import * as crypto from 'node:crypto';
import {type ChildProcess, spawn} from 'node:child_process';
import {IPCCommon} from './common.js';
import {IPCCommon, type IPCOptions} from './common.js';
import {timeout} from './util.js';
const IPC_SOCKET_ARG = 'ipc-socket';
@ -18,9 +18,9 @@ export class ParentIPC extends IPCCommon {
private cmdExitResult: { code: number | null, signal: string | null } | null = null;
private cmdExitCallbacks: ((result: { code: number | null, signal: string | null }) => void)[] = [];
constructor(cmdPath: string, cmdArgs: string[], ...localApis: object[]) {
constructor(cmdPath: string, cmdArgs: string[], opts?: IPCOptions, ...localApis: object[]) {
const socketPath = path.join(os.tmpdir(), `kitten-ipc-${ process.pid }-${ crypto.randomInt(2**48 - 1) }.sock`);
super(localApis, socketPath);
super(localApis, socketPath, opts);
this.cmdPath = cmdPath;
if (cmdArgs.includes(`--${ IPC_SOCKET_ARG }`)) {