diff --git a/.gitignore b/.gitignore index 6ceab67..d2d426b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,6 @@ -#/alist-lib/* -#!../alist-lib/alistlib -#!../alist-lib/scripts +/alist-lib/* +!/alist-lib/alistlib +!/alist-lib/scripts # Miscellaneous *.class diff --git a/alist-lib/alistlib/common.go b/alist-lib/alistlib/common.go new file mode 100644 index 0000000..8c9c510 --- /dev/null +++ b/alist-lib/alistlib/common.go @@ -0,0 +1,23 @@ +package alistlib + +import "net" + +func GetOutboundIP() (net.IP, error) { + conn, err := net.Dial("udp", "8.8.8.8:80") + if err != nil { + return nil, err + } + defer conn.Close() + + localAddr := conn.LocalAddr().(*net.UDPAddr) + return localAddr.IP, nil +} + +func GetOutboundIPString() string { + netIp, err := GetOutboundIP() + if err != nil { + return "localhost" + } + return netIp.String() +} + diff --git a/alist-lib/alistlib/internal/log.go b/alist-lib/alistlib/internal/log.go new file mode 100644 index 0000000..927c403 --- /dev/null +++ b/alist-lib/alistlib/internal/log.go @@ -0,0 +1,13 @@ +package internal + +import log "github.com/sirupsen/logrus" + +type MyFormatter struct { + log.Formatter + OnLog func(entry *log.Entry) +} + +func (f *MyFormatter) Format(entry *log.Entry) ([]byte, error) { + f.OnLog(entry) + return nil, nil +} diff --git a/alist-lib/alistlib/server.go b/alist-lib/alistlib/server.go new file mode 100644 index 0000000..8e56fd6 --- /dev/null +++ b/alist-lib/alistlib/server.go @@ -0,0 +1,188 @@ +package alistlib + +import ( + "context" + "errors" + "fmt" + "net" + "net/http" + "os" + "strconv" + "time" + + "github.com/alist-org/alist/v3/alistlib/internal" + "github.com/alist-org/alist/v3/cmd" + "github.com/alist-org/alist/v3/cmd/flags" + "github.com/alist-org/alist/v3/internal/bootstrap" + "github.com/alist-org/alist/v3/internal/conf" + "github.com/alist-org/alist/v3/pkg/utils" + "github.com/alist-org/alist/v3/server" + "github.com/gin-gonic/gin" + log "github.com/sirupsen/logrus" +) + +type LogCallback interface { + OnLog(level int16, time int64, message string) +} + +type Event interface { + OnStartError(t string, err string) + OnShutdown(t string) + OnProcessExit(code int) +} + +var event Event +var logFormatter *internal.MyFormatter + +func Init(e Event, cb LogCallback) error { + event = e + cmd.Init() + logFormatter = &internal.MyFormatter{ + OnLog: func(entry *log.Entry) { + cb.OnLog(int16(entry.Level), entry.Time.UnixMilli(), entry.Message) + }, + } + if utils.Log == nil { + return errors.New("utils.log is nil") + } else { + utils.Log.SetFormatter(logFormatter) + utils.Log.ExitFunc = event.OnProcessExit + } + return nil +} + +var httpSrv, httpsSrv, unixSrv *http.Server + +func listenAndServe(t string, srv *http.Server) { + err := srv.ListenAndServe() + if err != nil && err != http.ErrServerClosed { + event.OnStartError(t, err.Error()) + } else { + event.OnShutdown(t) + } +} + +func IsRunning(t string) bool { + switch t { + case "http": + return httpSrv != nil + case "https": + return httpsSrv != nil + case "unix": + return unixSrv != nil + } + + return httpSrv != nil && httpsSrv != nil && unixSrv != nil +} + +// Start starts the server +func Start() { + if conf.Conf.DelayedStart != 0 { + utils.Log.Infof("delayed start for %d seconds", conf.Conf.DelayedStart) + time.Sleep(time.Duration(conf.Conf.DelayedStart) * time.Second) + } + bootstrap.InitOfflineDownloadTools() + bootstrap.LoadStorages() + bootstrap.InitTaskManager() + if !flags.Debug && !flags.Dev { + gin.SetMode(gin.ReleaseMode) + } + r := gin.New() + r.Use(gin.LoggerWithWriter(log.StandardLogger().Out), gin.RecoveryWithWriter(log.StandardLogger().Out)) + server.Init(r) + + if conf.Conf.Scheme.HttpPort != -1 { + httpBase := fmt.Sprintf("%s:%d", conf.Conf.Scheme.Address, conf.Conf.Scheme.HttpPort) + utils.Log.Infof("start HTTP server @ %s", httpBase) + httpSrv = &http.Server{Addr: httpBase, Handler: r} + go func() { + listenAndServe("http", httpSrv) + httpSrv = nil + }() + } + if conf.Conf.Scheme.HttpsPort != -1 { + httpsBase := fmt.Sprintf("%s:%d", conf.Conf.Scheme.Address, conf.Conf.Scheme.HttpsPort) + utils.Log.Infof("start HTTPS server @ %s", httpsBase) + httpsSrv = &http.Server{Addr: httpsBase, Handler: r} + go func() { + listenAndServe("https", httpsSrv) + httpsSrv = nil + }() + } + if conf.Conf.Scheme.UnixFile != "" { + utils.Log.Infof("start unix server @ %s", conf.Conf.Scheme.UnixFile) + unixSrv = &http.Server{Handler: r} + go func() { + listener, err := net.Listen("unix", conf.Conf.Scheme.UnixFile) + if err != nil { + //utils.Log.Fatalf("failed to listenAndServe unix: %+v", err) + event.OnStartError("unix", err.Error()) + } else { + // set socket file permission + mode, err := strconv.ParseUint(conf.Conf.Scheme.UnixFilePerm, 8, 32) + if err != nil { + utils.Log.Errorf("failed to parse socket file permission: %+v", err) + } else { + err = os.Chmod(conf.Conf.Scheme.UnixFile, os.FileMode(mode)) + if err != nil { + utils.Log.Errorf("failed to chmod socket file: %+v", err) + } + } + err = unixSrv.Serve(listener) + if err != nil && err != http.ErrServerClosed { + event.OnStartError("unix", err.Error()) + } + } + + unixSrv = nil + }() + } +} + +func shutdown(srv *http.Server, timeout time.Duration) error { + if srv == nil { + return nil + } + + ctx, cancel := context.WithTimeout(context.Background(), timeout) + defer cancel() + + err := srv.Shutdown(ctx) + if err == nil { + cmd.Release() + } + + return err +} + +// Shutdown timeout 毫秒 +func Shutdown(timeout int64) (err error) { + timeoutDuration := time.Duration(timeout) * time.Millisecond + utils.Log.Println("Shutdown server...") + if conf.Conf.Scheme.HttpPort != -1 { + err := shutdown(httpSrv, timeoutDuration) + if err != nil { + return err + } + httpSrv = nil + utils.Log.Println("Server HTTP Shutdown") + } + if conf.Conf.Scheme.HttpsPort != -1 { + err := shutdown(httpsSrv, timeoutDuration) + if err != nil { + return err + } + httpsSrv = nil + utils.Log.Println("Server HTTPS Shutdown") + } + if conf.Conf.Scheme.UnixFile != "" { + err := shutdown(unixSrv, timeoutDuration) + if err != nil { + return err + } + unixSrv = nil + utils.Log.Println("Server UNIX Shutdown") + } + + return nil +} diff --git a/alist-lib/alistlib/settings.go b/alist-lib/alistlib/settings.go new file mode 100644 index 0000000..68cd4a3 --- /dev/null +++ b/alist-lib/alistlib/settings.go @@ -0,0 +1,41 @@ +package alistlib + +import ( + "github.com/alist-org/alist/v3/cmd" + "github.com/alist-org/alist/v3/cmd/flags" + "github.com/alist-org/alist/v3/internal/op" + "github.com/alist-org/alist/v3/pkg/utils" +) + +func SetConfigData(path string) { + flags.DataDir = path +} + +func SetConfigLogStd(b bool) { + flags.LogStd = b +} + +func SetConfigDebug(b bool) { + flags.Debug = b +} + +func SetConfigNoPrefix(b bool) { + flags.NoPrefix = b +} + +func SetAdminPassword(pwd string) { + admin, err := op.GetAdmin() + if err != nil { + utils.Log.Errorf("failed get admin user: %+v", err) + return + } + admin.SetPassword(pwd) + if err := op.UpdateUser(admin); err != nil { + utils.Log.Errorf("failed update admin user: %+v", err) + return + } + utils.Log.Infof("admin user has been updated:") + utils.Log.Infof("username: %s", admin.Username) + utils.Log.Infof("password: %s", pwd) + cmd.DelAdminCacheOnline() +} diff --git a/alist-lib/scripts/gobind.sh b/alist-lib/scripts/gobind.sh new file mode 100644 index 0000000..57629fc --- /dev/null +++ b/alist-lib/scripts/gobind.sh @@ -0,0 +1,11 @@ +#!/bin/bash + +cd ../alistlib || exit +if [ "$1" == "mini" ]; then + gomobile bind -ldflags "-s -w" -v -androidapi 19 -target="android/arm64" +else + gomobile bind -ldflags "-s -w" -v -androidapi 19 +fi + +mv -f *.aar ../../android/app/libs +mv -f *.jar ../../android/app/libs \ No newline at end of file diff --git a/alist-lib/scripts/init_alist.sh b/alist-lib/scripts/init_alist.sh new file mode 100644 index 0000000..b536ac6 --- /dev/null +++ b/alist-lib/scripts/init_alist.sh @@ -0,0 +1,13 @@ +#!/bin/bash + +GIT_REPO="https://github.com/alist-org/alist.git" +TAG_NAME=$(git -c 'versionsort.suffix=-' ls-remote --exit-code --refs --sort='version:refname' --tags $GIT_REPO | tail --lines=1 | cut --delimiter='/' --fields=3) + +echo "AList - ${TAG_NAME}" +rm -rf ./src +unset GIT_WORK_TREE +git clone --branch "$TAG_NAME" https://github.com/alist-org/alist.git ./src +rm -rf ./src/.git + +mv -f ./src/* ../ +rm -rf ./src \ No newline at end of file diff --git a/alist-lib/scripts/init_gomobile.sh b/alist-lib/scripts/init_gomobile.sh new file mode 100644 index 0000000..7d4470b --- /dev/null +++ b/alist-lib/scripts/init_gomobile.sh @@ -0,0 +1,5 @@ +#!/bin/bash + +go install golang.org/x/mobile/cmd/gomobile@latest +gomobile init +go get golang.org/x/mobile/bind \ No newline at end of file diff --git a/alist-lib/scripts/init_web.sh b/alist-lib/scripts/init_web.sh new file mode 100644 index 0000000..a4ec808 --- /dev/null +++ b/alist-lib/scripts/init_web.sh @@ -0,0 +1,7 @@ +#!/bin/bash + +curl -L https://github.com/alist-org/alist-web/releases/latest/download/dist.tar.gz -o dist.tar.gz +tar -zxvf dist.tar.gz +rm -rf ../public/dist +mv -f dist ../public +rm -rf dist.tar.gz \ No newline at end of file