mirror of
https://github.com/GopeedLab/gopeed.git
synced 2026-11-11 10:54:08 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
76bec67ab2 | ||
|
|
a2a9e3dc2a | ||
|
|
9a5680fb45 | ||
|
|
75a8a3a9ac | ||
|
|
3e8c85b945 | ||
|
|
90f70d1bf6 | ||
|
|
20a70d7f91 | ||
|
|
d33546a4b5 |
No files matched your search
@@ -34,7 +34,7 @@ jobs:
|
|||||||
|
|
||||||
build-windows:
|
build-windows:
|
||||||
if: ${{ github.event.inputs.platform == 'all' || github.event.inputs.platform == 'windows' }}
|
if: ${{ github.event.inputs.platform == 'all' || github.event.inputs.platform == 'windows' }}
|
||||||
runs-on: windows-latest
|
runs-on: windows-2022
|
||||||
needs: [get-release]
|
needs: [get-release]
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v3
|
||||||
@@ -258,7 +258,7 @@ jobs:
|
|||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
os: [ubuntu-24.04, ubuntu-24.04-arm]
|
os: [ubuntu-22.04, ubuntu-22.04-arm]
|
||||||
needs: [get-release]
|
needs: [get-release]
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v3
|
||||||
|
|||||||
@@ -69,7 +69,7 @@ jobs:
|
|||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
os: [windows-latest, macos-latest, ubuntu-24.04, ubuntu-24.04-arm]
|
os: [windows-latest, macos-latest, ubuntu-22.04, ubuntu-22.04-arm]
|
||||||
needs: [test]
|
needs: [test]
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v3
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package main
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/GopeedLab/gopeed/pkg/base"
|
"github.com/GopeedLab/gopeed/pkg/base"
|
||||||
"github.com/GopeedLab/gopeed/pkg/download"
|
"github.com/GopeedLab/gopeed/pkg/download"
|
||||||
"github.com/GopeedLab/gopeed/pkg/protocol/http"
|
"github.com/GopeedLab/gopeed/pkg/protocol/http"
|
||||||
|
|||||||
@@ -0,0 +1,19 @@
|
|||||||
|
//go:build !windows
|
||||||
|
// +build !windows
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Dial() (net.Conn, error) {
|
||||||
|
// Get binary path
|
||||||
|
exe, err := os.Executable()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return net.Dial("unix", filepath.Join(filepath.Dir(exe), "gopeed_host.sock"))
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net"
|
||||||
|
|
||||||
|
"github.com/Microsoft/go-winio"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Dial() (net.Conn, error) {
|
||||||
|
return winio.DialPipe(`\\.\pipe\gopeed_host`, nil)
|
||||||
|
}
|
||||||
+69
-24
@@ -1,22 +1,24 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
|
"context"
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
"net"
|
||||||
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"time"
|
||||||
|
|
||||||
"github.com/pkg/browser"
|
"github.com/pkg/browser"
|
||||||
"github.com/shirou/gopsutil/v4/process"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const identifier = "gopeed"
|
|
||||||
|
|
||||||
type Message struct {
|
type Message struct {
|
||||||
Method string `json:"method"`
|
Method string `json:"method"`
|
||||||
|
Meta map[string]any `json:"meta"`
|
||||||
Params json.RawMessage `json:"params"`
|
Params json.RawMessage `json:"params"`
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -26,31 +28,74 @@ type Response struct {
|
|||||||
Message string `json:"message,omitempty"`
|
Message string `json:"message,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
var apiMap = map[string]func(params json.RawMessage) (data any, err error){
|
func check() (data bool, err error) {
|
||||||
"ping": func(params json.RawMessage) (data any, err error) {
|
conn, err := Dial()
|
||||||
processes, err := process.Processes()
|
if err != nil {
|
||||||
if err != nil {
|
return false, err
|
||||||
return false, err
|
}
|
||||||
}
|
defer conn.Close()
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
|
||||||
for _, p := range processes {
|
func wakeup(hidden bool) error {
|
||||||
name, err := p.Name()
|
running, _ := check()
|
||||||
if err != nil {
|
if running {
|
||||||
continue
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if strings.Contains(strings.ToLower(name), strings.ToLower(identifier)) {
|
uri := "gopeed:"
|
||||||
return true, nil
|
if hidden {
|
||||||
}
|
uri = uri + "?hidden=true"
|
||||||
|
}
|
||||||
|
if err := browser.OpenURL(uri); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 0; i < 10; i++ {
|
||||||
|
if ok, _ := check(); ok {
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
return false, nil
|
time.Sleep(1 * time.Second)
|
||||||
|
}
|
||||||
|
return fmt.Errorf("start gopeed failed")
|
||||||
|
}
|
||||||
|
|
||||||
|
var apiMap = map[string]func(message *Message) (data any, err error){
|
||||||
|
"ping": func(message *Message) (data any, err error) {
|
||||||
|
return check()
|
||||||
},
|
},
|
||||||
"create": func(params json.RawMessage) (data any, err error) {
|
"create": func(message *Message) (data any, err error) {
|
||||||
var strParams string
|
buf, err := message.Params.MarshalJSON()
|
||||||
if err = json.Unmarshal(params, &strParams); err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
err = browser.OpenURL(fmt.Sprintf("%s:///create?params=%s", identifier, strParams))
|
|
||||||
|
silent := false
|
||||||
|
if v, ok := message.Meta["silent"]; ok {
|
||||||
|
silent, _ = v.(bool)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := wakeup(silent); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
client := &http.Client{
|
||||||
|
Transport: &http.Transport{
|
||||||
|
DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) {
|
||||||
|
return Dial()
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Timeout: 10 * time.Second,
|
||||||
|
}
|
||||||
|
req, err := http.NewRequest("POST", "http://127.0.0.1/create", bytes.NewBuffer(buf))
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if message.Meta != nil {
|
||||||
|
metaJson, _ := json.Marshal(message.Meta)
|
||||||
|
req.Header.Set("X-Gopeed-Host-Meta", string(metaJson))
|
||||||
|
}
|
||||||
|
_, err = client.Do(req)
|
||||||
return
|
return
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@@ -88,7 +133,7 @@ func main() {
|
|||||||
var data any
|
var data any
|
||||||
var err error
|
var err error
|
||||||
if handler, ok := apiMap[message.Method]; ok {
|
if handler, ok := apiMap[message.Method]; ok {
|
||||||
data, err = handler(message.Params)
|
data, err = handler(&message)
|
||||||
} else {
|
} else {
|
||||||
err = errors.New("Unknown method: " + message.Method)
|
err = errors.New("Unknown method: " + message.Method)
|
||||||
}
|
}
|
||||||
|
|||||||
+5
-6
@@ -5,7 +5,6 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
|
||||||
"syscall"
|
"syscall"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@@ -19,6 +18,7 @@ func main() {
|
|||||||
pid := flag.Int("pid", 0, "PID of the process to update")
|
pid := flag.Int("pid", 0, "PID of the process to update")
|
||||||
updateChannel := flag.String("channel", "", "Update channel")
|
updateChannel := flag.String("channel", "", "Update channel")
|
||||||
packagePath := flag.String("asset", "", "Path to the package asset")
|
packagePath := flag.String("asset", "", "Path to the package asset")
|
||||||
|
exeDir := flag.String("exeDir", "", "Directory of the entry executable")
|
||||||
logPath := flag.String("log", "", "Log file path")
|
logPath := flag.String("log", "", "Log file path")
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
|
|
||||||
@@ -43,7 +43,7 @@ func main() {
|
|||||||
restart bool
|
restart bool
|
||||||
err error
|
err error
|
||||||
)
|
)
|
||||||
if restart, err = update(*pid, *updateChannel, *packagePath); err != nil {
|
if restart, err = update(*pid, *updateChannel, *packagePath, *exeDir); err != nil {
|
||||||
log.Printf("Update failed: %v\n", err)
|
log.Printf("Update failed: %v\n", err)
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
@@ -61,7 +61,7 @@ func main() {
|
|||||||
os.Exit(0)
|
os.Exit(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
func update(pid int, updateChannel, packagePath string) (restart bool, err error) {
|
func update(pid int, updateChannel, packagePath, exeDir string) (restart bool, err error) {
|
||||||
killSignalChan := make(chan any, 1)
|
killSignalChan := make(chan any, 1)
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
@@ -76,9 +76,8 @@ func update(pid int, updateChannel, packagePath string) (restart bool, err error
|
|||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
appDir := filepath.Dir(os.Args[0])
|
log.Printf("Updating process updateChannel=%s packagePath=%s exeDir=%s\n", updateChannel, packagePath, exeDir)
|
||||||
log.Printf("Updating process updateChannel=%s packagePath=%s appDir=%s\n", updateChannel, packagePath, appDir)
|
if restart, err = install(killSignalChan, updateChannel, packagePath, exeDir); err != nil {
|
||||||
if restart, err = install(killSignalChan, updateChannel, packagePath, appDir); err != nil {
|
|
||||||
return false, errors.Wrap(err, "failed to install package")
|
return false, errors.Wrap(err, "failed to install package")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -25,16 +25,20 @@ func installByDmg(killSignalChan chan<- any, packagePath, destDir string) error
|
|||||||
mountPoint := ""
|
mountPoint := ""
|
||||||
for _, line := range strings.Split(string(output), "\n") {
|
for _, line := range strings.Split(string(output), "\n") {
|
||||||
if strings.Contains(line, "/Volumes/") {
|
if strings.Contains(line, "/Volumes/") {
|
||||||
fields := strings.Fields(line)
|
// Find the /Volumes/ path in the line
|
||||||
if len(fields) > 2 {
|
// hdiutil output format: /dev/disk4s1 Apple_HFS /Volumes/Gopeed
|
||||||
mountPoint = fields[len(fields)-1]
|
// or with sequence number: /dev/disk4s1 Apple_HFS /Volumes/Gopeed 1
|
||||||
|
idx := strings.Index(line, "/Volumes/")
|
||||||
|
if idx != -1 {
|
||||||
|
// Extract everything from /Volumes/ onwards and trim whitespace
|
||||||
|
mountPoint = strings.TrimSpace(line[idx:])
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if mountPoint == "" {
|
if mountPoint == "" {
|
||||||
return fmt.Errorf("failed to get mount point")
|
return fmt.Errorf("failed to get mount point from hdiutil output: %s", string(output))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Detach the mounted DMG
|
// Detach the mounted DMG
|
||||||
@@ -45,7 +49,7 @@ func installByDmg(killSignalChan chan<- any, packagePath, destDir string) error
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if len(matches) == 0 {
|
if len(matches) == 0 {
|
||||||
return fmt.Errorf("no .app found in dmg")
|
return fmt.Errorf("no .app found in dmg, mountPoint: %s", mountPoint)
|
||||||
}
|
}
|
||||||
|
|
||||||
killSignalChan <- nil
|
killSignalChan <- nil
|
||||||
|
|||||||
@@ -3,17 +3,18 @@ package bt
|
|||||||
import (
|
import (
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"github.com/GopeedLab/gopeed/internal/controller"
|
|
||||||
"github.com/GopeedLab/gopeed/internal/fetcher"
|
|
||||||
"github.com/GopeedLab/gopeed/internal/test"
|
|
||||||
"github.com/GopeedLab/gopeed/pkg/base"
|
|
||||||
"github.com/GopeedLab/gopeed/pkg/protocol/bt"
|
|
||||||
gohttp "net/http"
|
gohttp "net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"reflect"
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/GopeedLab/gopeed/internal/controller"
|
||||||
|
"github.com/GopeedLab/gopeed/internal/fetcher"
|
||||||
|
"github.com/GopeedLab/gopeed/internal/test"
|
||||||
|
"github.com/GopeedLab/gopeed/pkg/base"
|
||||||
|
"github.com/GopeedLab/gopeed/pkg/protocol/bt"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestFetcher_Resolve_Torrent(t *testing.T) {
|
func TestFetcher_Resolve_Torrent(t *testing.T) {
|
||||||
|
|||||||
@@ -5,11 +5,12 @@ package bt
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/anacrolix/torrent/storage"
|
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
|
||||||
|
"github.com/anacrolix/torrent/storage"
|
||||||
|
|
||||||
"github.com/anacrolix/missinggo/v2"
|
"github.com/anacrolix/missinggo/v2"
|
||||||
|
|
||||||
"github.com/anacrolix/torrent/common"
|
"github.com/anacrolix/torrent/common"
|
||||||
@@ -34,7 +35,7 @@ func newFileOpts(opts newFileClientOpts) storage.ClientImplCloser {
|
|||||||
if opts.FilePathMaker == nil {
|
if opts.FilePathMaker == nil {
|
||||||
opts.FilePathMaker = func(opts storage.FilePathMakerOpts) string {
|
opts.FilePathMaker = func(opts storage.FilePathMakerOpts) string {
|
||||||
var parts []string
|
var parts []string
|
||||||
if opts.Info.Length == 0 {
|
if opts.Info.Length == 0 || opts.File.Path == nil {
|
||||||
parts = append(parts, opts.Info.Name)
|
parts = append(parts, opts.Info.Name)
|
||||||
}
|
}
|
||||||
return filepath.Join(append(parts, opts.File.Path...)...)
|
return filepath.Join(append(parts, opts.File.Path...)...)
|
||||||
|
|||||||
@@ -386,19 +386,20 @@ func (f *Fetcher) run(index int, ctx context.Context) (err error) {
|
|||||||
resp *http.Response
|
resp *http.Response
|
||||||
)
|
)
|
||||||
f.redirectLock.Lock()
|
f.redirectLock.Lock()
|
||||||
if f.redirectURL != "" {
|
redirectURL := f.redirectURL
|
||||||
|
if redirectURL != "" {
|
||||||
f.redirectLock.Unlock()
|
f.redirectLock.Unlock()
|
||||||
}
|
} else {
|
||||||
err = func() (err error) {
|
// Only hold the lock when we need to potentially set redirectURL
|
||||||
defer func() {
|
defer func() {
|
||||||
if f.redirectURL == "" {
|
if redirectURL == "" && err == nil {
|
||||||
if err == nil {
|
f.redirectURL = resp.Request.URL.String()
|
||||||
f.redirectURL = resp.Request.URL.String()
|
|
||||||
}
|
|
||||||
f.redirectLock.Unlock()
|
|
||||||
}
|
}
|
||||||
|
f.redirectLock.Unlock()
|
||||||
}()
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
|
err = func() (err error) {
|
||||||
httpReq, err = f.buildRequest(ctx, f.meta.Req)
|
httpReq, err = f.buildRequest(ctx, f.meta.Req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
|
|||||||
+13
-12
@@ -2,15 +2,6 @@ package download
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"github.com/GopeedLab/gopeed/internal/controller"
|
|
||||||
"github.com/GopeedLab/gopeed/internal/fetcher"
|
|
||||||
"github.com/GopeedLab/gopeed/internal/logger"
|
|
||||||
"github.com/GopeedLab/gopeed/pkg/base"
|
|
||||||
"github.com/GopeedLab/gopeed/pkg/protocol/http"
|
|
||||||
"github.com/GopeedLab/gopeed/pkg/util"
|
|
||||||
gonanoid "github.com/matoous/go-nanoid/v2"
|
|
||||||
"github.com/rs/zerolog"
|
|
||||||
"github.com/rs/zerolog/pkgerrors"
|
|
||||||
"math"
|
"math"
|
||||||
gohttp "net/http"
|
gohttp "net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
@@ -22,6 +13,16 @@ import (
|
|||||||
"sync"
|
"sync"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/GopeedLab/gopeed/internal/controller"
|
||||||
|
"github.com/GopeedLab/gopeed/internal/fetcher"
|
||||||
|
"github.com/GopeedLab/gopeed/internal/logger"
|
||||||
|
"github.com/GopeedLab/gopeed/pkg/base"
|
||||||
|
"github.com/GopeedLab/gopeed/pkg/protocol/http"
|
||||||
|
"github.com/GopeedLab/gopeed/pkg/util"
|
||||||
|
gonanoid "github.com/matoous/go-nanoid/v2"
|
||||||
|
"github.com/rs/zerolog"
|
||||||
|
"github.com/rs/zerolog/pkgerrors"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -532,7 +533,7 @@ func (d *Downloader) ContinueBatch(filter *TaskFilter) (err error) {
|
|||||||
|
|
||||||
func (d *Downloader) Delete(filter *TaskFilter, force bool) (err error) {
|
func (d *Downloader) Delete(filter *TaskFilter, force bool) (err error) {
|
||||||
if filter == nil || filter.IsEmpty() {
|
if filter == nil || filter.IsEmpty() {
|
||||||
return d.deleteAll()
|
return d.deleteAll(force)
|
||||||
}
|
}
|
||||||
|
|
||||||
deleteTasks := d.GetTasksByFilter(filter)
|
deleteTasks := d.GetTasksByFilter(filter)
|
||||||
@@ -577,7 +578,7 @@ func (d *Downloader) Delete(filter *TaskFilter, force bool) (err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *Downloader) deleteAll() (err error) {
|
func (d *Downloader) deleteAll(force bool) (err error) {
|
||||||
var deleteTasksTemp []*Task
|
var deleteTasksTemp []*Task
|
||||||
func() {
|
func() {
|
||||||
d.lock.Lock()
|
d.lock.Lock()
|
||||||
@@ -591,7 +592,7 @@ func (d *Downloader) deleteAll() (err error) {
|
|||||||
}()
|
}()
|
||||||
|
|
||||||
for _, task := range deleteTasksTemp {
|
for _, task := range deleteTasksTemp {
|
||||||
if err = d.doDelete(task, true); err != nil {
|
if err = d.doDelete(task, force); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -131,6 +131,7 @@ type XMLHttpRequest struct {
|
|||||||
responseHeaders http.Header
|
responseHeaders http.Header
|
||||||
aborted bool
|
aborted bool
|
||||||
client *req.Client
|
client *req.Client
|
||||||
|
fingerprint string
|
||||||
|
|
||||||
WithCredentials bool `json:"withCredentials"`
|
WithCredentials bool `json:"withCredentials"`
|
||||||
Upload *XMLHttpRequestUpload `json:"upload"`
|
Upload *XMLHttpRequestUpload `json:"upload"`
|
||||||
@@ -164,7 +165,7 @@ func (xhr *XMLHttpRequest) SetRequestHeader(key, value string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (xhr *XMLHttpRequest) Send(data goja.Value) {
|
func (xhr *XMLHttpRequest) Send(data goja.Value) {
|
||||||
setFingerprint(xhr.client)
|
setFingerprint(xhr.client, xhr.fingerprint)
|
||||||
|
|
||||||
d := xhr.parseData(data)
|
d := xhr.parseData(data)
|
||||||
var (
|
var (
|
||||||
@@ -381,7 +382,8 @@ func Enable(runtime *goja.Runtime, proxyHandler func(r *http.Request) (*url.URL,
|
|||||||
}
|
}
|
||||||
|
|
||||||
instance := &XMLHttpRequest{
|
instance := &XMLHttpRequest{
|
||||||
client: client,
|
client: client,
|
||||||
|
fingerprint: util.SafeGet[string](runtime, FingerprintMagicKey),
|
||||||
Upload: &XMLHttpRequestUpload{
|
Upload: &XMLHttpRequestUpload{
|
||||||
EventProp: &EventProp{
|
EventProp: &EventProp{
|
||||||
eventListeners: make(map[string]func(event *ProgressEvent)),
|
eventListeners: make(map[string]func(event *ProgressEvent)),
|
||||||
@@ -395,8 +397,8 @@ func Enable(runtime *goja.Runtime, proxyHandler func(r *http.Request) (*url.URL,
|
|||||||
instanceValue.SetPrototype(call.This.Prototype())
|
instanceValue.SetPrototype(call.This.Prototype())
|
||||||
return instanceValue
|
return instanceValue
|
||||||
})
|
})
|
||||||
runtime.Set("__gopeed_setFingerprint", func(fingerprint Fingerprint) {
|
runtime.Set("__gopeed_setFingerprint", func(fingerprint string) {
|
||||||
currentFingerprint = fingerprint
|
runtime.Set(FingerprintMagicKey, fingerprint)
|
||||||
})
|
})
|
||||||
if err := runtime.Set("ProgressEvent", progressEvent); err != nil {
|
if err := runtime.Set("ProgressEvent", progressEvent); err != nil {
|
||||||
return err
|
return err
|
||||||
|
|||||||
@@ -1,21 +1,19 @@
|
|||||||
package xhr
|
package xhr
|
||||||
|
|
||||||
import (
|
import "github.com/imroc/req/v3"
|
||||||
"github.com/imroc/req/v3"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Fingerprint string
|
type Fingerprint string
|
||||||
|
|
||||||
const (
|
const (
|
||||||
fingerprintChrome Fingerprint = "chrome"
|
FingerprintMagicKey = "__gopeed_xhr_fingerprint"
|
||||||
fingerprintFirefox Fingerprint = "firefox"
|
|
||||||
fingerprintSafari Fingerprint = "safari"
|
fingerprintChrome = "chrome"
|
||||||
|
fingerprintFirefox = "firefox"
|
||||||
|
fingerprintSafari = "safari"
|
||||||
)
|
)
|
||||||
|
|
||||||
var currentFingerprint Fingerprint = ""
|
func setFingerprint(client *req.Client, fingerprint string) {
|
||||||
|
switch fingerprint {
|
||||||
func setFingerprint(client *req.Client) {
|
|
||||||
switch currentFingerprint {
|
|
||||||
case fingerprintChrome:
|
case fingerprintChrome:
|
||||||
client.ImpersonateChrome()
|
client.ImpersonateChrome()
|
||||||
case fingerprintFirefox:
|
case fingerprintFirefox:
|
||||||
|
|||||||
@@ -22,3 +22,16 @@ func AssertError[T error](err error) (t T, r bool) {
|
|||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func SafeGet[T any](vm *goja.Runtime, name string) T {
|
||||||
|
v := vm.Get(name)
|
||||||
|
if v == nil {
|
||||||
|
var init T
|
||||||
|
return init
|
||||||
|
}
|
||||||
|
if e, ok := v.Export().(T); ok {
|
||||||
|
return e
|
||||||
|
}
|
||||||
|
var init T
|
||||||
|
return init
|
||||||
|
}
|
||||||
@@ -16,6 +16,7 @@ import 'package:url_launcher/url_launcher.dart';
|
|||||||
import 'package:window_manager/window_manager.dart';
|
import 'package:window_manager/window_manager.dart';
|
||||||
|
|
||||||
import '../../../../api/api.dart';
|
import '../../../../api/api.dart';
|
||||||
|
import '../../../../api/model/create_task.dart';
|
||||||
import '../../../../api/model/downloader_config.dart';
|
import '../../../../api/model/downloader_config.dart';
|
||||||
import '../../../../api/model/request.dart';
|
import '../../../../api/model/request.dart';
|
||||||
import '../../../../core/common/start_config.dart';
|
import '../../../../core/common/start_config.dart';
|
||||||
@@ -31,7 +32,7 @@ import '../../../../util/package_info.dart';
|
|||||||
import '../../../../util/updater.dart';
|
import '../../../../util/updater.dart';
|
||||||
import '../../../../util/util.dart';
|
import '../../../../util/util.dart';
|
||||||
import '../../../routes/app_pages.dart';
|
import '../../../routes/app_pages.dart';
|
||||||
import '../../create/dto/create_router_params.dart';
|
import '../../../rpc/rpc.dart';
|
||||||
import '../../redirect/views/redirect_view.dart';
|
import '../../redirect/views/redirect_view.dart';
|
||||||
|
|
||||||
const unixSocketPath = 'gopeed.sock';
|
const unixSocketPath = 'gopeed.sock';
|
||||||
@@ -78,6 +79,9 @@ class AppController extends GetxController with WindowListener, TrayListener {
|
|||||||
_initTray().onError(
|
_initTray().onError(
|
||||||
(error, stackTrace) => logger.w("initTray error", error, stackTrace));
|
(error, stackTrace) => logger.w("initTray error", error, stackTrace));
|
||||||
|
|
||||||
|
_initRpcServer().onError((error, stackTrace) =>
|
||||||
|
logger.w("initRpcServer error", error, stackTrace));
|
||||||
|
|
||||||
_initForegroundTask().onError((error, stackTrace) =>
|
_initForegroundTask().onError((error, stackTrace) =>
|
||||||
logger.w("initForegroundTask error", error, stackTrace));
|
logger.w("initForegroundTask error", error, stackTrace));
|
||||||
|
|
||||||
@@ -271,6 +275,37 @@ class AppController extends GetxController with WindowListener, TrayListener {
|
|||||||
trayManager.addListener(this);
|
trayManager.addListener(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<void> _initRpcServer() async {
|
||||||
|
if (!Util.isDesktop()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
await startRpcServer({
|
||||||
|
"/create": (ctx) async {
|
||||||
|
final meta =
|
||||||
|
ctx.request.headers["X-Gopeed-Host-Meta"]?.firstOrNull ?? "{}";
|
||||||
|
final jsonMeta = jsonDecode(meta);
|
||||||
|
final silent = jsonMeta['silent'] as bool? ?? false;
|
||||||
|
final params = await ctx.readText();
|
||||||
|
final createTaskParams = _decodeToCreatTaskParams(params);
|
||||||
|
if (!silent) {
|
||||||
|
await windowManager.show();
|
||||||
|
_handleToCreate0(createTaskParams);
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
await createTask(createTaskParams);
|
||||||
|
} catch (e) {
|
||||||
|
logger.w(
|
||||||
|
"create task from extension fail", e, StackTrace.current);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
} catch (e) {
|
||||||
|
logger.w("start rpc server fail", e, StackTrace.current);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Future<void> _initForegroundTask() async {
|
Future<void> _initForegroundTask() async {
|
||||||
if (!Util.isMobile()) {
|
if (!Util.isMobile()) {
|
||||||
return;
|
return;
|
||||||
@@ -317,13 +352,7 @@ class AppController extends GetxController with WindowListener, TrayListener {
|
|||||||
if (uri.path == "/create") {
|
if (uri.path == "/create") {
|
||||||
final params = uri.queryParameters["params"];
|
final params = uri.queryParameters["params"];
|
||||||
if (params?.isNotEmpty == true) {
|
if (params?.isNotEmpty == true) {
|
||||||
final safeParams = params!.replaceAll(" ", "+");
|
_handleToCreate(params!);
|
||||||
final paramsJson =
|
|
||||||
String.fromCharCodes(base64Decode(base64.normalize(safeParams)));
|
|
||||||
Get.rootDelegate.offAndToNamed(Routes.REDIRECT,
|
|
||||||
arguments: RedirectArgs(Routes.CREATE,
|
|
||||||
arguments:
|
|
||||||
CreateRouterParams.fromJson(jsonDecode(paramsJson))));
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Get.rootDelegate.offAndToNamed(Routes.CREATE);
|
Get.rootDelegate.offAndToNamed(Routes.CREATE);
|
||||||
@@ -346,7 +375,7 @@ class AppController extends GetxController with WindowListener, TrayListener {
|
|||||||
}
|
}
|
||||||
Get.rootDelegate.offAndToNamed(Routes.REDIRECT,
|
Get.rootDelegate.offAndToNamed(Routes.REDIRECT,
|
||||||
arguments: RedirectArgs(Routes.CREATE,
|
arguments: RedirectArgs(Routes.CREATE,
|
||||||
arguments: CreateRouterParams(req: Request(url: path))));
|
arguments: CreateTask(req: Request(url: path))));
|
||||||
}
|
}
|
||||||
|
|
||||||
String runningAddress() {
|
String runningAddress() {
|
||||||
@@ -524,4 +553,21 @@ class AppController extends GetxController with WindowListener, TrayListener {
|
|||||||
apiToken: startConfig.value.apiToken));
|
apiToken: startConfig.value.apiToken));
|
||||||
await putConfig(downloaderConfig.value);
|
await putConfig(downloaderConfig.value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CreateTask _decodeToCreatTaskParams(String params) {
|
||||||
|
final safeParams = params.replaceAll('"', "").replaceAll(" ", "+");
|
||||||
|
final paramsJson =
|
||||||
|
String.fromCharCodes(base64Decode(base64.normalize(safeParams)));
|
||||||
|
return CreateTask.fromJson(jsonDecode(paramsJson));
|
||||||
|
}
|
||||||
|
|
||||||
|
_handleToCreate(String params) {
|
||||||
|
final createTaskParams = _decodeToCreatTaskParams(params);
|
||||||
|
_handleToCreate0(createTaskParams);
|
||||||
|
}
|
||||||
|
|
||||||
|
_handleToCreate0(CreateTask createTaskParams) {
|
||||||
|
Get.rootDelegate.offAndToNamed(Routes.REDIRECT,
|
||||||
|
arguments: RedirectArgs(Routes.CREATE, arguments: createTaskParams));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
import 'package:json_annotation/json_annotation.dart';
|
|
||||||
|
|
||||||
import '../../../../api/model/options.dart';
|
|
||||||
import '../../../../api/model/request.dart';
|
|
||||||
|
|
||||||
part 'create_router_params.g.dart';
|
|
||||||
|
|
||||||
@JsonSerializable(explicitToJson: true)
|
|
||||||
class CreateRouterParams {
|
|
||||||
Request? req;
|
|
||||||
Options? opt;
|
|
||||||
|
|
||||||
CreateRouterParams({
|
|
||||||
this.req,
|
|
||||||
this.opt,
|
|
||||||
});
|
|
||||||
|
|
||||||
factory CreateRouterParams.fromJson(
|
|
||||||
Map<String, dynamic> json,
|
|
||||||
) =>
|
|
||||||
_$CreateRouterParamsFromJson(json);
|
|
||||||
|
|
||||||
Map<String, dynamic> toJson() => _$CreateRouterParamsToJson(this);
|
|
||||||
}
|
|
||||||
@@ -1,31 +0,0 @@
|
|||||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
|
||||||
|
|
||||||
part of 'create_router_params.dart';
|
|
||||||
|
|
||||||
// **************************************************************************
|
|
||||||
// JsonSerializableGenerator
|
|
||||||
// **************************************************************************
|
|
||||||
|
|
||||||
CreateRouterParams _$CreateRouterParamsFromJson(Map<String, dynamic> json) =>
|
|
||||||
CreateRouterParams(
|
|
||||||
req: json['req'] == null
|
|
||||||
? null
|
|
||||||
: Request.fromJson(json['req'] as Map<String, dynamic>),
|
|
||||||
opt: json['opt'] == null
|
|
||||||
? null
|
|
||||||
: Options.fromJson(json['opt'] as Map<String, dynamic>),
|
|
||||||
);
|
|
||||||
|
|
||||||
Map<String, dynamic> _$CreateRouterParamsToJson(CreateRouterParams instance) {
|
|
||||||
final val = <String, dynamic>{};
|
|
||||||
|
|
||||||
void writeNotNull(String key, dynamic value) {
|
|
||||||
if (value != null) {
|
|
||||||
val[key] = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
writeNotNull('req', instance.req?.toJson());
|
|
||||||
writeNotNull('opt', instance.opt?.toJson());
|
|
||||||
return val;
|
|
||||||
}
|
|
||||||
@@ -27,7 +27,6 @@ import '../../../views/file_tree_view.dart';
|
|||||||
import '../../app/controllers/app_controller.dart';
|
import '../../app/controllers/app_controller.dart';
|
||||||
import '../../history/views/history_view.dart';
|
import '../../history/views/history_view.dart';
|
||||||
import '../controllers/create_controller.dart';
|
import '../controllers/create_controller.dart';
|
||||||
import '../dto/create_router_params.dart';
|
|
||||||
|
|
||||||
class CreateView extends GetView<CreateController> {
|
class CreateView extends GetView<CreateController> {
|
||||||
final _confirmFormKey = GlobalKey<FormState>();
|
final _confirmFormKey = GlobalKey<FormState>();
|
||||||
@@ -76,7 +75,7 @@ class CreateView extends GetView<CreateController> {
|
|||||||
_pathController.text = appController.downloaderConfig.value.downloadDir;
|
_pathController.text = appController.downloaderConfig.value.downloadDir;
|
||||||
}
|
}
|
||||||
|
|
||||||
final CreateRouterParams? routerParams = Get.rootDelegate.arguments();
|
final CreateTask? routerParams = Get.rootDelegate.arguments();
|
||||||
if (routerParams?.req?.url.isNotEmpty ?? false) {
|
if (routerParams?.req?.url.isNotEmpty ?? false) {
|
||||||
// get url from route arguments
|
// get url from route arguments
|
||||||
final url = routerParams!.req!.url;
|
final url = routerParams!.req!.url;
|
||||||
|
|||||||
@@ -0,0 +1,133 @@
|
|||||||
|
import 'dart:io';
|
||||||
|
import 'dart:convert';
|
||||||
|
|
||||||
|
import 'package:dart_ipc/dart_ipc.dart';
|
||||||
|
import 'package:path_provider/path_provider.dart';
|
||||||
|
|
||||||
|
import '../../util/util.dart';
|
||||||
|
|
||||||
|
/// RPC context class that contains request information and response methods
|
||||||
|
class RpcContext {
|
||||||
|
final HttpRequest request;
|
||||||
|
final HttpResponse response;
|
||||||
|
String? _bodyCache;
|
||||||
|
|
||||||
|
RpcContext(this.request, this.response);
|
||||||
|
|
||||||
|
/// Read and parse JSON request body
|
||||||
|
Future<Map<String, dynamic>> readJSON() async {
|
||||||
|
if (_bodyCache == null) {
|
||||||
|
final content = <int>[];
|
||||||
|
await for (var data in request) {
|
||||||
|
content.addAll(data);
|
||||||
|
}
|
||||||
|
_bodyCache = String.fromCharCodes(content);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_bodyCache!.isEmpty) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
return jsonDecode(_bodyCache!) as Map<String, dynamic>;
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<String> readText() async {
|
||||||
|
if (_bodyCache == null) {
|
||||||
|
final content = <int>[];
|
||||||
|
await for (var data in request) {
|
||||||
|
content.addAll(data);
|
||||||
|
}
|
||||||
|
_bodyCache = String.fromCharCodes(content);
|
||||||
|
}
|
||||||
|
|
||||||
|
return _bodyCache ?? '';
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Write JSON response
|
||||||
|
Future<void> writeJSON(Map<String, dynamic> data) async {
|
||||||
|
response.headers.contentType = ContentType.json;
|
||||||
|
response.write(jsonEncode(data));
|
||||||
|
await response.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Write error response
|
||||||
|
Future<void> writeError(String message, [int statusCode = 500]) async {
|
||||||
|
response.statusCode = statusCode;
|
||||||
|
await writeJSON({'error': message});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Route handler type definition
|
||||||
|
typedef RouteHandler = Future<void> Function(RpcContext ctx);
|
||||||
|
|
||||||
|
/// Route registry
|
||||||
|
class RouteRegistry {
|
||||||
|
final Map<String, RouteHandler> _routes = {};
|
||||||
|
|
||||||
|
/// Register a route
|
||||||
|
void register(String path, RouteHandler handler) {
|
||||||
|
_routes[path] = handler;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get route handler
|
||||||
|
RouteHandler? getHandler(String path) {
|
||||||
|
return _routes[path];
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get all registered routes
|
||||||
|
List<String> get routes => _routes.keys.toList();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Start RPC server
|
||||||
|
Future<void> startRpcServer([Map<String, RouteHandler>? routes]) async {
|
||||||
|
String path;
|
||||||
|
if (Util.isWindows()) {
|
||||||
|
path = r'\\.\pipe\gopeed_host';
|
||||||
|
} else {
|
||||||
|
path = await Util.homePathJoin("gopeed_host.sock");
|
||||||
|
// try to delete existing socket file
|
||||||
|
final socketFile = File(path);
|
||||||
|
if (await socketFile.exists()) {
|
||||||
|
try {
|
||||||
|
await socketFile.delete();
|
||||||
|
} catch (e) {
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create route registry
|
||||||
|
final registry = RouteRegistry();
|
||||||
|
|
||||||
|
// Register provided routes
|
||||||
|
if (routes != null) {
|
||||||
|
routes.forEach((path, handler) {
|
||||||
|
registry.register(path, handler);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
final serverSocket = await bind(path);
|
||||||
|
final httpServer = HttpServer.listenOn(serverSocket);
|
||||||
|
|
||||||
|
httpServer.forEach((HttpRequest request) async {
|
||||||
|
final ctx = RpcContext(request, request.response);
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Get request path
|
||||||
|
final requestPath = request.uri.path;
|
||||||
|
// Find route handler
|
||||||
|
final handler = registry.getHandler(requestPath);
|
||||||
|
if (handler != null) {
|
||||||
|
// Execute route handler
|
||||||
|
await handler(ctx);
|
||||||
|
} else {
|
||||||
|
// 404 Route not found
|
||||||
|
await ctx.writeError('Route not found: $requestPath', 404);
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
await ctx.writeError('Internal server error: $e', 500);
|
||||||
|
} finally {
|
||||||
|
await request.response.close();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
@@ -24,6 +24,8 @@ class Args {
|
|||||||
|
|
||||||
bool hidden = false;
|
bool hidden = false;
|
||||||
|
|
||||||
|
Args();
|
||||||
|
|
||||||
Args.parse(List<String> args) {
|
Args.parse(List<String> args) {
|
||||||
final parser = ArgParser();
|
final parser = ArgParser();
|
||||||
parser.addFlag(flagHidden);
|
parser.addFlag(flagHidden);
|
||||||
@@ -33,7 +35,22 @@ class Args {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void main(List<String> arguments) async {
|
void main(List<String> arguments) async {
|
||||||
final args = Args.parse(arguments);
|
Args args;
|
||||||
|
// Parse url scheme arguments, e.g. gopeed:?hidden=true
|
||||||
|
// TODO: macos open url handle
|
||||||
|
// TODO: macos updater test
|
||||||
|
if (arguments.firstOrNull?.startsWith("gopeed:") == true) {
|
||||||
|
try {
|
||||||
|
final uri = Uri.parse(arguments.first);
|
||||||
|
args = Args()..hidden = uri.queryParameters["hidden"] == "true";
|
||||||
|
} catch (e) {
|
||||||
|
// ignore
|
||||||
|
args = Args.parse([]);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
args = Args.parse(arguments);
|
||||||
|
}
|
||||||
|
|
||||||
await init(args);
|
await init(args);
|
||||||
onStart();
|
onStart();
|
||||||
|
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ const _firefoxNativeHostsKey = r'Software\Mozilla\NativeMessagingHosts';
|
|||||||
|
|
||||||
/// Install host binary for browser extension
|
/// Install host binary for browser extension
|
||||||
Future<void> doInstallHost() async {
|
Future<void> doInstallHost() async {
|
||||||
final hostPath = Util.homePathJoin(_hostExecName);
|
final hostPath = await Util.homePathJoin(_hostExecName);
|
||||||
await Util.installAsset('assets/exec/$_hostExecName', hostPath,
|
await Util.installAsset('assets/exec/$_hostExecName', hostPath,
|
||||||
executable: true);
|
executable: true);
|
||||||
}
|
}
|
||||||
@@ -62,7 +62,7 @@ Future<bool> doCheckBrowserInstalled(Browser browser) async {
|
|||||||
Future<bool> doCheckManifestInstalled(Browser browser) async {
|
Future<bool> doCheckManifestInstalled(Browser browser) async {
|
||||||
if (await checkBrowserInstalled(browser) == false) return false;
|
if (await checkBrowserInstalled(browser) == false) return false;
|
||||||
|
|
||||||
final manifestPath = _getManifestPath(browser);
|
final manifestPath = await _getManifestPath(browser);
|
||||||
if (manifestPath == null) return false;
|
if (manifestPath == null) return false;
|
||||||
|
|
||||||
if (Platform.isWindows) {
|
if (Platform.isWindows) {
|
||||||
@@ -86,7 +86,7 @@ Future<void> doInstallManifest(Browser browser) async {
|
|||||||
if (await checkBrowserInstalled(browser) == false) return;
|
if (await checkBrowserInstalled(browser) == false) return;
|
||||||
if (await checkManifestInstalled(browser)) return;
|
if (await checkManifestInstalled(browser)) return;
|
||||||
|
|
||||||
final manifestPath = _getManifestPath(browser)!;
|
final manifestPath = (await _getManifestPath(browser))!;
|
||||||
final manifestContent = await _getManifestContent(browser);
|
final manifestContent = await _getManifestContent(browser);
|
||||||
final manifestDir = path.dirname(manifestPath);
|
final manifestDir = path.dirname(manifestPath);
|
||||||
await Directory(manifestDir).create(recursive: true);
|
await Directory(manifestDir).create(recursive: true);
|
||||||
@@ -209,11 +209,11 @@ List<String> _getUnixExecutablePaths(Browser browser) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
String? _getManifestPath(Browser browser) {
|
Future<String?> _getManifestPath(Browser browser) async {
|
||||||
final manifestName =
|
final manifestName =
|
||||||
browser == Browser.firefox ? '$_hostName.moz.json' : '$_hostName.json';
|
browser == Browser.firefox ? '$_hostName.moz.json' : '$_hostName.json';
|
||||||
if (Platform.isWindows) {
|
if (Platform.isWindows) {
|
||||||
return Util.homePathJoin(manifestName);
|
return await Util.homePathJoin(manifestName);
|
||||||
}
|
}
|
||||||
|
|
||||||
final home =
|
final home =
|
||||||
@@ -259,7 +259,7 @@ Future<bool> _checkWindowsRegistry(String keyPath) async {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Future<String> _getManifestContent(Browser browser) async {
|
Future<String> _getManifestContent(Browser browser) async {
|
||||||
final hostPath = Util.homePathJoin(_hostExecName);
|
final hostPath = await Util.homePathJoin(_hostExecName);
|
||||||
final manifest = {
|
final manifest = {
|
||||||
'name': _hostName,
|
'name': _hostName,
|
||||||
'description': 'Gopeed browser extension host',
|
'description': 'Gopeed browser extension host',
|
||||||
|
|||||||
@@ -2,10 +2,12 @@ import 'package:dio/dio.dart';
|
|||||||
|
|
||||||
// List of mirrors for GitHub
|
// List of mirrors for GitHub
|
||||||
const _sourceMirror = [
|
const _sourceMirror = [
|
||||||
// ghfast.top: https://ghfast.top/https://raw.githubusercontent.com/ngosang/trackerslist/master/trackers_all.txt
|
// github.tbedu.top: https://github.tbedu.top/https://raw.githubusercontent.com/ngosang/trackerslist/master/trackers_all.txt
|
||||||
["https://ghfast.top/", r"(.*)"],
|
["https://github.tbedu.top/", r"(.*)"],
|
||||||
// github.moeyy.xyz: https://github.moeyy.xyz/https://raw.githubusercontent.com/ngosang/trackerslist/master/trackers_all.txt
|
// fastgit.cc: https://fastgit.cc/https://raw.githubusercontent.com/ngosang/trackerslist/master/trackers_all.txt
|
||||||
["https://github.moeyy.xyz/", r"(.*)"],
|
["https://fastgit.cc/", r"(.*)"],
|
||||||
|
// gitproxy.click: https://gitproxy.click/https://raw.githubusercontent.com/ngosang/trackerslist/master/trackers_all.txt
|
||||||
|
["https://gitproxy.click/", r"(.*)"],
|
||||||
// jsdelivr: https://fastly.jsdelivr.net/gh/ngosang/trackerslist/trackers_all.txt
|
// jsdelivr: https://fastly.jsdelivr.net/gh/ngosang/trackerslist/trackers_all.txt
|
||||||
[
|
[
|
||||||
"https://fastly.jsdelivr.net/gh",
|
"https://fastly.jsdelivr.net/gh",
|
||||||
@@ -15,10 +17,12 @@ const _sourceMirror = [
|
|||||||
|
|
||||||
// List of mirrors for GitHub release
|
// List of mirrors for GitHub release
|
||||||
const _assertMirror = [
|
const _assertMirror = [
|
||||||
// ghfast.top: https://ghfast.top/https://github.com/GopeedLab/gopeed/releases/download/v1.6.10/Gopeed-v1.6.10-windows-amd64.zip
|
// github.tbedu.top: https://https://github.tbedu.top/https://github.com/GopeedLab/gopeed/releases/download/v1.6.10/Gopeed-v1.6.10-windows-amd64.zip
|
||||||
["https://ghfast.top/", r"(.*)"],
|
["https://github.tbedu.top/", r"(.*)"],
|
||||||
// github.moeyy.xyz: https://github.moeyy.xyz/https://github.com/GopeedLab/gopeed/releases/download/v1.6.10/Gopeed-v1.6.10-windows-amd64.zip
|
// fastgit.cc: https://fastgit.cc/https://github.com/GopeedLab/gopeed/releases/download/v1.6.10/Gopeed-v1.6.10-windows-amd64.zip
|
||||||
["https://github.moeyy.xyz/", r"(.*)"],
|
["https://fastgit.cc/", r"(.*)"],
|
||||||
|
// gitproxy.click: https://gitproxy.click/https://github.com/GopeedLab/gopeed/releases/download/v1.6.10/Gopeed-v1.6.10-windows-amd64.zip
|
||||||
|
["https://gitproxy.click/", r"(.*)"],
|
||||||
];
|
];
|
||||||
|
|
||||||
enum MirrorType {
|
enum MirrorType {
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ final _updaterBin = "updater${Util.isWindows() ? ".exe" : ""}";
|
|||||||
|
|
||||||
Future<void> installUpdater() async {
|
Future<void> installUpdater() async {
|
||||||
await Util.installAsset(
|
await Util.installAsset(
|
||||||
'assets/exec/$_updaterBin', Util.homePathJoin(_updaterBin),
|
'assets/exec/$_updaterBin', await Util.homePathJoin(_updaterBin),
|
||||||
executable: true);
|
executable: true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -346,7 +346,7 @@ Future<void> _update(String version, Function(int, int) onProgress) async {
|
|||||||
case Channel.linuxFlathub:
|
case Channel.linuxFlathub:
|
||||||
case Channel.linuxSnap:
|
case Channel.linuxSnap:
|
||||||
case Channel.linuxDeb:
|
case Channel.linuxDeb:
|
||||||
final updaterPath = Util.homePathJoin(_updaterBin);
|
final updaterPath = await Util.homePathJoin(_updaterBin);
|
||||||
// Check the updater binary is exists
|
// Check the updater binary is exists
|
||||||
if (!await File(updaterPath).exists()) {
|
if (!await File(updaterPath).exists()) {
|
||||||
await launchUrl(
|
await launchUrl(
|
||||||
@@ -363,6 +363,8 @@ Future<void> _update(String version, Function(int, int) onProgress) async {
|
|||||||
Update channel
|
Update channel
|
||||||
-asset string
|
-asset string
|
||||||
Path to the package asset
|
Path to the package asset
|
||||||
|
-exeDir string
|
||||||
|
Directory of the entry executable
|
||||||
-log string
|
-log string
|
||||||
Log file path
|
Log file path
|
||||||
*/
|
*/
|
||||||
@@ -373,6 +375,8 @@ Future<void> _update(String version, Function(int, int) onProgress) async {
|
|||||||
_channel!.name,
|
_channel!.name,
|
||||||
"-asset",
|
"-asset",
|
||||||
newVersionAssetPath,
|
newVersionAssetPath,
|
||||||
|
"-exeDir",
|
||||||
|
path.dirname(Platform.resolvedExecutable),
|
||||||
"-log",
|
"-log",
|
||||||
path.join(logsDir(), "updater.log")
|
path.join(logsDir(), "updater.log")
|
||||||
]);
|
]);
|
||||||
|
|||||||
@@ -157,10 +157,15 @@ class Util {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
static String homePathJoin(String fileName) {
|
static Future<String> homePathJoin(String fileName) async {
|
||||||
final execPath = Platform.resolvedExecutable;
|
if (Util.isWindows()) {
|
||||||
final execDir = path.dirname(execPath);
|
final execPath = Platform.resolvedExecutable;
|
||||||
return path.join(execDir, fileName);
|
final execDir = path.dirname(execPath);
|
||||||
|
return path.join(execDir, fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
final dir = await getApplicationSupportDirectory();
|
||||||
|
return path.join(dir.path, fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
static Future<void> installAsset(String assetPath, String targetPath,
|
static Future<void> installAsset(String assetPath, String targetPath,
|
||||||
|
|||||||
+10
-2
@@ -286,6 +286,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.0.8"
|
version: "1.0.8"
|
||||||
|
dart_ipc:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: dart_ipc
|
||||||
|
sha256: "6cad558cda5304017c1f581df4c96fd4f8e4ee212aae7bfa4357716236faa9ba"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.0.1"
|
||||||
dart_style:
|
dart_style:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -1414,10 +1422,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: web_socket_channel
|
name: web_socket_channel
|
||||||
sha256: "9f187088ed104edd8662ca07af4b124465893caf063ba29758f97af57e61da8f"
|
sha256: d645757fb0f4773d602444000a8131ff5d48c9e47adfe9772652dd1a4f2d45c8
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.0.1"
|
version: "3.0.3"
|
||||||
win32:
|
win32:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ publish_to: "none" # Remove this line if you wish to publish to pub.dev
|
|||||||
# In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion.
|
# In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion.
|
||||||
# Read more about iOS versioning at
|
# Read more about iOS versioning at
|
||||||
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
|
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
|
||||||
version: 1.8.1+1
|
version: 1.8.2+1
|
||||||
|
|
||||||
environment:
|
environment:
|
||||||
sdk: ">=3.0.0 <4.0.0"
|
sdk: ">=3.0.0 <4.0.0"
|
||||||
@@ -82,6 +82,7 @@ dependencies:
|
|||||||
url: https://github.com/hui-z/flutter_install_plugin.git
|
url: https://github.com/hui-z/flutter_install_plugin.git
|
||||||
ref: cf08af829f4a4145634f8a047108f505fdbe5eaa
|
ref: cf08af829f4a4145634f8a047108f505fdbe5eaa
|
||||||
flutter_svg: ^2.0.17
|
flutter_svg: ^2.0.17
|
||||||
|
dart_ipc: ^1.0.1
|
||||||
dependency_overrides:
|
dependency_overrides:
|
||||||
permission_handler_windows:
|
permission_handler_windows:
|
||||||
git:
|
git:
|
||||||
|
|||||||
Reference in new issue
Block a user