feat: support flutter web

This commit is contained in:
levi authored and monkeyWie committed 2022-10-27 13:58:43 +08:00
1 parent c4a30dc4c2
commit 4d4d3b446a
39 files changed
+450 -299

No files matched your search

+1 -1
View File
@@ -31,7 +31,7 @@ jobs:
for goos in "${goos_arr[@]}"; do
for goarch in "${goarch_arr[@]}"; do
dir="dist/gopeed-$VERSION-$goos-$goarch/"
(GOOS=$goos GOARCH=$goarch go build -tags nosqlite -ldflags="-s -w" -o $dir github.com/monkeyWie/gopeed-core/cmd/gopeed \
(GOOS=$goos GOARCH=$goarch go build -tags nosqlite -ldflags="-s -w" -o $dir github.com/monkeyWie/gopeed/cmd/gopeed \
&& cd $dir \
&& zip -r ../zip/gopeed-$VERSION-$goos-$goarch.zip * \
&& cd ../..) \
+1 -1
View File
@@ -53,4 +53,4 @@ jobs:
go-version: '^1.18'
- uses: actions/checkout@v2
- name: Build
run: go build github.com/monkeyWie/gopeed-core/cmd/gopeed
run: go build github.com/monkeyWie/gopeed/cmd/gopeed
+4 -4
View File
@@ -1,6 +1,6 @@
[![Test Status](https://github.com/monkeyWie/gopeed-core/workflows/test/badge.svg)](https://github.com/monkeyWie/gopeed-core/actions?query=workflow%3Atest)
[![Test Status](https://github.com/monkeyWie/gopeed/workflows/test/badge.svg)](https://github.com/monkeyWie/gopeed/actions?query=workflow%3Atest)
[![Codecov](https://codecov.io/gh/monkeyWie/gopeed-core/branch/master/graph/badge.svg)](https://codecov.io/gh/monkeyWie/gopeed-core)
[![Release](https://img.shields.io/github/release/monkeyWie/gopeed-core.svg?style=flat-square)](https://github.com/monkeyWie/gopeed-core/releases)
[![Release](https://img.shields.io/github/release/monkeyWie/gopeed-core.svg?style=flat-square)](https://github.com/monkeyWie/gopeed/releases)
## gopeed
@@ -9,7 +9,7 @@
## 安装
```sh
go install github.com/monkeyWie/gopeed-core
go install github.com/monkeyWie/gopeed
```
## 示例
@@ -24,7 +24,7 @@ go install github.com/monkeyWie/gopeed-core
### 下载
前往[releases](https://github.com/monkeyWie/gopeed-core/releases)页面
前往[releases](https://github.com/monkeyWie/gopeed/releases)页面
## TODO
+2 -2
View File
@@ -2,8 +2,8 @@ package main
import (
"fmt"
"github.com/monkeyWie/gopeed-core/pkg/base"
"github.com/monkeyWie/gopeed-core/pkg/download"
"github.com/monkeyWie/gopeed/pkg/base"
"github.com/monkeyWie/gopeed/pkg/download"
)
func main() {
+4 -4
View File
@@ -1,12 +1,12 @@
// go build -ldflags="-w -s" -buildmode=c-shared -o bin/libgopeed.dll github.com/monkeyWie/gopeed-core/bind/desktop
// go build -ldflags="-w -s" -buildmode=c-shared -o bin/libgopeed.dylib github.com/monkeyWie/gopeed-core/bind/desktop
// go build -ldflags="-w -s" -buildmode=c-shared -o bin/libgopeed.dll github.com/monkeyWie/gopeed/bind/desktop
// go build -ldflags="-w -s" -buildmode=c-shared -o ui/flutter/macos//libgopeed.dylib github.com/monkeyWie/gopeed/bind/desktop
package main
import "C"
import (
"encoding/json"
"github.com/monkeyWie/gopeed-core/pkg/rest"
"github.com/monkeyWie/gopeed-core/pkg/rest/model"
"github.com/monkeyWie/gopeed/pkg/rest"
"github.com/monkeyWie/gopeed/pkg/rest/model"
)
func main() {}
+3 -3
View File
@@ -1,10 +1,10 @@
// gomobile bind -ldflags="-w -s" -o libgopeed.aar -target=android -androidapi 19 -javapkg=com.gopeed github.com/monkeyWie/gopeed-core/bind/mobile
// gomobile bind -ldflags="-w -s" -o libgopeed.aar -target=android -androidapi 19 -javapkg=com.gopeed github.com/monkeyWie/gopeed/bind/mobile
package libgopeed
import (
"encoding/json"
"github.com/monkeyWie/gopeed-core/pkg/rest"
"github.com/monkeyWie/gopeed-core/pkg/rest/model"
"github.com/monkeyWie/gopeed/pkg/rest"
"github.com/monkeyWie/gopeed/pkg/rest/model"
)
func Start(cfg string) (int, error) {
+3 -3
View File
@@ -2,9 +2,9 @@ package main
import (
"fmt"
"github.com/monkeyWie/gopeed-core/pkg/base"
"github.com/monkeyWie/gopeed-core/pkg/download"
"github.com/monkeyWie/gopeed-core/pkg/util"
"github.com/monkeyWie/gopeed/pkg/base"
"github.com/monkeyWie/gopeed/pkg/download"
"github.com/monkeyWie/gopeed/pkg/util"
"strings"
"sync"
)
+16
View File
@@ -0,0 +1,16 @@
package main
import (
"github.com/monkeyWie/gopeed/pkg/rest"
"github.com/monkeyWie/gopeed/pkg/rest/model"
)
func main() {
if err := rest.StartSync(&model.StartConfig{
Network: "tcp",
Address: "127.0.0.1:9999",
Storage: model.StorageMem,
}); err != nil {
panic(err)
}
}
+3 -1
View File
@@ -1,4 +1,4 @@
module github.com/monkeyWie/gopeed-core
module github.com/monkeyWie/gopeed
go 1.18
@@ -36,8 +36,10 @@ require (
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/dustin/go-humanize v1.0.0 // indirect
github.com/edsrzf/mmap-go v1.1.0 // indirect
github.com/felixge/httpsnoop v1.0.1 // indirect
github.com/google/btree v1.0.1 // indirect
github.com/google/uuid v1.3.0 // indirect
github.com/gorilla/handlers v1.5.1 // indirect
github.com/gorilla/websocket v1.4.2 // indirect
github.com/huandu/xstrings v1.3.2 // indirect
github.com/lispad/go-generics-tools v1.0.0 // indirect
+4
View File
@@ -106,6 +106,8 @@ github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1
github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I=
github.com/edsrzf/mmap-go v1.1.0 h1:6EUwBLQ/Mcr1EYLE4Tn1VdW1A4ckqCQWZBw8Hr0kjpQ=
github.com/edsrzf/mmap-go v1.1.0/go.mod h1:19H/e8pUPLicwkyNgOykDXkJ9F0MHE+Z52B8EIth78Q=
github.com/felixge/httpsnoop v1.0.1 h1:lvB5Jl89CsZtGIWuTcDM1E/vkVs49/Ml7JJe07l8SPQ=
github.com/felixge/httpsnoop v1.0.1/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
github.com/frankban/quicktest v1.9.0/go.mod h1:ui7WezCLWMWxVWr1GETZY3smRy0G4KWq9vcPtJmFl7Y=
github.com/frankban/quicktest v1.14.3 h1:FJKSZTDHjyhriyC81FLQ0LY93eSai0ZyR/ZIkd3ZUKE=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
@@ -159,6 +161,8 @@ github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e/go.mod h1:wJfORR
github.com/gopherjs/gopherjs v0.0.0-20190309154008-847fc94819f9/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/gopherjs/gopherjs v0.0.0-20190910122728-9d188e94fb99/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg=
github.com/gorilla/handlers v1.5.1 h1:9lRY6j8DEeeBT10CvO9hGW0gmky0BprnvDI5vfhUHH4=
github.com/gorilla/handlers v1.5.1/go.mod h1:t8XrUpc4KVXb7HGyJ4/cEnwQiaxrX/hz1Zv/4g96P1Q=
github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI=
github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
+2 -2
View File
@@ -1,8 +1,8 @@
package fetcher
import (
"github.com/monkeyWie/gopeed-core/internal/controller"
"github.com/monkeyWie/gopeed-core/pkg/base"
"github.com/monkeyWie/gopeed/internal/controller"
"github.com/monkeyWie/gopeed/pkg/base"
)
// 对应协议的下载支持
+4 -4
View File
@@ -4,10 +4,10 @@ import (
"github.com/anacrolix/torrent"
"github.com/anacrolix/torrent/metainfo"
"github.com/anacrolix/torrent/storage"
"github.com/monkeyWie/gopeed-core/internal/controller"
"github.com/monkeyWie/gopeed-core/internal/fetcher"
"github.com/monkeyWie/gopeed-core/pkg/base"
"github.com/monkeyWie/gopeed-core/pkg/util"
"github.com/monkeyWie/gopeed/internal/controller"
"github.com/monkeyWie/gopeed/internal/fetcher"
"github.com/monkeyWie/gopeed/pkg/base"
"github.com/monkeyWie/gopeed/pkg/util"
"path/filepath"
"sync"
"sync/atomic"
+3 -3
View File
@@ -1,9 +1,9 @@
package bt
import (
"github.com/monkeyWie/gopeed-core/internal/controller"
"github.com/monkeyWie/gopeed-core/internal/fetcher"
"github.com/monkeyWie/gopeed-core/pkg/base"
"github.com/monkeyWie/gopeed/internal/controller"
"github.com/monkeyWie/gopeed/internal/fetcher"
"github.com/monkeyWie/gopeed/pkg/base"
"reflect"
"testing"
)
+3 -3
View File
@@ -4,9 +4,9 @@ import (
"bytes"
"context"
"fmt"
"github.com/monkeyWie/gopeed-core/internal/fetcher"
"github.com/monkeyWie/gopeed-core/pkg/base"
"github.com/monkeyWie/gopeed-core/pkg/util"
"github.com/monkeyWie/gopeed/internal/fetcher"
"github.com/monkeyWie/gopeed/pkg/base"
"github.com/monkeyWie/gopeed/pkg/util"
"golang.org/x/sync/errgroup"
"io"
"mime"
+4 -4
View File
@@ -2,10 +2,10 @@ package http
import (
"fmt"
"github.com/monkeyWie/gopeed-core/internal/controller"
"github.com/monkeyWie/gopeed-core/internal/fetcher"
"github.com/monkeyWie/gopeed-core/internal/test"
"github.com/monkeyWie/gopeed-core/pkg/base"
"github.com/monkeyWie/gopeed/internal/controller"
"github.com/monkeyWie/gopeed/internal/fetcher"
"github.com/monkeyWie/gopeed/internal/test"
"github.com/monkeyWie/gopeed/pkg/base"
"net"
"reflect"
"testing"
+1 -1
View File
@@ -1,6 +1,6 @@
package http
import "github.com/monkeyWie/gopeed-core/pkg/base"
import "github.com/monkeyWie/gopeed/pkg/base"
type chunk struct {
Status base.Status
+7 -7
View File
@@ -2,12 +2,12 @@ package download
import (
"errors"
"github.com/monkeyWie/gopeed-core/internal/controller"
"github.com/monkeyWie/gopeed-core/internal/fetcher"
"github.com/monkeyWie/gopeed-core/internal/protocol/bt"
"github.com/monkeyWie/gopeed-core/internal/protocol/http"
"github.com/monkeyWie/gopeed-core/pkg/base"
"github.com/monkeyWie/gopeed-core/pkg/util"
"github.com/monkeyWie/gopeed/internal/controller"
"github.com/monkeyWie/gopeed/internal/fetcher"
"github.com/monkeyWie/gopeed/internal/protocol/bt"
"github.com/monkeyWie/gopeed/internal/protocol/http"
"github.com/monkeyWie/gopeed/pkg/base"
"github.com/monkeyWie/gopeed/pkg/util"
"strings"
"sync"
"sync/atomic"
@@ -380,7 +380,7 @@ func (d *Downloader) GetTasks() []*Task {
return d.tasks
}
func (d *Downloader) GetConfig(v any) error {
func (d *Downloader) GetConfig(v any) (bool, error) {
return d.storage.Get(bucketConfig, "config", v)
}
+2 -2
View File
@@ -1,8 +1,8 @@
package download
import (
"github.com/monkeyWie/gopeed-core/internal/test"
"github.com/monkeyWie/gopeed-core/pkg/base"
"github.com/monkeyWie/gopeed/internal/test"
"github.com/monkeyWie/gopeed/pkg/base"
"reflect"
"sync"
"testing"
+16 -7
View File
@@ -11,7 +11,7 @@ import (
type Storage interface {
Setup(buckets []string) error
Put(bucket string, key string, v any) error
Get(bucket string, key string, v any) error
Get(bucket string, key string, v any) (bool, error)
List(bucket string, v any) error
Pop(bucket string, key string, v any) error
Delete(bucket string, key string) error
@@ -67,9 +67,12 @@ func (n *MemStorage) Put(bucket string, key string, v any) error {
return nil
}
func (n *MemStorage) Get(bucket string, key string, v any) error {
changeValue(v, memData[bucket][key])
return nil
func (n *MemStorage) Get(bucket string, key string, v any) (bool, error) {
if dv, ok := memData[bucket][key]; ok {
changeValue(v, dv)
return true, nil
}
return false, nil
}
func (n *MemStorage) List(bucket string, v any) error {
@@ -147,7 +150,7 @@ func (b *BoltStorage) Put(bucket string, key string, v any) error {
})
}
func (b *BoltStorage) Get(bucket string, key string, v any) error {
func (b *BoltStorage) Get(bucket string, key string, v any) (bool, error) {
var data []byte
err := b.db.View(func(tx *bbolt.Tx) error {
b := tx.Bucket([]byte(bucket))
@@ -155,9 +158,15 @@ func (b *BoltStorage) Get(bucket string, key string, v any) error {
return nil
})
if err != nil {
return err
return false, err
}
return json.Unmarshal(data, v)
if data == nil {
return false, nil
}
if err := json.Unmarshal(data, v); err != nil {
return false, err
}
return true, nil
}
func (b *BoltStorage) List(bucket string, v any) error {
+3 -3
View File
@@ -2,9 +2,9 @@ package download
import (
gonanoid "github.com/matoous/go-nanoid/v2"
"github.com/monkeyWie/gopeed-core/internal/fetcher"
"github.com/monkeyWie/gopeed-core/pkg/base"
"github.com/monkeyWie/gopeed-core/pkg/util"
"github.com/monkeyWie/gopeed/internal/fetcher"
"github.com/monkeyWie/gopeed/pkg/base"
"github.com/monkeyWie/gopeed/pkg/util"
"sync"
"time"
)
+4 -4
View File
@@ -2,10 +2,10 @@ package rest
import (
"github.com/gorilla/mux"
"github.com/monkeyWie/gopeed-core/pkg/base"
"github.com/monkeyWie/gopeed-core/pkg/download"
"github.com/monkeyWie/gopeed-core/pkg/rest/model"
"github.com/monkeyWie/gopeed-core/pkg/rest/util"
"github.com/monkeyWie/gopeed/pkg/base"
"github.com/monkeyWie/gopeed/pkg/download"
"github.com/monkeyWie/gopeed/pkg/rest/model"
"github.com/monkeyWie/gopeed/pkg/rest/util"
"net/http"
"strings"
)
+1 -1
View File
@@ -1,6 +1,6 @@
package model
import "github.com/monkeyWie/gopeed-core/pkg/base"
import "github.com/monkeyWie/gopeed/pkg/base"
type CreateTask struct {
Res *base.Resource `json:"res"`
+76 -46
View File
@@ -2,10 +2,11 @@ package rest
import (
"context"
"github.com/gorilla/handlers"
"github.com/gorilla/mux"
"github.com/monkeyWie/gopeed-core/pkg/download"
"github.com/monkeyWie/gopeed-core/pkg/rest/model"
"github.com/monkeyWie/gopeed-core/pkg/util"
"github.com/monkeyWie/gopeed/pkg/download"
"github.com/monkeyWie/gopeed/pkg/rest/model"
"github.com/monkeyWie/gopeed/pkg/util"
"net"
"net/http"
"strconv"
@@ -18,59 +19,34 @@ var (
)
func Start(startCfg *model.StartConfig) (int, error) {
if startCfg == nil {
startCfg = &model.StartConfig{}
}
startCfg.Init()
downloadCfg := &download.DownloaderConfig{}
if startCfg.Storage == model.StorageBolt {
downloadCfg.Storage = download.NewBoltStorage(startCfg.StorageDir)
} else {
downloadCfg.Storage = download.NewMemStorage()
}
downloadCfg.RefreshInterval = startCfg.RefreshInterval
Downloader = download.NewDownloader(downloadCfg.Init())
if err := Downloader.Setup(); err != nil {
return 0, err
}
serverConfig := getAndPutServerConfig(startCfg)
var address string
if startCfg.Network == "unix" {
address = startCfg.Address
util.SafeRemove(address)
} else {
address = net.JoinHostPort(serverConfig.Host, strconv.Itoa(serverConfig.Port))
}
listener, err := net.Listen(startCfg.Network, address)
srv, listener, err := buildServer(startCfg)
if err != nil {
return 0, err
}
var r = mux.NewRouter()
r.Methods(http.MethodPost).Path("/api/v1/resolve").HandlerFunc(Resolve)
r.Methods(http.MethodPost).Path("/api/v1/tasks").HandlerFunc(CreateTask)
r.Methods(http.MethodPut).Path("/api/v1/tasks/{id}/pause").HandlerFunc(PauseTask)
r.Methods(http.MethodPut).Path("/api/v1/tasks/{id}/continue").HandlerFunc(ContinueTask)
r.Methods(http.MethodDelete).Path("/api/v1/tasks/{id}").HandlerFunc(DeleteTask)
r.Methods(http.MethodGet).Path("/api/v1/tasks/{id}").HandlerFunc(GetTask)
r.Methods(http.MethodGet).Path("/api/v1/tasks").HandlerFunc(GetTasks)
r.Methods(http.MethodGet).Path("/api/v1/config").HandlerFunc(GetConfig)
r.Methods(http.MethodPut).Path("/api/v1/config").HandlerFunc(PutConfig)
srv = &http.Server{Handler: r}
go func() {
if err := srv.Serve(listener); err != nil && err != http.ErrServerClosed {
// TODO log
panic(err)
}
}()
port := 0
if addr, ok := listener.Addr().(*net.TCPAddr); ok {
return addr.Port, nil
port = addr.Port
}
return 0, nil
return port, nil
}
func StartSync(startCfg *model.StartConfig) error {
srv, listener, err := buildServer(startCfg)
if err != nil {
return err
}
if err := srv.Serve(listener); err != nil && err != http.ErrServerClosed {
return err
}
return nil
}
func Stop() {
@@ -86,11 +62,65 @@ func Stop() {
}
}
func buildServer(startCfg *model.StartConfig) (*http.Server, net.Listener, error) {
if startCfg == nil {
startCfg = &model.StartConfig{}
}
startCfg.Init()
downloadCfg := &download.DownloaderConfig{}
if startCfg.Storage == model.StorageBolt {
downloadCfg.Storage = download.NewBoltStorage(startCfg.StorageDir)
} else {
downloadCfg.Storage = download.NewMemStorage()
}
downloadCfg.RefreshInterval = startCfg.RefreshInterval
Downloader = download.NewDownloader(downloadCfg.Init())
if err := Downloader.Setup(); err != nil {
return nil, nil, err
}
serverConfig := getAndPutServerConfig(startCfg)
var address string
if startCfg.Network == "unix" {
address = startCfg.Address
util.SafeRemove(address)
} else {
address = net.JoinHostPort(serverConfig.Host, strconv.Itoa(serverConfig.Port))
}
listener, err := net.Listen(startCfg.Network, address)
if err != nil {
return nil, nil, err
}
var r = mux.NewRouter()
r.Methods(http.MethodPost).Path("/api/v1/resolve").HandlerFunc(Resolve)
r.Methods(http.MethodPost).Path("/api/v1/tasks").HandlerFunc(CreateTask)
r.Methods(http.MethodPut).Path("/api/v1/tasks/{id}/pause").HandlerFunc(PauseTask)
r.Methods(http.MethodPut).Path("/api/v1/tasks/{id}/continue").HandlerFunc(ContinueTask)
r.Methods(http.MethodDelete).Path("/api/v1/tasks/{id}").HandlerFunc(DeleteTask)
r.Methods(http.MethodGet).Path("/api/v1/tasks/{id}").HandlerFunc(GetTask)
r.Methods(http.MethodGet).Path("/api/v1/tasks").HandlerFunc(GetTasks)
r.Methods(http.MethodGet).Path("/api/v1/config").HandlerFunc(GetConfig)
r.Methods(http.MethodPut).Path("/api/v1/config").HandlerFunc(PutConfig)
srv = &http.Server{Handler: handlers.CORS(
handlers.AllowedHeaders([]string{"X-Requested-With", "Content-Type", "Authorization"}),
handlers.AllowedMethods([]string{"GET", "POST", "PUT", "DELETE", "OPTIONS"}),
handlers.AllowedOrigins([]string{"*"}),
)(r)}
return srv, listener, nil
}
func getAndPutServerConfig(startCfg *model.StartConfig) *model.ServerConfig {
var serverConfig model.ServerConfig
err := Downloader.GetConfig(&serverConfig)
// first start
exist, err := Downloader.GetConfig(&serverConfig)
if err != nil {
// TODO log
}
// first start
if !exist {
if startCfg.Network == "tcp" {
host, port, _ := net.SplitHostPort(startCfg.Address)
serverConfig.Host = host
+4 -4
View File
@@ -5,10 +5,10 @@ import (
"encoding/json"
"errors"
"fmt"
"github.com/monkeyWie/gopeed-core/internal/test"
"github.com/monkeyWie/gopeed-core/pkg/base"
"github.com/monkeyWie/gopeed-core/pkg/download"
"github.com/monkeyWie/gopeed-core/pkg/rest/model"
"github.com/monkeyWie/gopeed/internal/test"
"github.com/monkeyWie/gopeed/pkg/base"
"github.com/monkeyWie/gopeed/pkg/download"
"github.com/monkeyWie/gopeed/pkg/rest/model"
"io"
"net"
"net/http"
+1 -1
View File
@@ -2,7 +2,7 @@ package util
import (
"encoding/json"
"github.com/monkeyWie/gopeed-core/pkg/rest/model"
"github.com/monkeyWie/gopeed/pkg/rest/model"
"net/http"
)
+1 -1
View File
@@ -1,6 +1,6 @@
/* Code generated by cmd/cgo; DO NOT EDIT. */
/* package github.com/monkeyWie/gopeed-core/bind/desktop */
/* package github.com/monkeyWie/gopeed/bind/desktop */
#line 1 "cgo-builtin-export-prolog"
+16 -13
View File
@@ -23,20 +23,23 @@ class _Client {
if (_instance == null) {
_instance = _Client._internal();
var dio = Dio();
dio.options.baseUrl = "http://127.0.0.1:${LibgopeedBoot.instance.port}";
dio.options.baseUrl = "http://${LibgopeedBoot.instance.config.address}";
_instance!.dio = dio;
(_instance!.dio.httpClientAdapter as DefaultHttpClientAdapter)
.onHttpClientCreate = (client) {
if (LibgopeedBoot.instance.network == "unix") {
client.connectionFactory =
(Uri uri, String? proxyHost, int? proxyPort) {
var address = InternetAddress(LibgopeedBoot.instance.address,
type: InternetAddressType.unix);
return Socket.startConnect(address, 0);
};
}
return client;
};
if(_instance!.dio.httpClientAdapter is DefaultHttpClientAdapter){
(_instance!.dio.httpClientAdapter as DefaultHttpClientAdapter)
.onHttpClientCreate = (client) {
if (LibgopeedBoot.instance.config.network == "unix") {
client.connectionFactory =
(Uri uri, String? proxyHost, int? proxyPort) {
var address = InternetAddress(LibgopeedBoot.instance.config.address,
type: InternetAddressType.unix);
return Socket.startConnect(address, 0);
};
}
return client;
};
}
}
return _instance!;
}
@@ -0,0 +1,22 @@
import 'dart:async';
import '../libgopeed_boot.dart';
LibgopeedBoot create() => LibgopeedBootBrowser();
class LibgopeedBootBrowser implements LibgopeedBoot {
late LibgopeedConfig _config;
LibgopeedBootBrowser() {
_config = LibgopeedConfig();
}
@override
LibgopeedConfig get config => _config;
@override
Future<void> start() async {}
@override
Future<void> stop() async {}
}
@@ -0,0 +1,173 @@
import 'dart:async';
import 'dart:ffi';
import 'dart:io';
import 'dart:isolate';
import 'package:flutter/foundation.dart';
import 'package:gopeed/core/common/libgopeed_channel.dart';
import 'package:gopeed/util/util.dart';
import 'package:path_provider/path_provider.dart';
import '../common/libgopeed_ffi.dart';
import '../common/libgopeed_interface.dart';
import '../common/start_config.dart';
import '../ffi/libgopeed_bind.dart';
import '../libgopeed_boot.dart';
LibgopeedBoot create() => LibgopeedBootNative();
class LibgopeedBootNative implements LibgopeedBoot {
late LibgopeedConfig _config;
late LibgopeedInterface _libgopeed;
late SendPort _childSendPort;
LibgopeedBootNative() {
_config = LibgopeedConfig();
if (!Util.isDesktop()) {
_libgopeed = LibgopeedChannel();
}
}
@override
LibgopeedConfig get config => _config;
@override
Future<void> start() async {
// if is debug mode,use local http server
if (kDebugMode) {
return;
}
var storageDir = "./";
if (!Util.isUnix()) {
// not support unix socket, use tcp
_config.network = "tcp";
_config.address = "127.0.0.1:0";
} else {
_config.network = "unix";
if (Util.isDesktop()) {
_config.address = LibgopeedBoot.unixSocketPath;
} else if (Platform.isAndroid) {
_config.address =
"${(await getTemporaryDirectory()).path}/${LibgopeedBoot.unixSocketPath}";
storageDir = (await getExternalStorageDirectory())?.path ?? "";
}
}
final cfg = StartConfig(
network: _config.network,
address: _config.address,
storage: 'bolt',
storageDir: storageDir,
refreshInterval: _config.refreshInterval);
var port =
Util.isDesktop() ? await _ffiStart(cfg) : await _libgopeed.start(cfg);
if (_config.network == "tcp") {
_config.address = "${_config.address.split(":")[0]}:$port";
}
}
@override
Future<void> stop() async {
if (Util.isDesktop()) {
await _ffiStop();
} else {
await _libgopeed.stop();
}
}
_ffiInit() {
if (Platform.isMacOS) {
_libgopeed =
LibgopeedFFi(LibgopeedBind(DynamicLibrary.open('libgopeed.dylib')));
}
}
// FFI run in isolate
Future<int> _ffiStart(StartConfig cfg) async {
var startCompleter = Completer<int>();
var mainReceive = ReceivePort();
var isolate = await Isolate.spawn((SendPort sendPort) {
_ffiInit();
var childReceive = ReceivePort();
sendPort.send(childReceive.sendPort);
childReceive.listen((message) async {
late _Result result;
try {
if (message is _StartParam) {
result = _StartResult();
(result as _StartResult).port = await _libgopeed.start(message.cfg);
}
if (message is _StopParam) {
result = _StopResult();
await _libgopeed.stop();
childReceive.close();
Isolate.exit(sendPort);
}
} on Exception catch (e) {
result.exception = e;
}
sendPort.send(result);
});
}, mainReceive.sendPort);
var childCompleter = Completer<void>();
mainReceive.listen((message) {
if (message is SendPort) {
_childSendPort = message;
childCompleter.complete();
}
if (message is _StartResult) {
if (message.exception != null) {
startCompleter.completeError(message.exception!);
} else {
startCompleter.complete(message.port!);
}
}
if (message is _StopResult) {
isolate.kill();
if (message.exception != null) {
_stopCompleter.completeError(message.exception!);
} else {
_stopCompleter.complete();
}
}
});
await childCompleter.future;
_childSendPort.send(_StartParam(cfg: cfg));
return startCompleter.future;
}
late Completer<void> _stopCompleter;
Future<void> _ffiStop() async {
_stopCompleter = Completer<void>();
_childSendPort.send(_StopParam());
return _stopCompleter.future;
}
}
class _Result {
Exception? exception;
_Result();
}
class _StartParam {
final StartConfig cfg;
_StartParam({required this.cfg});
}
class _StartResult extends _Result {
int? port;
_StartResult();
}
class _StopParam {}
class _StopResult extends _Result {
_StopResult();
}
+20 -157
View File
@@ -1,171 +1,34 @@
import 'dart:async';
import 'dart:ffi';
import 'dart:io';
import 'dart:isolate';
import "./libgopeed_boot_stub.dart"
if (dart.library.html) 'entry/libgopeed_boot_browser.dart'
if (dart.library.io) 'entry/libgopeed_boot_native.dart';
import 'package:gopeed/core/common/libgopeed_channel.dart';
import 'package:gopeed/core/common/libgopeed_ffi.dart';
import 'package:gopeed/core/common/start_config.dart';
import 'package:path_provider/path_provider.dart';
class LibgopeedConfig {
late String network;
late String address;
late int refreshInterval;
import '../util/util.dart';
import 'common/libgopeed_interface.dart';
import 'ffi/libgopeed_bind.dart';
LibgopeedConfig({
this.network = "tcp",
this.address = "127.0.0.1:9999",
this.refreshInterval = 500,
});
}
const unixSocketPath = 'gopeed.sock';
class LibgopeedBoot {
String network = "";
String address = "";
int port = 0;
int refreshInterval = 250;
late LibgopeedInterface _libgopeed;
late SendPort _childSendPort;
abstract class LibgopeedBoot {
static const unixSocketPath = 'gopeed.sock';
static LibgopeedBoot? _instance;
static LibgopeedBoot get instance {
if (_instance == null) {
_instance = LibgopeedBoot._internal();
if (!Util.isDesktop()) {
_instance!._libgopeed = LibgopeedChannel();
}
}
_instance ??= LibgopeedBoot();
return _instance!;
}
LibgopeedBoot._internal();
factory LibgopeedBoot() => create();
Future<void> start() async {
var storageDir = "./";
if (!Util.isUnix()) {
// not support unix socket, use tcp
network = "tcp";
address = "127.0.0.1:0";
} else {
network = "unix";
if (Util.isDesktop()) {
address = unixSocketPath;
} else if (Platform.isAndroid) {
address = "${(await getTemporaryDirectory()).path}/$unixSocketPath";
storageDir = (await getExternalStorageDirectory())?.path ?? "";
}
}
final cfg = StartConfig(
network: network,
address: address,
storage: 'bolt',
storageDir: storageDir,
refreshInterval: refreshInterval);
if (Util.isDesktop()) {
port = await _ffiStart(cfg);
} else {
port = await _libgopeed.start(cfg);
}
}
Future<void> start();
Future<void> stop() async {
if (Util.isDesktop()) {
await _ffiStop();
} else {
await _libgopeed.stop();
}
}
Future<void> stop();
_ffiInit() {
if (Platform.isMacOS) {
_libgopeed =
LibgopeedFFi(LibgopeedBind(DynamicLibrary.open('libgopeed.dylib')));
}
}
// FFI run in isolate
Future<int> _ffiStart(StartConfig cfg) async {
var startCompleter = Completer<int>();
var mainReceive = ReceivePort();
var isolate = await Isolate.spawn((SendPort sendPort) {
_ffiInit();
var childReceive = ReceivePort();
sendPort.send(childReceive.sendPort);
childReceive.listen((message) async {
late _Result result;
try {
if (message is _StartParam) {
result = _StartResult();
(result as _StartResult).port = await _libgopeed.start(message.cfg);
}
if (message is _StopParam) {
result = _StopResult();
await _libgopeed.stop();
childReceive.close();
Isolate.exit(sendPort);
}
} on Exception catch (e) {
result.exception = e;
}
sendPort.send(result);
});
}, mainReceive.sendPort);
var childCompleter = Completer<void>();
mainReceive.listen((message) {
if (message is SendPort) {
_childSendPort = message;
childCompleter.complete();
}
if (message is _StartResult) {
if (message.exception != null) {
startCompleter.completeError(message.exception!);
} else {
startCompleter.complete(message.port!);
}
}
if (message is _StopResult) {
isolate.kill();
if (message.exception != null) {
_stopCompleter.completeError(message.exception!);
} else {
_stopCompleter.complete();
}
}
});
await childCompleter.future;
_childSendPort.send(_StartParam(cfg: cfg));
return startCompleter.future;
}
late Completer<void> _stopCompleter;
Future<void> _ffiStop() async {
_stopCompleter = Completer<void>();
_childSendPort.send(_StopParam());
return _stopCompleter.future;
}
}
class _Result {
Exception? exception;
_Result();
}
class _StartParam {
final StartConfig cfg;
_StartParam({required this.cfg});
}
class _StartResult extends _Result {
int? port;
_StartResult();
}
class _StopParam {}
class _StopResult extends _Result {
_StopResult();
LibgopeedConfig get config;
}
@@ -0,0 +1,3 @@
import 'libgopeed_boot.dart';
LibgopeedBoot create() => throw UnimplementedError();
+1 -1
View File
@@ -21,4 +21,4 @@ void main() async {
themeMode: Setting.instance.themeMode,
getPages: Routes.routes,
));
}
}
+4 -4
View File
@@ -1,4 +1,3 @@
import 'dart:developer' as developer;
import 'dart:io';
import 'package:flutter/material.dart';
@@ -15,6 +14,7 @@ import 'package:permission_handler/permission_handler.dart';
import 'package:rounded_loading_button/rounded_loading_button.dart';
import '../../routes/router.dart';
import '../../util/util.dart';
import '../../widget/directory_selector.dart';
class CreateView extends GetView<CreateController> {
@@ -114,7 +114,7 @@ class CreateView extends GetView<CreateController> {
width: width,
child: Form(
key: createFormKey,
autovalidateMode: AutovalidateMode.always, //开启自动校验
autovalidateMode: AutovalidateMode.always,
child: Column(
children: [
Expanded(
@@ -159,7 +159,7 @@ class CreateView extends GetView<CreateController> {
try {
if (createFormKey.currentState!.validate()) {
downloadController.start();
if (Platform.isAndroid) {
if (Util.isAndroid()) {
if (!await Permission.storage.request().isGranted) {
Get.snackbar("错误", "需要开启存储权限");
return;
@@ -183,7 +183,7 @@ class CreateView extends GetView<CreateController> {
}
} catch (e) {
Get.snackbar("错误", e.toString());
developer.log(e.toString(), name: 'flutter');
rethrow;
} finally {
downloadController.reset();
}
@@ -55,7 +55,7 @@ class TaskController extends GetxController {
loadTab();
_timer = Timer.periodic(
Duration(milliseconds: LibgopeedBoot.instance.refreshInterval),
Duration(milliseconds: LibgopeedBoot.instance.config.refreshInterval),
(timer) async {
loadTab();
});
+5 -5
View File
@@ -1,9 +1,5 @@
import 'dart:convert';
import 'dart:io';
import 'package:external_path/external_path.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:gopeed/api/api.dart';
import 'package:path_provider/path_provider.dart';
@@ -48,7 +44,11 @@ class Setting {
this.themeMode = ThemeMode.values.byName(themeMode);
}
if (Platform.isAndroid) {
if(Util.isWeb()){
downloadDir = "./";
return;
}
if (Util.isAndroid()) {
downloadDir =
'${await ExternalPath.getExternalStoragePublicDirectory(ExternalPath.DIRECTORY_DOWNLOADS)}/com.gopeed';
return;
+4 -2
View File
@@ -3,11 +3,13 @@ import 'dart:io';
import 'package:macos_secure_bookmarks/macos_secure_bookmarks.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'util.dart';
class MacSecureUtil {
static const _bookmarkKey = "bookmark:";
static Future<void> saveBookmark(String dir) async {
if (!Platform.isMacOS) {
if (!Util.isMacos()) {
return;
}
final secureBookmarks = SecureBookmarks();
@@ -17,7 +19,7 @@ class MacSecureUtil {
}
static Future<void> loadBookmark() async {
if (!Platform.isMacOS) {
if (!Util.isMacos()) {
return;
}
final prefs = await SharedPreferences.getInstance();
+20
View File
@@ -1,5 +1,7 @@
import 'dart:io';
import 'package:flutter/foundation.dart';
class Util {
static String fmtByte(int byte) {
if (byte < 1024) {
@@ -21,11 +23,29 @@ class Util {
return (dir == "" ? "" : "$dir/") + buildPath(path, name);
}
static isWeb() {
return kIsWeb;
}
static isAndroid() {
return !kIsWeb && Platform.isAndroid;
}
static isMacos() {
return !kIsWeb && Platform.isMacOS;
}
static isDesktop() {
if (kIsWeb) {
return false;
}
return Platform.isWindows || Platform.isLinux || Platform.isMacOS;
}
static isUnix() {
if (kIsWeb) {
return false;
}
return !Platform.isWindows;
}
}
@@ -6,10 +6,12 @@
<true/>
<key>com.apple.security.cs.allow-jit</key>
<true/>
<key>com.apple.security.files.bookmarks.app-scope</key>
<true/>
<key>com.apple.security.files.downloads.read-write</key>
<true/>
<key>com.apple.security.files.user-selected.read-write</key>
<true/>
<key>com.apple.security.files.bookmarks.app-scope</key>
<true/>
<key>com.apple.security.network.client</key>
<true/>
<key>com.apple.security.network.server</key>
+4 -2
View File
@@ -4,10 +4,12 @@
<dict>
<key>com.apple.security.app-sandbox</key>
<true/>
<key>com.apple.security.files.bookmarks.app-scope</key>
<true/>
<key>com.apple.security.files.downloads.read-write</key>
<true/>
<key>com.apple.security.files.user-selected.read-write</key>
<true/>
<key>com.apple.security.files.bookmarks.app-scope</key>
<true/>
<key>com.apple.security.network.client</key>
<true/>
<key>com.apple.security.network.server</key>