[runtime] Add cancelation of bound method calls and context passing

This commit is contained in:
stffabi
2024-03-04 10:34:14 +01:00
parent 7e687750b2
commit bfe9a9d015
25 changed files with 319 additions and 124 deletions
@@ -1,6 +1,7 @@
package assetserver
import (
"context"
"fmt"
"net/http"
"net/url"
@@ -106,7 +107,10 @@ func (a *AssetServer) processWebViewRequestInternal(r webview.Request) {
}
defer body.Close()
req, err := http.NewRequest(method, uri, body)
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
req, err := http.NewRequestWithContext(ctx, method, uri, body)
if err != nil {
a.webviewRequestErrorHandler(uri, rw, fmt.Errorf("HTTP-Request: %w", err))
return
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+8 -4
View File
@@ -155,7 +155,7 @@ func (p *Project) GenerateBinding(thisStructName string, method *BoundMethod, us
}
result = strings.ReplaceAll(result, "Comments", comments)
var params string
for _, input := range method.Inputs {
for _, input := range method.JSInputs() {
input.project = p
inputName := sanitiseJSVarName(input.Name)
pkgName := getPackageName(input)
@@ -181,7 +181,7 @@ func (p *Project) GenerateBinding(thisStructName string, method *BoundMethod, us
//}
result = strings.ReplaceAll(result, "* @param names {string}", params)
var inputs string
for _, input := range method.Inputs {
for _, input := range method.JSInputs() {
pkgName := getPackageName(input)
if pkgName != "" {
models = append(models, pkgName)
@@ -256,7 +256,7 @@ func (p *Project) GenerateBindingTypescript(thisStructName string, method *Bound
}
result = strings.ReplaceAll(result, "Comments", comments)
var params string
for _, input := range method.Inputs {
for _, input := range method.JSInputs() {
input.project = p
inputName := sanitiseJSVarName(input.Name)
pkgName := getPackageName(input)
@@ -279,7 +279,7 @@ func (p *Project) GenerateBindingTypescript(thisStructName string, method *Bound
// params = "\n" + params
//}
var inputs string
for _, input := range method.Inputs {
for _, input := range method.JSInputs() {
pkgName := getPackageName(input)
if pkgName != "" {
models = append(models, pkgName)
@@ -341,6 +341,10 @@ func getPackageName(input *Parameter) string {
return result
}
func isContext(input *Parameter) bool {
return input.Type.Package == "context" && input.Type.Name == "Context"
}
func (p *Project) GenerateBindings(bindings map[string]map[string][]*BoundMethod, useIDs bool, useTypescript bool) map[string]map[string]string {
var result = make(map[string]map[string]string)
+12 -1
View File
@@ -3,7 +3,6 @@ package parser
import (
"errors"
"fmt"
"github.com/wailsapp/wails/v3/internal/flags"
"go/ast"
"go/build"
"go/parser"
@@ -16,6 +15,8 @@ import (
"strings"
"time"
"github.com/wailsapp/wails/v3/internal/flags"
"github.com/samber/lo"
"github.com/wailsapp/wails/v3/internal/hash"
)
@@ -138,6 +139,16 @@ type BoundMethod struct {
Alias *uint32
}
func (m BoundMethod) JSInputs() []*Parameter {
if len(m.Inputs) > 0 {
if firstArg := m.Inputs[0]; isContext(firstArg) {
return m.Inputs[1:]
}
}
return m.Inputs
}
func (m BoundMethod) IDAsString() string {
return strconv.Itoa(int(m.ID))
}
@@ -13,3 +13,13 @@ import {Call} from '@wailsio/runtime';
export async function Greet(name) {
return Call.ByID(1411160069, ...Array.prototype.slice.call(arguments, 0));
}
/**
* Greet someone
* @function GreetWithContext
* @param name {string}
* @returns {Promise<string>}
**/
export async function GreetWithContext(name) {
return Call.ByID(1310150960, ...Array.prototype.slice.call(arguments, 0));
}
@@ -13,3 +13,13 @@ import {Call} from '@wailsio/runtime';
export async function Greet(name) {
return Call.ByName("main.GreetService.Greet", ...Array.prototype.slice.call(arguments, 0));
}
/**
* Greet someone
* @function GreetWithContext
* @param name {string}
* @returns {Promise<string>}
**/
export async function GreetWithContext(name) {
return Call.ByName("main.GreetService.GreetWithContext", ...Array.prototype.slice.call(arguments, 0));
}
@@ -7,3 +7,8 @@ export async function Greet(name: string) : Promise<string> {
return Call.ByName("main.GreetService.Greet", name);
}
// Greet someone
export async function GreetWithContext(name: string) : Promise<string> {
return Call.ByName("main.GreetService.GreetWithContext", name);
}
@@ -7,3 +7,8 @@ export async function Greet(name: string) : Promise<string> {
return Call.ByID(1411160069, name);
}
// Greet someone
export async function GreetWithContext(name: string) : Promise<string> {
return Call.ByID(1310150960, name);
}
+8 -1
View File
@@ -1,9 +1,11 @@
package main
import (
"context"
_ "embed"
"github.com/wailsapp/wails/v3/pkg/application"
"log"
"github.com/wailsapp/wails/v3/pkg/application"
)
// GreetService is great
@@ -17,6 +19,11 @@ func (*GreetService) Greet(name string) string {
return "Hello " + name
}
// Greet someone
func (*GreetService) GreetWithContext(ctx context.Context, name string) string {
return "Hello " + name
}
func NewGreetService() *GreetService {
return &GreetService{}
}
+1
View File
@@ -35,6 +35,7 @@ tasks:
- build:production
cmds:
- cmd: wails3 tool cp ../commands/build_assets/runtime/runtime.js ../../examples/binding/assets/runtime.js
- cmd: wails3 tool cp ../commands/build_assets/runtime/runtime.js ../../examples/frameless/assets/runtime.js
- cmd: wails3 tool cp ../commands/build_assets/runtime/runtime.js ../../examples/window-api/assets/runtime.js
- cmd: wails3 tool cp ../commands/build_assets/runtime/runtime.js ../../examples/wml/assets/runtime.js
@@ -20,6 +20,7 @@ window._wails.callErrorHandler = errorHandler;
const CallBinding = 0;
const call = newRuntimeCallerWithID(objectNames.Call, '');
const cancelCall = newRuntimeCallerWithID(objectNames.CancelCall, '');
let callResponses = new Map();
/**
@@ -84,18 +85,36 @@ function getAndDeleteResponse(id) {
*
* @param {string|number} type - The type of call to execute.
* @param {Object} [options={}] - Additional options for the call.
* @return {Promise} - A promise that will be resolved or rejected based on the result of the call.
* @return {Promise} - A promise that will be resolved or rejected based on the result of the call. It also has a cancel method to cancel a long running request.
*/
function callBinding(type, options = {}) {
return new Promise((resolve, reject) => {
const id = generateID();
const id = generateID();
const doCancel = () => { cancelCall(type, {"call-id": id}) };
var queuedCancel = false, callRunning = false;
var p = new Promise((resolve, reject) => {
options["call-id"] = id;
callResponses.set(id, { resolve, reject });
call(type, options).catch((error) => {
reject(error);
callResponses.delete(id);
});
call(type, options).
then((_) => {
callRunning = true;
if (queuedCancel) {
doCancel();
}
}).
catch((error) => {
reject(error);
callResponses.delete(id);
});
});
p.cancel = () => {
if (callRunning) {
doCancel();
} else {
queuedCancel = true;
}
};
return p;
}
/**
@@ -25,6 +25,7 @@ export const objectNames = {
Screens: 7,
System: 8,
Browser: 9,
CancelCall: 10,
}
export let clientId = nanoid();