mirror of
https://github.com/wailsapp/wails.git
synced 2025-05-02 23:39:21 +08:00
Add bindings hook
This commit is contained in:
parent
91676080eb
commit
f9ffe915f2
8
v3/examples/binding/GreetService.go
Normal file
8
v3/examples/binding/GreetService.go
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
type GreetService struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*GreetService) Greet(name string) string {
|
||||||
|
return "Hello " + name
|
||||||
|
}
|
@ -4,17 +4,13 @@ import (
|
|||||||
_ "embed"
|
_ "embed"
|
||||||
"log"
|
"log"
|
||||||
|
|
||||||
"github.com/wailsapp/wails/v3/examples/binding/services"
|
|
||||||
"github.com/wailsapp/wails/v3/pkg/application"
|
"github.com/wailsapp/wails/v3/pkg/application"
|
||||||
)
|
)
|
||||||
|
|
||||||
type localStruct struct{}
|
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
app := application.New(application.Options{
|
app := application.New(application.Options{
|
||||||
Bind: []interface{}{
|
Bind: []interface{}{
|
||||||
&localStruct{},
|
&GreetService{},
|
||||||
&services.GreetService{},
|
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -1,8 +0,0 @@
|
|||||||
// Code generated by tygo. DO NOT EDIT.
|
|
||||||
|
|
||||||
//////////
|
|
||||||
// source: person.go
|
|
||||||
|
|
||||||
export interface Person {
|
|
||||||
Name: string;
|
|
||||||
}
|
|
@ -1,5 +0,0 @@
|
|||||||
package models
|
|
||||||
|
|
||||||
type Person struct {
|
|
||||||
Name string
|
|
||||||
}
|
|
@ -1,23 +0,0 @@
|
|||||||
package services
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/wailsapp/wails/v3/examples/binding/models"
|
|
||||||
)
|
|
||||||
|
|
||||||
type GreetService struct {
|
|
||||||
SomeVariable int
|
|
||||||
lowercase string
|
|
||||||
Parent *models.Person
|
|
||||||
}
|
|
||||||
|
|
||||||
func (*GreetService) Greet(name string) string {
|
|
||||||
return "Hello " + name
|
|
||||||
}
|
|
||||||
|
|
||||||
func (g *GreetService) GetPerson() *models.Person {
|
|
||||||
return g.Parent
|
|
||||||
}
|
|
||||||
|
|
||||||
func (g *GreetService) SetPerson(person *models.Person) {
|
|
||||||
g.Parent = person
|
|
||||||
}
|
|
@ -1,9 +0,0 @@
|
|||||||
// Code generated by tygo. DO NOT EDIT.
|
|
||||||
|
|
||||||
//////////
|
|
||||||
// source: GreetService.go
|
|
||||||
|
|
||||||
export interface GreetService {
|
|
||||||
SomeVariable: number /* int */;
|
|
||||||
Parent?: any /* models.Person */;
|
|
||||||
}
|
|
@ -112,7 +112,8 @@ type App struct {
|
|||||||
menuItemsLock sync.Mutex
|
menuItemsLock sync.Mutex
|
||||||
|
|
||||||
// Running
|
// Running
|
||||||
running bool
|
running bool
|
||||||
|
bindings *Bindings
|
||||||
|
|
||||||
// platform app
|
// platform app
|
||||||
impl platformApp
|
impl platformApp
|
||||||
@ -270,6 +271,12 @@ func (a *App) Run() error {
|
|||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
var err error
|
||||||
|
a.bindings, err = NewBindings(a.options.Bind)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
// run windows
|
// run windows
|
||||||
for _, window := range a.windows {
|
for _, window := range a.windows {
|
||||||
go window.run()
|
go window.run()
|
||||||
|
242
v3/pkg/application/bindings.go
Normal file
242
v3/pkg/application/bindings.go
Normal file
@ -0,0 +1,242 @@
|
|||||||
|
package application
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"reflect"
|
||||||
|
"runtime"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Parameter defines a Go method parameter
|
||||||
|
type Parameter struct {
|
||||||
|
Name string `json:"name,omitempty"`
|
||||||
|
TypeName string `json:"type"`
|
||||||
|
reflectType reflect.Type
|
||||||
|
}
|
||||||
|
|
||||||
|
func newParameter(Name string, Type reflect.Type) *Parameter {
|
||||||
|
return &Parameter{
|
||||||
|
Name: Name,
|
||||||
|
TypeName: Type.String(),
|
||||||
|
reflectType: Type,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsType returns true if the given
|
||||||
|
func (p *Parameter) IsType(typename string) bool {
|
||||||
|
return p.TypeName == typename
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsError returns true if the parameter type is an error
|
||||||
|
func (p *Parameter) IsError() bool {
|
||||||
|
return p.IsType("error")
|
||||||
|
}
|
||||||
|
|
||||||
|
// BoundMethod defines all the data related to a Go method that is
|
||||||
|
// bound to the Wails application
|
||||||
|
type BoundMethod struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Inputs []*Parameter `json:"inputs,omitempty"`
|
||||||
|
Outputs []*Parameter `json:"outputs,omitempty"`
|
||||||
|
Comments string `json:"comments,omitempty"`
|
||||||
|
Method reflect.Value `json:"-"`
|
||||||
|
PackageName string
|
||||||
|
StructName string
|
||||||
|
PackagePath string
|
||||||
|
}
|
||||||
|
|
||||||
|
type Bindings struct {
|
||||||
|
boundMethods map[string]map[string]map[string]*BoundMethod
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewBindings(bindings []any) (*Bindings, error) {
|
||||||
|
b := &Bindings{
|
||||||
|
boundMethods: make(map[string]map[string]map[string]*BoundMethod),
|
||||||
|
}
|
||||||
|
for _, binding := range bindings {
|
||||||
|
err := b.Add(binding)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return b, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add the given struct methods to the Bindings
|
||||||
|
func (b *Bindings) Add(structPtr interface{}) error {
|
||||||
|
|
||||||
|
methods, err := b.getMethods(structPtr)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("cannot bind value to app: %s", err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, method := range methods {
|
||||||
|
packageName := method.PackageName
|
||||||
|
structName := method.StructName
|
||||||
|
methodName := method.Name
|
||||||
|
|
||||||
|
// Add it as a regular method
|
||||||
|
if _, ok := b.boundMethods[packageName]; !ok {
|
||||||
|
b.boundMethods[packageName] = make(map[string]map[string]*BoundMethod)
|
||||||
|
}
|
||||||
|
if _, ok := b.boundMethods[packageName][structName]; !ok {
|
||||||
|
b.boundMethods[packageName][structName] = make(map[string]*BoundMethod)
|
||||||
|
}
|
||||||
|
b.boundMethods[packageName][structName][methodName] = method
|
||||||
|
//b.db.AddMethod(packageName, structName, methodName, method)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *Bindings) getMethods(value interface{}) ([]*BoundMethod, error) {
|
||||||
|
|
||||||
|
// Create result placeholder
|
||||||
|
var result []*BoundMethod
|
||||||
|
|
||||||
|
// Check type
|
||||||
|
if !isStructPtr(value) {
|
||||||
|
|
||||||
|
if isStruct(value) {
|
||||||
|
name := reflect.ValueOf(value).Type().Name()
|
||||||
|
return nil, fmt.Errorf("%s is a struct, not a pointer to a struct", name)
|
||||||
|
}
|
||||||
|
|
||||||
|
if isFunction(value) {
|
||||||
|
name := runtime.FuncForPC(reflect.ValueOf(value).Pointer()).Name()
|
||||||
|
return nil, fmt.Errorf("%s is a function, not a pointer to a struct. Wails v2 has deprecated the binding of functions. Please wrap your functions up in a struct and bind a pointer to that struct.", name)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, fmt.Errorf("not a pointer to a struct.")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process Struct
|
||||||
|
structType := reflect.TypeOf(value)
|
||||||
|
structValue := reflect.ValueOf(value)
|
||||||
|
structTypeString := structType.String()
|
||||||
|
baseName := structTypeString[1:]
|
||||||
|
|
||||||
|
// Process Methods
|
||||||
|
for i := 0; i < structType.NumMethod(); i++ {
|
||||||
|
methodDef := structType.Method(i)
|
||||||
|
methodName := methodDef.Name
|
||||||
|
packageName, structName, _ := strings.Cut(baseName, ".")
|
||||||
|
fullMethodName := baseName + "." + methodName
|
||||||
|
method := structValue.MethodByName(methodName)
|
||||||
|
|
||||||
|
// Create new method
|
||||||
|
boundMethod := &BoundMethod{
|
||||||
|
Name: fullMethodName,
|
||||||
|
PackageName: packageName,
|
||||||
|
StructName: structName,
|
||||||
|
Inputs: nil,
|
||||||
|
Outputs: nil,
|
||||||
|
Comments: "",
|
||||||
|
Method: method,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Iterate inputs
|
||||||
|
methodType := method.Type()
|
||||||
|
inputParamCount := methodType.NumIn()
|
||||||
|
var inputs []*Parameter
|
||||||
|
for inputIndex := 0; inputIndex < inputParamCount; inputIndex++ {
|
||||||
|
input := methodType.In(inputIndex)
|
||||||
|
thisParam := newParameter("", input)
|
||||||
|
//
|
||||||
|
//thisInput := input
|
||||||
|
//
|
||||||
|
//if thisInput.Kind() == reflect.Slice {
|
||||||
|
// thisInput = thisInput.Elem()
|
||||||
|
//}
|
||||||
|
//
|
||||||
|
//// Process struct pointer params
|
||||||
|
//if thisInput.Kind() == reflect.Ptr {
|
||||||
|
// if thisInput.Elem().Kind() == reflect.Struct {
|
||||||
|
// typ := thisInput.Elem()
|
||||||
|
// a := reflect.New(typ)
|
||||||
|
// s := reflect.Indirect(a).Interface()
|
||||||
|
// name := typ.Name()
|
||||||
|
// packageName := getPackageName(thisInput.String())
|
||||||
|
// b.AddStructToGenerateTS(packageName, name, s)
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
//
|
||||||
|
//// Process struct params
|
||||||
|
//if thisInput.Kind() == reflect.Struct {
|
||||||
|
// a := reflect.New(thisInput)
|
||||||
|
// s := reflect.Indirect(a).Interface()
|
||||||
|
// name := thisInput.Name()
|
||||||
|
// packageName := getPackageName(thisInput.String())
|
||||||
|
// b.AddStructToGenerateTS(packageName, name, s)
|
||||||
|
//}
|
||||||
|
|
||||||
|
inputs = append(inputs, thisParam)
|
||||||
|
}
|
||||||
|
|
||||||
|
boundMethod.Inputs = inputs
|
||||||
|
|
||||||
|
outputParamCount := methodType.NumOut()
|
||||||
|
var outputs []*Parameter
|
||||||
|
for outputIndex := 0; outputIndex < outputParamCount; outputIndex++ {
|
||||||
|
output := methodType.Out(outputIndex)
|
||||||
|
thisParam := newParameter("", output)
|
||||||
|
//
|
||||||
|
//thisOutput := output
|
||||||
|
//
|
||||||
|
//if thisOutput.Kind() == reflect.Slice {
|
||||||
|
// thisOutput = thisOutput.Elem()
|
||||||
|
//}
|
||||||
|
//
|
||||||
|
//// Process struct pointer params
|
||||||
|
//if thisOutput.Kind() == reflect.Ptr {
|
||||||
|
// if thisOutput.Elem().Kind() == reflect.Struct {
|
||||||
|
// typ := thisOutput.Elem()
|
||||||
|
// a := reflect.New(typ)
|
||||||
|
// s := reflect.Indirect(a).Interface()
|
||||||
|
// name := typ.Name()
|
||||||
|
// packageName := getPackageName(thisOutput.String())
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
//
|
||||||
|
//// Process struct params
|
||||||
|
//if thisOutput.Kind() == reflect.Struct {
|
||||||
|
// a := reflect.New(thisOutput)
|
||||||
|
// s := reflect.Indirect(a).Interface()
|
||||||
|
// name := thisOutput.Name()
|
||||||
|
// packageName := getPackageName(thisOutput.String())
|
||||||
|
// b.AddStructToGenerateTS(packageName, name, s)
|
||||||
|
//}
|
||||||
|
|
||||||
|
outputs = append(outputs, thisParam)
|
||||||
|
}
|
||||||
|
boundMethod.Outputs = outputs
|
||||||
|
|
||||||
|
// Save method in result
|
||||||
|
result = append(result, boundMethod)
|
||||||
|
|
||||||
|
}
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// isStructPtr returns true if the value given is a
|
||||||
|
// pointer to a struct
|
||||||
|
func isStructPtr(value interface{}) bool {
|
||||||
|
return reflect.ValueOf(value).Kind() == reflect.Ptr &&
|
||||||
|
reflect.ValueOf(value).Elem().Kind() == reflect.Struct
|
||||||
|
}
|
||||||
|
|
||||||
|
// isFunction returns true if the given value is a function
|
||||||
|
func isFunction(value interface{}) bool {
|
||||||
|
return reflect.ValueOf(value).Kind() == reflect.Func
|
||||||
|
}
|
||||||
|
|
||||||
|
// isStructPtr returns true if the value given is a struct
|
||||||
|
func isStruct(value interface{}) bool {
|
||||||
|
return reflect.ValueOf(value).Kind() == reflect.Struct
|
||||||
|
}
|
||||||
|
|
||||||
|
func getPackageName(in string) string {
|
||||||
|
result := strings.Split(in, ".")[0]
|
||||||
|
result = strings.ReplaceAll(result, "[]", "")
|
||||||
|
result = strings.ReplaceAll(result, "*", "")
|
||||||
|
return result
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user