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