Compare commits
19 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2390a3ef61 | ||
|
|
ffda81715f | ||
|
|
f991700031 | ||
|
|
e1ba6a90ff | ||
|
|
354161037b | ||
|
|
00d28df3ee | ||
|
|
23abed0949 | ||
|
|
2acf01dcb7 | ||
|
|
470c6a8b0e | ||
|
|
efc2810d1d | ||
|
|
de2374577f | ||
|
|
2a1f949c13 | ||
|
|
959e274063 | ||
|
|
b6a2bd37b1 | ||
|
|
3e60c9913a | ||
|
|
fd7f3f4029 | ||
|
|
2705a5d444 | ||
|
|
556055cfcb | ||
|
|
67a0d06944 |
@@ -54,10 +54,11 @@ function build() {
|
|||||||
cp -R "$ROOT"/www "$DIST"/
|
cp -R "$ROOT"/www "$DIST"/
|
||||||
cp -R "$ROOT"/pages "$DIST"/
|
cp -R "$ROOT"/pages "$DIST"/
|
||||||
|
|
||||||
# we support TOA on linux/amd64 only
|
# we support TOA on linux only
|
||||||
if [ "$OS" == "linux" ] && [ "$ARCH" == "amd64" ]
|
if [ "$OS" == "linux" ] && [ -f "${ROOT}/edge-toa/edge-toa-${ARCH}" ]
|
||||||
then
|
then
|
||||||
cp -R "$ROOT"/edge-toa "$DIST"
|
mkdir "$DIST/edge-toa"
|
||||||
|
cp "${ROOT}/edge-toa/edge-toa-${ARCH}" "$DIST/edge-toa/edge-toa"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo "building ..."
|
echo "building ..."
|
||||||
|
|||||||
Binary file not shown.
@@ -7,6 +7,7 @@ import (
|
|||||||
"github.com/TeaOSLab/EdgeNode/internal/apps"
|
"github.com/TeaOSLab/EdgeNode/internal/apps"
|
||||||
teaconst "github.com/TeaOSLab/EdgeNode/internal/const"
|
teaconst "github.com/TeaOSLab/EdgeNode/internal/const"
|
||||||
"github.com/TeaOSLab/EdgeNode/internal/nodes"
|
"github.com/TeaOSLab/EdgeNode/internal/nodes"
|
||||||
|
fsutils "github.com/TeaOSLab/EdgeNode/internal/utils/fs"
|
||||||
_ "github.com/iwind/TeaGo/bootstrap"
|
_ "github.com/iwind/TeaGo/bootstrap"
|
||||||
"github.com/iwind/TeaGo/logs"
|
"github.com/iwind/TeaGo/logs"
|
||||||
"github.com/iwind/TeaGo/maps"
|
"github.com/iwind/TeaGo/maps"
|
||||||
@@ -365,6 +366,29 @@ func main() {
|
|||||||
}
|
}
|
||||||
fmt.Println(string(statsJSON))
|
fmt.Println(string(statsJSON))
|
||||||
})
|
})
|
||||||
|
app.On("disk", func() {
|
||||||
|
var args = os.Args[2:]
|
||||||
|
if len(args) > 0 {
|
||||||
|
switch args[0] {
|
||||||
|
case "speed":
|
||||||
|
speedMB, isFast, err := fsutils.CheckDiskIsFast()
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("[ERROR]" + err.Error())
|
||||||
|
} else {
|
||||||
|
fmt.Printf("Speed: %.2fMB/s\n", speedMB)
|
||||||
|
if isFast {
|
||||||
|
fmt.Println("IsFast: true")
|
||||||
|
} else {
|
||||||
|
fmt.Println("IsFast: false")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
fmt.Println("Usage: edge-node disk [speed]")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
fmt.Println("Usage: edge-node disk [speed]")
|
||||||
|
}
|
||||||
|
})
|
||||||
app.Run(func() {
|
app.Run(func() {
|
||||||
var node = nodes.NewNode()
|
var node = nodes.NewNode()
|
||||||
node.Start()
|
node.Start()
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import "errors"
|
|||||||
// 常用的几个错误
|
// 常用的几个错误
|
||||||
var (
|
var (
|
||||||
ErrNotFound = errors.New("cache not found")
|
ErrNotFound = errors.New("cache not found")
|
||||||
ErrFileIsWriting = errors.New("the file is writing")
|
ErrFileIsWriting = errors.New("the cache file is updating")
|
||||||
ErrInvalidRange = errors.New("invalid range")
|
ErrInvalidRange = errors.New("invalid range")
|
||||||
ErrEntityTooLarge = errors.New("entity too large")
|
ErrEntityTooLarge = errors.New("entity too large")
|
||||||
ErrWritingUnavailable = errors.New("writing unavailable")
|
ErrWritingUnavailable = errors.New("writing unavailable")
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
package teaconst
|
package teaconst
|
||||||
|
|
||||||
const (
|
const (
|
||||||
Version = "1.2.2"
|
Version = "1.2.6"
|
||||||
|
|
||||||
ProductName = "Edge Node"
|
ProductName = "Edge Node"
|
||||||
ProcessName = "edge-node"
|
ProcessName = "edge-node"
|
||||||
|
|||||||
@@ -3,10 +3,11 @@ package events
|
|||||||
type Event = string
|
type Event = string
|
||||||
|
|
||||||
const (
|
const (
|
||||||
EventStart Event = "start" // start loading
|
EventStart Event = "start" // start loading
|
||||||
EventLoaded Event = "loaded" // first load
|
EventLoaded Event = "loaded" // first load
|
||||||
EventQuit Event = "quit" // quit node gracefully
|
EventQuit Event = "quit" // quit node gracefully
|
||||||
EventReload Event = "reload" // reload config
|
EventReload Event = "reload" // reload config
|
||||||
EventTerminated Event = "terminated" // process terminated
|
EventTerminated Event = "terminated" // process terminated
|
||||||
EventNFTablesReady Event = "nftablesReady" // nftables ready
|
EventNFTablesReady Event = "nftablesReady" // nftables ready
|
||||||
|
EventReloadSomeServers Event = "reloadSomeServers" // reload some servers
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -24,6 +24,12 @@ func On(event Event, callback func()) {
|
|||||||
OnKey(event, nil, callback)
|
OnKey(event, nil, callback)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func OnEvents(events []Event, callback func()) {
|
||||||
|
for _, event := range events {
|
||||||
|
On(event, callback)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func OnClose(callback func()) {
|
func OnClose(callback func()) {
|
||||||
On(EventQuit, callback)
|
On(EventQuit, callback)
|
||||||
On(EventTerminated, callback)
|
On(EventTerminated, callback)
|
||||||
|
|||||||
@@ -1,27 +1,28 @@
|
|||||||
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||||
|
|
||||||
package goman
|
package goman_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"github.com/TeaOSLab/EdgeNode/internal/goman"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestNew(t *testing.T) {
|
func TestNew(t *testing.T) {
|
||||||
New(func() {
|
goman.New(func() {
|
||||||
t.Log("Hello")
|
t.Log("Hello")
|
||||||
|
|
||||||
t.Log(List())
|
t.Log(goman.List())
|
||||||
})
|
})
|
||||||
|
|
||||||
time.Sleep(1 * time.Second)
|
time.Sleep(1 * time.Second)
|
||||||
t.Log(List())
|
t.Log(goman.List())
|
||||||
|
|
||||||
time.Sleep(1 * time.Second)
|
time.Sleep(1 * time.Second)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestNewWithArgs(t *testing.T) {
|
func TestNewWithArgs(t *testing.T) {
|
||||||
NewWithArgs(func(args ...interface{}) {
|
goman.NewWithArgs(func(args ...interface{}) {
|
||||||
t.Log(args[0], args[1])
|
t.Log(args[0], args[1])
|
||||||
}, 1, 2)
|
}, 1, 2)
|
||||||
time.Sleep(1 * time.Second)
|
time.Sleep(1 * time.Second)
|
||||||
|
|||||||
52
internal/goman/task_group.go
Normal file
52
internal/goman/task_group.go
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
// Copyright 2023 GoEdge CDN goedge.cdn@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||||
|
|
||||||
|
package goman
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/TeaOSLab/EdgeNode/internal/zero"
|
||||||
|
"runtime"
|
||||||
|
"sync"
|
||||||
|
)
|
||||||
|
|
||||||
|
type TaskGroup struct {
|
||||||
|
semi chan zero.Zero
|
||||||
|
wg *sync.WaitGroup
|
||||||
|
locker *sync.RWMutex
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewTaskGroup() *TaskGroup {
|
||||||
|
var concurrent = runtime.NumCPU()
|
||||||
|
if concurrent <= 1 {
|
||||||
|
concurrent = 2
|
||||||
|
}
|
||||||
|
return &TaskGroup{
|
||||||
|
semi: make(chan zero.Zero, concurrent),
|
||||||
|
wg: &sync.WaitGroup{},
|
||||||
|
locker: &sync.RWMutex{},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *TaskGroup) Run(f func()) {
|
||||||
|
this.wg.Add(1)
|
||||||
|
go func() {
|
||||||
|
defer this.wg.Done()
|
||||||
|
|
||||||
|
this.semi <- zero.Zero{}
|
||||||
|
|
||||||
|
f()
|
||||||
|
|
||||||
|
<-this.semi
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *TaskGroup) Wait() {
|
||||||
|
this.wg.Wait()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *TaskGroup) Lock() {
|
||||||
|
this.locker.Lock()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *TaskGroup) Unlock() {
|
||||||
|
this.locker.Unlock()
|
||||||
|
}
|
||||||
30
internal/goman/task_group_test.go
Normal file
30
internal/goman/task_group_test.go
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
// Copyright 2023 GoEdge CDN goedge.cdn@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||||
|
|
||||||
|
package goman_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/TeaOSLab/EdgeNode/internal/goman"
|
||||||
|
"runtime"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestNewTaskGroup(t *testing.T) {
|
||||||
|
var group = goman.NewTaskGroup()
|
||||||
|
var m = map[int]bool{}
|
||||||
|
|
||||||
|
for i := 0; i < runtime.NumCPU()*2; i++ {
|
||||||
|
var index = i
|
||||||
|
group.Run(func() {
|
||||||
|
t.Log("task", index)
|
||||||
|
|
||||||
|
group.Lock()
|
||||||
|
_, ok := m[index]
|
||||||
|
if ok {
|
||||||
|
t.Error("duplicated:", index)
|
||||||
|
}
|
||||||
|
m[index] = true
|
||||||
|
group.Unlock()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
group.Wait()
|
||||||
|
}
|
||||||
@@ -129,9 +129,8 @@ func (this *ClientConn) Read(b []byte) (n int, err error) {
|
|||||||
// 检测是否为超时错误
|
// 检测是否为超时错误
|
||||||
var isTimeout = err != nil && os.IsTimeout(err)
|
var isTimeout = err != nil && os.IsTimeout(err)
|
||||||
var isHandshakeError = isTimeout && !this.hasRead
|
var isHandshakeError = isTimeout && !this.hasRead
|
||||||
if isTimeout {
|
|
||||||
_ = this.SetLinger(0)
|
if err != nil {
|
||||||
} else {
|
|
||||||
_ = this.SetLinger(nodeconfigs.DefaultTCPLinger)
|
_ = this.SetLinger(nodeconfigs.DefaultTCPLinger)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"os"
|
||||||
"regexp"
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
@@ -131,21 +132,29 @@ func (this *HTTPCacheTaskManager) Loop() error {
|
|||||||
|
|
||||||
var pbResults = []*pb.UpdateHTTPCacheTaskKeysStatusRequest_KeyResult{}
|
var pbResults = []*pb.UpdateHTTPCacheTaskKeysStatusRequest_KeyResult{}
|
||||||
|
|
||||||
|
var taskGroup = goman.NewTaskGroup()
|
||||||
for _, key := range keys {
|
for _, key := range keys {
|
||||||
err = this.processKey(key)
|
var taskKey = key
|
||||||
|
taskGroup.Run(func() {
|
||||||
|
processErr := this.processKey(taskKey)
|
||||||
|
var pbResult = &pb.UpdateHTTPCacheTaskKeysStatusRequest_KeyResult{
|
||||||
|
Id: taskKey.Id,
|
||||||
|
NodeClusterId: taskKey.NodeClusterId,
|
||||||
|
Error: "",
|
||||||
|
}
|
||||||
|
|
||||||
var pbResult = &pb.UpdateHTTPCacheTaskKeysStatusRequest_KeyResult{
|
if processErr != nil {
|
||||||
Id: key.Id,
|
pbResult.Error = processErr.Error()
|
||||||
NodeClusterId: key.NodeClusterId,
|
}
|
||||||
Error: "",
|
|
||||||
}
|
|
||||||
|
|
||||||
if err != nil {
|
taskGroup.Lock()
|
||||||
pbResult.Error = err.Error()
|
pbResults = append(pbResults, pbResult)
|
||||||
}
|
taskGroup.Unlock()
|
||||||
pbResults = append(pbResults, pbResult)
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
taskGroup.Wait()
|
||||||
|
|
||||||
_, err = rpcClient.HTTPCacheTaskKeyRPC.UpdateHTTPCacheTaskKeysStatus(rpcClient.Context(), &pb.UpdateHTTPCacheTaskKeysStatusRequest{KeyResults: pbResults})
|
_, err = rpcClient.HTTPCacheTaskKeyRPC.UpdateHTTPCacheTaskKeysStatus(rpcClient.Context(), &pb.UpdateHTTPCacheTaskKeysStatusRequest{KeyResults: pbResults})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -242,6 +251,7 @@ func (this *HTTPCacheTaskManager) fetchKey(key *pb.HTTPCacheTaskKey) error {
|
|||||||
req.Header.Set("Accept-Encoding", "gzip, deflate, br")
|
req.Header.Set("Accept-Encoding", "gzip, deflate, br")
|
||||||
resp, err := this.httpClient.Do(req)
|
resp, err := this.httpClient.Do(req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
err = this.simplifyErr(err)
|
||||||
return errors.New("request failed: " + fullKey + ": " + err.Error())
|
return errors.New("request failed: " + fullKey + ": " + err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -249,13 +259,32 @@ func (this *HTTPCacheTaskManager) fetchKey(key *pb.HTTPCacheTaskKey) error {
|
|||||||
_ = resp.Body.Close()
|
_ = resp.Body.Close()
|
||||||
}()
|
}()
|
||||||
|
|
||||||
// 读取内容,以便于生成缓存
|
|
||||||
_, _ = io.Copy(io.Discard, resp.Body)
|
|
||||||
|
|
||||||
// 处理502
|
// 处理502
|
||||||
if resp.StatusCode == http.StatusBadGateway {
|
if resp.StatusCode == http.StatusBadGateway {
|
||||||
return errors.New("read origin site timeout")
|
return errors.New("read origin site timeout")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 读取内容,以便于生成缓存
|
||||||
|
_, err = io.Copy(io.Discard, resp.Body)
|
||||||
|
if err != nil {
|
||||||
|
if err != io.EOF {
|
||||||
|
err = this.simplifyErr(err)
|
||||||
|
return errors.New("request failed: " + fullKey + ": " + err.Error())
|
||||||
|
} else {
|
||||||
|
err = nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (this *HTTPCacheTaskManager) simplifyErr(err error) error {
|
||||||
|
if err == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if os.IsTimeout(err) {
|
||||||
|
return errors.New("timeout to read origin site")
|
||||||
|
}
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
|
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
|
||||||
"github.com/TeaOSLab/EdgeNode/internal/goman"
|
"github.com/TeaOSLab/EdgeNode/internal/goman"
|
||||||
"github.com/TeaOSLab/EdgeNode/internal/remotelogs"
|
|
||||||
"github.com/pires/go-proxyproto"
|
"github.com/pires/go-proxyproto"
|
||||||
"golang.org/x/net/http2"
|
"golang.org/x/net/http2"
|
||||||
"net"
|
"net"
|
||||||
@@ -132,14 +131,8 @@ func (this *HTTPClientPool) Client(req *HTTPRequest,
|
|||||||
var transport = &HTTPClientTransport{
|
var transport = &HTTPClientTransport{
|
||||||
Transport: &http.Transport{
|
Transport: &http.Transport{
|
||||||
DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) {
|
DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) {
|
||||||
// 支持TOA的连接
|
|
||||||
conn, err := this.handleTOA(req, ctx, network, originAddr, connectionTimeout)
|
|
||||||
if conn != nil || err != nil {
|
|
||||||
return conn, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// 普通的连接
|
// 普通的连接
|
||||||
conn, err = (&net.Dialer{
|
conn, err := (&net.Dialer{
|
||||||
Timeout: connectionTimeout,
|
Timeout: connectionTimeout,
|
||||||
KeepAlive: 1 * time.Minute,
|
KeepAlive: 1 * time.Minute,
|
||||||
}).DialContext(ctx, network, originAddr)
|
}).DialContext(ctx, network, originAddr)
|
||||||
@@ -215,38 +208,6 @@ func (this *HTTPClientPool) cleanClients() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 支持TOA
|
|
||||||
func (this *HTTPClientPool) handleTOA(req *HTTPRequest, ctx context.Context, network string, originAddr string, connectionTimeout time.Duration) (net.Conn, error) {
|
|
||||||
// TODO 每个服务读取自身所属集群的TOA设置
|
|
||||||
var toaConfig = sharedTOAManager.Config()
|
|
||||||
if toaConfig != nil && toaConfig.IsOn {
|
|
||||||
var retries = 3
|
|
||||||
for i := 1; i <= retries; i++ {
|
|
||||||
var port = int(toaConfig.RandLocalPort())
|
|
||||||
// TODO 思考是否支持X-Real-IP/X-Forwarded-IP
|
|
||||||
err := sharedTOAManager.SendMsg("add:" + strconv.Itoa(port) + ":" + req.requestRemoteAddr(true))
|
|
||||||
if err != nil {
|
|
||||||
remotelogs.Error("TOA", "add failed: "+err.Error())
|
|
||||||
} else {
|
|
||||||
dialer := net.Dialer{
|
|
||||||
Timeout: connectionTimeout,
|
|
||||||
KeepAlive: 1 * time.Minute,
|
|
||||||
LocalAddr: &net.TCPAddr{
|
|
||||||
Port: port,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
conn, err := dialer.DialContext(ctx, network, originAddr)
|
|
||||||
// TODO 需要在合适的时机删除TOA记录
|
|
||||||
if err == nil || i == retries {
|
|
||||||
return conn, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// 支持PROXY Protocol
|
// 支持PROXY Protocol
|
||||||
func (this *HTTPClientPool) handlePROXYProtocol(conn net.Conn, req *HTTPRequest, proxyProtocol *serverconfigs.ProxyProtocolConfig) error {
|
func (this *HTTPClientPool) handlePROXYProtocol(conn net.Conn, req *HTTPRequest, proxyProtocol *serverconfigs.ProxyProtocolConfig) error {
|
||||||
if proxyProtocol != nil && proxyProtocol.IsOn && (proxyProtocol.Version == serverconfigs.ProxyProtocolVersion1 || proxyProtocol.Version == serverconfigs.ProxyProtocolVersion2) {
|
if proxyProtocol != nil && proxyProtocol.IsOn && (proxyProtocol.Version == serverconfigs.ProxyProtocolVersion1 || proxyProtocol.Version == serverconfigs.ProxyProtocolVersion2) {
|
||||||
|
|||||||
@@ -38,8 +38,13 @@ func (this *HTTPRequest) doCacheRead(useStale bool) (shouldStop bool) {
|
|||||||
|
|
||||||
// 添加 X-Cache Header
|
// 添加 X-Cache Header
|
||||||
var addStatusHeader = this.web.Cache.AddStatusHeader
|
var addStatusHeader = this.web.Cache.AddStatusHeader
|
||||||
|
var cacheBypassDescription = ""
|
||||||
if addStatusHeader {
|
if addStatusHeader {
|
||||||
defer func() {
|
defer func() {
|
||||||
|
if len(cacheBypassDescription) > 0 {
|
||||||
|
this.writer.Header().Set("X-Cache", cacheBypassDescription)
|
||||||
|
return
|
||||||
|
}
|
||||||
var cacheStatus = this.varMapping["cache.status"]
|
var cacheStatus = this.varMapping["cache.status"]
|
||||||
if cacheStatus != "HIT" {
|
if cacheStatus != "HIT" {
|
||||||
this.writer.Header().Set("X-Cache", cacheStatus)
|
this.writer.Header().Set("X-Cache", cacheStatus)
|
||||||
@@ -94,6 +99,7 @@ func (this *HTTPRequest) doCacheRead(useStale bool) (shouldStop bool) {
|
|||||||
// 校验请求
|
// 校验请求
|
||||||
if !this.cacheRef.MatchRequest(this.RawReq) {
|
if !this.cacheRef.MatchRequest(this.RawReq) {
|
||||||
this.cacheRef = nil
|
this.cacheRef = nil
|
||||||
|
cacheBypassDescription = "BYPASS, not match"
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -106,6 +112,7 @@ func (this *HTTPRequest) doCacheRead(useStale bool) (shouldStop bool) {
|
|||||||
if this.cacheRef.EnableRequestCachePragma {
|
if this.cacheRef.EnableRequestCachePragma {
|
||||||
if this.RawReq.Header.Get("Cache-Control") == "no-cache" || this.RawReq.Header.Get("Pragma") == "no-cache" {
|
if this.RawReq.Header.Get("Cache-Control") == "no-cache" || this.RawReq.Header.Get("Pragma") == "no-cache" {
|
||||||
this.cacheRef = nil
|
this.cacheRef = nil
|
||||||
|
cacheBypassDescription = "BYPASS, Cache-Control or Pragma"
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -119,6 +126,7 @@ func (this *HTTPRequest) doCacheRead(useStale bool) (shouldStop bool) {
|
|||||||
var key = this.Format(this.cacheRef.Key)
|
var key = this.Format(this.cacheRef.Key)
|
||||||
if len(key) == 0 {
|
if len(key) == 0 {
|
||||||
this.cacheRef = nil
|
this.cacheRef = nil
|
||||||
|
cacheBypassDescription = "BYPASS, empty key"
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
var method = this.Method()
|
var method = this.Method()
|
||||||
@@ -134,6 +142,7 @@ func (this *HTTPRequest) doCacheRead(useStale bool) (shouldStop bool) {
|
|||||||
var storage = caches.SharedManager.FindStorageWithPolicy(cachePolicy.Id)
|
var storage = caches.SharedManager.FindStorageWithPolicy(cachePolicy.Id)
|
||||||
if storage == nil {
|
if storage == nil {
|
||||||
this.cacheRef = nil
|
this.cacheRef = nil
|
||||||
|
cacheBypassDescription = "BYPASS, no policy found"
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
this.writer.cacheStorage = storage
|
this.writer.cacheStorage = storage
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import (
|
|||||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/firewallconfigs"
|
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/firewallconfigs"
|
||||||
"github.com/TeaOSLab/EdgeNode/internal/ttlcache"
|
"github.com/TeaOSLab/EdgeNode/internal/ttlcache"
|
||||||
"github.com/TeaOSLab/EdgeNode/internal/waf"
|
"github.com/TeaOSLab/EdgeNode/internal/waf"
|
||||||
|
"github.com/iwind/TeaGo/types"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"time"
|
"time"
|
||||||
@@ -35,9 +36,24 @@ func (this *HTTPRequest) doMismatch() {
|
|||||||
// 根据配置进行相应的处理
|
// 根据配置进行相应的处理
|
||||||
var globalServerConfig = sharedNodeConfig.GlobalServerConfig
|
var globalServerConfig = sharedNodeConfig.GlobalServerConfig
|
||||||
if globalServerConfig != nil && globalServerConfig.HTTPAll.MatchDomainStrictly {
|
if globalServerConfig != nil && globalServerConfig.HTTPAll.MatchDomainStrictly {
|
||||||
|
var statusCode = 404
|
||||||
|
var httpAllConfig = globalServerConfig.HTTPAll
|
||||||
|
var mismatchAction = httpAllConfig.DomainMismatchAction
|
||||||
|
|
||||||
|
if mismatchAction != nil && mismatchAction.Options != nil {
|
||||||
|
var mismatchStatusCode = mismatchAction.Options.GetInt("statusCode")
|
||||||
|
if mismatchStatusCode > 0 && mismatchStatusCode >= 100 && mismatchStatusCode < 1000 {
|
||||||
|
statusCode = mismatchStatusCode
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 是否正在访问IP
|
// 是否正在访问IP
|
||||||
if globalServerConfig.HTTPAll.NodeIPShowPage && net.ParseIP(this.ReqHost) != nil {
|
if globalServerConfig.HTTPAll.NodeIPShowPage && net.ParseIP(this.ReqHost) != nil {
|
||||||
_, _ = this.writer.WriteString(globalServerConfig.HTTPAll.NodeIPPageHTML)
|
var contentHTML = this.Format(globalServerConfig.HTTPAll.NodeIPPageHTML)
|
||||||
|
this.writer.Header().Set("Content-Type", "text/html; charset=utf-8")
|
||||||
|
this.writer.Header().Set("Content-Length", types.String(len(contentHTML)))
|
||||||
|
this.writer.WriteHeader(statusCode)
|
||||||
|
_, _ = this.writer.WriteString(contentHTML)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -55,13 +71,13 @@ func (this *HTTPRequest) doMismatch() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 处理当前连接
|
// 处理当前连接
|
||||||
var httpAllConfig = globalServerConfig.HTTPAll
|
|
||||||
var mismatchAction = httpAllConfig.DomainMismatchAction
|
|
||||||
if mismatchAction != nil && mismatchAction.Code == "page" {
|
if mismatchAction != nil && mismatchAction.Code == "page" {
|
||||||
if mismatchAction.Options != nil {
|
if mismatchAction.Options != nil {
|
||||||
|
var contentHTML = this.Format(mismatchAction.Options.GetString("contentHTML"))
|
||||||
this.writer.Header().Set("Content-Type", "text/html; charset=utf-8")
|
this.writer.Header().Set("Content-Type", "text/html; charset=utf-8")
|
||||||
this.writer.WriteHeader(mismatchAction.Options.GetInt("statusCode"))
|
this.writer.Header().Set("Content-Length", types.String(len(contentHTML)))
|
||||||
_, _ = this.writer.Write([]byte(mismatchAction.Options.GetString("contentHTML")))
|
this.writer.WriteHeader(statusCode)
|
||||||
|
_, _ = this.writer.Write([]byte(contentHTML))
|
||||||
} else {
|
} else {
|
||||||
http.Error(this.writer, "404 page not found: '"+this.URL()+"'", http.StatusNotFound)
|
http.Error(this.writer, "404 page not found: '"+this.URL()+"'", http.StatusNotFound)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func (this *HTTPRequest) doCheckUserAgent() (shouldStop bool) {
|
func (this *HTTPRequest) doCheckUserAgent() (shouldStop bool) {
|
||||||
if this.web.UserAgent == nil {
|
if this.web.UserAgent == nil || !this.web.UserAgent.IsOn {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -324,11 +324,11 @@ func (this *HTTPWriter) PrepareCache(resp *http.Response, size int64) {
|
|||||||
|
|
||||||
// 待写入尺寸
|
// 待写入尺寸
|
||||||
var totalSize = size
|
var totalSize = size
|
||||||
if totalSize < 0 && this.isPartial {
|
if this.isPartial {
|
||||||
var contentRange = resp.Header.Get("Content-Range")
|
var contentRange = resp.Header.Get("Content-Range")
|
||||||
if len(contentRange) > 0 {
|
if len(contentRange) > 0 {
|
||||||
_, partialTotalSize := httpRequestParseContentRangeHeader(contentRange)
|
_, partialTotalSize := httpRequestParseContentRangeHeader(contentRange)
|
||||||
if partialTotalSize > 0 {
|
if partialTotalSize > 0 && partialTotalSize > totalSize {
|
||||||
totalSize = partialTotalSize
|
totalSize = partialTotalSize
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import (
|
|||||||
"bytes"
|
"bytes"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
"github.com/TeaOSLab/EdgeCommon/pkg/configutils"
|
"github.com/TeaOSLab/EdgeCommon/pkg/configutils"
|
||||||
iplib "github.com/TeaOSLab/EdgeCommon/pkg/iplibrary"
|
iplib "github.com/TeaOSLab/EdgeCommon/pkg/iplibrary"
|
||||||
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
|
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
|
||||||
@@ -26,6 +27,7 @@ import (
|
|||||||
"github.com/TeaOSLab/EdgeNode/internal/utils"
|
"github.com/TeaOSLab/EdgeNode/internal/utils"
|
||||||
_ "github.com/TeaOSLab/EdgeNode/internal/utils/agents" // 引入Agent管理器
|
_ "github.com/TeaOSLab/EdgeNode/internal/utils/agents" // 引入Agent管理器
|
||||||
_ "github.com/TeaOSLab/EdgeNode/internal/utils/clock" // 触发时钟更新
|
_ "github.com/TeaOSLab/EdgeNode/internal/utils/clock" // 触发时钟更新
|
||||||
|
fsutils "github.com/TeaOSLab/EdgeNode/internal/utils/fs"
|
||||||
"github.com/TeaOSLab/EdgeNode/internal/utils/jsonutils"
|
"github.com/TeaOSLab/EdgeNode/internal/utils/jsonutils"
|
||||||
"github.com/TeaOSLab/EdgeNode/internal/waf"
|
"github.com/TeaOSLab/EdgeNode/internal/waf"
|
||||||
"github.com/andybalholm/brotli"
|
"github.com/andybalholm/brotli"
|
||||||
@@ -141,7 +143,7 @@ func (this *Node) Start() {
|
|||||||
// 调整系统参数
|
// 调整系统参数
|
||||||
this.checkSystem()
|
this.checkSystem()
|
||||||
|
|
||||||
// 检查硬盘类型
|
// 检查硬盘
|
||||||
this.checkDisk()
|
this.checkDisk()
|
||||||
|
|
||||||
// 启动事件
|
// 启动事件
|
||||||
@@ -1054,6 +1056,9 @@ func (this *Node) reloadServer() {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
remotelogs.Error("NODE", "apply server config error: "+err.Error())
|
remotelogs.Error("NODE", "apply server config error: "+err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// notify event
|
||||||
|
events.Notify(events.EventReloadSomeServers)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1109,23 +1114,16 @@ func (this *Node) checkSystem() {
|
|||||||
|
|
||||||
// 检查硬盘
|
// 检查硬盘
|
||||||
func (this *Node) checkDisk() {
|
func (this *Node) checkDisk() {
|
||||||
if runtime.GOOS != "linux" {
|
speedMB, isFast, err := fsutils.CheckDiskIsFast()
|
||||||
|
if err != nil {
|
||||||
|
remotelogs.Error("NODE", "check disk speed failed: "+err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
for n := 'a'; n <= 'z'; n++ {
|
teaconst.DiskIsFast = isFast
|
||||||
for _, path := range []string{
|
if isFast {
|
||||||
"/sys/block/vd" + string(n) + "/queue/rotational",
|
remotelogs.Println("NODE", "disk is fast, writing test speed: "+fmt.Sprintf("%.2fMB/s", speedMB))
|
||||||
"/sys/block/sd" + string(n) + "/queue/rotational",
|
} else {
|
||||||
} {
|
remotelogs.Println("NODE", "disk is slow, writing test speed: "+fmt.Sprintf("%.2fMB/s", speedMB))
|
||||||
data, err := os.ReadFile(path)
|
|
||||||
if err != nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if string(data) == "0" {
|
|
||||||
teaconst.DiskIsFast = true
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -15,3 +15,7 @@ func (this *Node) reloadIPLibrary() {
|
|||||||
func (this *Node) notifyPlusChange() error {
|
func (this *Node) notifyPlusChange() error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (this *Node) execTOAChangedTask() error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|||||||
@@ -90,6 +90,8 @@ func (this *Node) execTask(rpcClient *rpc.RPCClient, task *pb.NodeTask) error {
|
|||||||
err = this.execUpdatingServersTask(rpcClient)
|
err = this.execUpdatingServersTask(rpcClient)
|
||||||
case "plusChanged":
|
case "plusChanged":
|
||||||
err = this.notifyPlusChange()
|
err = this.notifyPlusChange()
|
||||||
|
case "toaChanged":
|
||||||
|
err = this.execTOAChangedTask()
|
||||||
default:
|
default:
|
||||||
remotelogs.Error("NODE", "task '"+types.String(task.Id)+"', type '"+task.Type+"' has not been handled")
|
remotelogs.Error("NODE", "task '"+types.String(task.Id)+"', type '"+task.Type+"' has not been handled")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,117 +1,31 @@
|
|||||||
|
// Copyright 2023 GoEdge CDN goedge.cdn@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||||
|
//go:build !plus
|
||||||
|
|
||||||
package nodes
|
package nodes
|
||||||
|
|
||||||
import (
|
import "github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
|
||||||
"errors"
|
|
||||||
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
|
|
||||||
teaconst "github.com/TeaOSLab/EdgeNode/internal/const"
|
|
||||||
"github.com/TeaOSLab/EdgeNode/internal/events"
|
|
||||||
"github.com/TeaOSLab/EdgeNode/internal/goman"
|
|
||||||
"github.com/TeaOSLab/EdgeNode/internal/remotelogs"
|
|
||||||
executils "github.com/TeaOSLab/EdgeNode/internal/utils/exec"
|
|
||||||
"github.com/iwind/TeaGo/Tea"
|
|
||||||
"net"
|
|
||||||
"os"
|
|
||||||
"strings"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
var sharedTOAManager = NewTOAManager()
|
var sharedTOAManager = NewTOAManager()
|
||||||
|
|
||||||
func init() {
|
|
||||||
if !teaconst.IsMain {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
events.On(events.EventReload, func() {
|
|
||||||
err := sharedTOAManager.Run(sharedNodeConfig.TOA)
|
|
||||||
if err != nil {
|
|
||||||
remotelogs.Error("TOA", err.Error())
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
type TOAManager struct {
|
type TOAManager struct {
|
||||||
config *nodeconfigs.TOAConfig
|
|
||||||
pid int
|
|
||||||
conn net.Conn
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewTOAManager() *TOAManager {
|
func NewTOAManager() *TOAManager {
|
||||||
return &TOAManager{}
|
return &TOAManager{}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (this *TOAManager) Run(config *nodeconfigs.TOAConfig) error {
|
func (this *TOAManager) Apply(config *nodeconfigs.TOAConfig) error {
|
||||||
this.config = config
|
|
||||||
|
|
||||||
if this.pid > 0 {
|
|
||||||
remotelogs.Println("TOA", "stopping ...")
|
|
||||||
err := this.Quit()
|
|
||||||
if err != nil {
|
|
||||||
remotelogs.Error("TOA", "quit error: "+err.Error())
|
|
||||||
}
|
|
||||||
if this.conn != nil {
|
|
||||||
_ = this.conn.Close()
|
|
||||||
}
|
|
||||||
this.conn = nil
|
|
||||||
this.pid = 0
|
|
||||||
}
|
|
||||||
|
|
||||||
if !config.IsOn {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
binPath := Tea.Root + "/edge-toa/edge-toa" // TODO 可以做成配置
|
|
||||||
_, err := os.Stat(binPath)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
remotelogs.Println("TOA", "starting ...")
|
|
||||||
remotelogs.Println("TOA", "args: "+strings.Join(config.AsArgs(), " "))
|
|
||||||
cmd := executils.NewCmd(binPath, config.AsArgs()...)
|
|
||||||
err = cmd.Start()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
var process = cmd.Process()
|
|
||||||
if process == nil {
|
|
||||||
return errors.New("start failed")
|
|
||||||
}
|
|
||||||
this.pid = process.Pid
|
|
||||||
|
|
||||||
goman.New(func() {
|
|
||||||
_ = cmd.Wait()
|
|
||||||
})
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (this *TOAManager) Config() *nodeconfigs.TOAConfig {
|
func (this *TOAManager) Config() *nodeconfigs.TOAConfig {
|
||||||
return this.config
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (this *TOAManager) Quit() error {
|
func (this *TOAManager) Quit() error {
|
||||||
return this.SendMsg("quit:0")
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (this *TOAManager) SendMsg(msg string) error {
|
func (this *TOAManager) SendMsg(msg string) error {
|
||||||
if this.config == nil {
|
return nil
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if this.conn != nil {
|
|
||||||
_, err := this.conn.Write([]byte(msg + "\n"))
|
|
||||||
if err != nil {
|
|
||||||
_ = this.conn.Close()
|
|
||||||
this.conn = nil
|
|
||||||
}
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
conn, err := net.DialTimeout("unix", this.config.SockFile(), 1*time.Second)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
this.conn = conn
|
|
||||||
_, err = this.conn.Write([]byte(msg + "\n"))
|
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,17 +0,0 @@
|
|||||||
package nodes
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestTOAManager_Run(t *testing.T) {
|
|
||||||
manager := NewTOAManager()
|
|
||||||
err := manager.Run(&nodeconfigs.TOAConfig{
|
|
||||||
IsOn: true,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
t.Log("ok")
|
|
||||||
}
|
|
||||||
@@ -29,6 +29,7 @@ var sharedUpgradeManager = NewUpgradeManager()
|
|||||||
type UpgradeManager struct {
|
type UpgradeManager struct {
|
||||||
isInstalling bool
|
isInstalling bool
|
||||||
lastFile string
|
lastFile string
|
||||||
|
exe string
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewUpgradeManager 获取新对象
|
// NewUpgradeManager 获取新对象
|
||||||
@@ -38,6 +39,14 @@ func NewUpgradeManager() *UpgradeManager {
|
|||||||
|
|
||||||
// Start 启动升级
|
// Start 启动升级
|
||||||
func (this *UpgradeManager) Start() {
|
func (this *UpgradeManager) Start() {
|
||||||
|
// 必须放在文件解压之前读取可执行文件路径,防止解析之后,当前的可执行文件路径发生改变
|
||||||
|
exe, err := os.Executable()
|
||||||
|
if err != nil {
|
||||||
|
remotelogs.Error("UPGRADE_MANAGER", "can not find current executable file name")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.exe = exe
|
||||||
|
|
||||||
// 测试环境下不更新
|
// 测试环境下不更新
|
||||||
if Tea.IsTesting() {
|
if Tea.IsTesting() {
|
||||||
return
|
return
|
||||||
@@ -49,7 +58,7 @@ func (this *UpgradeManager) Start() {
|
|||||||
this.isInstalling = true
|
this.isInstalling = true
|
||||||
|
|
||||||
remotelogs.Println("UPGRADE_MANAGER", "upgrading node ...")
|
remotelogs.Println("UPGRADE_MANAGER", "upgrading node ...")
|
||||||
err := this.install()
|
err = this.install()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
remotelogs.Error("UPGRADE_MANAGER", "download failed: "+err.Error())
|
remotelogs.Error("UPGRADE_MANAGER", "download failed: "+err.Error())
|
||||||
|
|
||||||
@@ -104,7 +113,7 @@ func (this *UpgradeManager) install() error {
|
|||||||
|
|
||||||
remotelogs.Println("UPGRADE_MANAGER", "downloading new node ...")
|
remotelogs.Println("UPGRADE_MANAGER", "downloading new node ...")
|
||||||
|
|
||||||
var path = dir + "/edge-node" + ".tmp"
|
var path = dir + "/edge-node.tmp"
|
||||||
fp, err := os.OpenFile(path, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0777)
|
fp, err := os.OpenFile(path, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0777)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -238,11 +247,6 @@ func (this *UpgradeManager) restart() error {
|
|||||||
if DaemonIsOn && DaemonPid == os.Getppid() {
|
if DaemonIsOn && DaemonPid == os.Getppid() {
|
||||||
utils.Exit() // TODO 试着更优雅重启
|
utils.Exit() // TODO 试着更优雅重启
|
||||||
} else {
|
} else {
|
||||||
exe, err := os.Executable()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// quit
|
// quit
|
||||||
events.Notify(events.EventQuit)
|
events.Notify(events.EventQuit)
|
||||||
|
|
||||||
@@ -250,10 +254,9 @@ func (this *UpgradeManager) restart() error {
|
|||||||
events.Notify(events.EventTerminated)
|
events.Notify(events.EventTerminated)
|
||||||
|
|
||||||
// 启动
|
// 启动
|
||||||
exe = filepath.Dir(exe) + "/" + teaconst.ProcessName
|
var exe = filepath.Dir(this.exe) + "/" + teaconst.ProcessName
|
||||||
|
|
||||||
var cmd = executils.NewCmd(exe, "start")
|
var cmd = executils.NewCmd(exe, "start")
|
||||||
err = cmd.Start()
|
err := cmd.Start()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,10 +7,12 @@ import (
|
|||||||
"database/sql"
|
"database/sql"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
teaconst "github.com/TeaOSLab/EdgeNode/internal/const"
|
||||||
"github.com/TeaOSLab/EdgeNode/internal/events"
|
"github.com/TeaOSLab/EdgeNode/internal/events"
|
||||||
"github.com/TeaOSLab/EdgeNode/internal/remotelogs"
|
"github.com/TeaOSLab/EdgeNode/internal/remotelogs"
|
||||||
"github.com/TeaOSLab/EdgeNode/internal/utils/fileutils"
|
"github.com/TeaOSLab/EdgeNode/internal/utils/fileutils"
|
||||||
_ "github.com/mattn/go-sqlite3"
|
_ "github.com/mattn/go-sqlite3"
|
||||||
|
"net/url"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
@@ -21,6 +23,7 @@ var errDBIsClosed = errors.New("the database is closed")
|
|||||||
type DB struct {
|
type DB struct {
|
||||||
locker *fileutils.Locker
|
locker *fileutils.Locker
|
||||||
rawDB *sql.DB
|
rawDB *sql.DB
|
||||||
|
dsn string
|
||||||
|
|
||||||
statusLocker sync.Mutex
|
statusLocker sync.Mutex
|
||||||
countUpdating int32
|
countUpdating int32
|
||||||
@@ -41,6 +44,10 @@ func OpenReader(dsn string) (*DB, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func open(dsn string, lock bool) (*DB, error) {
|
func open(dsn string, lock bool) (*DB, error) {
|
||||||
|
if teaconst.IsQuiting {
|
||||||
|
return nil, errors.New("can not open database when process is quiting")
|
||||||
|
}
|
||||||
|
|
||||||
// locker
|
// locker
|
||||||
var locker *fileutils.Locker
|
var locker *fileutils.Locker
|
||||||
if lock {
|
if lock {
|
||||||
@@ -64,14 +71,15 @@ func open(dsn string, lock bool) (*DB, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
var db = NewDB(rawDB)
|
var db = NewDB(rawDB, dsn)
|
||||||
db.locker = locker
|
db.locker = locker
|
||||||
return db, nil
|
return db, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewDB(rawDB *sql.DB) *DB {
|
func NewDB(rawDB *sql.DB, dsn string) *DB {
|
||||||
var db = &DB{
|
var db = &DB{
|
||||||
rawDB: rawDB,
|
rawDB: rawDB,
|
||||||
|
dsn: dsn,
|
||||||
}
|
}
|
||||||
|
|
||||||
events.OnKey(events.EventQuit, fmt.Sprintf("db_%p", db), func() {
|
events.OnKey(events.EventQuit, fmt.Sprintf("db_%p", db), func() {
|
||||||
@@ -193,6 +201,14 @@ func (this *DB) Close() error {
|
|||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
// print log
|
||||||
|
if len(this.dsn) > 0 {
|
||||||
|
u, _ := url.Parse(this.dsn)
|
||||||
|
if u != nil && len(u.Path) > 0 {
|
||||||
|
remotelogs.Debug("DB", "close '"+u.Path)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return this.rawDB.Close()
|
return this.rawDB.Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
17
internal/utils/dbs/db_test.go
Normal file
17
internal/utils/dbs/db_test.go
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
// Copyright 2023 GoEdge CDN goedge.cdn@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||||
|
|
||||||
|
package dbs_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/url"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestParseDSN(t *testing.T) {
|
||||||
|
var dsn = "file:/home/cache/p43/.indexes/db-3.db?cache=private&mode=ro&_journal_mode=WAL&_sync=OFF&_cache_size=88000"
|
||||||
|
u, err := url.Parse(dsn)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
t.Log(u.Path) // expect: :/home/cache/p43/.indexes/db-3.db
|
||||||
|
}
|
||||||
69
internal/utils/fs/disk.go
Normal file
69
internal/utils/fs/disk.go
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
// Copyright 2023 GoEdge CDN goedge.cdn@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||||
|
|
||||||
|
package fsutils
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"os"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// CheckDiskWritingSpeed test disk writing speed
|
||||||
|
func CheckDiskWritingSpeed() (speedMB float64, err error) {
|
||||||
|
var tempDir = os.TempDir()
|
||||||
|
if len(tempDir) == 0 {
|
||||||
|
tempDir = "/tmp"
|
||||||
|
}
|
||||||
|
|
||||||
|
const filename = "edge-disk-writing-test.data"
|
||||||
|
var path = tempDir + "/" + filename
|
||||||
|
_ = os.Remove(path) // always try to delete the file
|
||||||
|
|
||||||
|
fp, err := os.OpenFile(path, os.O_CREATE|os.O_WRONLY, 0666)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var isClosed bool
|
||||||
|
defer func() {
|
||||||
|
if !isClosed {
|
||||||
|
_ = fp.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
_ = os.Remove(path)
|
||||||
|
}()
|
||||||
|
|
||||||
|
var data = bytes.Repeat([]byte{'A'}, 16<<20)
|
||||||
|
var before = time.Now()
|
||||||
|
_, err = fp.Write(data)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = fp.Sync()
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = fp.Close()
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var costSeconds = time.Since(before).Seconds()
|
||||||
|
speedMB = float64(len(data)) / (1 << 20) / costSeconds
|
||||||
|
|
||||||
|
isClosed = true
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// CheckDiskIsFast check disk is 'fast' disk to write
|
||||||
|
func CheckDiskIsFast() (speedMB float64, isFast bool, err error) {
|
||||||
|
speedMB, err = CheckDiskWritingSpeed()
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
isFast = speedMB > 120
|
||||||
|
return
|
||||||
|
}
|
||||||
16
internal/utils/fs/disk_test_test.go
Normal file
16
internal/utils/fs/disk_test_test.go
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
// Copyright 2023 GoEdge CDN goedge.cdn@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||||
|
|
||||||
|
package fsutils_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
fsutils "github.com/TeaOSLab/EdgeNode/internal/utils/fs"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestCheckDiskWritingSpeed(t *testing.T) {
|
||||||
|
t.Log(fsutils.CheckDiskWritingSpeed())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCheckDiskIsFast(t *testing.T) {
|
||||||
|
t.Log(fsutils.CheckDiskIsFast())
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user