mirror of
https://github.com/GopeedLab/gopeed.git
synced 2026-11-04 07:45:30 +00:00
fix(extension): restore deprecated request APIs for compatibility (#1628)
This commit is contained in:
@@ -27,6 +27,33 @@ type Request struct {
|
||||
SkipVerifyCert bool `json:"skipVerifyCert"`
|
||||
}
|
||||
|
||||
// SetLabels replaces all labels on the request.
|
||||
//
|
||||
// Deprecated: In onResolve and onDone, assign request labels directly.
|
||||
// In onStart and onError, use task.meta.req.setLabels instead.
|
||||
func (r *Request) SetLabels(labels map[string]string) {
|
||||
r.Labels = labels
|
||||
}
|
||||
|
||||
// PutLabel sets a label on the request.
|
||||
//
|
||||
// Deprecated: In onResolve and onDone, assign request labels directly.
|
||||
// In onStart and onError, use task.meta.req.putLabel instead.
|
||||
func (r *Request) PutLabel(key, value string) {
|
||||
if r.Labels == nil {
|
||||
r.Labels = make(map[string]string)
|
||||
}
|
||||
r.Labels[key] = value
|
||||
}
|
||||
|
||||
// DelLabel deletes a label from the request.
|
||||
//
|
||||
// Deprecated: In onResolve and onDone, delete request labels directly.
|
||||
// In onStart and onError, use task.meta.req.delLabel instead.
|
||||
func (r *Request) DelLabel(key string) {
|
||||
delete(r.Labels, key)
|
||||
}
|
||||
|
||||
func (r *Request) Validate() error {
|
||||
if r.URL == "" {
|
||||
return fmt.Errorf("invalid request url")
|
||||
|
||||
@@ -46,7 +46,7 @@ type generationTestManager struct {
|
||||
func TestExtensionTaskMethodsMatchEventCapabilities(t *testing.T) {
|
||||
taskType := reflect.TypeOf((*Task)(nil))
|
||||
for _, typ := range []reflect.Type{taskType, reflect.TypeOf((*ExtensionTask)(nil)), reflect.TypeOf((*OnErrorExtensionTask)(nil))} {
|
||||
for _, name := range []string{"SetUrl", "SetExtra", "PatchExtra", "PatchHeaders", "SetMethod", "SetBody", "SetHeaders", "PutHeader", "DelHeader", "SetTrackers"} {
|
||||
for _, name := range []string{"SetExtra", "PatchExtra", "PatchHeaders", "SetMethod", "SetBody", "SetHeaders", "PutHeader", "DelHeader", "SetTrackers"} {
|
||||
if _, ok := typ.MethodByName(name); ok {
|
||||
t.Fatalf("%v unexpectedly exposes %s", typ, name)
|
||||
}
|
||||
@@ -79,6 +79,11 @@ func TestExtensionTaskMethodsMatchEventCapabilities(t *testing.T) {
|
||||
}
|
||||
|
||||
extensionTaskType := reflect.TypeOf((*ExtensionTask)(nil))
|
||||
for _, typ := range []reflect.Type{extensionTaskType, reflect.TypeOf((*OnErrorExtensionTask)(nil))} {
|
||||
if _, ok := typ.MethodByName("SetUrl"); !ok {
|
||||
t.Fatalf("%v does not expose the deprecated SetUrl alias", typ)
|
||||
}
|
||||
}
|
||||
if _, ok := extensionTaskType.MethodByName("Continue"); ok {
|
||||
t.Fatal("non-error extension task unexpectedly exposes Continue")
|
||||
}
|
||||
|
||||
@@ -825,6 +825,13 @@ func newOnDoneExtensionTask(task *Task) *Task {
|
||||
return cloneExtensionTask(task)
|
||||
}
|
||||
|
||||
// SetUrl replaces the task request URL.
|
||||
//
|
||||
// Deprecated: Use task.meta.req.setUrl instead.
|
||||
func (t *ExtensionTask) SetUrl(url string) {
|
||||
t.Meta.Req.SetUrl(url)
|
||||
}
|
||||
|
||||
func (t *OnErrorExtensionTask) Continue() error {
|
||||
return t.download.Continue(&TaskFilter{
|
||||
IDs: []string{t.ID},
|
||||
|
||||
@@ -0,0 +1,89 @@
|
||||
package download
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/GopeedLab/gopeed/internal/fetcher"
|
||||
"github.com/GopeedLab/gopeed/pkg/base"
|
||||
)
|
||||
|
||||
func TestExtensionDeprecatedRequestAPIs(t *testing.T) {
|
||||
for _, event := range []ActivationEvent{EventOnResolve, EventOnStart, EventOnError, EventOnDone} {
|
||||
for _, withLabels := range []bool{false, true} {
|
||||
t.Run(fmt.Sprintf("%s/labels=%v", event, withLabels), func(t *testing.T) {
|
||||
d := NewDownloader(&DownloaderConfig{Storage: NewMemStorage(), StorageDir: t.TempDir()})
|
||||
if err := d.Setup(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer d.Clear()
|
||||
|
||||
extDir := t.TempDir()
|
||||
manifest := fmt.Sprintf(`{"name":"legacy-request","title":"Legacy request APIs","version":"0.0.1","scripts":[{"event":%q,"match":{"urls":["*://example.com/*"]},"entry":"index.js"}]}`, event)
|
||||
request := "ctx.task.meta.req"
|
||||
urlMutation := ""
|
||||
if event == EventOnResolve {
|
||||
request = "ctx.req"
|
||||
} else if event == EventOnStart || event == EventOnError {
|
||||
urlMutation = `await ctx.task.setUrl('https://example.com/legacy');
|
||||
if (req.url !== 'https://example.com/legacy') throw new Error('legacy URL did not write through');
|
||||
await req.setUrl('https://example.com/new');
|
||||
if (req.url !== 'https://example.com/new') throw new Error('new URL did not write through');
|
||||
await ctx.task.setUrl('https://example.com/final');`
|
||||
}
|
||||
script := fmt.Sprintf(`gopeed.events.%s(async ctx => {
|
||||
const req = %s;
|
||||
await req.delLabel('missing');
|
||||
await req.putLabel('initial', 'yes');
|
||||
if (req.labels.initial !== 'yes') throw new Error('putLabel did not initialize labels');
|
||||
await req.setLabels({keep: 'yes', remove: 'yes'});
|
||||
if (req.labels.initial !== undefined || req.labels.old !== undefined) throw new Error('setLabels did not replace labels');
|
||||
await req.putLabel('added', 'yes');
|
||||
await req.delLabel('remove');
|
||||
if (req.labels.keep !== 'yes' || req.labels.added !== 'yes' || req.labels.remove !== undefined) throw new Error('label mutation failed');
|
||||
%s
|
||||
await req.putLabel('completed', 'yes');
|
||||
});`, event, request, urlMutation)
|
||||
for name, content := range map[string]string{"manifest.json": manifest, "index.js": script} {
|
||||
if err := os.WriteFile(filepath.Join(extDir, name), []byte(content), 0600); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
if _, err := d.InstallExtensionByFolder(extDir, false); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
req := &base.Request{URL: "https://example.com/original"}
|
||||
if withLabels {
|
||||
req.Labels = map[string]string{"old": "yes"}
|
||||
}
|
||||
task := &Task{Protocol: "http", Meta: &fetcher.FetcherMeta{Req: req, Opts: &base.Options{}}}
|
||||
switch event {
|
||||
case EventOnResolve:
|
||||
if _, err := d.triggerOnResolve(req); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
case EventOnStart:
|
||||
d.triggerOnStart(task)
|
||||
case EventOnError:
|
||||
d.triggerOnError(task, errors.New("retry"))
|
||||
case EventOnDone:
|
||||
d.triggerOnDone(task)
|
||||
}
|
||||
if !reflect.DeepEqual(req.Labels, map[string]string{"keep": "yes", "added": "yes", "completed": "yes"}) {
|
||||
t.Fatalf("legacy handler did not update the original request: %#v", req.Labels)
|
||||
}
|
||||
expectedURL := "https://example.com/original"
|
||||
if urlMutation != "" {
|
||||
expectedURL = "https://example.com/final"
|
||||
}
|
||||
if req.URL != expectedURL {
|
||||
t.Fatalf("URL = %q, want %q", req.URL, expectedURL)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -152,7 +152,7 @@ func TestExtensionOnErrorRequestWritesToOriginalTask(t *testing.T) {
|
||||
request.setHeaders({Keep:'new'});
|
||||
request.putHeader('Authorization','Bearer new');
|
||||
request.setMethod('POST');
|
||||
if (typeof task.setUrl !== 'undefined' || typeof task.extra !== 'undefined') throw new Error('legacy task API');
|
||||
if (typeof task.setUrl !== 'function' || typeof task.extra !== 'undefined') throw new Error('unexpected legacy task API');
|
||||
request.setUrl('https://example.com/new');
|
||||
request.setLabels({keep:'yes',remove:'yes'});
|
||||
request.putLabel('new','value');
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
gopeed.events.onResolve(async function (ctx) {
|
||||
for (const method of ['setUrl', 'setLabels', 'putLabel', 'delLabel', 'setMethod', 'putHeader', 'setTrackers']) {
|
||||
for (const method of ['setUrl', 'setMethod', 'putHeader', 'setTrackers']) {
|
||||
if (typeof ctx.req[method] !== 'undefined') throw new Error(`onResolve exposes ${method}`);
|
||||
}
|
||||
ctx.req.labels = { replaced: "true", removed: "true" };
|
||||
|
||||
Reference in New Issue
Block a user