tons of code

This commit is contained in:
Egor Aristov 2025-10-26 14:04:09 +03:00
parent 3ef477922d
commit f3a9abffe7
Signed by: egor3f
GPG Key ID: 40482A264AAEC85F
9 changed files with 63 additions and 48 deletions

View File

@ -10,14 +10,10 @@ import (
kittenipc "efprojects.com/kitten-ipc" kittenipc "efprojects.com/kitten-ipc"
) )
type callable interface {
Call(method string, params ...any) (kittenipc.Vals, error)
}
{{range $e := .Api.Endpoints}} {{range $e := .Api.Endpoints}}
type {{.Name}} struct { type {{.Name}} struct {
Ipc callable Ipc kittenipc.Callable
} }
{{range $mtd := $e.Methods}} {{range $mtd := $e.Methods}}
@ -26,10 +22,11 @@ func ({{$e.Name | receiver}} *{{$e.Name}}) {{$mtd.Name}}(
) ( ) (
{{range $mtd.Ret}}{{.Type | typedef}}, {{end}}error, {{range $mtd.Ret}}{{.Type | typedef}}, {{end}}error,
) { ) {
results, err := {{$e.Name | receiver}}.Ipc.Call("{{$e.Name}}", "{{$mtd.Name}}"{{range $mtd.Params}}, {{.Name}}{{end}}) results, err := {{$e.Name | receiver}}.Ipc.Call("{{$e.Name}}.{{$mtd.Name}}"{{range $mtd.Params}}, {{.Name}}{{end}})
if err != nil { if err != nil {
return {{range $mtd.Ret}}{{.Type | zerovalue}}, {{end}} fmt.Errorf("call to {{$e.Name}}.{{$mtd.Name}} failed: %w", err) return {{range $mtd.Ret}}{{.Type | zerovalue}}, {{end}} fmt.Errorf("call to {{$e.Name}}.{{$mtd.Name}} failed: %w", err)
} }
_ = results
return {{range $idx, $ret := $mtd.Ret}}results[{{$idx}}].({{$ret.Type | typedef}}), {{end}}nil return {{range $idx, $ret := $mtd.Ret}}results[{{$idx}}].({{$ret.Type | typedef}}), {{end}}nil
} }
{{end}} {{end}}

View File

@ -74,7 +74,7 @@ func (g *GoApiGenerator) Generate(apis *api.Api, destFile string) error {
} }
func (g *GoApiGenerator) writeDest(destFile string, bytes []byte) error { func (g *GoApiGenerator) writeDest(destFile string, bytes []byte) error {
f, err := os.OpenFile(destFile, os.O_WRONLY|os.O_CREATE, 0644) f, err := os.OpenFile(destFile, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644)
if err != nil { if err != nil {
return fmt.Errorf("open destination file: %w", err) return fmt.Errorf("open destination file: %w", err)
} }

View File

@ -57,7 +57,7 @@ func (g *TypescriptApiGenerator) Generate(apis *api.Api, destFile string) error
} }
func (g *TypescriptApiGenerator) writeDest(destFile string, bytes []byte) error { func (g *TypescriptApiGenerator) writeDest(destFile string, bytes []byte) error {
f, err := os.OpenFile(destFile, os.O_WRONLY|os.O_CREATE, 0644) f, err := os.OpenFile(destFile, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644)
if err != nil { if err != nil {
return fmt.Errorf("open destination file: %w", err) return fmt.Errorf("open destination file: %w", err)
} }

View File

@ -104,19 +104,21 @@ func (t *TypescriptApiParser) Parse(sourceFilePath string) (*api.Api, error) {
} }
apiMethod.Params = append(apiMethod.Params, apiPar) apiMethod.Params = append(apiMethod.Params, apiPar)
} }
var apiRet api.Val if method.Type != nil {
switch method.Type.Kind { var apiRet api.Val
case ast.KindNumberKeyword: switch method.Type.Kind {
apiRet.Type = api.TInt case ast.KindNumberKeyword:
case ast.KindStringKeyword: apiRet.Type = api.TInt
apiRet.Type = api.TString case ast.KindStringKeyword:
case ast.KindBooleanKeyword: apiRet.Type = api.TString
apiRet.Type = api.TBool case ast.KindBooleanKeyword:
default: apiRet.Type = api.TBool
err = fmt.Errorf("return type %s is not supported yet", method.Type.Kind) default:
return false err = fmt.Errorf("return type %s is not supported yet", method.Type.Kind)
return false
}
apiMethod.Ret = []api.Val{apiRet}
} }
apiMethod.Ret = []api.Val{apiRet}
endpoint.Methods = append(endpoint.Methods, apiMethod) endpoint.Methods = append(endpoint.Methods, apiMethod)
} }

View File

