123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301 |
- // SiYuan - Refactor your thinking
- // Copyright (c) 2020-present, b3log.org
- //
- // This program is free software: you can redistribute it and/or modify
- // it under the terms of the GNU Affero General Public License as published by
- // the Free Software Foundation, either version 3 of the License, or
- // (at your option) any later version.
- //
- // This program is distributed in the hope that it will be useful,
- // but WITHOUT ANY WARRANTY; without even the implied warranty of
- // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- // GNU Affero General Public License for more details.
- //
- // You should have received a copy of the GNU Affero General Public License
- // along with this program. If not, see <https://www.gnu.org/licenses/>.
- package util
- import (
- "bytes"
- "io/fs"
- "net"
- "os"
- "path"
- "path/filepath"
- "sort"
- "strings"
- "time"
- "github.com/88250/gulu"
- "github.com/siyuan-note/filelock"
- "github.com/siyuan-note/logging"
- )
- var (
- SSL = false
- UserAgent = "SiYuan/" + Ver
- )
- func GetTreeID(treePath string) string {
- return strings.TrimSuffix(path.Base(treePath), ".sy")
- }
- func ShortPathForBootingDisplay(p string) string {
- if 25 > len(p) {
- return p
- }
- p = strings.TrimSuffix(p, ".sy")
- p = path.Base(p)
- return p
- }
- var LocalIPs []string
- func GetLocalIPs() (ret []string) {
- if ContainerAndroid == Container || ContainerHarmony == Container {
- // Android 上用不了 net.InterfaceAddrs() https://github.com/golang/go/issues/40569,所以前面使用启动内核传入的参数 localIPs
- LocalIPs = append(LocalIPs, LocalHost)
- LocalIPs = gulu.Str.RemoveDuplicatedElem(LocalIPs)
- return LocalIPs
- }
- ret = []string{}
- addrs, err := net.InterfaceAddrs()
- if err != nil {
- logging.LogWarnf("get interface addresses failed: %s", err)
- return
- }
- IPv4Nets := []*net.IPNet{}
- IPv6Nets := []*net.IPNet{}
- for _, addr := range addrs {
- if networkIp, ok := addr.(*net.IPNet); ok && networkIp.IP.String() != "<nil>" {
- if networkIp.IP.To4() != nil {
- IPv4Nets = append(IPv4Nets, networkIp)
- } else if networkIp.IP.To16() != nil {
- IPv6Nets = append(IPv6Nets, networkIp)
- }
- }
- }
- // loopback address
- for _, net := range IPv4Nets {
- if net.IP.IsLoopback() {
- ret = append(ret, net.IP.String())
- }
- }
- // private address
- for _, net := range IPv4Nets {
- if net.IP.IsPrivate() {
- ret = append(ret, net.IP.String())
- }
- }
- // IPv4 private address
- for _, net := range IPv4Nets {
- if net.IP.IsGlobalUnicast() {
- ret = append(ret, net.IP.String())
- }
- }
- // link-local unicast address
- for _, net := range IPv4Nets {
- if net.IP.IsLinkLocalUnicast() {
- ret = append(ret, net.IP.String())
- }
- }
- // loopback address
- for _, net := range IPv6Nets {
- if net.IP.IsLoopback() {
- ret = append(ret, "["+net.IP.String()+"]")
- }
- }
- // private address
- for _, net := range IPv6Nets {
- if net.IP.IsPrivate() {
- ret = append(ret, "["+net.IP.String()+"]")
- }
- }
- // IPv6 private address
- for _, net := range IPv6Nets {
- if net.IP.IsGlobalUnicast() {
- ret = append(ret, "["+net.IP.String()+"]")
- }
- }
- // link-local unicast address
- for _, net := range IPv6Nets {
- if net.IP.IsLinkLocalUnicast() {
- ret = append(ret, "["+net.IP.String()+"]")
- }
- }
- ret = append(ret, LocalHost)
- ret = gulu.Str.RemoveDuplicatedElem(ret)
- return
- }
- func isRunningInDockerContainer() bool {
- if _, runInContainer := os.LookupEnv("RUN_IN_CONTAINER"); runInContainer {
- return true
- }
- if _, err := os.Stat("/.dockerenv"); err == nil {
- return true
- }
- return false
- }
- func IsRelativePath(dest string) bool {
- if 1 > len(dest) {
- return true
- }
- if '/' == dest[0] {
- return false
- }
- return !strings.Contains(dest, ":/") && !strings.Contains(dest, ":\\")
- }
- func TimeFromID(id string) (ret string) {
- if 14 > len(id) {
- logging.LogWarnf("invalid id [%s], stack [\n%s]", id, logging.ShortStack())
- return time.Now().Format("20060102150405")
- }
- ret = id[:14]
- return
- }
- func GetChildDocDepth(treeAbsPath string) (ret int) {
- dir := strings.TrimSuffix(treeAbsPath, ".sy")
- if !gulu.File.IsDir(dir) {
- return
- }
- baseDepth := strings.Count(filepath.ToSlash(treeAbsPath), "/")
- depth := 1
- filelock.Walk(dir, func(path string, d fs.DirEntry, err error) error {
- p := filepath.ToSlash(path)
- currentDepth := strings.Count(p, "/")
- if depth < currentDepth {
- depth = currentDepth
- }
- return nil
- })
- ret = depth - baseDepth
- return
- }
- func NormalizeConcurrentReqs(concurrentReqs int, provider int) int {
- if 1 > concurrentReqs {
- if 2 == provider { // S3
- return 8
- } else if 3 == provider { // WebDAV
- return 1
- }
- return 8
- }
- if 16 < concurrentReqs {
- return 16
- }
- return concurrentReqs
- }
- func NormalizeTimeout(timeout int) int {
- if 7 > timeout {
- if 1 > timeout {
- return 60
- }
- return 7
- }
- if 300 < timeout {
- return 300
- }
- return timeout
- }
- func NormalizeEndpoint(endpoint string) string {
- endpoint = strings.TrimSpace(endpoint)
- if "" == endpoint {
- return ""
- }
- if !strings.HasPrefix(endpoint, "http://") && !strings.HasPrefix(endpoint, "https://") {
- endpoint = "http://" + endpoint
- }
- if !strings.HasSuffix(endpoint, "/") {
- endpoint = endpoint + "/"
- }
- return endpoint
- }
- func FilterMoveDocFromPaths(fromPaths []string, toPath string) (ret []string) {
- tmp := FilterSelfChildDocs(fromPaths)
- for _, fromPath := range tmp {
- fromDir := strings.TrimSuffix(fromPath, ".sy")
- if strings.HasPrefix(toPath, fromDir) {
- continue
- }
- ret = append(ret, fromPath)
- }
- return
- }
- func FilterSelfChildDocs(paths []string) (ret []string) {
- sort.Slice(paths, func(i, j int) bool { return strings.Count(paths[i], "/") < strings.Count(paths[j], "/") })
- dirs := map[string]string{}
- for _, fromPath := range paths {
- dir := strings.TrimSuffix(fromPath, ".sy")
- existParent := false
- for d, _ := range dirs {
- if strings.HasPrefix(fromPath, d) {
- existParent = true
- break
- }
- }
- if existParent {
- continue
- }
- dirs[dir] = fromPath
- ret = append(ret, fromPath)
- }
- return
- }
- func IsAssetLinkDest(dest []byte) bool {
- return bytes.HasPrefix(dest, []byte("assets/"))
- }
- var (
- SiYuanAssetsImage = []string{".apng", ".ico", ".cur", ".jpg", ".jpe", ".jpeg", ".jfif", ".pjp", ".pjpeg", ".png", ".gif", ".webp", ".bmp", ".svg", ".avif"}
- SiYuanAssetsAudio = []string{".mp3", ".wav", ".ogg", ".m4a", ".flac"}
- SiYuanAssetsVideo = []string{".mov", ".weba", ".mkv", ".mp4", ".webm"}
- )
- func IsDisplayableAsset(p string) bool {
- ext := strings.ToLower(filepath.Ext(p))
- if "" == ext {
- return false
- }
- if gulu.Str.Contains(ext, SiYuanAssetsImage) {
- return true
- }
- if gulu.Str.Contains(ext, SiYuanAssetsAudio) {
- return true
- }
- if gulu.Str.Contains(ext, SiYuanAssetsVideo) {
- return true
- }
- return false
- }
- func GetAbsPathInWorkspace(relPath string) (string, error) {
- absPath := filepath.Join(WorkspaceDir, relPath)
- absPath = filepath.Clean(absPath)
- if WorkspaceDir == absPath {
- return absPath, nil
- }
- if IsSubPath(WorkspaceDir, absPath) {
- return absPath, nil
- }
- return "", os.ErrPermission
- }
|