Files
EdgeAPI/internal/instances/instance.go

1049 lines
24 KiB
Go
Raw Normal View History

2024-07-27 14:15:25 +08:00
// Copyright 2024 GoEdge CDN goedge.cdn@gmail.com. All rights reserved. Official site: https://goedge.cloud .
2024-01-29 17:57:01 +08:00
package instances
import (
2024-03-02 20:51:13 +08:00
"context"
2024-01-29 17:57:01 +08:00
"encoding/json"
"errors"
"fmt"
2024-07-27 14:15:25 +08:00
"log"
"net"
"os"
"path/filepath"
"regexp"
"runtime"
"strings"
"time"
2024-01-29 17:57:01 +08:00
teaconst "github.com/TeaOSLab/EdgeAPI/internal/const"
"github.com/TeaOSLab/EdgeAPI/internal/db/models"
"github.com/TeaOSLab/EdgeAPI/internal/installers/helpers"
"github.com/TeaOSLab/EdgeAPI/internal/setup"
executils "github.com/TeaOSLab/EdgeAPI/internal/utils/exec"
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/firewallconfigs"
2024-01-29 18:56:37 +08:00
"github.com/TeaOSLab/EdgeCommon/pkg/systemconfigs"
2024-01-29 17:57:01 +08:00
"github.com/iwind/TeaGo"
"github.com/iwind/TeaGo/Tea"
"github.com/iwind/TeaGo/dbs"
"github.com/iwind/TeaGo/lists"
"github.com/iwind/TeaGo/rands"
"github.com/iwind/TeaGo/types"
"gopkg.in/yaml.v3"
)
type Instance struct {
options Options
}
func NewInstance(options Options) *Instance {
return &Instance{
options: options,
}
}
func (this *Instance) SetupAll() error {
type TaskFn func() error
for _, taskFn := range []TaskFn{
this.SetupDB,
this.SetupAdminNode,
this.SetupAPINode,
this.SetupNode,
this.SetupUserNode,
this.Clean,
this.Startup,
} {
err := taskFn()
if err != nil {
return err
}
}
return nil
}
func (this *Instance) SetupDB() error {
if this.options.Verbose {
2024-03-03 17:14:29 +08:00
log.Println("setup db " + this.options.DB.Host + ":" + types.String(this.options.DB.Port) + "/" + this.options.DB.Name + " ...")
2024-01-29 17:57:01 +08:00
}
// 检查数据库名
{
db, dbErr := this.dbInstanceWithoutDBName()
if dbErr != nil {
return dbErr
}
defer func() {
_ = db.Close()
}()
2024-03-02 20:51:13 +08:00
// 等待连接成功
for i := 0; i < 30; i++ {
err := db.Raw().PingContext(context.Background())
if err == nil {
break
}
time.Sleep(1 * time.Second)
}
2024-01-29 17:57:01 +08:00
_, err := db.Exec("USE `" + this.options.DB.Name + "`")
if err != nil {
if models.CheckSQLErrCode(err, 1049) {
_, err = db.Exec("CREATE DATABASE `" + this.options.DB.Name + "` DEFAULT CHARSET utf8mb4")
if err != nil {
return fmt.Errorf("create new database failed: %w", err)
}
} else {
return fmt.Errorf("check database failed: %w", err)
}
}
}
// 检查版本
{
db, instanceErr := this.dbInstance(false)
if instanceErr != nil {
return instanceErr
}
defer func() {
_ = db.Close()
}()
dbConfig, configErr := db.Config()
if configErr != nil {
return configErr
}
var shouldExecute bool
version, err := db.FindCol(0, "SELECT version FROM edgeVersions")
if err != nil {
shouldExecute = true
} else {
if !strings.HasPrefix(types.String(version), teaconst.Version+".") {
shouldExecute = true
}
}
if shouldExecute {
var executor = setup.NewSQLExecutor(dbConfig)
err = executor.Run(false)
if err != nil {
return fmt.Errorf("execute sql failed: %w", err)
}
// wait to commit
time.Sleep(1 * time.Second)
}
}
// 启用数据库
db, instanceErr := this.dbInstance(true)
if instanceErr != nil {
return instanceErr
}
defer func() {
_ = db.Close()
}()
// 创建Admin Token
var tx *dbs.Tx
{
one, err := db.FindOne("SELECT * FROM edgeAPITokens WHERE role='admin'")
if err != nil {
return err
}
if len(one) == 0 {
var nodeId = rands.HexString(32)
var secret = rands.String(32)
err = models.SharedApiTokenDAO.CreateAPIToken(tx, nodeId, secret, "admin")
if err != nil {
return fmt.Errorf("create admin node token failed: %w", err)
}
}
}
// 创建Admin
{
one, err := db.FindOne("SELECT * FROM edgeAdmins")
if err != nil {
return err
}
if len(one) == 0 {
var password = rands.String(16)
// 保存密码到文件
var dir = this.options.WorkDir + "/usr/local/goedge"
_, err = os.Stat(dir)
if err != nil {
err = os.MkdirAll(dir, 0777)
if err != nil {
return fmt.Errorf("create directory '"+dir+"' failed: %w", err)
}
}
err = os.WriteFile(dir+"/password.txt", []byte("Admin Password: "+password+"\n"), 0666)
if err != nil {
return fmt.Errorf("write 'password.txt' failed: %w", err)
}
_, err = models.SharedAdminDAO.CreateAdmin(tx, "admin", true, password, "Admin", true, []byte("[]"))
if err != nil {
return fmt.Errorf("create admin failed: %w", err)
}
}
}
// 创建API Node
{
one, findErr := db.FindOne("SELECT * FROM edgeAPINodes")
if findErr != nil {
return findErr
}
if len(one) == 0 {
// http
var httpConfig = &serverconfigs.HTTPProtocolConfig{}
httpConfig.IsOn = true
httpConfig.Listen = []*serverconfigs.NetworkAddressConfig{
{
Protocol: "http",
PortRange: types.String(this.options.APINode.HTTPPort),
},
}
httpJSON, encodeErr := json.Marshal(httpConfig)
if encodeErr != nil {
return fmt.Errorf("encode api http config failed: %w", encodeErr)
}
// rest
var restHTTPConfig = &serverconfigs.HTTPProtocolConfig{}
restHTTPConfig.IsOn = true
restHTTPConfig.Listen = []*serverconfigs.NetworkAddressConfig{
{
Protocol: "http",
PortRange: types.String(this.options.APINode.RestHTTPPort),
},
}
restHTTPJSON, encodeErr := json.Marshal(restHTTPConfig)
if encodeErr != nil {
return fmt.Errorf("encode api rest http config failed: %w", encodeErr)
}
// access addrs
var accessAddrs = []*serverconfigs.NetworkAddressConfig{
{
Protocol: "http",
Host: "127.0.0.1",
PortRange: types.String(this.options.APINode.HTTPPort),
},
}
accessAddrsJSON, encodeErr := json.Marshal(accessAddrs)
if encodeErr != nil {
return fmt.Errorf("encode access addresses failed: %w", encodeErr)
}
_, err := models.SharedAPINodeDAO.CreateAPINode(tx, "API Node", "Primary API Node", httpJSON, nil, true, restHTTPJSON, nil, accessAddrsJSON, true)
if err != nil {
return err
}
}
{
// check token
nodes, nodesErr := models.SharedAPINodeDAO.FindAllEnabledAPINodes(tx)
if nodesErr != nil {
return nodesErr
}
for _, node := range nodes {
token, err := models.SharedApiTokenDAO.FindEnabledTokenWithNode(tx, node.UniqueId)
if err != nil {
return err
}
if token == nil {
err = models.SharedApiTokenDAO.CreateAPIToken(tx, node.UniqueId, node.Secret, nodeconfigs.NodeRoleAPI)
if err != nil {
return err
}
}
}
}
}
// 创建Node
var clusterId int64
{
{
// check cluster
clusterIdCol, err := db.FindCol(0, "SELECT id FROM edgeNodeClusters WHERE state=1")
if err != nil {
return err
}
clusterId = types.Int64(clusterIdCol)
if clusterId == 0 {
return errors.New("invalid cluster id '" + types.String(clusterId) + "'")
}
}
one, findErr := db.FindOne("SELECT * FROM edgeNodes")
if findErr != nil {
return findErr
}
if len(one) == 0 {
_, err := models.SharedNodeDAO.CreateNode(tx, 0, "Local Node", clusterId, 0, 0)
if err != nil {
return fmt.Errorf("create node failed: %w", err)
}
}
}
// 检查User
var userId int64
{
one, findErr := db.FindOne("SELECT id FROM edgeUsers WHERE state=1")
if findErr != nil {
return findErr
}
if len(one) == 0 {
return errors.New("user must not be created yet")
}
userId = one.GetInt64("id")
}
// 创建用户节点
{
one, findErr := db.FindOne("SELECT * FROM edgeUserNodes")
if findErr != nil {
return findErr
}
if len(one) == 0 {
// http
var httpConfig = &serverconfigs.HTTPProtocolConfig{}
httpConfig.IsOn = true
httpConfig.Listen = []*serverconfigs.NetworkAddressConfig{
{
Protocol: "http",
PortRange: types.String(this.options.UserNode.HTTPPort),
},
}
httpJSON, encodeErr := json.Marshal(httpConfig)
if encodeErr != nil {
return fmt.Errorf("encode api http config failed: %w", encodeErr)
}
// access addrs
var accessAddrs = []*serverconfigs.NetworkAddressConfig{
{
Protocol: "http",
Host: "127.0.0.1",
PortRange: types.String(this.options.UserNode.HTTPPort),
},
}
accessAddrsJSON, encodeErr := json.Marshal(accessAddrs)
if encodeErr != nil {
return fmt.Errorf("encode access addresses failed: %w", encodeErr)
}
_, err := models.SharedUserNodeDAO.CreateUserNode(tx, "User Platform", "Created by system", httpJSON, nil, accessAddrsJSON, true)
if err != nil {
return err
}
}
}
// 创建网站
{
one, findErr := db.FindOne("SELECT id FROM edgeServers WHERE state=1")
if findErr != nil {
return findErr
}
if len(one) == 0 {
var webId int64
{
{
var err error
webId, err = models.SharedHTTPWebDAO.CreateWeb(tx, 0, userId, nil)
if err != nil {
return fmt.Errorf("create web failed: %w", err)
}
}
// 访问日志
{
err := models.SharedHTTPWebDAO.UpdateWebAccessLogConfig(tx, webId, []byte(`{
"isPrior": false,
"isOn": true,
"fields": [1, 2, 6, 7],
"status1": true,
"status2": true,
"status3": true,
"status4": true,
"status5": true,
"storageOnly": false,
"storagePolicies": [],
"firewallOnly": false
}`))
if err != nil {
return err
}
}
// websocket
{
websocketId, err := models.SharedHTTPWebsocketDAO.CreateWebsocket(tx, []byte(`{
"count": 30,
"unit": "second"
}`), true, nil, true, "")
if err != nil {
return err
}
err = models.SharedHTTPWebDAO.UpdateWebsocket(tx, webId, []byte(`{
"isPrior": false,
"isOn": true,
"websocketId": `+types.String(websocketId)+`
}`))
if err != nil {
return err
}
}
// cache
{
var cacheConfig = &serverconfigs.HTTPCacheConfig{
IsPrior: false,
IsOn: true,
AddStatusHeader: true,
PurgeIsOn: false,
PurgeKey: "",
CacheRefs: []*serverconfigs.HTTPCacheRef{},
}
cacheConfigJSON, err := json.Marshal(cacheConfig)
if err != nil {
return err
}
err = models.SharedHTTPWebDAO.UpdateWebCache(tx, webId, cacheConfigJSON)
if err != nil {
return err
}
}
// waf
{
var firewallRef = &firewallconfigs.HTTPFirewallRef{
IsPrior: false,
IsOn: true,
FirewallPolicyId: 0,
}
firewallRefJSON, err := json.Marshal(firewallRef)
if err != nil {
return err
}
err = models.SharedHTTPWebDAO.UpdateWebFirewall(tx, webId, firewallRefJSON)
if err != nil {
return err
}
}
// stat
{
var statConfig = &serverconfigs.HTTPStatRef{
IsPrior: false,
IsOn: true,
}
statJSON, err := json.Marshal(statConfig)
if err != nil {
return err
}
err = models.SharedHTTPWebDAO.UpdateWebStat(tx, webId, statJSON)
if err != nil {
return err
}
}
}
var httpConfig = &serverconfigs.HTTPProtocolConfig{}
httpConfig.IsOn = true
httpConfig.Listen = []*serverconfigs.NetworkAddressConfig{
{
Protocol: "http",
PortRange: types.String(this.options.Node.HTTPPort),
},
}
httpConfigJSON, err := json.Marshal(httpConfig)
if err != nil {
return err
}
// reverse proxy
reverseProxyId, err := models.SharedReverseProxyDAO.CreateReverseProxy(tx, 0, userId, nil, nil, nil)
if err != nil {
return err
}
var reverseProxyRef = &serverconfigs.ReverseProxyRef{
IsOn: true,
ReverseProxyId: reverseProxyId,
}
reverseProxyRefJSON, err := json.Marshal(reverseProxyRef)
if err != nil {
return err
}
2024-04-21 20:12:29 +08:00
_, err = models.SharedServerDAO.CreateServer(tx, 0, userId, serverconfigs.ServerTypeHTTPProxy, "First Site", "Created by system", []byte(`[{"name": "example.org", "type":"full"}]`), false, nil, httpConfigJSON, nil, nil, nil, nil, webId, reverseProxyRefJSON, clusterId, nil, nil, nil, 0)
2024-01-29 17:57:01 +08:00
if err != nil {
return fmt.Errorf("create server failed: %w", err)
}
}
}
// 数据库清理
{
var config = systemconfigs.NewDatabaseConfig()
configJSON, err := json.Marshal(config)
if err != nil {
return fmt.Errorf("encode database config failed: %w", err)
}
err = models.SharedSysSettingDAO.UpdateSetting(tx, systemconfigs.SettingCodeDatabaseConfigSetting, configJSON)
if err != nil {
return err
}
}
2024-01-29 17:57:01 +08:00
// 删除任务
{
err := models.SharedNodeTaskDAO.DeleteAllNodeTasks(tx)
if err != nil {
return err
}
}
2024-01-29 18:56:37 +08:00
// 设置未初始化
{
err := models.SharedSysSettingDAO.UpdateSetting(tx, systemconfigs.SettingCodeStandaloneInstanceInitialized, []byte("0"))
if err != nil {
return err
}
}
2024-01-29 17:57:01 +08:00
return nil
}
func (this *Instance) SetupAdminNode() error {
if this.options.Verbose {
log.Println("setup admin node ...")
}
{
err := this.unzip("admin", teaconst.Version)
if err != nil {
return err
}
}
// create api_node.yaml
db, findErr := this.dbInstance(true)
if findErr != nil {
return findErr
}
var apiYAMLData []byte
{
node, err := db.FindOne("SELECT nodeId,secret FROM edgeAPITokens WHERE state=1 AND role='admin'")
if err != nil {
return err
}
if node == nil {
return errors.New("can not find admin api token in database")
}
var apiConfig = &APIConfig{
RPCEndpoints: []string{"http://127.0.0.1:" + types.String(this.options.APINode.HTTPPort)},
RPCDisableUpdate: true,
NodeId: node.GetString("nodeId"),
Secret: node.GetString("secret"),
}
data, err := apiConfig.AsYAML()
if err != nil {
return err
}
apiYAMLData = data
err = os.WriteFile(this.targetPrefix()+"/edge-admin/configs/api_admin.yaml", data, 0666)
if err != nil {
return err
}
}
// backup
// ignore errors
{
homeDir, err := os.UserHomeDir()
if err == nil {
var dir = homeDir + "/.edge-admin/"
_, err = os.Stat(dir)
if err != nil {
_ = os.MkdirAll(dir, 0777)
}
_ = os.WriteFile(dir+"/api_admin.yaml", apiYAMLData, 0666)
}
}
// create database config
{
dbConfig, err := db.Config()
if err != nil {
return fmt.Errorf("retrieve database config failed: %w", err)
}
var fullConfig = dbs.Config{}
fullConfig.Default.DB = "prod"
fullConfig.DBs = map[string]*dbs.DBConfig{
"prod": dbConfig,
}
data, err := yaml.Marshal(fullConfig)
if err != nil {
return err
}
err = os.WriteFile(this.targetPrefix()+"/edge-admin/configs/api_db.yaml", data, 0666)
if err != nil {
return err
}
}
// server.yaml
{
var serverConfig = &TeaGo.ServerConfig{}
serverConfig.Env = "prod"
serverConfig.Http.On = true
serverConfig.Http.Listen = []string{":" + types.String(this.options.AdminNode.Port)}
data, err := yaml.Marshal(serverConfig)
if err != nil {
return err
}
err = os.WriteFile(this.targetPrefix()+"/edge-admin/configs/server.yaml", data, 0666)
if err != nil {
return err
}
}
return nil
}
func (this *Instance) SetupAPINode() error {
if this.options.Verbose {
log.Println("setup api node ...")
}
{
err := this.unzip("api", teaconst.NodeVersion)
if err != nil {
return err
}
}
// create api_node.yaml
db, findErr := this.dbInstance(true)
if findErr != nil {
return findErr
}
{
node, err := db.FindOne("SELECT uniqueId,secret FROM edgeAPINodes WHERE state=1")
if err != nil {
return err
}
if node == nil {
return errors.New("can not find node in database")
}
var apiConfig = &APIConfig{
NodeId: node.GetString("uniqueId"),
Secret: node.GetString("secret"),
}
data, err := apiConfig.AsYAML()
if err != nil {
return err
}
err = os.WriteFile(this.targetPrefix()+"/edge-api/configs/api.yaml", data, 0666)
if err != nil {
return err
}
}
// create database config
{
dbConfig, err := db.Config()
if err != nil {
return fmt.Errorf("retrieve database config failed: %w", err)
}
var fullConfig = dbs.Config{}
fullConfig.Default.DB = "prod"
fullConfig.DBs = map[string]*dbs.DBConfig{
"prod": dbConfig,
}
data, err := yaml.Marshal(fullConfig)
if err != nil {
return err
}
err = os.WriteFile(this.targetPrefix()+"/edge-api/configs/db.yaml", data, 0666)
if err != nil {
return err
}
}
return nil
}
func (this *Instance) SetupNode() error {
if this.options.Verbose {
log.Println("setup node ...")
}
{
err := this.unzip("node", teaconst.NodeVersion)
if err != nil {
return err
}
}
// create api_node.yaml
{
db, err := this.dbInstance(true)
if err != nil {
return err
}
node, err := db.FindOne("SELECT uniqueId,secret FROM edgeNodes WHERE state=1")
if err != nil {
return err
}
if node == nil {
return errors.New("can not find node in database")
}
var apiConfig = &APIConfig{
RPCEndpoints: []string{"http://127.0.0.1:" + types.String(this.options.APINode.HTTPPort)},
RPCDisableUpdate: true,
NodeId: node.GetString("uniqueId"),
Secret: node.GetString("secret"),
}
data, err := apiConfig.AsYAML()
if err != nil {
return err
}
err = os.WriteFile(this.targetPrefix()+"/edge-node/configs/api_node.yaml", data, 0666)
if err != nil {
return err
}
}
return nil
}
func (this *Instance) SetupUserNode() error {
if !this.isPlus() {
return nil
}
if this.options.Verbose {
log.Println("setup user node ...")
}
{
err := this.unzip("user", teaconst.NodeVersion)
if err != nil {
return err
}
}
// create api_node.yaml
{
db, err := this.dbInstance(true)
if err != nil {
return err
}
node, err := db.FindOne("SELECT uniqueId,secret FROM edgeUserNodes WHERE state=1")
if err != nil {
return err
}
if node == nil {
return errors.New("can not find node in database")
}
var apiConfig = &APIConfig{
RPCEndpoints: []string{"http://127.0.0.1:" + types.String(this.options.APINode.HTTPPort)},
RPCDisableUpdate: true,
NodeId: node.GetString("uniqueId"),
Secret: node.GetString("secret"),
}
data, err := apiConfig.AsYAML()
if err != nil {
return err
}
err = os.WriteFile(this.targetPrefix()+"/edge-user/configs/api_user.yaml", data, 0666)
if err != nil {
return err
}
}
return nil
}
func (this *Instance) Clean() error {
if this.options.Verbose {
log.Println("cleaning ...")
}
{
var dir = this.targetPrefix() + "/edge-admin/edge-api"
_, err := os.Stat(dir)
if err == nil {
err = os.RemoveAll(dir)
if err != nil {
return fmt.Errorf("remove %s failed: %w", dir, err)
}
}
}
if !this.options.IsTesting {
matches, _ := filepath.Glob(this.options.SrcDir + "/*.zip")
for _, filePath := range matches {
err := os.Remove(filePath)
if err != nil {
return fmt.Errorf("remove %s failed: %w", filePath, err)
}
}
}
return nil
}
func (this *Instance) Startup() error {
if this.options.Verbose {
log.Println("startup ...")
}
type NodeInfo struct {
Role string
Ports []int
}
for _, node := range []NodeInfo{
{"api", []int{this.options.APINode.HTTPPort, this.options.APINode.RestHTTPPort}},
{"admin", []int{this.options.AdminNode.Port}},
{"node", []int{this.options.Node.HTTPPort}},
{"user", []int{this.options.UserNode.HTTPPort}},
} {
var exe = this.targetPrefix() + "/edge-" + node.Role + "/bin/edge-" + node.Role
_, err := os.Stat(exe)
if err != nil {
continue
}
var cmd = executils.NewTimeoutCmd(30*time.Second, exe, "start")
err = cmd.Run()
if err != nil {
return fmt.Errorf("start '"+node.Role+"' failed: %w", err)
}
for _, port := range node.Ports {
var isOk bool
for i := 0; i < 30; /** seconds **/ i++ {
conn, connErr := net.DialTimeout("tcp", ":"+types.String(port), 5*time.Second)
if connErr != nil {
time.Sleep(1 * time.Second)
continue
}
_ = conn.Close()
isOk = true
}
if !isOk {
return fmt.Errorf("waiting '%s' port '%d' timeout", node.Role, port)
}
}
}
return nil
}
func (this *Instance) dbInstance(enableDAO bool) (*dbs.DB, error) {
Tea.Env = "prod"
db, err := dbs.NewInstanceFromConfig(&dbs.DBConfig{
Driver: "mysql",
Dsn: this.options.DB.Username + ":" + this.options.DB.Password + "@tcp(" + this.options.DB.Host + ":" + types.String(this.options.DB.Port) + ")/" + this.options.DB.Name + "?charset=utf8mb4&timeout=30s",
Prefix: "edge",
})
if err != nil {
return nil, fmt.Errorf("create database instance failed: %w", err)
}
if enableDAO {
this.setupDAO(db)
}
return db, nil
}
func (this *Instance) dbInstanceWithoutDBName() (*dbs.DB, error) {
Tea.Env = "prod"
db, err := dbs.NewInstanceFromConfig(&dbs.DBConfig{
Driver: "mysql",
Dsn: this.options.DB.Username + ":" + this.options.DB.Password + "@tcp(" + this.options.DB.Host + ":" + types.String(this.options.DB.Port) + ")/?charset=utf8mb4&timeout=30s",
Prefix: "edge",
})
if err != nil {
return nil, fmt.Errorf("create database instance failed: %w", err)
}
return db, nil
}
func (this *Instance) setupDAO(db *dbs.DB) {
dbConfig, err := db.Config()
if err == nil {
dbs.GlobalConfig().DBs = map[string]*dbs.DBConfig{
"dev": dbConfig,
"prod": dbConfig,
}
}
{
models.SharedNodeClusterDAO = models.NewNodeClusterDAO()
models.SharedNodeClusterDAO.Instance = db
}
{
models.SharedNodeDAO = models.NewNodeDAO()
models.SharedNodeDAO.Instance = db
}
{
models.SharedNodeTaskDAO = models.NewNodeTaskDAO()
models.SharedNodeTaskDAO.Instance = db
}
{
models.SharedSysLockerDAO = models.NewSysLockerDAO()
models.SharedSysLockerDAO.Instance = db
}
{
models.SharedAdminDAO = models.NewAdminDAO()
models.SharedAdminDAO.Instance = db
}
{
models.SharedAPINodeDAO = models.NewAPINodeDAO()
models.SharedAPINodeDAO.Instance = db
}
{
models.SharedApiTokenDAO = models.NewApiTokenDAO()
models.SharedApiTokenDAO.Instance = db
}
{
models.SharedUserDAO = models.NewUserDAO()
models.SharedUserDAO.Instance = db
}
{
models.SharedUserNodeDAO = models.NewUserNodeDAO()
models.SharedUserNodeDAO.Instance = db
}
{
models.SharedServerDAO = models.NewServerDAO()
models.SharedServerDAO.Instance = db
}
{
models.SharedHTTPWebDAO = models.NewHTTPWebDAO()
models.SharedHTTPWebDAO.Instance = db
}
{
models.SharedHTTPWebsocketDAO = models.NewHTTPWebsocketDAO()
models.SharedHTTPWebsocketDAO.Instance = db
}
{
models.SharedHTTPLocationDAO = models.NewHTTPLocationDAO()
models.SharedHTTPLocationDAO.Instance = db
}
{
models.SharedServerGroupDAO = models.NewServerGroupDAO()
models.SharedServerGroupDAO.Instance = db
}
{
models.SharedReverseProxyDAO = models.NewReverseProxyDAO()
models.SharedReverseProxyDAO.Instance = db
}
2024-01-29 18:56:37 +08:00
{
models.SharedSysSettingDAO = models.NewSysSettingDAO()
models.SharedSysSettingDAO.Instance = db
}
2024-01-29 17:57:01 +08:00
}
func (this *Instance) unzip(role string, version string) error {
if !regexp.MustCompile(`^\w+$`).MatchString(role) {
return errors.New("invalid role '" + role + "'")
}
var arch = runtime.GOARCH
if runtime.GOOS != "linux" {
arch = "amd64"
}
var plusTag string
if this.isPlus() && lists.ContainsString([]string{nodeconfigs.NodeRoleAdmin, nodeconfigs.NodeRoleAPI, nodeconfigs.NodeRoleNode}, role) {
plusTag = "-plus"
}
var zipFile = this.options.SrcDir + "/edge-" + role + "-linux-" + arch + plusTag + "-v" + version + ".zip"
{
stat, err := os.Stat(zipFile)
if err != nil {
return fmt.Errorf("stat '"+zipFile+"' failed: %w", err)
}
if stat.IsDir() {
return errors.New("'" + zipFile + "' should be a file instead of directory")
}
}
var targetPrefix = this.targetPrefix()
{
stat, err := os.Stat(targetPrefix)
if err != nil || !stat.IsDir() {
err = os.MkdirAll(targetPrefix, 0777)
if err != nil {
return fmt.Errorf("create directory '"+targetPrefix+"' failed: %w", err)
}
}
}
if this.options.Cacheable {
var targetDir = targetPrefix + "/edge-" + role
_, err := os.Stat(targetDir)
if err == nil {
return nil
}
}
var unzip = helpers.NewUnzip(zipFile, targetPrefix)
return unzip.Run()
}
func (this *Instance) targetPrefix() string {
return this.options.WorkDir + "/usr/local/goedge"
}
func (this *Instance) isPlus() bool {
return teaconst.Tag == "plus"
}