@ -39,6 +39,10 @@ type Message struct {
Error string `json:"error"` Error string `json:"error"`
} }
type Callable interface {
Call(method string, params ...any) (Vals, error)
}
type ipcCommon struct { type ipcCommon struct {
localApi any localApi any
socketPath string socketPath string
@ -279,7 +283,7 @@ func (p *ParentIPC) acceptConn() error {
return fmt.Errorf("accept: %w", res.Error()) return fmt.Errorf("accept: %w", res.Error())
} }
p.conn = res.MustGet() p.conn = res.MustGet()
p.readConn() go p.readConn()
} }
return nil return nil
} }

View File

@ -23,13 +23,13 @@ interface CallResult {
error: Error | null; error: Error | null;
} }
declare abstract class IPCCommon { declare abstract class IPCCommon {
protected localApi: any; protected localApis: Record<string, any>;
protected socketPath: string; protected socketPath: string;
protected conn: net.Socket | null; protected conn: net.Socket | null;
protected nextId: number; protected nextId: number;
protected pendingCalls: Record<number, (result: CallResult) => void>; protected pendingCalls: Record<number, (result: CallResult) => void>;
protected errors: QueuedEvent<Error>; protected errors: QueuedEvent<Error>;
protected constructor(localApi: any, socketPath: string); protected constructor(localApis: object[], socketPath: string);
protected readConn(): void; protected readConn(): void;
protected processMsg(msg: Message): void; protected processMsg(msg: Message): void;
protected handleCall(msg: CallMessage): void; protected handleCall(msg: CallMessage): void;
@ -43,13 +43,13 @@ export declare class ParentIPC extends IPCCommon {
private readonly cmdArgs; private readonly cmdArgs;
private cmd; private cmd;
private readonly listener; private readonly listener;
constructor(cmdPath: string, cmdArgs: string[], localApi: any); constructor(cmdPath: string, cmdArgs: string[], ...localApis: object[]);
start(): Promise<void>; start(): Promise<void>;
private acceptConn; private acceptConn;
wait(): Promise<void>; wait(): Promise<void>;
} }
export declare class ChildIPC extends IPCCommon { export declare class ChildIPC extends IPCCommon {
constructor(localApi: any); constructor(...localApis: object[]);
start(): Promise<void>; start(): Promise<void>;
wait(): Promise<void>; wait(): Promise<void>;
} }

View File

@ -1 +1 @@
{"version":3,"file":"lib.d.ts","sourceRoot":"","sources":["../src/lib.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,GAAG,MAAM,UAAU,CAAC;AAOhC,OAAO,EAAC,WAAW,EAAC,MAAM,WAAW,CAAC;AAItC,aAAK,OAAO;IACR,IAAI,IAAI;IACR,QAAQ,IAAI;CACf;AAED,KAAK,IAAI,GAAG,GAAG,EAAE,CAAC;AAElB,UAAU,WAAW;IACjB,IAAI,EAAE,OAAO,CAAC,IAAI,CAAC;IACnB,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,IAAI,CAAC;CAChB;AAED,UAAU,eAAe;IACrB,IAAI,EAAE,OAAO,CAAC,QAAQ,CAAC;IACvB,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,CAAC,EAAE,IAAI,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,KAAK,OAAO,GAAG,WAAW,GAAG,eAAe,CAAC;AAE7C,UAAU,UAAU;IAChB,MAAM,EAAE,IAAI,CAAC;IACb,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;CACvB;AAED,uBAAe,SAAS;IACpB,SAAS,CAAC,QAAQ,EAAE,GAAG,CAAC;IACxB,SAAS,CAAC,UAAU,EAAE,MAAM,CAAC;IAC7B,SAAS,CAAC,IAAI,EAAE,GAAG,CAAC,MAAM,GAAG,IAAI,CAAQ;IACzC,SAAS,CAAC,MAAM,EAAE,MAAM,CAAK;IAC7B,SAAS,CAAC,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,MAAM,EAAE,UAAU,KAAK,IAAI,CAAC,CAAM;IAC1E,SAAS,CAAC,MAAM,EAAE,WAAW,CAAC,KAAK,CAAC,CAAC;IAErC,SAAS,aAAa,QAAQ,EAAE,GAAG,EAAE,UAAU,EAAE,MAAM;IAMvD,SAAS,CAAC,QAAQ,IAAI,IAAI;IA0B1B,SAAS,CAAC,UAAU,CAAC,GAAG,EAAE,OAAO,GAAG,IAAI;IAWxC,SAAS,CAAC,UAAU,CAAC,GAAG,EAAE,WAAW,GAAG,IAAI;IAyC5C,SAAS,CAAC,OAAO,CAAC,GAAG,EAAE,OAAO,GAAG,IAAI;IAWrC,SAAS,CAAC,cAAc,CAAC,GAAG,EAAE,eAAe,GAAG,IAAI;IAapD,SAAS,CAAC,QAAQ,CAAC,GAAG,EAAE,KAAK,GAAG,IAAI;IAIpC,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,EAAE,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;CAmBvD;AAGD,qBAAa,SAAU,SAAQ,SAAS;IACpC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IACjC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAW;IACnC,OAAO,CAAC,GAAG,CAA6B;IACxC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAa;gBAE1B,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,EAAE,QAAQ,EAAE,GAAG;IAavD,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;YAuBd,UAAU;IAmBlB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;CAgB9B;AAGD,qBAAa,QAAS,SAAQ,SAAS;gBACvB,QAAQ,EAAE,GAAG;IAInB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAUtB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;CAK9B"} {"version":3,"file":"lib.d.ts","sourceRoot":"","sources":["../src/lib.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,GAAG,MAAM,UAAU,CAAC;AAOhC,OAAO,EAAC,WAAW,EAAC,MAAM,WAAW,CAAC;AAItC,aAAK,OAAO;IACR,IAAI,IAAI;IACR,QAAQ,IAAI;CACf;AAED,KAAK,IAAI,GAAG,GAAG,EAAE,CAAC;AAElB,UAAU,WAAW;IACjB,IAAI,EAAE,OAAO,CAAC,IAAI,CAAC;IACnB,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,IAAI,CAAC;CAChB;AAED,UAAU,eAAe;IACrB,IAAI,EAAE,OAAO,CAAC,QAAQ,CAAC;IACvB,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,CAAC,EAAE,IAAI,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,KAAK,OAAO,GAAG,WAAW,GAAG,eAAe,CAAC;AAE7C,UAAU,UAAU;IAChB,MAAM,EAAE,IAAI,CAAC;IACb,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;CACvB;AAED,uBAAe,SAAS;IACpB,SAAS,CAAC,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IACzC,SAAS,CAAC,UAAU,EAAE,MAAM,CAAC;IAC7B,SAAS,CAAC,IAAI,EAAE,GAAG,CAAC,MAAM,GAAG,IAAI,CAAQ;IACzC,SAAS,CAAC,MAAM,EAAE,MAAM,CAAK;IAC7B,SAAS,CAAC,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,MAAM,EAAE,UAAU,KAAK,IAAI,CAAC,CAAM;IAC1E,SAAS,CAAC,MAAM,EAAE,WAAW,CAAC,KAAK,CAAC,CAAC;IAErC,SAAS,aAAa,SAAS,EAAE,MAAM,EAAE,EAAE,UAAU,EAAE,MAAM;IAW7D,SAAS,CAAC,QAAQ,IAAI,IAAI;IA0B1B,SAAS,CAAC,UAAU,CAAC,GAAG,EAAE,OAAO,GAAG,IAAI;IAWxC,SAAS,CAAC,UAAU,CAAC,GAAG,EAAE,WAAW,GAAG,IAAI;IA8C5C,SAAS,CAAC,OAAO,CAAC,GAAG,EAAE,OAAO,GAAG,IAAI;IAWrC,SAAS,CAAC,cAAc,CAAC,GAAG,EAAE,eAAe,GAAG,IAAI;IAapD,SAAS,CAAC,QAAQ,CAAC,GAAG,EAAE,KAAK,GAAG,IAAI;IAIpC,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,EAAE,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;CAmBvD;AAGD,qBAAa,SAAU,SAAQ,SAAS;IACpC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IACjC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAW;IACnC,OAAO,CAAC,GAAG,CAA6B;IACxC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAa;gBAE1B,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,EAAE,GAAG,SAAS,EAAE,MAAM,EAAE;IAahE,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;YAuBd,UAAU;IAmBlB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;CAgB9B;AAGD,qBAAa,QAAS,SAAQ,SAAS;gBACvB,GAAG,SAAS,EAAE,MAAM,EAAE;IAI5B,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAUtB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;CAK9B"}

File diff suppressed because one or more lines are too long

View File

@ -7,7 +7,7 @@ import * as fs from 'node:fs';
import * as util from 'node:util'; import * as util from 'node:util';
import {QueuedEvent} from 'ts-events'; import {QueuedEvent} from 'ts-events';
const IPC_SOCKET_ARG = '--ipc-socket'; const IPC_SOCKET_ARG = 'ipc-socket';
enum MsgType { enum MsgType {
Call = 1, Call = 1,
@ -38,17 +38,22 @@ interface CallResult {
} }
abstract class IPCCommon { abstract class IPCCommon {
protected localApi: any; protected localApis: Record<string, any>;
protected socketPath: string; protected socketPath: string;
protected conn: net.Socket | null = null; protected conn: net.Socket | null = null;
protected nextId: number = 0; protected nextId: number = 0;
protected pendingCalls: Record<number, (result: CallResult) => void> = {}; protected pendingCalls: Record<number, (result: CallResult) => void> = {};
protected errors: QueuedEvent<Error>; protected errors: QueuedEvent<Error>;
protected constructor(localApi: any, socketPath: string) { protected constructor(localApis: object[], socketPath: string) {
this.localApi = localApi;
this.socketPath = socketPath; this.socketPath = socketPath;
this.errors = new QueuedEvent(); this.errors = new QueuedEvent();
this.localApis = {};
for (const localApi of localApis) {
const className = (localApi as {name: string})['name'];
this.localApis[className] = localApi;
}
} }
protected readConn(): void { protected readConn(): void {
@ -89,12 +94,17 @@ abstract class IPCCommon {
} }
protected handleCall(msg: CallMessage): void { protected handleCall(msg: CallMessage): void {
if (!this.localApi) { const [endpointName, methodName] = msg.method.split('.');
this.sendMsg({type: MsgType.Response, id: msg.id, error: 'remote side does not accept ipc calls'}); if(!endpointName || !methodName) {
this.sendMsg({type: MsgType.Response, id: msg.id, error: `call malformed: ${msg.method}`});
return; return;
} }
const endpoint = this.localApis[endpointName];
const method = this.localApi[msg.method]; if(!endpoint) {
this.sendMsg({type: MsgType.Response, id: msg.id, error: `endpoint not found: ${endpointName}`});
return;
}
const method = endpoint[methodName];
if (!method || typeof method !== 'function') { if (!method || typeof method !== 'function') {
this.sendMsg({type: MsgType.Response, id: msg.id, error: `method not found: ${msg.method}`}); this.sendMsg({type: MsgType.Response, id: msg.id, error: `method not found: ${msg.method}`});
return; return;
@ -111,7 +121,7 @@ abstract class IPCCommon {
} }
try { try {
const result = method.apply(this.localApi, msg.params); const result = method.apply(this.localApis, msg.params);
if (result instanceof Promise) { if (result instanceof Promise) {
result result
@ -185,13 +195,13 @@ export class ParentIPC extends IPCCommon {
private cmd: ChildProcess | null = null; private cmd: ChildProcess | null = null;
private readonly listener: net.Server; private readonly listener: net.Server;
constructor(cmdPath: string, cmdArgs: string[], localApi: any) { constructor(cmdPath: string, cmdArgs: string[], ...localApis: object[]) {
const socketPath = path.join(os.tmpdir(), `kitten-ipc-${process.pid}.sock`); const socketPath = path.join(os.tmpdir(), `kitten-ipc-${process.pid}.sock`);
super(localApi, socketPath); super(localApis, socketPath);
this.cmdPath = cmdPath; this.cmdPath = cmdPath;
if (cmdArgs.includes(IPC_SOCKET_ARG)) { if (cmdArgs.includes(`--${IPC_SOCKET_ARG}`)) {
throw new Error(`you should not use '${IPC_SOCKET_ARG}' argument in your command`); throw new Error(`you should not use '--${IPC_SOCKET_ARG}' argument in your command`);
} }
this.cmdArgs = cmdArgs; this.cmdArgs = cmdArgs;
@ -211,7 +221,7 @@ export class ParentIPC extends IPCCommon {
this.listener.on('error', reject); this.listener.on('error', reject);
}); });
const cmdArgs = [...this.cmdArgs, IPC_SOCKET_ARG, this.socketPath]; const cmdArgs = [...this.cmdArgs, `--${IPC_SOCKET_ARG}`, this.socketPath];
this.cmd = spawn(this.cmdPath, cmdArgs, {stdio: 'inherit'}); this.cmd = spawn(this.cmdPath, cmdArgs, {stdio: 'inherit'});
this.cmd.on('error', (err) => { this.cmd.on('error', (err) => {
@ -260,8 +270,8 @@ export class ParentIPC extends IPCCommon {
export class ChildIPC extends IPCCommon { export class ChildIPC extends IPCCommon {
constructor(localApi: any) { constructor(...localApis: object[]) {
super(localApi, socketPathFromArgs()); super(localApis, socketPathFromArgs());
} }
async start(): Promise<void> { async start(): Promise<void> {
@ -283,17 +293,19 @@ export class ChildIPC extends IPCCommon {
function socketPathFromArgs(): string { function socketPathFromArgs(): string {
const {values} = util.parseArgs({options: { const {values} = util.parseArgs({
IPC_SOCKET_ARG: { options: {
[IPC_SOCKET_ARG]: {
type: 'string', type: 'string',
} }
}}); }
});
if(!values.IPC_SOCKET_ARG) { if (!values[IPC_SOCKET_ARG]) {
throw new Error('ipc socket path is missing'); throw new Error('ipc socket path is missing');
} }
return values.IPC_SOCKET_ARG; return values[IPC_SOCKET_ARG];
} }