Files

426 lines
10 KiB
Go

package rest
import (
"io"
"net/http"
"net/url"
"runtime"
"github.com/GopeedLab/gopeed/pkg/base"
"github.com/GopeedLab/gopeed/pkg/download"
"github.com/GopeedLab/gopeed/pkg/rest/model"
"github.com/gorilla/mux"
)
func Info(w http.ResponseWriter, r *http.Request) {
info := map[string]any{
"version": base.Version,
"runtime": runtime.Version(),
"os": runtime.GOOS,
"arch": runtime.GOARCH,
"inDocker": base.InDocker == "true",
}
WriteJson(w, model.NewOkResult(info))
}
func Resolve(w http.ResponseWriter, r *http.Request) {
var req model.ResolveTask
if ReadJson(r, w, &req) {
rr, err := Downloader.Resolve(req.Req, req.Opts)
if err != nil {
WriteJson(w, model.NewErrorResult(err.Error()))
return
}
WriteJson(w, model.NewOkResult(rr))
}
}
func CreateTask(w http.ResponseWriter, r *http.Request) {
var req model.CreateTask
if ReadJson(r, w, &req) {
var (
taskId string
err error
)
if req.Rid != "" {
taskId, err = Downloader.Create(req.Rid)
} else if req.Req != nil {
taskId, err = Downloader.CreateDirect(req.Req, req.Opts)
} else {
WriteJson(w, model.NewErrorResult("param invalid: rid or req", model.CodeInvalidParam))
return
}
if err != nil {
WriteJson(w, model.NewErrorResult(err.Error()))
return
}
WriteJson(w, model.NewOkResult(taskId))
}
}
func CreateTaskBatch(w http.ResponseWriter, r *http.Request) {
var req base.CreateTaskBatch
if ReadJson(r, w, &req) {
if len(req.Reqs) == 0 {
WriteJson(w, model.NewErrorResult("param invalid: reqs", model.CodeInvalidParam))
return
}
taskIds, err := Downloader.CreateDirectBatch(&req)
if err != nil {
WriteJson(w, model.NewErrorResult(err.Error()))
return
}
WriteJson(w, model.NewOkResult(taskIds))
}
}
func PatchTask(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
taskId := vars["id"]
if taskId == "" {
WriteJson(w, model.NewErrorResult("param invalid: id", model.CodeInvalidParam))
return
}
var req model.ResolveTask
if ReadJson(r, w, &req) {
if err := Downloader.Patch(taskId, req.Req, req.Opts); err != nil {
if err == download.ErrTaskNotFound {
WriteJson(w, model.NewErrorResult("task not found", model.CodeTaskNotFound))
return
}
WriteJson(w, model.NewErrorResult(err.Error()))
return
}
WriteJson(w, model.NewNilResult())
}
}
func PauseTask(w http.ResponseWriter, r *http.Request) {
filter, errResult := parseIdFilter(r)
if errResult != nil {
WriteJson(w, errResult)
return
}
if err := Downloader.Pause(filter); err != nil {
WriteJson(w, model.NewErrorResult(err.Error()))
return
}
WriteJson(w, model.NewNilResult())
}
func PauseTasks(w http.ResponseWriter, r *http.Request) {
filter, errResult := parseFilter(r)
if errResult != nil {
WriteJson(w, errResult)
return
}
if err := Downloader.Pause(filter); err != nil {
WriteJson(w, model.NewErrorResult(err.Error()))
return
}
WriteJson(w, model.NewNilResult())
}
func ContinueTask(w http.ResponseWriter, r *http.Request) {
filter, errResult := parseIdFilter(r)
if errResult != nil {
WriteJson(w, errResult)
return
}
if err := Downloader.Continue(filter); err != nil {
WriteJson(w, model.NewErrorResult(err.Error()))
return
}
WriteJson(w, model.NewNilResult())
}
func ContinueTasks(w http.ResponseWriter, r *http.Request) {
filter, errResult := parseFilter(r)
if errResult != nil {
WriteJson(w, errResult)
return
}
if err := Downloader.Continue(filter); err != nil {
WriteJson(w, model.NewErrorResult(err.Error()))
return
}
WriteJson(w, model.NewNilResult())
}
func DeleteTask(w http.ResponseWriter, r *http.Request) {
filter, errResult := parseIdFilter(r)
if errResult != nil {
WriteJson(w, errResult)
return
}
force := r.FormValue("force")
if err := Downloader.Delete(filter, force == "true"); err != nil {
WriteJson(w, model.NewErrorResult(err.Error()))
return
}
WriteJson(w, model.NewNilResult())
}
func DeleteTasks(w http.ResponseWriter, r *http.Request) {
filter, errResult := parseFilter(r)
if errResult != nil {
WriteJson(w, errResult)
return
}
force := r.FormValue("force")
if err := Downloader.Delete(filter, force == "true"); err != nil {
WriteJson(w, model.NewErrorResult(err.Error()))
return
}
WriteJson(w, model.NewNilResult())
}
func GetTask(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
taskId := vars["id"]
if taskId == "" {
WriteJson(w, model.NewErrorResult("param invalid: id", model.CodeInvalidParam))
return
}
task := Downloader.GetTask(taskId)
if task == nil {
WriteJson(w, model.NewErrorResult("task not found", model.CodeTaskNotFound))
return
}
WriteJson(w, model.NewOkResult(task))
}
func GetTasks(w http.ResponseWriter, r *http.Request) {
filter, errResult := parseFilter(r)
if errResult != nil {
WriteJson(w, errResult)
return
}
tasks := Downloader.GetTasksByFilter(filter)
WriteJson(w, model.NewOkResult(tasks))
}
func GetConfig(w http.ResponseWriter, r *http.Request) {
WriteJson(w, model.NewOkResult(getServerConfig()))
}
func PutConfig(w http.ResponseWriter, r *http.Request) {
var cfg base.DownloaderStoreConfig
if ReadJson(r, w, &cfg) {
if err := Downloader.PutConfig(&cfg); err != nil {
WriteJson(w, model.NewErrorResult(err.Error()))
return
}
}
WriteJson(w, model.NewNilResult())
}
func InstallExtension(w http.ResponseWriter, r *http.Request) {
var req model.InstallExtension
if ReadJson(r, w, &req) {
var (
installedExt *download.Extension
err error
)
if req.DevMode {
installedExt, err = Downloader.InstallExtensionByFolder(req.URL, true)
} else {
installedExt, err = Downloader.InstallExtensionByGit(req.URL)
}
if err != nil {
WriteJson(w, model.NewErrorResult(err.Error()))
return
}
WriteJson(w, model.NewOkResult(installedExt.Identity))
}
}
func GetExtensions(w http.ResponseWriter, r *http.Request) {
list := Downloader.GetExtensions()
WriteJson(w, model.NewOkResult(list))
}
func GetExtension(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
identity := vars["identity"]
ext, err := Downloader.GetExtension(identity)
if err != nil {
WriteJson(w, model.NewErrorResult(err.Error()))
return
}
WriteJson(w, model.NewOkResult(ext))
}
func UpdateExtensionSettings(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
identity := vars["identity"]
var req model.UpdateExtensionSettings
if ReadJson(r, w, &req) {
if err := Downloader.UpdateExtensionSettings(identity, req.Settings); err != nil {
WriteJson(w, model.NewErrorResult(err.Error()))
return
}
}
WriteJson(w, model.NewNilResult())
}
func SwitchExtension(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
identity := vars["identity"]
var switchExtension model.SwitchExtension
if ReadJson(r, w, &switchExtension) {
if err := Downloader.SwitchExtension(identity, switchExtension.Status); err != nil {
WriteJson(w, model.NewErrorResult(err.Error()))
return
}
}
WriteJson(w, model.NewNilResult())
}
func DeleteExtension(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
identity := vars["identity"]
if err := Downloader.DeleteExtension(identity); err != nil {
WriteJson(w, model.NewErrorResult(err.Error()))
return
}
WriteJson(w, model.NewNilResult())
}
func UpdateCheckExtension(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
identity := vars["identity"]
newVersion, err := Downloader.UpgradeCheckExtension(identity)
if err != nil {
WriteJson(w, model.NewErrorResult(err.Error()))
return
}
WriteJson(w, model.NewOkResult(&model.UpdateCheckExtensionResp{
NewVersion: newVersion,
}))
}
func UpdateExtension(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
identity := vars["identity"]
if err := Downloader.UpgradeExtension(identity); err != nil {
WriteJson(w, model.NewErrorResult(err.Error()))
return
}
WriteJson(w, model.NewNilResult())
}
func DoProxy(w http.ResponseWriter, r *http.Request) {
target := r.Header.Get("X-Target-Uri")
if target == "" {
writeError(w, "param invalid: X-Target-Uri")
return
}
targetUrl, err := url.Parse(target)
if err != nil {
writeError(w, err.Error())
return
}
r.RequestURI = ""
r.URL = targetUrl
r.Host = targetUrl.Host
r.Header.Del("Authorization")
r.Header.Del("X-Target-Uri")
resp, err := http.DefaultClient.Do(r)
if err != nil {
writeError(w, err.Error())
return
}
defer resp.Body.Close()
for k, vv := range resp.Header {
for _, v := range vv {
w.Header().Set(k, v)
}
}
w.WriteHeader(resp.StatusCode)
buf, err := io.ReadAll(resp.Body)
if err != nil {
writeError(w, err.Error())
return
}
w.Write(buf)
}
func GetStats(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
taskId := vars["id"]
if taskId == "" {
WriteJson(w, model.NewErrorResult("param invalid: id", model.CodeInvalidParam))
return
}
statsResult, err := Downloader.Stats(taskId)
if err != nil {
writeError(w, err.Error())
return
}
WriteJson(w, model.NewOkResult(statsResult))
}
func parseIdFilter(r *http.Request) (*download.TaskFilter, any) {
vars := mux.Vars(r)
taskId := vars["id"]
if taskId == "" {
return nil, model.NewErrorResult("param invalid: id", model.CodeInvalidParam)
}
filter := &download.TaskFilter{
IDs: []string{taskId},
}
return filter, nil
}
func parseFilter(r *http.Request) (*download.TaskFilter, any) {
if err := r.ParseForm(); err != nil {
return nil, model.NewErrorResult(err.Error())
}
filter := &download.TaskFilter{
IDs: r.Form["id"],
Statuses: convertStatues(r.Form["status"]),
NotStatuses: convertStatues(r.Form["notStatus"]),
}
return filter, nil
}
func convertStatues(statues []string) []base.Status {
result := make([]base.Status, 0)
for _, status := range statues {
result = append(result, base.Status(status))
}
return result
}
func writeError(w http.ResponseWriter, msg string) {
w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte(msg))
}
func getServerConfig() *base.DownloaderStoreConfig {
cfg, _ := Downloader.GetConfig()
return cfg
}
func TestWebhook(w http.ResponseWriter, r *http.Request) {
var req model.TestWebhookReq
if ReadJson(r, w, &req) {
if err := Downloader.TestWebhookUrl(req.URL); err != nil {
WriteJson(w, model.NewErrorResult(err.Error()))
return
}
WriteJson(w, model.NewNilResult())
}
}