continue work on supporting buffers
This commit is contained in:
parent
ae7ebb8127
commit
fd02618c2f
@ -6,6 +6,7 @@ import (
|
||||
"os"
|
||||
"os/exec"
|
||||
"path"
|
||||
"slices"
|
||||
"time"
|
||||
|
||||
kittenipc "efprojects.com/kitten-ipc"
|
||||
@ -56,11 +57,20 @@ func main() {
|
||||
}
|
||||
|
||||
remoteApi := TsIpcApi{Ipc: ipc}
|
||||
res, err := remoteApi.Div(10, 2)
|
||||
resDiv, err := remoteApi.Div(10, 2)
|
||||
if err != nil {
|
||||
log.Panic(err)
|
||||
}
|
||||
log.Printf("call result go->ts Div = %v", res)
|
||||
log.Printf("call result go->ts Div = %v", resDiv)
|
||||
|
||||
data1 := slices.Repeat([]byte{0b10101010}, 10)
|
||||
data2 := slices.Repeat([]byte{0b11110000}, 10)
|
||||
|
||||
resXor, err := remoteApi.XorData(data1, data2)
|
||||
if err != nil {
|
||||
log.Panic(err)
|
||||
}
|
||||
log.Printf("call result go->ts XorData = %v", resXor)
|
||||
|
||||
if err := ipc.Wait(1 * time.Second); err != nil {
|
||||
log.Panic(err)
|
||||
|
||||
@ -5,21 +5,35 @@ package main
|
||||
import (
|
||||
kittenipc "efprojects.com/kitten-ipc"
|
||||
"fmt"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
type TsIpcApi struct {
|
||||
Ipc kittenipc.Callable
|
||||
Ipc kittenipc.IpcCommon
|
||||
}
|
||||
|
||||
func (t *TsIpcApi) Div(
|
||||
func (self *TsIpcApi) Div(
|
||||
a int, b int,
|
||||
) (
|
||||
int, error,
|
||||
) {
|
||||
results, err := t.Ipc.Call("TsIpcApi.Div", a, b)
|
||||
results, err := self.Ipc.Call("TsIpcApi.Div", a, b)
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("call to TsIpcApi.Div failed: %w", err)
|
||||
}
|
||||
_ = results
|
||||
return int(results[0].(float64)), nil
|
||||
}
|
||||
|
||||
func (self *TsIpcApi) XorData(
|
||||
data1 []byte, data2 []byte,
|
||||
) (
|
||||
[]byte, error,
|
||||
) {
|
||||
results, err := self.Ipc.Call("TsIpcApi.XorData", data1, data2)
|
||||
if err != nil {
|
||||
return []byte{}, fmt.Errorf("call to TsIpcApi.XorData failed: %w", err)
|
||||
}
|
||||
_ = results
|
||||
return self.Ipc.ConvType(reflect.TypeOf([]byte{}), reflect.TypeOf(""), results[0]).([]byte), nil
|
||||
}
|
||||
|
||||
@ -11,6 +11,19 @@ class TsIpcApi {
|
||||
}
|
||||
return a / b;
|
||||
}
|
||||
XorData(data1: Buffer, data2: Buffer): Buffer {
|
||||
if (data1.length === 0 || data2.length === 0) {
|
||||
throw new Error('empty input data');
|
||||
}
|
||||
if (data1.length !== data2.length) {
|
||||
throw new Error('input data length mismatch');
|
||||
}
|
||||
const result = Buffer.alloc(data1.length);
|
||||
for (let i = 0; i < data1.length; i++) {
|
||||
result[i] = data1[i]! ^ data2[i]!;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
async function main() {
|
||||
|
||||
@ -10,13 +10,18 @@ export default class GoIpcApi {
|
||||
}
|
||||
|
||||
async Div(a: number, b: number): Promise<number> {
|
||||
a = this.ipc.convType(a, "number");
|
||||
b = this.ipc.convType(b, "number");
|
||||
const results = await this.ipc.call("GoIpcApi.Div", a, b);
|
||||
results[0] = this.ipc.convType(results[0], "number");
|
||||
return results[0] as number;
|
||||
}
|
||||
|
||||
async XorData(data1: Buffer, data2: Buffer): Promise<Buffer> {
|
||||
data1 = this.ipc.convType(data1, "Buffer");
|
||||
data2 = this.ipc.convType(data2, "Buffer");
|
||||
const results = await this.ipc.call("GoIpcApi.XorData", data1, data2);
|
||||
results[0] = Buffer.from(results[0], "base64");
|
||||
results[0] = this.ipc.convType(results[0], "Buffer");
|
||||
return results[0] as Buffer;
|
||||
}
|
||||
}
|
||||
|
||||
@ -5,7 +5,6 @@ import (
|
||||
"fmt"
|
||||
"go/format"
|
||||
"os"
|
||||
"strings"
|
||||
"text/template"
|
||||
|
||||
_ "embed"
|
||||
@ -34,16 +33,19 @@ func (g *GoApiGenerator) Generate(apis *api.Api, destFile string) error {
|
||||
Api: apis,
|
||||
}
|
||||
|
||||
const defaultReceiver = "self"
|
||||
|
||||
tpl := template.New("gogen")
|
||||
tpl = tpl.Funcs(map[string]any{
|
||||
"receiver": func(name string) string {
|
||||
return strings.ToLower(name)[0:1]
|
||||
return defaultReceiver
|
||||
},
|
||||
"typedef": func(t api.ValType) (string, error) {
|
||||
td, ok := map[api.ValType]string{
|
||||
api.TInt: "int",
|
||||
api.TString: "string",
|
||||
api.TBool: "bool",
|
||||
api.TBlob: "[]byte",
|
||||
}[t]
|
||||
if !ok {
|
||||
return "", fmt.Errorf("cannot generate type %v", t)
|
||||
@ -55,6 +57,11 @@ func (g *GoApiGenerator) Generate(apis *api.Api, destFile string) error {
|
||||
api.TInt: fmt.Sprintf("int(%s.(float64))", valDef),
|
||||
api.TString: fmt.Sprintf("%s.(string)", valDef),
|
||||
api.TBool: fmt.Sprintf("%s.(bool)", valDef),
|
||||
api.TBlob: fmt.Sprintf(
|
||||
"%s.Ipc.ConvType(reflect.TypeOf([]byte{}), reflect.TypeOf(\"\"), %s).([]byte)",
|
||||
defaultReceiver,
|
||||
valDef,
|
||||
),
|
||||
}[t]
|
||||
if !ok {
|
||||
return "", fmt.Errorf("cannot convert type %v for val %s", t, valDef)
|
||||
@ -66,6 +73,7 @@ func (g *GoApiGenerator) Generate(apis *api.Api, destFile string) error {
|
||||
api.TInt: "0",
|
||||
api.TString: `""`,
|
||||
api.TBool: "false",
|
||||
api.TBlob: "[]byte{}",
|
||||
}[t]
|
||||
if !ok {
|
||||
return "", fmt.Errorf("cannot generate zero value for type %v", t)
|
||||
|
||||
@ -12,7 +12,7 @@ import (
|
||||
{{ range $e := .Api.Endpoints }}
|
||||
|
||||
type {{ .Name }} struct {
|
||||
Ipc kittenipc.Callable
|
||||
Ipc kittenipc.IpcCommon
|
||||
}
|
||||
|
||||
{{ range $mtd := $e.Methods }}
|
||||
|
||||
@ -14,17 +14,22 @@ export default class {{ $e.Name }} {
|
||||
|
||||
{{ range $mtd := $e.Methods }}
|
||||
async {{ $mtd.Name }}(
|
||||
{{ range $par := $mtd.Params }}{{ $par.Name }}: {{ $par.Type | typedef }}, {{ end }}
|
||||
{{ range $par := $mtd.Params }}{{ $par.Name }}: {{ $par.Type | typedef }}, {{ end }}
|
||||
): Promise<{{ if len $mtd.Ret }}{{ (index $mtd.Ret 0).Type | typedef }}{{ else }}void{{ end }}> {
|
||||
|
||||
{{ range $par := $mtd.Params -}}
|
||||
{{ $par.Name }} = this.ipc.convType({{ $par.Name }}, '{{ $par.Type | typedef }}');
|
||||
{{- end -}}
|
||||
|
||||
const results = await this.ipc.call('{{ $e.Name }}.{{ $mtd.Name }}',
|
||||
{{ range $par := $mtd.Params }}{{ $par.Name }}, {{ end }}
|
||||
);
|
||||
|
||||
{{- if eq (index $mtd.Ret 0).Type.String "blob" -}}
|
||||
results[0] = Buffer.from(results[0], 'base64');
|
||||
{{- range $i, $ret := $mtd.Ret -}}
|
||||
results[{{ $i }}] = this.ipc.convType(results[{{ $i }}], '{{ $ret.Type | typedef }}');
|
||||
{{- end -}}
|
||||
|
||||
return {{ range $i, $ret := $mtd.Ret }}{{ if $i }}, {{ end }}results[{{ $i }}] as {{ $ret.Type | typedef }}{{ end }}
|
||||
return {{ range $i, $ret := $mtd.Ret }}{{ if $i }}, {{ end }}results[{{ $i }}] as {{ $ret.Type | typedef }}{{ end }}
|
||||
}
|
||||
{{ end }}
|
||||
}
|
||||
|
||||
@ -45,8 +45,9 @@ type Message struct {
|
||||
Error string `json:"error"`
|
||||
}
|
||||
|
||||
type Callable interface {
|
||||
type IpcCommon interface {
|
||||
Call(method string, params ...any) (Vals, error)
|
||||
ConvType(needType reflect.Type, gotType reflect.Type, arg any) any
|
||||
}
|
||||
|
||||
type pendingCall struct {
|
||||
@ -138,7 +139,7 @@ func (ipc *ipcCommon) handleCall(msg Message) {
|
||||
for i, arg := range msg.Args {
|
||||
paramType := method.Type().In(i)
|
||||
argType := reflect.TypeOf(arg)
|
||||
arg = ipc.convType(paramType, argType, arg)
|
||||
arg = ipc.ConvType(paramType, argType, arg)
|
||||
args = append(args, reflect.ValueOf(arg))
|
||||
}
|
||||
|
||||
@ -159,7 +160,7 @@ func (ipc *ipcCommon) handleCall(msg Message) {
|
||||
ipc.sendResponse(msg.Id, results, resErr)
|
||||
}
|
||||
|
||||
func (ipc *ipcCommon) convType(needType reflect.Type, gotType reflect.Type, arg any) any {
|
||||
func (ipc *ipcCommon) ConvType(needType reflect.Type, gotType reflect.Type, arg any) any {
|
||||
switch needType.Kind() {
|
||||
case reflect.Int:
|
||||
// JSON decodes any number to float64. If we need int, we should check and convert
|
||||
|
||||
@ -124,7 +124,7 @@ abstract class IPCCommon {
|
||||
this.sendMsg({type: MsgType.Response, id: msg.id, error: `endpoint not found: ${ endpointName }`});
|
||||
return;
|
||||
}
|
||||
const method = endpoint[methodName];
|
||||
const method: Function = endpoint[methodName];
|
||||
if (!method || typeof method !== 'function') {
|
||||
this.sendMsg({type: MsgType.Response, id: msg.id, error: `method not found: ${ msg.method }`});
|
||||
return;
|
||||
@ -183,7 +183,7 @@ abstract class IPCCommon {
|
||||
}
|
||||
};
|
||||
try {
|
||||
this.sendMsg({type: MsgType.Call, id, method, args: args.map(this.convType)});
|
||||
this.sendMsg({type: MsgType.Call, id, method, args: args.map(arg => this.convType(arg))});
|
||||
} catch (e) {
|
||||
delete this.pendingCalls[id];
|
||||
reject(new Error(`send call: ${ e }`));
|
||||
@ -191,10 +191,14 @@ abstract class IPCCommon {
|
||||
});
|
||||
}
|
||||
|
||||
private convType(arg: any): JSONSerializable {
|
||||
public convType(arg: any, toType?: string): any {
|
||||
// noinspection FallThroughInSwitchStatementJS
|
||||
switch (typeof arg) {
|
||||
case 'string':
|
||||
if(toType === 'Buffer') {
|
||||
return Buffer.from(arg, 'base64');
|
||||
}
|
||||
return arg;
|
||||
case 'boolean':
|
||||
case 'number':
|
||||
return arg;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user