mirror of
https://github.com/GopeedLab/gopeed.git
synced 2026-11-05 16:15:43 +00:00
141 lines
4.1 KiB
Go
141 lines
4.1 KiB
Go
package download
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"net/http"
|
|
"strings"
|
|
|
|
"github.com/GopeedLab/gopeed/pkg/base"
|
|
btProtocol "github.com/GopeedLab/gopeed/pkg/protocol/bt"
|
|
httpProtocol "github.com/GopeedLab/gopeed/pkg/protocol/http"
|
|
"github.com/GopeedLab/gopeed/pkg/util"
|
|
"github.com/dop251/goja"
|
|
)
|
|
|
|
// ExtensionTaskRequest exposes request operations without exposing the backing task.
|
|
// It always reads the current request so a retained handle sees subsequent updates.
|
|
type ExtensionTaskRequest struct {
|
|
*base.Request
|
|
task *Task
|
|
}
|
|
|
|
// SetUrl replaces the task request URL.
|
|
func (r *ExtensionTaskRequest) SetUrl(url string) { r.task.Meta.Req.URL = url }
|
|
|
|
// SetLabels replaces all labels on the request.
|
|
func (r *ExtensionTaskRequest) SetLabels(labels map[string]string) {
|
|
r.Labels = labels
|
|
}
|
|
|
|
// PutLabel sets a label on the request.
|
|
func (r *ExtensionTaskRequest) 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.
|
|
func (r *ExtensionTaskRequest) DelLabel(key string) {
|
|
delete(r.Labels, key)
|
|
}
|
|
|
|
// mutateTaskExtra converts into an independent protocol value before mutation.
|
|
// Other protocols are a no-op. Failed conversion or mutation must not change the live request.
|
|
func mutateTaskExtra[E any](task *Task, protocol string, mutate func(*E) error) error {
|
|
if task.Protocol != protocol {
|
|
return nil
|
|
}
|
|
if task.Meta == nil || task.Meta.Req == nil {
|
|
return fmt.Errorf("task request is missing")
|
|
}
|
|
var extra E
|
|
if err := util.MapToStruct(task.Meta.Req.Extra, &extra); err != nil {
|
|
return err
|
|
}
|
|
if err := mutate(&extra); err != nil {
|
|
return err
|
|
}
|
|
task.Meta.Req.Extra = &extra
|
|
return nil
|
|
}
|
|
|
|
func (t *ExtensionTaskRequest) SetMethod(method string) error {
|
|
return mutateTaskExtra(t.task, "http", func(extra *httpProtocol.ReqExtra) error { extra.Method = method; return nil })
|
|
}
|
|
|
|
func (t *ExtensionTaskRequest) SetBody(body string) error {
|
|
return mutateTaskExtra(t.task, "http", func(extra *httpProtocol.ReqExtra) error { extra.Body = body; return nil })
|
|
}
|
|
|
|
// decodeHeaders omits undefined properties and rejects non-string values.
|
|
func decodeHeaders(value *goja.Object) (map[string]string, error) {
|
|
if value == nil {
|
|
return nil, fmt.Errorf("headers must be an object")
|
|
}
|
|
data, err := value.MarshalJSON()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
var input map[string]*string
|
|
if err := json.Unmarshal(data, &input); err != nil {
|
|
return nil, err
|
|
}
|
|
if input == nil {
|
|
return nil, fmt.Errorf("headers must be an object")
|
|
}
|
|
headers := make(map[string]string, len(input))
|
|
seen := make(map[string]bool, len(input))
|
|
for name, value := range input {
|
|
if value == nil {
|
|
return nil, fmt.Errorf("header %q must be a string", name)
|
|
}
|
|
lower := strings.ToLower(name)
|
|
if seen[lower] {
|
|
return nil, fmt.Errorf("duplicate header name %q", name)
|
|
}
|
|
seen[lower] = true
|
|
headers[http.CanonicalHeaderKey(name)] = *value
|
|
}
|
|
return headers, nil
|
|
}
|
|
|
|
func (t *ExtensionTaskRequest) SetHeaders(headers *goja.Object) error {
|
|
return mutateTaskExtra(t.task, "http", func(extra *httpProtocol.ReqExtra) error {
|
|
values, err := decodeHeaders(headers)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
extra.Header = values
|
|
return nil
|
|
})
|
|
}
|
|
|
|
func (t *ExtensionTaskRequest) PutHeader(name, value string) error {
|
|
return mutateTaskExtra(t.task, "http", func(extra *httpProtocol.ReqExtra) error {
|
|
if extra.Header == nil {
|
|
extra.Header = make(map[string]string)
|
|
}
|
|
deleteHeader(extra.Header, name)
|
|
extra.Header[http.CanonicalHeaderKey(name)] = value
|
|
return nil
|
|
})
|
|
}
|
|
|
|
func (t *ExtensionTaskRequest) DelHeader(name string) error {
|
|
return mutateTaskExtra(t.task, "http", func(extra *httpProtocol.ReqExtra) error { deleteHeader(extra.Header, name); return nil })
|
|
}
|
|
|
|
func deleteHeader(headers map[string]string, name string) {
|
|
for key := range headers {
|
|
if strings.EqualFold(key, name) {
|
|
delete(headers, key)
|
|
}
|
|
}
|
|
}
|
|
|
|
func (t *ExtensionTaskRequest) SetTrackers(trackers []string) error {
|
|
return mutateTaskExtra(t.task, "bt", func(extra *btProtocol.ReqExtra) error { extra.Trackers = append([]string{}, trackers...); return nil })
|
|
}
|