Преглед изворни кода

v0.3.7 (#600)

* add send notify function

* add shell script

* add system notiry

* remove disk and test common package

* update http status

* add share function to common

* remove temp path

* remove /DATA directory initialization - moved to local-storage (#578)

* update goreleaser configuration

* wip

* change service type to notify for systemd so its status is OK only when service is initialized successfully

* update CasaOS-Common to fix runtime error

* wip

* add send notify function

* add shell script

* add system notiry

* remove disk and test common package

* update http status

* add share function to common

* remove temp path

* remove /DATA directory initialization - moved to local-storage (#578)

* update goreleaser configuration

* wip

* change service type to notify for systemd so its status is OK only when service is initialized successfully

* update CasaOS-Common to fix runtime error

* wip

* wip

* wip

* wip

* wip

* Utilization interface to supplement disk information

* fix upload file

* wip

* wip

* add update url

* wip

* wip

* add change log

* update changelog

Co-authored-by: LinkLeong <a624669980@163.com>
Tiger Wang пре 2 година
родитељ
комит
381fb85b1d
57 измењених фајлова са 1326 додато и 2355 уклоњено
  1. 2 1
      .gitignore
  2. 167 0
      .goreleaser.debug.yaml
  3. 4 4
      .goreleaser.yaml
  4. 14 0
      CHANGELOG.md
  5. 30 33
      build/scripts/migration/script.d/03-migrate-casaos.sh
  6. 3 3
      build/scripts/migration/service.d/casaos/migration.list
  7. 7 12
      build/scripts/setup/service.d/casaos/debian/setup-casaos.sh
  8. 0 1
      build/sysroot/etc/casaos/casaos.conf.sample
  9. 2 1
      build/sysroot/usr/lib/systemd/system/casaos.service
  10. 0 0
      build/sysroot/usr/share/casaos/cleanup/script.d/01-cleanup-casaos.sh
  11. 46 0
      build/sysroot/usr/share/casaos/cleanup/script.d/03-cleanup-casaos.sh
  12. 1 0
      build/sysroot/usr/share/casaos/cleanup/service.d/casaos/debian/bullseye/cleanup-casaos.sh
  13. 204 0
      build/sysroot/usr/share/casaos/cleanup/service.d/casaos/debian/cleanup-casaos.sh
  14. 1 0
      build/sysroot/usr/share/casaos/cleanup/service.d/casaos/ubuntu/cleanup-casaos.sh
  15. 1 0
      build/sysroot/usr/share/casaos/cleanup/service.d/casaos/ubuntu/jammy/cleanup-casaos.sh
  16. 1 1
      build/sysroot/usr/share/casaos/shell/update.sh
  17. 0 10
      cmd/migration-tool/log.go
  18. 14 11
      cmd/migration-tool/main.go
  19. 0 182
      cmd/migration-tool/migration-034-035.go
  20. 60 0
      cmd/migration-tool/migration-sample.go
  21. 89 0
      common/notify.go
  22. 29 0
      common/notify_test.go
  23. 78 0
      common/share.go
  24. 14 0
      common/share_test.go
  25. 0 1
      conf/conf.conf.sample
  26. 2 2
      go.mod
  27. 2 4
      go.sum
  28. 43 26
      main.go
  29. 0 62
      middleware/gin.go
  30. 0 98
      model/disk.go
  31. 6 0
      model/docker.go
  32. 0 1
      model/receive/app.go
  33. 6 6
      model/sys_common.go
  34. 5 8
      pkg/config/init.go
  35. 0 32
      pkg/config/update.go
  36. 36 36
      pkg/docker/helper.go
  37. 1 1
      pkg/sqlite/db.go
  38. 7 6
      pkg/utils/command/command_helper.go
  39. 33 20
      pkg/utils/file/file.go
  40. 0 46
      route/init.go
  41. 36 229
      route/periodical.go
  42. 59 75
      route/route.go
  43. 96 5
      route/v1/app.go
  44. 0 622
      route/v1/disk.go
  45. 2 2
      route/v1/docker.go
  46. 74 66
      route/v1/file.go
  47. 23 0
      route/v1/notiry.go
  48. 0 109
      route/v1/storage.go
  49. 10 202
      route/v1/system.go
  50. 0 8
      service/casa.go
  51. 0 285
      service/disk.go
  52. 53 38
      service/docker.go
  53. 0 25
      service/model/o_disk.go
  54. 36 41
      service/notify.go
  55. 0 7
      service/service.go
  56. 20 23
      service/system.go
  57. 9 10
      types/system.go

+ 2 - 1
.gitignore

@@ -35,4 +35,5 @@ __debug_bin
 main
 github.com
 .all-contributorsrc
-dist
+dist
+CasaOS

+ 167 - 0
.goreleaser.debug.yaml

@@ -0,0 +1,167 @@
+# This is an example .goreleaser.yml file with some sensible defaults.
+# Make sure to check the documentation at https://goreleaser.com
+project_name: casaos
+before:
+  hooks:
+    # You may remove this if you don't use go modules.
+    - go mod tidy
+builds:
+  - id: casaos-amd64
+    binary: build/sysroot/usr/bin/casaos
+    env:
+      - CGO_ENABLED=1
+      - CC=x86_64-linux-gnu-gcc
+    gcflags:
+      - all=-N -l
+    ldflags:
+      - -extldflags "-static"
+    tags:
+      - musl
+      - netgo
+    goos:
+      - linux
+    goarch:
+      - amd64
+    hooks:
+      post:
+        - find build/sysroot -type f | xargs -L 1 realpath --relative-to=build/sysroot > build/sysroot.manifest
+  - id: casaos-arm64
+    binary: build/sysroot/usr/bin/casaos
+    env:
+      - CGO_ENABLED=1
+      - CC=aarch64-linux-gnu-gcc
+    gcflags:
+      - all=-N -l
+    ldflags:
+      - -extldflags "-static"
+    tags:
+      - musl
+      - netgo
+    goos:
+      - linux
+    goarch:
+      - arm64
+    hooks:
+      post:
+        - find build/sysroot -type f | xargs -L 1 realpath --relative-to=build/sysroot > build/sysroot.manifest
+  - id: casaos-arm-7
+    binary: build/sysroot/usr/bin/casaos
+    env:
+      - CGO_ENABLED=1
+      - CC=arm-linux-gnueabihf-gcc
+    gcflags:
+      - all=-N -l
+    ldflags:
+      - -extldflags "-static"
+    tags:
+      - musl
+      - netgo
+    goos:
+      - linux
+    goarch:
+      - arm
+    goarm:
+      - "7"
+    hooks:
+      post:
+        - find build/sysroot -type f | xargs -L 1 realpath --relative-to=build/sysroot > build/sysroot.manifest
+  - id: casaos-migration-tool-amd64
+    binary: build/sysroot/usr/bin/casaos-migration-tool
+    main: ./cmd/migration-tool
+    env:
+      - CGO_ENABLED=1
+      - CC=x86_64-linux-gnu-gcc
+    gcflags:
+      - all=-N -l
+    ldflags:
+      - -extldflags "-static"
+    tags:
+      - musl
+      - netgo
+    goos:
+      - linux
+    goarch:
+      - amd64
+  - id: casaos-migration-tool-arm64
+    binary: build/sysroot/usr/bin/casaos-migration-tool
+    main: ./cmd/migration-tool
+    env:
+      - CGO_ENABLED=1
+      - CC=aarch64-linux-gnu-gcc
+    gcflags:
+      - all=-N -l
+    ldflags:
+      - -extldflags "-static"
+    tags:
+      - musl
+      - netgo
+    goos:
+      - linux
+    goarch:
+      - arm64
+  - id: casaos-migration-tool-arm-7
+    binary: build/sysroot/usr/bin/casaos-migration-tool
+    main: ./cmd/migration-tool
+    env:
+      - CGO_ENABLED=1
+      - CC=arm-linux-gnueabihf-gcc
+    gcflags:
+      - all=-N -l
+    ldflags:
+      - -extldflags "-static"
+    tags:
+      - musl
+      - netgo
+    goos:
+      - linux
+    goarch:
+      - arm
+    goarm:
+      - "7"
+archives:
+  - name_template: "{{ .Os }}-{{ .Arch }}-{{ .ProjectName }}-v{{ .Version }}"
+    id: casaos
+    builds:
+      - casaos-amd64
+      - casaos-arm64
+      - casaos-arm-7
+    replacements:
+      arm: arm-7
+    files:
+      - build/**/*
+  - name_template: "{{ .Os }}-{{ .Arch }}-{{ .ProjectName }}-migration-tool-v{{ .Version }}"
+    id: casaos-migration-tool
+    builds:
+      - casaos-migration-tool-amd64
+      - casaos-migration-tool-arm64
+      - casaos-migration-tool-arm-7
+    replacements:
+      arm: arm-7
+    files:
+      - build/sysroot/etc/**/*
+checksum:
+  name_template: "checksums.txt"
+snapshot:
+  name_template: "{{ incpatch .Version }}"
+changelog:
+  sort: asc
+  filters:
+    exclude:
+      - "^docs:"
+      - "^test:"
+# release:
+#   github:
+#     owner: IceWhaleTech
+#     name: CasaOS
+#   draft: true
+#   prerelease: auto
+#   mode: replace
+#   name_template: "v{{ .Version }}"
+release:
+  github:
+    owner: IceWhaleTech
+    name: CasaOS
+  draft: true
+  prerelease: auto
+  mode: replace
+  name_template: "v{{ .Version }}"

+ 4 - 4
.goreleaser.yaml

@@ -117,7 +117,7 @@ builds:
     goarch:
       - arm
     goarm:
-      - "7"    
+      - "7"
 archives:
   - name_template: "{{ .Os }}-{{ .Arch }}-{{ .ProjectName }}-v{{ .Version }}"
     id: casaos
@@ -159,9 +159,9 @@ changelog:
 #   name_template: "v{{ .Version }}"
 release:
   github:
-    owner: LinkLeong
-    name: casaos-alpha
+    owner: IceWhaleTech
+    name: CasaOS
   draft: true
   prerelease: auto
   mode: replace
-  name_template: "v{{ .Version }}"
+  name_template: "v{{ .Version }}"

+ 14 - 0
CHANGELOG.md

@@ -18,6 +18,20 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
 
 ### Fixed
 
+## [0.3.7]
+
+### Added
+- [Storage] Disk merge (Beta), you can merge multiple disks into a single storage space (currently you need to enable this feature from the command line)
+
+### Changed
+- [Files] Changed the cache file storage location, now the file upload size is not limited by the system disk capacity.
+- [Scripts] Updated installation and upgrade scripts to support more Debian-based Linux distributions.
+- [Engineering] Refactored Local Storage into a standalone service as part of CasaOS modularization.
+
+### Fixed
+- [Apps] App list update mechanism improved, now you can see the latest apps in App Store immediately.
+- [Storage] Fixed a lot of known issues
+
 
 ## [0.3.6-alpha.1] - 2022-09-06
 

+ 30 - 33
build/scripts/migration/script.d/03-migrate-casaos.sh

@@ -60,8 +60,6 @@ BUILD_PATH=$(dirname "${BASH_SOURCE[0]}")/../../..
 SOURCE_ROOT=${BUILD_PATH}/sysroot
 
 APP_NAME="casaos"
-# APP_NAME_FORMAL="CasaOS"
-APP_NAME_FORMAL="casaos-alpha"
 
 # check if migration is needed
 SOURCE_BIN_PATH=${SOURCE_ROOT}/usr/bin
@@ -85,6 +83,25 @@ if [ "${NEED_MIGRATION}" = "false" ]; then
     exit 0
 fi
 
+ARCH="unknown"
+
+case $(uname -m) in
+    x86_64)
+        ARCH="amd64"
+        ;;
+    aarch64)
+        ARCH="arm64"
+        ;;
+    armv7l)
+        ARCH="arm-7"
+        ;;
+    *)
+        __error "Unsupported architecture"
+        ;;
+esac
+
+__info "ARCH: ${ARCH}"
+
 MIGRATION_SERVICE_DIR=${1}
 
 if [ -z "${MIGRATION_SERVICE_DIR}" ]; then
@@ -95,10 +112,10 @@ MIGRATION_PATH=()
 
 CURRENT_VERSION_FOUND="false"
 
-# a VERSION_PAIR looks like "v0.3.5 v0.3.6-alpha2"
+# a VERSION_PAIR looks like "v0.3.5 <url>"
 #
 # - "v0.3.5" is the current version installed on this host
-# - "v0.3.6-alpha2" is the version of the migration tool from GitHub
+# - "<url>" is the url of the migration tool
 while read -r VERSION_PAIR; do
     if [ -z "${VERSION_PAIR}" ]; then
         continue
@@ -107,15 +124,15 @@ while read -r VERSION_PAIR; do
     # obtain "v0.3.5" from "v0.3.5 v0.3.6-alpha2"
     VER1=$(echo "${VERSION_PAIR}" | cut -d' ' -f1)
 
-    # obtain "v0.3.6-alpha2" from "v0.3.5 v0.3.6-alpha2"
-    VER2=$(echo "${VERSION_PAIR}" | cut -d' ' -f2)
+    # obtain "<url>" from "v0.3.5 <url>"
+    URL=$(eval echo "${VERSION_PAIR}" | cut -d' ' -f2)
 
     if [ "${CURRENT_VERSION}" = "${VER1// /}" ] || [ "${CURRENT_VERSION}" = "LEGACY_WITHOUT_VERSION" ]; then
         CURRENT_VERSION_FOUND="true"
     fi
 
     if [ "${CURRENT_VERSION_FOUND}" = "true" ]; then
-        MIGRATION_PATH+=("${VER2// /}")
+        MIGRATION_PATH+=("${URL// /}")
     fi
 done < "${MIGRATION_LIST_FILE}"
 
@@ -124,38 +141,18 @@ if [ ${#MIGRATION_PATH[@]} -eq 0 ]; then
     exit 0
 fi
 
-ARCH="unknown"
-
-case $(uname -m) in
-    x86_64)
-        ARCH="amd64"
-        ;;
-    aarch64)
-        ARCH="arm64"
-        ;;
-    armv7l)
-        ARCH="arm-7"
-        ;;
-    *)
-        __error "Unsupported architecture"
-        ;;
-esac
-
 pushd "${MIGRATION_SERVICE_DIR}"
 
-{ for VER2 in "${MIGRATION_PATH[@]}"; do
-
-
-        MIGRATION_TOOL_FILE=linux-"${ARCH}"-"${APP_NAME}"-migration-tool-"${VER2}".tar.gz
+{ for URL in "${MIGRATION_PATH[@]}"; do
+        MIGRATION_TOOL_FILE=$(basename "${URL}")
 
         if [ -f "${MIGRATION_TOOL_FILE}" ]; then
             __info "Migration tool ${MIGRATION_TOOL_FILE} exists. Skip downloading."
             continue
         fi
 
-        MIGRATION_TOOL_URL=https://github.com/LinkLeong/"${APP_NAME_FORMAL}"/releases/download/"${VER2}"/linux-"${ARCH}"-"${APP_NAME}"-migration-tool-"${VER2}".tar.gz
-        echo "Dowloading ${MIGRATION_TOOL_URL}..."
-        curl -sL -O "${MIGRATION_TOOL_URL}"
+        __info "Dowloading ${URL}..."
+        curl -fsSL -o "${MIGRATION_TOOL_FILE}" -O "${URL}"
     done
 } || {
     popd
@@ -163,8 +160,8 @@ pushd "${MIGRATION_SERVICE_DIR}"
 }
 
 {
-    for VER2 in "${MIGRATION_PATH[@]}"; do
-        MIGRATION_TOOL_FILE=linux-"${ARCH}"-"${APP_NAME}"-migration-tool-"${VER2}".tar.gz
+    for URL in "${MIGRATION_PATH[@]}"; do
+        MIGRATION_TOOL_FILE=$(basename "${URL}")
         __info "Extracting ${MIGRATION_TOOL_FILE}..."
         tar zxvf "${MIGRATION_TOOL_FILE}" || __error "Failed to extract ${MIGRATION_TOOL_FILE}"
 

+ 3 - 3
build/scripts/migration/service.d/casaos/migration.list

@@ -1,3 +1,3 @@
-LEGACY_WITHOUT_VERSION v0.3.6
-v0.3.5 v0.3.6
-v0.3.5.1 v0.3.6
+LEGACY_WITHOUT_VERSION https://github.com/IceWhaleTech/CasaOS/releases/download/v0.3.6/linux-${ARCH}-casaos-migration-tool-v0.3.6.tar.gz
+v0.3.5 https://github.com/IceWhaleTech/CasaOS/releases/download/v0.3.6/linux-${ARCH}-casaos-migration-tool-v0.3.6.tar.gz
+v0.3.5.1 https://github.com/IceWhaleTech/CasaOS/releases/download/v0.3.6/linux-${ARCH}-casaos-migration-tool-v0.3.6.tar.gz

+ 7 - 12
build/scripts/setup/service.d/casaos/debian/setup-casaos.sh

@@ -31,15 +31,10 @@ if [ ! -f "${CONF_FILE}" ]; then
     cp -v "${CONF_FILE_SAMPLE}" "${CONF_FILE}"
 fi
 
-if systemctl is-active "${APP_NAME}.service" &>/dev/null ;then
-    echo "server started"
-else
-    # enable and start service
-    systemctl daemon-reload
-
-    echo "Enabling service..."
-    systemctl enable --force --no-ask-password "${APP_NAME}.service"
-
-    echo "Starting service..."
-    systemctl start --force --no-ask-password "${APP_NAME}.service"
-fi
+rm -rf /etc/systemd/system/casaos.service # remove old service file
+
+systemctl daemon-reload
+
+# enable service (without starting)
+echo "Enabling service..."
+systemctl enable --force --no-ask-password "${APP_NAME}.service"

+ 0 - 1
build/sysroot/etc/casaos/casaos.conf.sample

@@ -11,7 +11,6 @@ DateFormat = 2006-01-02
 DBPath     = /var/lib/casaos
 ShellPath  = /usr/share/casaos/shell
 UserDataPath = /var/lib/casaos/conf
-TempPath    = /var/lib/casaos/temp
 
 [server]
 RunMode = release

+ 2 - 1
build/sysroot/usr/lib/systemd/system/casaos.service

@@ -1,12 +1,13 @@
 [Unit]
 After=casaos-gateway.service
 ConditionFileNotEmpty=/etc/casaos/casaos.conf
-Description=CasaOS Service
+Description=CasaOS Main Service
 
 [Service]
 ExecStart=/usr/bin/casaos -c /etc/casaos/casaos.conf
 PIDFile=/var/run/casaos/casaos.pid
 Restart=always
+Type=notify
 
 [Install]
 WantedBy=multi-user.target

+ 0 - 0
build/sysroot/usr/share/casaos/cleanup/script.d/01-cleanup-casaos.sh


+ 46 - 0
build/sysroot/usr/share/casaos/cleanup/script.d/03-cleanup-casaos.sh

@@ -0,0 +1,46 @@
+#!/bin/bash
+
+set -e
+
+readonly APP_NAME_SHORT=casaos
+
+__get_setup_script_directory_by_os_release() {
+	pushd "$(dirname "${BASH_SOURCE[0]}")/../service.d/${APP_NAME_SHORT}" &>/dev/null
+
+	{
+		# shellcheck source=/dev/null
+		{
+			source /etc/os-release
+			{
+				pushd "${ID}"/"${VERSION_CODENAME}" &>/dev/null
+			} || {
+				pushd "${ID}" &>/dev/null
+			} || {
+				pushd "${ID_LIKE}" &>/dev/null
+			} || {
+				echo "Unsupported OS: ${ID} ${VERSION_CODENAME} (${ID_LIKE})"
+				exit 1
+			}
+
+			pwd
+
+			popd &>/dev/null
+
+		} || {
+			echo "Unsupported OS: unknown"
+			exit 1
+		}
+
+	}
+
+	popd &>/dev/null
+}
+
+SETUP_SCRIPT_DIRECTORY=$(__get_setup_script_directory_by_os_release)
+
+readonly SETUP_SCRIPT_DIRECTORY
+readonly SETUP_SCRIPT_FILENAME="cleanup-${APP_NAME_SHORT}.sh"
+readonly SETUP_SCRIPT_FILEPATH="${SETUP_SCRIPT_DIRECTORY}/${SETUP_SCRIPT_FILENAME}"
+
+echo "🟩 Running ${SETUP_SCRIPT_FILENAME}..."
+$SHELL "${SETUP_SCRIPT_FILEPATH}" "${BUILD_PATH}"

+ 1 - 0
build/sysroot/usr/share/casaos/cleanup/service.d/casaos/debian/bullseye/cleanup-casaos.sh

@@ -0,0 +1 @@
+../cleanup-casaos.sh

+ 204 - 0
build/sysroot/usr/share/casaos/cleanup/service.d/casaos/debian/cleanup-casaos.sh

@@ -0,0 +1,204 @@
+#!/bin/bash
+
+set -e
+
+readonly CASA_SERVICES=(
+    "casaos.service"
+    "devmon@devmon.service"
+)
+
+readonly CASA_EXEC=casaos
+readonly CASA_CONF=/etc/casaos/casaos.conf
+readonly CASA_URL=/var/run/casaos/casaos.url
+readonly CASA_SERVICE_USR=/usr/lib/systemd/system/casaos.service
+readonly CASA_SERVICE_LIB=/lib/systemd/system/casaos.service
+readonly CASA_SERVICE_ETC=/etc/systemd/system/casaos.service
+
+# Old Casa Files
+readonly CASA_PATH=/casaOS
+readonly CASA_CONF_PATH_OLD=/etc/casaos.conf
+
+readonly aCOLOUR=(
+    '\e[38;5;154m' # green  	| Lines, bullets and separators
+    '\e[1m'        # Bold white	| Main descriptions
+    '\e[90m'       # Grey		| Credits
+    '\e[91m'       # Red		| Update notifications Alert
+    '\e[33m'       # Yellow		| Emphasis
+)
+
+Show() {
+    # OK
+    if (($1 == 0)); then
+        echo -e "${aCOLOUR[2]}[$COLOUR_RESET${aCOLOUR[0]}  OK  $COLOUR_RESET${aCOLOUR[2]}]$COLOUR_RESET $2"
+    # FAILED
+    elif (($1 == 1)); then
+        echo -e "${aCOLOUR[2]}[$COLOUR_RESET${aCOLOUR[3]}FAILED$COLOUR_RESET${aCOLOUR[2]}]$COLOUR_RESET $2"
+    # INFO
+    elif (($1 == 2)); then
+        echo -e "${aCOLOUR[2]}[$COLOUR_RESET${aCOLOUR[0]} INFO $COLOUR_RESET${aCOLOUR[2]}]$COLOUR_RESET $2"
+    # NOTICE
+    elif (($1 == 3)); then
+        echo -e "${aCOLOUR[2]}[$COLOUR_RESET${aCOLOUR[4]}NOTICE$COLOUR_RESET${aCOLOUR[2]}]$COLOUR_RESET $2"
+    fi
+}
+
+Warn() {
+    echo -e "${aCOLOUR[3]}$1$COLOUR_RESET"
+}
+
+trap 'onCtrlC' INT
+onCtrlC() {
+    echo -e "${COLOUR_RESET}"
+    exit 1
+}
+
+Detecting_CasaOS() {
+    if [[ ! -x "$(command -v ${CASA_EXEC})" ]]; then
+        Show 2 "CasaOS is not detected, exit the script."
+        exit 1
+    else
+        Show 0 "This script will delete the containers you no longer use, and the CasaOS configuration files."
+    fi
+}
+
+Uninstall_Container() {
+    if [[ ${UNINSTALL_ALL_CONTAINER} == true && "$(docker ps -aq)" != "" ]]; then
+        Show 2 "Start deleting containers."
+        docker stop "$(docker ps -aq)" || Show 1 "Failed to stop all containers."
+        docker rm "$(docker ps -aq)" || Show 1 "Failed to delete all containers."
+    fi
+}
+
+Remove_Images() {
+    if [[ ${REMOVE_IMAGES} == "all" && "$(docker images -q)" != "" ]]; then
+        Show 2 "Start deleting all images."
+        docker rmi "$(docker images -q)" || Show 1 "Failed to delete all images."
+    elif [[ ${REMOVE_IMAGES} == "unuse" && "$(docker images -q)" != "" ]]; then
+        Show 2 "Start deleting unuse images."
+        docker image prune -af || Show 1 "Failed to delete unuse images."
+    fi
+}
+
+
+Uninstall_Casaos() {
+
+    for SERVICE in "${CASA_SERVICES[@]}"; do
+        Show 2 "Stopping ${SERVICE}..."
+        systemctl disable --now "${SERVICE}" || Show 3 "Failed to disable ${SERVICE}"
+    done
+
+    # Remove Service file
+    if [[ -f ${CASA_SERVICE_USR} ]]; then
+        rm -rvf ${CASA_SERVICE_USR}
+    fi
+
+    if [[ -f ${CASA_SERVICE_LIB} ]]; then
+        rm -rvf ${CASA_SERVICE_LIB}
+    fi
+
+    if [[ -f ${CASA_SERVICE_ETC} ]]; then
+        rm -rvf ${CASA_SERVICE_ETC}
+    fi
+
+    # Old Casa Files
+    if [[ -d ${CASA_PATH} ]]; then
+        rm -rvf ${CASA_PATH} || Show 1 "Failed to delete legacy CasaOS files."
+    fi
+
+    if [[ -f ${CASA_CONF_PATH_OLD} ]]; then
+        rm -rvf ${CASA_CONF_PATH_OLD}
+    fi
+
+    # New Casa Files
+    if [[ ${REMOVE_APP_DATA} = true ]]; then
+        rm -rvf /DATA/AppData || Show 1 "Failed to delete AppData."
+    fi
+
+    rm -rvf "$(which ${CASA_EXEC})" || Show 3 "Failed to remove ${CASA_EXEC}"
+    rm -rvf ${CASA_CONF} || Show 3 "Failed to remove ${CASA_CONF}"
+    rm -rvf ${CASA_URL} || Show 3 "Failed to remove ${CASA_URL}"
+
+    rm -rvf /var/lib/casaos/app_category.json
+    rm -rvf /var/lib/casaos/app_list.json
+    rm -rvf /var/lib/casaos/docker_root
+}
+
+Detecting_CasaOS
+
+while true; do
+    echo -n -e "         ${aCOLOUR[4]}Do you want delete all containers? Y/n :${COLOUR_RESET}"
+    read -r input
+    case $input in
+    [yY][eE][sS] | [yY])
+        UNINSTALL_ALL_CONTAINER=true
+        break
+        ;;
+    [nN][oO] | [nN])
+        UNINSTALL_ALL_CONTAINER=false
+        break
+        ;;
+    *)
+        Warn "         Invalid input..."
+        ;;
+    esac
+done
+
+if [[ ${UNINSTALL_ALL_CONTAINER} == true ]]; then
+    while true; do
+        echo -n -e "         ${aCOLOUR[4]}Do you want delete all images? Y/n :${COLOUR_RESET}"
+        read -r input
+        case $input in
+        [yY][eE][sS] | [yY])
+            REMOVE_IMAGES="all"
+            break
+            ;;
+        [nN][oO] | [nN])
+            REMOVE_IMAGES="none"
+            break
+            ;;
+        *)
+            Warn "         Invalid input..."
+            ;;
+        esac
+    done
+
+    while true; do
+        echo -n -e "         ${aCOLOUR[4]}Do you want delete all AppData of CasaOS? Y/n :${COLOUR_RESET}"
+        read -r input
+        case $input in
+        [yY][eE][sS] | [yY])
+            REMOVE_APP_DATA=true
+            break
+            ;;
+        [nN][oO] | [nN])
+            REMOVE_APP_DATA=false
+            break
+            ;;
+        *)
+            Warn "         Invalid input..."
+            ;;
+        esac
+    done
+else
+    while true; do
+        echo -n -e "         ${aCOLOUR[4]}Do you want to delete all images that are not used by the container? Y/n :${COLOUR_RESET}"
+        read -r input
+        case $input in
+        [yY][eE][sS] | [yY])
+            REMOVE_IMAGES="unuse"
+            break
+            ;;
+        [nN][oO] | [nN])
+            REMOVE_IMAGES="none"
+            break
+            ;;
+        *)
+            Warn "         Invalid input..."
+            ;;
+        esac
+    done
+fi
+
+Uninstall_Container
+Remove_Images
+Uninstall_Casaos

+ 1 - 0
build/sysroot/usr/share/casaos/cleanup/service.d/casaos/ubuntu/cleanup-casaos.sh

@@ -0,0 +1 @@
+../debian/cleanup-casaos.sh

+ 1 - 0
build/sysroot/usr/share/casaos/cleanup/service.d/casaos/ubuntu/jammy/cleanup-casaos.sh

@@ -0,0 +1 @@
+../../debian/bullseye/cleanup-casaos.sh

+ 1 - 1
build/sysroot/usr/share/casaos/shell/update.sh

@@ -9,4 +9,4 @@
 ### 
 
 
-curl -fsSL https://raw.githubusercontent.com/IceWhaleTech/get/main/update.sh | bash
+curl -fsSL https://raw.githubusercontent.com/IceWhaleTech/get/main/update.sh | bash

+ 0 - 10
cmd/migration-tool/log.go

@@ -1,13 +1,3 @@
-/*
- * @Author: LinkLeong link@icewhale.org
- * @Date: 2022-08-30 22:15:30
- * @LastEditors: LinkLeong
- * @LastEditTime: 2022-08-30 22:15:47
- * @FilePath: /CasaOS/cmd/migration-tool/log.go
- * @Description:
- * @Website: https://www.casaos.io
- * Copyright (c) 2022 by icewhale, All Rights Reserved.
- */
 package main
 
 import (

+ 14 - 11
cmd/migration-tool/main.go

@@ -28,25 +28,29 @@ const (
 	casaosServiceName = "casaos.service"
 )
 
-var _logger *Logger
-var sqliteDB *gorm.DB
+var (
+	_logger  *Logger
+	sqliteDB *gorm.DB
+)
 
-var configFlag = ""
-var dbFlag = ""
+var (
+	configFlag = ""
+	dbFlag     = ""
+)
 
 func init() {
 	config.InitSetup(configFlag)
-	config.UpdateSetup()
 
 	if len(dbFlag) == 0 {
 		dbFlag = config.AppInfo.DBPath + "/db"
 	}
 
 	sqliteDB = sqlite.GetDb(dbFlag)
-	//gredis.GetRedisConn(config.RedisInfo),
+	// gredis.GetRedisConn(config.RedisInfo),
 
 	service.MyService = service.NewService(sqliteDB, "")
 }
+
 func main() {
 	versionFlag := flag.Bool("v", false, "version")
 	debugFlag := flag.Bool("d", true, "debug")
@@ -79,7 +83,7 @@ func main() {
 	}
 
 	migrationTools := []interfaces.MigrationTool{
-		NewMigrationToolFor_035(),
+		// nothing to migrate from last version
 	}
 
 	var selectedMigrationTool interfaces.MigrationTool
@@ -110,8 +114,7 @@ func main() {
 		panic(err)
 	}
 
-	selectedMigrationTool.PostMigrate()
-	_logger.Info("casaos migration ok")
-	//panic(err)
-
+	if err := selectedMigrationTool.PostMigrate(); err != nil {
+		_logger.Error("Migration succeeded, but post-migration failed: %s", err)
+	}
 }

+ 0 - 182
cmd/migration-tool/migration-034-035.go

@@ -1,182 +0,0 @@
-/*
- * @Author: LinkLeong link@icewhale.org
- * @Date: 2022-08-24 17:36:00
- * @LastEditors: LinkLeong
- * @LastEditTime: 2022-09-05 11:24:27
- * @FilePath: /CasaOS/cmd/migration-tool/migration-034-035.go
- * @Description:
- * @Website: https://www.casaos.io
- * Copyright (c) 2022 by icewhale, All Rights Reserved.
- */
-package main
-
-import (
-	"io"
-	"io/ioutil"
-	"os"
-	"path"
-	"strings"
-
-	interfaces "github.com/IceWhaleTech/CasaOS-Common"
-	"github.com/IceWhaleTech/CasaOS-Common/utils/version"
-	"github.com/IceWhaleTech/CasaOS/pkg/config"
-	"github.com/IceWhaleTech/CasaOS/pkg/utils/command"
-	"github.com/IceWhaleTech/CasaOS/pkg/utils/file"
-	"github.com/IceWhaleTech/CasaOS/service"
-)
-
-type migrationTool struct{}
-
-func (u *migrationTool) IsMigrationNeeded() (bool, error) {
-
-	majorVersion, minorVersion, patchVersion, err := version.DetectLegacyVersion()
-	if err != nil {
-		if err == version.ErrLegacyVersionNotFound {
-			return false, nil
-		}
-
-		return false, err
-	}
-
-	if majorVersion > 0 {
-		return false, nil
-	}
-
-	if minorVersion > 3 {
-		return false, nil
-	}
-
-	if minorVersion == 3 && patchVersion > 5 {
-		return false, nil
-	}
-
-	_logger.Info("Migration is needed for a CasaOS version 0.3.5 and older...")
-	return true, nil
-
-}
-
-func (u *migrationTool) PreMigrate() error {
-
-	return nil
-}
-
-func (u *migrationTool) Migrate() error {
-
-	if service.MyService.System().GetSysInfo().KernelArch == "aarch64" && config.ServerInfo.USBAutoMount != "True" && strings.Contains(service.MyService.System().GetDeviceTree(), "Raspberry Pi") {
-		service.MyService.System().UpdateUSBAutoMount("False")
-		service.MyService.System().ExecUSBAutoMountShell("False")
-	}
-	newAPIUrl := "https://api.casaos.io/casaos-api"
-	if config.ServerInfo.ServerApi == "https://api.casaos.zimaboard.com" {
-		config.ServerInfo.ServerApi = newAPIUrl
-		config.Cfg.Section("server").Key("ServerApi").SetValue(newAPIUrl)
-		config.Cfg.SaveTo(config.SystemConfigInfo.ConfigPath)
-	}
-	command.OnlyExec("curl -fsSL https://raw.githubusercontent.com/IceWhaleTech/get/main/assist.sh | bash")
-	if !file.CheckNotExist("/casaOS") {
-		command.OnlyExec("source /casaOS/server/shell/update.sh ;")
-		command.OnlyExec("source " + config.AppInfo.ShellPath + "/delete-old-service.sh ;")
-	}
-
-	service.MyService.App().ImportApplications(true)
-
-	src := "/casaOS/server/conf/conf.ini"
-	if file.Exists(src) {
-		dst := "/etc/casaos/casaos.conf"
-		source, err := os.Open(src)
-		if err != nil {
-			return err
-		}
-		defer source.Close()
-
-		destination, err := os.Create(dst)
-		if err != nil {
-			return err
-		}
-		defer destination.Close()
-		_, err = io.Copy(destination, source)
-		if err != nil {
-			return err
-		}
-
-	}
-
-	if file.Exists("/casaOS/server/db") {
-		var fds []os.FileInfo
-		var err error
-		to := "/var/lib/casaos/db"
-		file.IsNotExistMkDir(to)
-		from := "/casaOS/server/db"
-		if fds, err = ioutil.ReadDir(from); err != nil {
-			return err
-		}
-
-		for _, fd := range fds {
-			srcfp := path.Join(from, fd.Name())
-			dstfp := path.Join(to, fd.Name())
-			source, err := os.Open(srcfp)
-			if err != nil {
-				return err
-			}
-			defer source.Close()
-
-			destination, err := os.Create(dstfp)
-			if err != nil {
-				return err
-			}
-			defer destination.Close()
-			_, err = io.Copy(destination, source)
-			if err != nil {
-				return err
-			}
-		}
-
-	}
-
-	if file.Exists("/casaOS/server/conf") {
-		var fds []os.FileInfo
-		var err error
-		to := "/var/lib/casaos/conf"
-		file.IsNotExistMkDir(to)
-		from := "/casaOS/server/conf"
-		if fds, err = ioutil.ReadDir(from); err != nil {
-			return err
-		}
-
-		for _, fd := range fds {
-			fExt := path.Ext(fd.Name())
-			if fExt != ".json" {
-				continue
-			}
-			srcfp := path.Join(from, fd.Name())
-			dstfp := path.Join(to, fd.Name())
-			source, err := os.Open(srcfp)
-			if err != nil {
-				return err
-			}
-			defer source.Close()
-
-			destination, err := os.Create(dstfp)
-			if err != nil {
-				return err
-			}
-			defer destination.Close()
-			_, err = io.Copy(destination, source)
-			if err != nil {
-				return err
-			}
-		}
-
-	}
-
-	_logger.Info("update done")
-	return nil
-}
-
-func (u *migrationTool) PostMigrate() error {
-	return nil
-}
-
-func NewMigrationToolFor_035() interfaces.MigrationTool {
-	return &migrationTool{}
-}

+ 60 - 0
cmd/migration-tool/migration-sample.go

@@ -0,0 +1,60 @@
+/*
+ * @Author: LinkLeong link@icewhale.org
+ * @Date: 2022-08-24 17:36:00
+ * @LastEditors: LinkLeong
+ * @LastEditTime: 2022-09-05 11:24:27
+ * @FilePath: /CasaOS/cmd/migration-tool/migration-034-035.go
+ * @Description:
+ * @Website: https://www.casaos.io
+ * Copyright (c) 2022 by icewhale, All Rights Reserved.
+ */
+package main
+
+import (
+	interfaces "github.com/IceWhaleTech/CasaOS-Common"
+	"github.com/IceWhaleTech/CasaOS-Common/utils/version"
+)
+
+type migrationTool struct{}
+
+func (u *migrationTool) IsMigrationNeeded() (bool, error) {
+	majorVersion, minorVersion, patchVersion, err := version.DetectLegacyVersion()
+	if err != nil {
+		if err == version.ErrLegacyVersionNotFound {
+			return false, nil
+		}
+
+		return false, err
+	}
+
+	if majorVersion > 0 {
+		return false, nil
+	}
+
+	if minorVersion > 3 {
+		return false, nil
+	}
+
+	if minorVersion == 3 && patchVersion > 5 {
+		return false, nil
+	}
+
+	_logger.Info("Migration is needed for a CasaOS version 0.3.5 and older...")
+	return true, nil
+}
+
+func (u *migrationTool) PreMigrate() error {
+	return nil
+}
+
+func (u *migrationTool) Migrate() error {
+	return nil
+}
+
+func (u *migrationTool) PostMigrate() error {
+	return nil
+}
+
+func NewMigrationToolFor_036() interfaces.MigrationTool {
+	return &migrationTool{}
+}

+ 89 - 0
common/notify.go

@@ -0,0 +1,89 @@
+package common
+
+import (
+	"bytes"
+	"encoding/json"
+	"errors"
+	"fmt"
+	"net/http"
+	"os"
+	"path/filepath"
+	"strings"
+)
+
+const (
+	CasaOSURLFilename = "casaos.url"
+	APICasaOSNotify   = "/v1/notify"
+)
+
+type NotifyService interface {
+	SendNotify(path string, message map[string]interface{}) error
+	SendSystemStatusNotify(message map[string]interface{}) error
+}
+type notifyService struct {
+	address string
+}
+
+func (n *notifyService) SendNotify(path string, message map[string]interface{}) error {
+
+	url := strings.TrimSuffix(n.address, "/") + APICasaOSNotify + "/" + path
+	body, err := json.Marshal(message)
+	if err != nil {
+		return err
+	}
+	response, err := http.Post(url, "application/json", bytes.NewBuffer(body))
+	if err != nil {
+		return err
+	}
+
+	if response.StatusCode != http.StatusOK {
+		return errors.New("failed to send notify (status code: " + fmt.Sprint(response.StatusCode) + ")")
+	}
+	return nil
+
+}
+
+// disk: "sys_disk":{"size":56866869248,"avail":5855485952,"health":true,"used":48099700736}
+// usb:   "sys_usb":[{"name": "sdc","size": 7747397632,"model": "DataTraveler_2.0","avail": 7714418688,"children": null}]
+func (n *notifyService) SendSystemStatusNotify(message map[string]interface{}) error {
+
+	url := strings.TrimSuffix(n.address, "/") + APICasaOSNotify + "/system_status"
+	fmt.Println(url)
+	body, err := json.Marshal(message)
+	if err != nil {
+		return err
+	}
+	response, err := http.Post(url, "application/json", bytes.NewBuffer(body))
+	if err != nil {
+		return err
+	}
+
+	if response.StatusCode != http.StatusOK {
+		return errors.New("failed to send notify (status code: " + fmt.Sprint(response.StatusCode) + ")")
+	}
+	return nil
+
+}
+func NewNotifyService(runtimePath string) (NotifyService, error) {
+	casaosAddressFile := filepath.Join(runtimePath, CasaOSURLFilename)
+
+	buf, err := os.ReadFile(casaosAddressFile)
+	if err != nil {
+		return nil, err
+	}
+
+	address := string(buf)
+
+	response, err := http.Get(address + "/ping")
+	if err != nil {
+		return nil, err
+	}
+
+	if response.StatusCode != 200 {
+		return nil, errors.New("failed to ping casaos service")
+	}
+
+	return &notifyService{
+		address: address,
+	}, nil
+}

+ 29 - 0
common/notify_test.go

@@ -0,0 +1,29 @@
+package common
+
+import "testing"
+
+func TestSendNotify(t *testing.T) {
+	notify, err := NewNotifyService("/var/run/casaos")
+	if err != nil {
+		t.Fatal(err)
+	}
+	err = notify.SendNotify("test", map[string]interface{}{
+		"test": "test",
+	})
+	if err != nil {
+		t.Fatal(err)
+	}
+}
+
+func TestSendSystemStatusNotify(t *testing.T) {
+	notify, err := NewNotifyService("/var/run/casaos")
+	if err != nil {
+		t.Fatal(err)
+	}
+	err = notify.SendSystemStatusNotify(map[string]interface{}{
+		"sys_usb": `[{"name": "sdc","size": 7747397632,"model": "DataTraveler_2.0","avail": 7714418688,"children": null}]`,
+	})
+	if err != nil {
+		t.Fatal(err)
+	}
+}

+ 78 - 0
common/share.go

@@ -0,0 +1,78 @@
+package common
+
+import (
+	"bytes"
+	"encoding/json"
+	"errors"
+	"fmt"
+	"net/http"
+	"os"
+	"path/filepath"
+	"strings"
+)
+
+const (
+	APICasaOSShare = "/v1/samba/shares"
+)
+
+type ShareService interface {
+	DeleteShare(id string) error
+}
+type shareService struct {
+	address string
+}
+
+func (n *shareService) DeleteShare(id string) error {
+	url := strings.TrimSuffix(n.address, "/") + APICasaOSShare + "/" + id
+	fmt.Println(url)
+	message := "{}"
+	body, err := json.Marshal(message)
+	if err != nil {
+		return err
+	}
+
+	client := &http.Client{}
+
+	// Create request
+	req, err := http.NewRequest("DELETE", url, bytes.NewBuffer(body))
+	if err != nil {
+		return err
+	}
+
+	// Fetch Request
+	response, err := client.Do(req)
+	if err != nil {
+		return err
+	}
+	defer response.Body.Close()
+
+	if response.StatusCode != http.StatusOK {
+		return errors.New("failed to send share (status code: " + fmt.Sprint(response.StatusCode) + ")")
+	}
+	return nil
+
+}
+
+func NewShareService(runtimePath string) (ShareService, error) {
+	casaosAddressFile := filepath.Join(runtimePath, CasaOSURLFilename)
+
+	buf, err := os.ReadFile(casaosAddressFile)
+	if err != nil {
+		return nil, err
+	}
+
+	address := string(buf)
+
+	response, err := http.Get(address + "/ping")
+	if err != nil {
+		return nil, err
+	}
+
+	if response.StatusCode != 200 {
+		return nil, errors.New("failed to ping casaos service")
+	}
+
+	return &shareService{
+		address: address,
+	}, nil
+}

+ 14 - 0
common/share_test.go

@@ -0,0 +1,14 @@
+package common
+
+import "testing"
+
+func TestDeleteShare(t *testing.T) {
+	share, err := NewShareService("/var/run/casaos")
+	if err != nil {
+		t.Fatal(err)
+	}
+	err = share.DeleteShare("1")
+	if err != nil {
+		t.Fatal(err)
+	}
+}

+ 0 - 1
conf/conf.conf.sample

@@ -11,7 +11,6 @@ DateFormat = 2006-01-02
 DBPath     = /var/lib/casaos
 ShellPath  = /usr/share/casaos/shell
 UserDataPath = /var/lib/casaos/conf
-TempPath    = /var/lib/casaos/temp
 
 [server]
 RunMode = release

+ 2 - 2
go.mod

@@ -4,13 +4,14 @@ go 1.16
 
 require (
 	github.com/Curtis-Milo/nat-type-identifier-go v0.0.0-20220215191915-18d42168c63d
-	github.com/IceWhaleTech/CasaOS-Common v0.0.0-20220909125858-92fc5b2e0ae5
+	github.com/IceWhaleTech/CasaOS-Common v0.0.0-20220929035515-b1287110d6d8
 	github.com/IceWhaleTech/CasaOS-Gateway v0.3.6
 	github.com/Microsoft/go-winio v0.5.0 // indirect
 	github.com/ambelovsky/go-structs v1.1.0 // indirect
 	github.com/ambelovsky/gosf v0.0.0-20201109201340-237aea4d6109
 	github.com/ambelovsky/gosf-socketio v0.0.0-20201109193639-add9d32f8b19 // indirect
 	github.com/containerd/containerd v1.5.7 // indirect
+	github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e
 	github.com/disintegration/imaging v1.6.2
 	github.com/docker/distribution v2.8.0+incompatible // indirect
 	github.com/docker/docker v20.10.7+incompatible
@@ -34,7 +35,6 @@ require (
 	github.com/morikuni/aec v1.0.0 // indirect
 	github.com/opencontainers/image-spec v1.0.2 // indirect
 	github.com/patrickmn/go-cache v2.1.0+incompatible
-	github.com/pilebones/go-udev v0.9.0
 	github.com/pkg/errors v0.9.1
 	github.com/robfig/cron v1.2.0
 	github.com/satori/go.uuid v1.2.0

+ 2 - 4
go.sum

@@ -84,8 +84,8 @@ github.com/Curtis-Milo/nat-type-identifier-go v0.0.0-20220215191915-18d42168c63d
 github.com/Curtis-Milo/nat-type-identifier-go v0.0.0-20220215191915-18d42168c63d/go.mod h1:lW9x+yEjqKdPbE3+cf2fGPJXCw/hChX3Omi9QHTLFsQ=
 github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ=
 github.com/IceWhaleTech/CasaOS-Common v0.0.0-20220901034123-ca130f6b5ce9/go.mod h1:2MiivEMzvh41codhEKUcn46WK3Ffesop/04qa9jsvQk=
-github.com/IceWhaleTech/CasaOS-Common v0.0.0-20220909125858-92fc5b2e0ae5 h1:vgAf0jVKCBo3wyjOZ4z9tB77lVrgIfz2CcQX2+4JTSI=
-github.com/IceWhaleTech/CasaOS-Common v0.0.0-20220909125858-92fc5b2e0ae5/go.mod h1:2MiivEMzvh41codhEKUcn46WK3Ffesop/04qa9jsvQk=
+github.com/IceWhaleTech/CasaOS-Common v0.0.0-20220929035515-b1287110d6d8 h1:r8nhgQ6tnrn6ikXN9aLH/K4H4H64Nc0hZ6jyW2B22x0=
+github.com/IceWhaleTech/CasaOS-Common v0.0.0-20220929035515-b1287110d6d8/go.mod h1:2MiivEMzvh41codhEKUcn46WK3Ffesop/04qa9jsvQk=
 github.com/IceWhaleTech/CasaOS-Gateway v0.3.6 h1:2tQQo85+jzbbjqIsKKn77QlAA73bc7vZsVCFvWnK4mg=
 github.com/IceWhaleTech/CasaOS-Gateway v0.3.6/go.mod h1:hnZwGUzcOyiufMpVO7l3gu2gAm6Ws4TY4Nlj3kMshXA=
 github.com/Microsoft/go-winio v0.4.11/go.mod h1:VhR8bwka0BXejwEJY73c50VrPtXAaKcyvVC4A4RozmA=
@@ -814,8 +814,6 @@ github.com/pelletier/go-toml/v2 v2.0.1/go.mod h1:r9LEWfGN8R5k0VXJ+0BkIe7MYkRdwZO
 github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU=
 github.com/pierrec/lz4/v4 v4.1.2 h1:qvY3YFXRQE/XB8MlLzJH7mSzBs74eA2gg52YTk6jUPM=
 github.com/pierrec/lz4/v4 v4.1.2/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
-github.com/pilebones/go-udev v0.9.0 h1:N1uEO/SxUwtIctc0WLU0t69JeBxIYEYnj8lT/Nabl9Q=
-github.com/pilebones/go-udev v0.9.0/go.mod h1:T2eI2tUSK0hA2WS5QLjXJUfQkluZQu+18Cqvem3CaXI=
 github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
 github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
 github.com/pkg/errors v0.8.1-0.20171018195549-f15c970de5b7/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=

+ 43 - 26
main.go

@@ -5,6 +5,7 @@ import (
 	"fmt"
 	"net"
 	"net/http"
+	"path/filepath"
 	"time"
 
 	"github.com/IceWhaleTech/CasaOS-Gateway/common"
@@ -12,10 +13,13 @@ import (
 	"github.com/IceWhaleTech/CasaOS/pkg/cache"
 	"github.com/IceWhaleTech/CasaOS/pkg/config"
 	"github.com/IceWhaleTech/CasaOS/pkg/sqlite"
+	"github.com/IceWhaleTech/CasaOS/pkg/utils/file"
 	"github.com/IceWhaleTech/CasaOS/pkg/utils/loger"
 	"github.com/IceWhaleTech/CasaOS/route"
 	"github.com/IceWhaleTech/CasaOS/service"
 	"github.com/IceWhaleTech/CasaOS/types"
+	"github.com/coreos/go-systemd/daemon"
+	"go.uber.org/zap"
 
 	"github.com/robfig/cron"
 	"gorm.io/gorm"
@@ -25,9 +29,11 @@ const LOCALHOST = "127.0.0.1"
 
 var sqliteDB *gorm.DB
 
-var configFlag = flag.String("c", "", "config address")
-var dbFlag = flag.String("db", "", "db path")
-var versionFlag = flag.Bool("v", false, "version")
+var (
+	configFlag  = flag.String("c", "", "config address")
+	dbFlag      = flag.String("db", "", "db path")
+	versionFlag = flag.Bool("v", false, "version")
+)
 
 func init() {
 	flag.Parse()
@@ -36,7 +42,6 @@ func init() {
 		return
 	}
 	config.InitSetup(*configFlag)
-	config.UpdateSetup()
 
 	loger.LogInit()
 	if len(*dbFlag) == 0 {
@@ -44,7 +49,7 @@ func init() {
 	}
 
 	sqliteDB = sqlite.GetDb(*dbFlag)
-	//gredis.GetRedisConn(config.RedisInfo),
+	// gredis.GetRedisConn(config.RedisInfo),
 
 	service.MyService = service.NewService(sqliteDB, config.CommonInfo.RuntimePath)
 
@@ -57,7 +62,6 @@ func init() {
 
 	// go service.LoopFriend()
 	// go service.MyService.App().CheckNewImage()
-
 }
 
 // @title casaOS API
@@ -77,22 +81,21 @@ func main() {
 		return
 	}
 	go route.SocketInit(service.NotifyMsg)
-	go route.MonitoryUSB()
-	//model.Setup()
-	//gredis.Setup()
+	// model.Setup()
+	// gredis.Setup()
 
 	r := route.InitRouter()
-	//service.SyncTask(sqliteDB)
+	// service.SyncTask(sqliteDB)
 	cron2 := cron.New()
-	//every day execution
+	// every day execution
 
 	err := cron2.AddFunc("0/5 * * * * *", func() {
 		if service.ClientCount > 0 {
-			//route.SendNetINfoBySocket()
-			//route.SendCPUBySocket()
-			//route.SendMemBySocket()
+			// route.SendNetINfoBySocket()
+			// route.SendCPUBySocket()
+			// route.SendMemBySocket()
 			// route.SendDiskBySocket()
-			//route.SendUSBBySocket()
+			// route.SendUSBBySocket()
 			route.SendAllHardwareStatusBySocket()
 		}
 	})
@@ -107,7 +110,7 @@ func main() {
 	if err != nil {
 		panic(err)
 	}
-	routers := []string{"sys", "apps", "container", "app-categories", "port", "file", "folder", "batch", "image", "disks", "storage", "samba"}
+	routers := []string{"sys", "apps", "container", "app-categories", "port", "file", "folder", "batch", "image", "samba", "notify"}
 	for _, v := range routers {
 		err = service.MyService.Gateway().CreateRoute(&common.Route{
 			Path:   "/v1/" + v,
@@ -121,7 +124,7 @@ func main() {
 	}
 	go func() {
 		time.Sleep(time.Second * 2)
-		//v0.3.6
+		// v0.3.6
 		if config.ServerInfo.HttpPort != "" {
 			changePort := common.ChangePortRequest{}
 			changePort.Port = config.ServerInfo.HttpPort
@@ -133,15 +136,29 @@ func main() {
 		}
 	}()
 
-	// s := &http.Server{
-	// 	Addr:           listener.Addr().String(), //fmt.Sprintf(":%v", config.ServerInfo.HttpPort),
-	// 	Handler:        r,
-	// 	ReadTimeout:    60 * time.Second,
-	// 	WriteTimeout:   60 * time.Second,
-	// 	MaxHeaderBytes: 1 << 20,
-	// }
-	// s.ListenAndServe()
-	err = http.Serve(listener, r)
+	urlFilePath := filepath.Join(config.CommonInfo.RuntimePath, "casaos.url")
+	err = file.CreateFileAndWriteContent(urlFilePath, "http://"+listener.Addr().String())
+	if err != nil {
+		loger.Error("Management service is listening...",
+			zap.Any("address", listener.Addr().String()),
+			zap.Any("filepath", urlFilePath),
+		)
+	}
+
+	if supported, err := daemon.SdNotify(false, daemon.SdNotifyReady); err != nil {
+		loger.Error("Failed to notify systemd that casaos main service is ready", zap.Any("error", err))
+	} else if supported {
+		loger.Info("Notified systemd that casaos main service is ready")
+	} else {
+		loger.Info("This process is not running as a systemd service.")
+	}
+
+	s := &http.Server{
+		Handler:           r,
+		ReadHeaderTimeout: 5 * time.Second, // fix G112: Potential slowloris attack (see https://github.com/securego/gosec)
+	}
+
+	err = s.Serve(listener) // not using http.serve() to fix G114: Use of net/http serve function that has no support for setting timeouts (see https://github.com/securego/gosec)
 	if err != nil {
 		panic(err)
 	}

+ 0 - 62
middleware/gin.go

@@ -1,62 +0,0 @@
-/*
- * @Author: LinkLeong link@icewhale.com
- * @Date: 2021-10-08 10:29:08
- * @LastEditors: LinkLeong
- * @LastEditTime: 2022-07-22 11:06:07
- * @FilePath: /CasaOS/middleware/gin.go
- * @Description:
- * @Website: https://www.casaos.io
- * Copyright (c) 2022 by icewhale, All Rights Reserved.
- */
-package middleware
-
-import (
-	"fmt"
-	"net/http"
-	"strings"
-
-	"github.com/IceWhaleTech/CasaOS/pkg/utils/loger"
-	"github.com/gin-gonic/gin"
-	"go.uber.org/zap"
-)
-
-func Cors() gin.HandlerFunc {
-	return func(c *gin.Context) {
-		method := c.Request.Method
-
-		c.Header("Access-Control-Allow-Origin", "*")
-		c.Header("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE,UPDATE")
-		//允许跨域设置可以返回其他子段,可以自定义字段
-		c.Header("Access-Control-Allow-Headers", "Authorization, Content-Length, X-CSRF-Token, Token,session,Language,Content-Type,Access-Control-Allow-Origin,Access-Control-Allow-Headers,Access-Control-Allow-Methods,Connection,Host,Origin,Referer,User-Agent,X-Requested-With")
-		// 允许浏览器(客户端)可以解析的头部 (重要)
-		c.Header("Access-Control-Expose-Headers", "Content-Length, Access-Control-Allow-Origin, Access-Control-Allow-Headers")
-		//c.Writer.Header().Set("Access-Control-Allow-Headers", "Accept, Authorization, Content-Type, Content-Length, X-CSRF-Token, Token, session, Origin, Host, Connection, Accept-Encoding, Accept-Language, X-Requested-With")
-		//设置缓存时间
-		c.Header("Access-Control-Max-Age", "172800")
-		c.Header("Access-Control-Allow-Credentials", "true")
-		c.Set("Content-Type", "application/json")
-		//}
-
-		//允许类型校验
-		if method == "OPTIONS" {
-			c.JSON(http.StatusOK, "ok!")
-		}
-
-		defer func() {
-			if err := recover(); err != nil {
-				fmt.Println(err)
-			}
-		}()
-
-		c.Next()
-	}
-}
-func WriteLog() gin.HandlerFunc {
-	return func(c *gin.Context) {
-		if !strings.Contains(c.Request.URL.String(), "password") {
-			loger.Info("request:", zap.Any("path", c.Request.URL.String()), zap.Any("param", c.Params), zap.Any("query", c.Request.URL.Query()), zap.Any("method", c.Request.Method))
-			c.Next()
-		}
-
-	}
-}

+ 0 - 98
model/disk.go

@@ -1,98 +0,0 @@
-/*
- * @Author: LinkLeong link@icewhale.com
- * @Date: 2022-07-13 10:43:45
- * @LastEditors: LinkLeong
- * @LastEditTime: 2022-08-03 14:45:35
- * @FilePath: /CasaOS/model/disk.go
- * @Description:
- * @Website: https://www.casaos.io
- * Copyright (c) 2022 by icewhale, All Rights Reserved.
- */
-package model
-
-type LSBLKModel struct {
-	Name        string       `json:"name"`
-	FsType      string       `json:"fstype"`
-	Size        uint64       `json:"size"`
-	FSSize      string       `json:"fssize"`
-	Path        string       `json:"path"`
-	Model       string       `json:"model"` //设备标识符
-	RM          bool         `json:"rm"`    //是否为可移动设备
-	RO          bool         `json:"ro"`    //是否为只读设备
-	State       string       `json:"state"`
-	PhySec      int          `json:"phy-sec"` //物理扇区大小
-	Type        string       `json:"type"`
-	Vendor      string       `json:"vendor"`  //供应商
-	Rev         string       `json:"rev"`     //修订版本
-	FSAvail     string       `json:"fsavail"` //可用空间
-	FSUse       string       `json:"fsuse%"`  //已用百分比
-	MountPoint  string       `json:"mountpoint"`
-	Format      string       `json:"format"`
-	Health      string       `json:"health"`
-	HotPlug     bool         `json:"hotplug"`
-	UUID        string       `json:"uuid"`
-	FSUsed      string       `json:"fsused"`
-	Temperature int          `json:"temperature"`
-	Tran        string       `json:"tran"`
-	MinIO       uint64       `json:"min-io"`
-	UsedPercent float64      `json:"used_percent"`
-	Serial      string       `json:"serial"`
-	Children    []LSBLKModel `json:"children"`
-	SubSystems  string       `json:"subsystems"`
-	Label       string       `json:"label"`
-	//详情特有
-	StartSector uint64 `json:"start_sector,omitempty"`
-	Rota        bool   `json:"rota"` //true(hhd) false(ssd)
-	DiskType    string `json:"disk_type"`
-	EndSector   uint64 `json:"end_sector,omitempty"`
-}
-
-type Drive struct {
-	Name           string `json:"name"`
-	Size           uint64 `json:"size"`
-	Model          string `json:"model"`
-	Health         string `json:"health"`
-	Temperature    int    `json:"temperature"`
-	DiskType       string `json:"disk_type"`
-	NeedFormat     bool   `json:"need_format"`
-	Serial         string `json:"serial"`
-	Path           string `json:"path"`
-	ChildrenNumber int    `json:"children_number"`
-}
-
-type DriveUSB struct {
-	Name     string        `json:"name"`
-	Size     uint64        `json:"size"`
-	Model    string        `json:"model"`
-	Avail    uint64        `json:"avail"`
-	Children []USBChildren `json:"children"`
-}
-type USBChildren struct {
-	Name       string `json:"name"`
-	Size       uint64 `json:"size"`
-	Avail      uint64 `json:"avail"`
-	MountPoint string `json:"mount_point"`
-}
-
-type Storage struct {
-	MountPoint string `json:"mount_point"`
-	Size       string `json:"size"`
-	Avail      string `json:"avail"` //可用空间
-	Type       string `json:"type"`
-	Path       string `json:"path"`
-	DriveName  string `json:"drive_name"`
-	Label      string `json:"label"`
-}
-type Storages struct {
-	DiskName string    `json:"disk_name"`
-	Size     uint64    `json:"size"`
-	Path     string    `json:"path"`
-	Children []Storage `json:"children"`
-}
-
-type Summary struct {
-	Size   uint64 `json:"size"`
-	Avail  uint64 `json:"avail"` //可用空间
-	Health bool   `json:"health"`
-	Used   uint64 `json:"used"`
-}

+ 6 - 0
model/docker.go

@@ -16,3 +16,9 @@ type DockerStatsModel struct {
 	Data     interface{} `json:"data"`
 	Previous interface{} `json:"previous"`
 }
+
+// reference - https://docs.docker.com/engine/reference/commandline/dockerd/#daemon-configuration-file
+type DockerDaemonConfigurationModel struct {
+	// e.g. `/var/lib/docker`
+	Root string `json:"data-root,omitempty"`
+}

+ 0 - 1
model/receive/app.go

@@ -1 +0,0 @@
-package receive

+ 6 - 6
model/sys_common.go

@@ -12,12 +12,12 @@ package model
 
 import "time"
 
-//系统配置
+// 系统配置
 type SysInfoModel struct {
 	Name string //系统名称
 }
 
-//服务配置
+// 服务配置
 type ServerModel struct {
 	HttpPort     string
 	RunMode      string
@@ -26,9 +26,10 @@ type ServerModel struct {
 	Token        string
 	USBAutoMount string
 	SocketPort   string
+	UpdateUrl    string
 }
 
-//服务配置
+// 服务配置
 type APPModel struct {
 	LogPath        string
 	LogSaveName    string
@@ -40,20 +41,19 @@ type APPModel struct {
 	DateFormat     string
 	DBPath         string
 	ShellPath      string
-	TempPath       string
 }
 type CommonModel struct {
 	RuntimePath string
 }
 
-//公共返回模型
+// 公共返回模型
 type Result struct {
 	Success int         `json:"success" example:"200"`
 	Message string      `json:"message" example:"ok"`
 	Data    interface{} `json:"data" example:"返回结果"`
 }
 
-//redis配置文件
+// redis配置文件
 type RedisModel struct {
 	Host        string
 	Password    string

+ 5 - 8
pkg/config/init.go

@@ -23,17 +23,17 @@ import (
 	"github.com/go-ini/ini"
 )
 
-//系统配置
+// 系统配置
 var SysInfo = &model.SysInfoModel{}
 
-//用户相关
+// 用户相关
 var AppInfo = &model.APPModel{}
 
 var CommonInfo = &model.CommonModel{}
 
 //var RedisInfo = &model.RedisModel{}
 
-//server相关
+// server相关
 var ServerInfo = &model.ServerModel{}
 
 var SystemConfigInfo = &model.SystemConfig{}
@@ -44,7 +44,7 @@ var FileSettingInfo = &model.FileSetting{}
 
 var Cfg *ini.File
 
-//初始化设置,获取系统的部分信息。
+// 初始化设置,获取系统的部分信息。
 func InitSetup(config string) {
 
 	var configDir = USERCONFIGURL
@@ -86,9 +86,6 @@ func InitSetup(config string) {
 	if len(AppInfo.UserDataPath) == 0 {
 		AppInfo.UserDataPath = "/var/lib/casaos/conf"
 	}
-	if len(AppInfo.TempPath) == 0 {
-		AppInfo.TempPath = "/var/lib/casaos/temp"
-	}
 	if len(CommonInfo.RuntimePath) == 0 {
 		CommonInfo.RuntimePath = "/var/run/casaos"
 	}
@@ -97,7 +94,7 @@ func InitSetup(config string) {
 
 }
 
-//映射
+// 映射
 func mapTo(section string, v interface{}) {
 	err := Cfg.Section(section).MapTo(v)
 	if err != nil {

+ 0 - 32
pkg/config/update.go

@@ -1,32 +0,0 @@
-package config
-
-import (
-	"runtime"
-
-	"github.com/IceWhaleTech/CasaOS/pkg/utils/file"
-)
-
-//检查目录是否存在
-func mkdirDATAAll() {
-	sysType := runtime.GOOS
-	var dirArray []string
-	if sysType == "linux" {
-		dirArray = []string{"/DATA/AppData", "/DATA/Documents", "/DATA/Downloads", "/DATA/Gallery", "/DATA/Media/Movies", "/DATA/Media/TV Shows", "/DATA/Media/Music"}
-	}
-
-	if sysType == "windows" {
-		dirArray = []string{"C:\\CasaOS\\DATA\\AppData", "C:\\CasaOS\\DATA\\Documents", "C:\\CasaOS\\DATA\\Downloads", "C:\\CasaOS\\DATA\\Gallery", "C:\\CasaOS\\DATA\\Media/Movies", "C:\\CasaOS\\DATA\\Media\\TV Shows", "C:\\CasaOS\\DATA\\Media\\Music"}
-	}
-	if sysType == "darwin" {
-		dirArray = []string{"./CasaOS/DATA/AppData", "./CasaOS/DATA/Documents", "./CasaOS/DATA/Downloads", "./CasaOS/DATA/Gallery", "./CasaOS/DATA/Media/Movies", "./CasaOS/DATA/Media/TV Shows", "./CasaOS/DATA/Media/Music"}
-	}
-
-	for _, v := range dirArray {
-		file.IsNotExistMkDir(v)
-	}
-
-}
-
-func UpdateSetup() {
-	mkdirDATAAll()
-}

+ 36 - 36
pkg/docker/helper.go

@@ -15,7 +15,6 @@ import (
 )
 
 func NewSshClient(user, password string, port string) (*ssh.Client, error) {
-
 	// connet to ssh
 	// addr = fmt.Sprintf("%s:%d", host, port)
 
@@ -23,10 +22,10 @@ func NewSshClient(user, password string, port string) (*ssh.Client, error) {
 		Timeout:         time.Second * 5,
 		User:            user,
 		HostKeyCallback: ssh.InsecureIgnoreHostKey(),
-		//HostKeyCallback: ,
-		//HostKeyCallback: hostKeyCallBackFunc(h.Host),
+		// HostKeyCallback: ,
+		// HostKeyCallback: hostKeyCallBackFunc(h.Host),
 	}
-	//if h.Type == "password" {
+	// if h.Type == "password" {
 	config.Auth = []ssh.AuthMethod{ssh.Password(password)}
 	//} else {
 	//	config.Auth = []ssh.AuthMethod{publicKeyAuthFunc(h.Key)}
@@ -90,11 +89,11 @@ func (w *wsBufferWriter) Write(p []byte) (int, error) {
 	defer w.mu.Unlock()
 	return w.buffer.Write(p)
 }
+
 func (s *SshConn) Close() {
 	if s.Session != nil {
 		s.Session.Close()
 	}
-
 }
 
 const (
@@ -102,16 +101,15 @@ const (
 	wsMsgResize = "resize"
 )
 
-//ReceiveWsMsg  receive websocket msg do some handling then write into ssh.session.stdin
+// ReceiveWsMsg  receive websocket msg do some handling then write into ssh.session.stdin
 func ReceiveWsMsgUser(wsConn *websocket.Conn, logBuff *bytes.Buffer) string {
-	//tells other go routine quit
+	// tells other go routine quit
 	username := ""
 	for {
 
-		//read websocket msg
+		// read websocket msg
 		_, wsData, err := wsConn.ReadMessage()
 		if err != nil {
-
 			return ""
 		}
 
@@ -125,8 +123,8 @@ func ReceiveWsMsgUser(wsConn *websocket.Conn, logBuff *bytes.Buffer) string {
 		//}
 		switch msgObj.Type {
 		case wsMsgCmd:
-			//handle xterm.js stdin
-			//decodeBytes, err := base64.StdEncoding.DecodeString(msgObj.Cmd)
+			// handle xterm.js stdin
+			// decodeBytes, err := base64.StdEncoding.DecodeString(msgObj.Cmd)
 			decodeBytes := []byte(msgObj.Cmd)
 			if msgObj.Cmd == "\u007f" {
 				if len(username) == 0 {
@@ -144,7 +142,7 @@ func ReceiveWsMsgUser(wsConn *websocket.Conn, logBuff *bytes.Buffer) string {
 			if err := wsConn.WriteMessage(websocket.TextMessage, decodeBytes); err != nil {
 				logrus.WithError(err).Error("ws cmd bytes write to ssh.stdin pipe failed")
 			}
-			//write input cmd to log buffer
+			// write input cmd to log buffer
 			if _, err := logBuff.Write(decodeBytes); err != nil {
 				logrus.WithError(err).Error("write received cmd into log buffer failed")
 			}
@@ -154,11 +152,11 @@ func ReceiveWsMsgUser(wsConn *websocket.Conn, logBuff *bytes.Buffer) string {
 }
 
 func ReceiveWsMsgPassword(wsConn *websocket.Conn, logBuff *bytes.Buffer) string {
-	//tells other go routine quit
+	// tells other go routine quit
 	password := ""
 	for {
 
-		//read websocket msg
+		// read websocket msg
 		_, wsData, err := wsConn.ReadMessage()
 		if err != nil {
 			logrus.WithError(err).Error("reading webSocket message failed")
@@ -175,8 +173,8 @@ func ReceiveWsMsgPassword(wsConn *websocket.Conn, logBuff *bytes.Buffer) string
 		//}
 		switch msgObj.Type {
 		case wsMsgCmd:
-			//handle xterm.js stdin
-			//decodeBytes, err := base64.StdEncoding.DecodeString(msgObj.Cmd)
+			// handle xterm.js stdin
+			// decodeBytes, err := base64.StdEncoding.DecodeString(msgObj.Cmd)
 			if msgObj.Cmd == "\r" {
 				return password
 			}
@@ -194,16 +192,16 @@ func ReceiveWsMsgPassword(wsConn *websocket.Conn, logBuff *bytes.Buffer) string
 	}
 }
 
-//ReceiveWsMsg  receive websocket msg do some handling then write into ssh.session.stdin
+// ReceiveWsMsg  receive websocket msg do some handling then write into ssh.session.stdin
 func (ssConn *SshConn) ReceiveWsMsg(wsConn *websocket.Conn, logBuff *bytes.Buffer, exitCh chan bool) {
-	//tells other go routine quit
+	// tells other go routine quit
 	defer setQuit(exitCh)
 	for {
 		select {
 		case <-exitCh:
 			return
 		default:
-			//read websocket msg
+			// read websocket msg
 			_, wsData, err := wsConn.ReadMessage()
 			if err != nil {
 				logrus.WithError(err).Error("reading webSocket message failed")
@@ -227,15 +225,15 @@ func (ssConn *SshConn) ReceiveWsMsg(wsConn *websocket.Conn, logBuff *bytes.Buffe
 			switch msgObj.Type {
 
 			case wsMsgResize:
-				//handle xterm.js size change
+				// handle xterm.js size change
 				if msgObj.Cols > 0 && msgObj.Rows > 0 {
 					if err := ssConn.Session.WindowChange(msgObj.Rows, msgObj.Cols); err != nil {
 						logrus.WithError(err).Error("ssh pty change windows size failed")
 					}
 				}
 			case wsMsgCmd:
-				//handle xterm.js stdin
-				//decodeBytes, err := base64.StdEncoding.DecodeString(msgObj.Cmd)
+				// handle xterm.js stdin
+				// decodeBytes, err := base64.StdEncoding.DecodeString(msgObj.Cmd)
 				decodeBytes := []byte(msgObj.Cmd)
 				if err != nil {
 					logrus.WithError(err).Error("websock cmd string base64 decoding failed")
@@ -243,7 +241,7 @@ func (ssConn *SshConn) ReceiveWsMsg(wsConn *websocket.Conn, logBuff *bytes.Buffe
 				if _, err := ssConn.StdinPipe.Write(decodeBytes); err != nil {
 					logrus.WithError(err).Error("ws cmd bytes write to ssh.stdin pipe failed")
 				}
-				//write input cmd to log buffer
+				// write input cmd to log buffer
 				if _, err := logBuff.Write(decodeBytes); err != nil {
 					logrus.WithError(err).Error("write received cmd into log buffer failed")
 				}
@@ -253,17 +251,17 @@ func (ssConn *SshConn) ReceiveWsMsg(wsConn *websocket.Conn, logBuff *bytes.Buffe
 }
 
 func (ssConn *SshConn) SendComboOutput(wsConn *websocket.Conn, exitCh chan bool) {
-	//tells other go routine quit
-	//defer setQuit(exitCh)
+	// tells other go routine quit
+	// defer setQuit(exitCh)
 
-	//every 120ms write combine output bytes into websocket response
+	// every 120ms write combine output bytes into websocket response
 	tick := time.NewTicker(time.Millisecond * time.Duration(120))
-	//for range time.Tick(120 * time.Millisecond){}
+	// for range time.Tick(120 * time.Millisecond){}
 	defer tick.Stop()
 	for {
 		select {
 		case <-tick.C:
-			//write combine output bytes into websocket response
+			// write combine output bytes into websocket response
 			if err := flushComboOutput(ssConn.ComboOutput, wsConn); err != nil {
 				logrus.WithError(err).Error("ssh sending combo output to webSocket failed")
 				return
@@ -273,6 +271,7 @@ func (ssConn *SshConn) SendComboOutput(wsConn *websocket.Conn, exitCh chan bool)
 		}
 	}
 }
+
 func flushComboOutput(w *wsBufferWriter, wsConn *websocket.Conn) error {
 	if w.buffer.Len() != 0 {
 		err := wsConn.WriteMessage(websocket.TextMessage, w.buffer.Bytes())
@@ -284,16 +283,16 @@ func flushComboOutput(w *wsBufferWriter, wsConn *websocket.Conn) error {
 	return nil
 }
 
-//ReceiveWsMsg  receive websocket msg do some handling then write into ssh.session.stdin
+// ReceiveWsMsg  receive websocket msg do some handling then write into ssh.session.stdin
 func (ssConn *SshConn) Login(wsConn *websocket.Conn, logBuff *bytes.Buffer, exitCh chan bool) {
-	//tells other go routine quit
+	// tells other go routine quit
 	defer setQuit(exitCh)
 	for {
 		select {
 		case <-exitCh:
 			return
 		default:
-			//read websocket msg
+			// read websocket msg
 			_, wsData, err := wsConn.ReadMessage()
 			if err != nil {
 				logrus.WithError(err).Error("reading webSocket message failed")
@@ -317,15 +316,15 @@ func (ssConn *SshConn) Login(wsConn *websocket.Conn, logBuff *bytes.Buffer, exit
 			switch msgObj.Type {
 
 			case wsMsgResize:
-				//handle xterm.js size change
+				// handle xterm.js size change
 				if msgObj.Cols > 0 && msgObj.Rows > 0 {
 					if err := ssConn.Session.WindowChange(msgObj.Rows, msgObj.Cols); err != nil {
 						logrus.WithError(err).Error("ssh pty change windows size failed")
 					}
 				}
 			case wsMsgCmd:
-				//handle xterm.js stdin
-				//decodeBytes, err := base64.StdEncoding.DecodeString(msgObj.Cmd)
+				// handle xterm.js stdin
+				// decodeBytes, err := base64.StdEncoding.DecodeString(msgObj.Cmd)
 				decodeBytes := []byte(msgObj.Cmd)
 				if err != nil {
 					logrus.WithError(err).Error("websock cmd string base64 decoding failed")
@@ -333,7 +332,7 @@ func (ssConn *SshConn) Login(wsConn *websocket.Conn, logBuff *bytes.Buffer, exit
 				if _, err := ssConn.StdinPipe.Write(decodeBytes); err != nil {
 					logrus.WithError(err).Error("ws cmd bytes write to ssh.stdin pipe failed")
 				}
-				//write input cmd to log buffer
+				// write input cmd to log buffer
 				if _, err := logBuff.Write(decodeBytes); err != nil {
 					logrus.WithError(err).Error("write received cmd into log buffer failed")
 				}
@@ -341,6 +340,7 @@ func (ssConn *SshConn) Login(wsConn *websocket.Conn, logBuff *bytes.Buffer, exit
 		}
 	}
 }
+
 func (ssConn *SshConn) SessionWait(quitChan chan bool) {
 	if err := ssConn.Session.Wait(); err != nil {
 		logrus.WithError(err).Error("ssh session wait failed")
@@ -395,7 +395,7 @@ func WsReaderCopy(reader *websocket.Conn, writer io.Writer) {
 			if err = json2.Unmarshal(p, &msgObj); err != nil {
 				writer.Write(p)
 			} else if msgObj.Type == wsMsgResize {
-				//writer.Write([]byte("stty rows " + strconv.Itoa(msgObj.Rows) + " && stty cols " + strconv.Itoa(msgObj.Cols) + " \r"))
+				// writer.Write([]byte("stty rows " + strconv.Itoa(msgObj.Rows) + " && stty cols " + strconv.Itoa(msgObj.Cols) + " \r"))
 			}
 		}
 	}

+ 1 - 1
pkg/sqlite/db.go

@@ -43,7 +43,7 @@ func GetDb(dbPath string) *gorm.DB {
 	}
 	gdb = db
 
-	err = db.AutoMigrate(&model2.AppNotify{}, &model2.AppListDBModel{}, &model2.SerialDisk{}, model2.SharesDBModel{}, model2.ConnectionsDBModel{})
+	err = db.AutoMigrate(&model2.AppNotify{}, &model2.AppListDBModel{}, model2.SharesDBModel{}, model2.ConnectionsDBModel{})
 	db.Exec("DROP TABLE IF EXISTS o_application")
 	db.Exec("DROP TABLE IF EXISTS o_friend")
 	db.Exec("DROP TABLE IF EXISTS o_person_download")

+ 7 - 6
pkg/utils/command/command_helper.go

@@ -35,8 +35,8 @@ func ExecResultStrArray(cmdStr string) []string {
 		fmt.Println(err)
 		return nil
 	}
-	//str, err := ioutil.ReadAll(stdout)
-	var networklist = []string{}
+	// str, err := ioutil.ReadAll(stdout)
+	networklist := []string{}
 	outputBuf := bufio.NewReader(stdout)
 	for {
 		output, _, err := outputBuf.ReadLine()
@@ -54,6 +54,8 @@ func ExecResultStrArray(cmdStr string) []string {
 
 func ExecResultStr(cmdStr string) string {
 	cmd := exec.Command("/bin/bash", "-c", cmdStr)
+	println(cmd.String())
+
 	stdout, err := cmd.StdoutPipe()
 	if err != nil {
 		fmt.Println(err)
@@ -73,7 +75,7 @@ func ExecResultStr(cmdStr string) string {
 	return string(str)
 }
 
-//执行 lsblk 命令
+// 执行 lsblk 命令
 func ExecLSBLK() []byte {
 	output, err := exec.Command("lsblk", "-O", "-J", "-b").Output()
 	if err != nil {
@@ -83,7 +85,7 @@ func ExecLSBLK() []byte {
 	return output
 }
 
-//执行 lsblk 命令
+// 执行 lsblk 命令
 func ExecLSBLKByPath(path string) []byte {
 	output, err := exec.Command("lsblk", path, "-O", "-J", "-b").Output()
 	if err != nil {
@@ -93,7 +95,7 @@ func ExecLSBLKByPath(path string) []byte {
 	return output
 }
 
-//exec smart
+// exec smart
 func ExecSmartCTLByPath(path string) []byte {
 	timeout := 3
 	ctx, cancel := context.WithTimeout(context.Background(), time.Duration(timeout)*time.Second)
@@ -107,6 +109,5 @@ func ExecSmartCTLByPath(path string) []byte {
 }
 
 func ExecEnabledSMART(path string) {
-
 	exec.Command("smartctl", "-s on", path).Output()
 }

+ 33 - 20
pkg/utils/file/file.go

@@ -5,6 +5,7 @@ import (
 	"errors"
 	"fmt"
 	"io"
+	"io/fs"
 	"io/ioutil"
 	"log"
 	"mime/multipart"
@@ -60,7 +61,7 @@ func MkDir(src string) error {
 	if err != nil {
 		return err
 	}
-	os.Chmod(src, 0777)
+	os.Chmod(src, 0o777)
 
 	return nil
 }
@@ -103,7 +104,7 @@ func MustOpen(fileName, filePath string) (*os.File, error) {
 		return nil, fmt.Errorf("file.IsNotExistMkDir src: %s, err: %v", src, err)
 	}
 
-	f, err := Open(src+fileName, os.O_APPEND|os.O_CREATE|os.O_RDWR, 0644)
+	f, err := Open(src+fileName, os.O_APPEND|os.O_CREATE|os.O_RDWR, 0o644)
 	if err != nil {
 		return nil, fmt.Errorf("Fail to OpenFile :%v", err)
 	}
@@ -113,7 +114,7 @@ func MustOpen(fileName, filePath string) (*os.File, error) {
 
 // 判断所给路径文件/文件夹是否存在
 func Exists(path string) bool {
-	_, err := os.Stat(path) //os.Stat获取文件信息
+	_, err := os.Stat(path) // os.Stat获取文件信息
 	if err != nil {
 		if os.IsExist(err) {
 			return true
@@ -147,7 +148,7 @@ func CreateFile(path string) error {
 }
 
 func CreateFileAndWriteContent(path string, content string) error {
-	file, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE, 0666)
+	file, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE, 0o666)
 	if err != nil {
 		return err
 	}
@@ -163,7 +164,7 @@ func CreateFileAndWriteContent(path string, content string) error {
 
 // IsNotExistMkDir create a directory if it does not exist
 func IsNotExistCreateFile(src string) error {
-	if notExist := CheckNotExist(src); notExist == true {
+	if notExist := CheckNotExist(src); notExist {
 		if err := CreateFile(src); err != nil {
 			return err
 		}
@@ -267,7 +268,7 @@ func CopySingleFile(src, dst, style string) error {
 	return os.Chmod(dst, srcinfo.Mode())
 }
 
-//Check for duplicate file names
+// Check for duplicate file names
 func GetNoDuplicateFileName(fullPath string) string {
 	path, fileName := filepath.Split(fullPath)
 	fileSuffix := path2.Ext(fileName)
@@ -293,7 +294,7 @@ func CopyDir(src string, dst string, style string) error {
 		}
 		return nil
 	}
-	//dstPath := dst
+	// dstPath := dst
 	lastPath := src[strings.LastIndex(src, "/")+1:]
 	dst += "/" + lastPath
 	// for i := 0; Exists(dst); i++ {
@@ -314,7 +315,7 @@ func CopyDir(src string, dst string, style string) error {
 	}
 	for _, fd := range fds {
 		srcfp := path.Join(src, fd.Name())
-		dstfp := dst //path.Join(dst, fd.Name())
+		dstfp := dst // path.Join(dst, fd.Name())
 
 		if fd.IsDir() {
 			if err = CopyDir(srcfp, dstfp, style); err != nil {
@@ -336,10 +337,17 @@ func WriteToPath(data []byte, path, name string) error {
 	} else {
 		fullPath += "/" + name
 	}
-	IsNotExistCreateFile(fullPath)
+	return WriteToFullPath(data, fullPath, 0o666)
+}
+
+func WriteToFullPath(data []byte, fullPath string, perm fs.FileMode) error {
+	if err := IsNotExistCreateFile(fullPath); err != nil {
+		return err
+	}
+
 	file, err := os.OpenFile(fullPath,
 		os.O_WRONLY|os.O_TRUNC|os.O_CREATE,
-		0666,
+		perm,
 	)
 	if err != nil {
 		return err
@@ -350,26 +358,31 @@ func WriteToPath(data []byte, path, name string) error {
 	return err
 }
 
-//最终拼接
+// 最终拼接
 func SpliceFiles(dir, path string, length int, startPoint int) error {
-
 	fullPath := path
 
-	IsNotExistCreateFile(fullPath)
+	if err := IsNotExistCreateFile(fullPath); err != nil {
+		return err
+	}
 
 	file, _ := os.OpenFile(fullPath,
 		os.O_WRONLY|os.O_TRUNC|os.O_CREATE,
-		0666,
+		0o666,
 	)
+
 	defer file.Close()
+
 	bufferedWriter := bufio.NewWriter(file)
-	for i := 0; i < length+startPoint; i++ {
+
+	// todo: here should have a goroutine to remove each partial file after it is read, to save disk space
+
+	for i := 0; i < length+startPoint-1; i++ {
 		data, err := ioutil.ReadFile(dir + "/" + strconv.Itoa(i+startPoint))
 		if err != nil {
 			return err
 		}
-		_, err = bufferedWriter.Write(data)
-		if err != nil {
+		if _, err := bufferedWriter.Write(data); err != nil { // recommend to use https://github.com/iceber/iouring-go for faster write
 			return err
 		}
 	}
@@ -380,7 +393,6 @@ func SpliceFiles(dir, path string, length int, startPoint int) error {
 }
 
 func GetCompressionAlgorithm(t string) (string, archiver.Writer, error) {
-
 	switch t {
 	case "zip", "":
 		return ".zip", archiver.NewZip(), nil
@@ -400,8 +412,8 @@ func GetCompressionAlgorithm(t string) (string, archiver.Writer, error) {
 		return "", nil, errors.New("format not implemented")
 	}
 }
-func AddFile(ar archiver.Writer, path, commonPath string) error {
 
+func AddFile(ar archiver.Writer, path, commonPath string) error {
 	info, err := os.Stat(path)
 	if err != nil {
 		return err
@@ -447,6 +459,7 @@ func AddFile(ar archiver.Writer, path, commonPath string) error {
 
 	return nil
 }
+
 func CommonPrefix(sep byte, paths ...string) string {
 	// Handle special cases.
 	switch len(paths) {
@@ -513,7 +526,7 @@ func GetFileOrDirSize(path string) (int64, error) {
 	return fileInfo.Size(), nil
 }
 
-//getFileSize get file size by path(B)
+// getFileSize get file size by path(B)
 func DirSizeB(path string) (int64, error) {
 	var size int64
 	err := filepath.Walk(path, func(_ string, info os.FileInfo, err error) error {

+ 0 - 46
route/init.go

@@ -3,65 +3,19 @@ package route
 import (
 	"fmt"
 	"os"
-	"strconv"
 	"strings"
 	"time"
 
-	"github.com/IceWhaleTech/CasaOS/pkg/config"
 	"github.com/IceWhaleTech/CasaOS/pkg/samba"
-	"github.com/IceWhaleTech/CasaOS/pkg/utils/command"
 	"github.com/IceWhaleTech/CasaOS/pkg/utils/file"
 	"github.com/IceWhaleTech/CasaOS/pkg/utils/loger"
 	"github.com/IceWhaleTech/CasaOS/service"
-	model2 "github.com/IceWhaleTech/CasaOS/service/model"
 	"go.uber.org/zap"
 )
 
 func InitFunction() {
-	CheckSerialDiskMount()
 	go InitNetworkMount()
 }
-
-func CheckSerialDiskMount() {
-	// check mount point
-	dbList := service.MyService.Disk().GetSerialAll()
-
-	list := service.MyService.Disk().LSBLK(true)
-	mountPoint := make(map[string]string, len(dbList))
-	//remount
-	for _, v := range dbList {
-		mountPoint[v.UUID] = v.MountPoint
-	}
-	for _, v := range list {
-		command.ExecEnabledSMART(v.Path)
-		if v.Children != nil {
-			for _, h := range v.Children {
-				//if len(h.MountPoint) == 0 && len(v.Children) == 1 && h.FsType == "ext4" {
-				if m, ok := mountPoint[h.UUID]; ok {
-					//mount point check
-					volume := m
-					if !file.CheckNotExist(m) {
-						for i := 0; file.CheckNotExist(volume); i++ {
-							volume = m + strconv.Itoa(i+1)
-						}
-					}
-					service.MyService.Disk().MountDisk(h.Path, volume)
-					if volume != m {
-						ms := model2.SerialDisk{}
-						ms.UUID = v.UUID
-						ms.MountPoint = volume
-						service.MyService.Disk().UpdateMountPoint(ms)
-					}
-
-				}
-				//}
-			}
-		}
-	}
-	service.MyService.Disk().RemoveLSBLKCache()
-	command.OnlyExec("source " + config.AppInfo.ShellPath + "/helper.sh ;AutoRemoveUnuseDir")
-}
-
 func InitNetworkMount() {
 	time.Sleep(time.Second * 10)
 	connections := service.MyService.Connections().GetConnectionsList()

+ 36 - 229
route/periodical.go

@@ -14,20 +14,12 @@
 package route
 
 import (
-	"os"
-	"os/signal"
-	"reflect"
-	"strconv"
 	"strings"
-	"syscall"
 	"time"
 	"unsafe"
 
 	"github.com/IceWhaleTech/CasaOS/model"
-	"github.com/IceWhaleTech/CasaOS/pkg/utils/loger"
 	"github.com/IceWhaleTech/CasaOS/service"
-	"github.com/pilebones/go-udev/netlink"
-	"go.uber.org/zap"
 )
 
 func SendNetINfoBySocket() {
@@ -61,104 +53,6 @@ func SendMemBySocket() {
 	service.MyService.Notify().SendMemInfoBySocket(service.MyService.System().GetMemInfo())
 }
 
-func SendDiskBySocket() {
-	list := service.MyService.Disk().LSBLK(true)
-
-	summary := model.Summary{}
-	healthy := true
-	findSystem := 0
-
-	for i := 0; i < len(list); i++ {
-		if len(list[i].Children) > 0 && findSystem == 0 {
-
-			for j := 0; j < len(list[i].Children); j++ {
-
-				if len(list[i].Children[j].Children) > 0 {
-					for _, v := range list[i].Children[j].Children {
-						if v.MountPoint == "/" {
-							s, _ := strconv.ParseUint(v.FSSize, 10, 64)
-							a, _ := strconv.ParseUint(v.FSAvail, 10, 64)
-							u, _ := strconv.ParseUint(v.FSUsed, 10, 64)
-							summary.Size += s
-							summary.Avail += a
-							summary.Used += u
-							findSystem = 1
-							break
-						}
-					}
-				} else {
-					if list[i].Children[j].MountPoint == "/" {
-						s, _ := strconv.ParseUint(list[i].Children[j].FSSize, 10, 64)
-						a, _ := strconv.ParseUint(list[i].Children[j].FSAvail, 10, 64)
-						u, _ := strconv.ParseUint(list[i].Children[j].FSUsed, 10, 64)
-						summary.Size += s
-						summary.Avail += a
-						summary.Used += u
-						findSystem = 1
-						break
-					}
-				}
-			}
-
-		}
-		if findSystem == 1 {
-			findSystem += 1
-			continue
-		}
-		if list[i].Tran == "sata" || list[i].Tran == "nvme" || list[i].Tran == "spi" || list[i].Tran == "sas" || strings.Contains(list[i].SubSystems, "virtio") || (list[i].Tran == "ata" && list[i].Type == "disk") {
-			temp := service.MyService.Disk().SmartCTL(list[i].Path)
-			if reflect.DeepEqual(temp, model.SmartctlA{}) {
-				healthy = true
-			} else {
-				healthy = temp.SmartStatus.Passed
-			}
-
-			//list[i].Temperature = temp.Temperature.Current
-
-			if len(list[i].Children) > 0 {
-				for _, v := range list[i].Children {
-					s, _ := strconv.ParseUint(v.FSSize, 10, 64)
-					a, _ := strconv.ParseUint(v.FSAvail, 10, 64)
-					u, _ := strconv.ParseUint(v.FSUsed, 10, 64)
-					summary.Size += s
-					summary.Avail += a
-					summary.Used += u
-				}
-			}
-
-		}
-	}
-
-	summary.Health = healthy
-	service.MyService.Notify().SendDiskInfoBySocket(summary)
-}
-
-func SendUSBBySocket() {
-	usbList := service.MyService.Disk().LSBLK(false)
-	usb := []model.DriveUSB{}
-	for _, v := range usbList {
-		if v.Tran == "usb" {
-			isMount := false
-			temp := model.DriveUSB{}
-			temp.Model = v.Model
-			temp.Name = v.Name
-			temp.Size = v.Size
-			for _, child := range v.Children {
-				if len(child.MountPoint) > 0 {
-					isMount = true
-					avail, _ := strconv.ParseUint(child.FSAvail, 10, 64)
-					temp.Avail += avail
-
-				}
-			}
-			if isMount {
-				usb = append(usb, temp)
-			}
-		}
-	}
-	service.MyService.Notify().SendUSBInfoBySocket(usb)
-}
-
 func SendAllHardwareStatusBySocket() {
 
 	netList := service.MyService.System().GetNetInfo()
@@ -183,131 +77,44 @@ func SendAllHardwareStatusBySocket() {
 	cpuData["temperature"] = service.MyService.System().GetCPUTemperature()
 	cpuData["power"] = service.MyService.System().GetCPUPower()
 
-	list := service.MyService.Disk().LSBLK(true)
-
-	summary := model.Summary{}
-	healthy := true
-	findSystem := 0
-
-	for i := 0; i < len(list); i++ {
-		if len(list[i].Children) > 0 && findSystem == 0 {
-
-			for j := 0; j < len(list[i].Children); j++ {
-
-				if len(list[i].Children[j].Children) > 0 {
-					for _, v := range list[i].Children[j].Children {
-						if v.MountPoint == "/" {
-							s, _ := strconv.ParseUint(v.FSSize, 10, 64)
-							a, _ := strconv.ParseUint(v.FSAvail, 10, 64)
-							u, _ := strconv.ParseUint(v.FSUsed, 10, 64)
-							summary.Size += s
-							summary.Avail += a
-							summary.Used += u
-							findSystem = 1
-							break
-						}
-					}
-				} else {
-					if list[i].Children[j].MountPoint == "/" {
-						s, _ := strconv.ParseUint(list[i].Children[j].FSSize, 10, 64)
-						a, _ := strconv.ParseUint(list[i].Children[j].FSAvail, 10, 64)
-						u, _ := strconv.ParseUint(list[i].Children[j].FSUsed, 10, 64)
-						summary.Size += s
-						summary.Avail += a
-						summary.Used += u
-						findSystem = 1
-						break
-					}
-				}
-			}
-
-		}
-		if findSystem == 1 {
-			findSystem += 1
-			continue
-		}
-		if list[i].Tran == "sata" || list[i].Tran == "nvme" || list[i].Tran == "spi" || list[i].Tran == "sas" || strings.Contains(list[i].SubSystems, "virtio") || (list[i].Tran == "ata" && list[i].Type == "disk") {
-			temp := service.MyService.Disk().SmartCTL(list[i].Path)
-			if reflect.DeepEqual(temp, model.SmartctlA{}) {
-				healthy = true
-			} else {
-				healthy = temp.SmartStatus.Passed
-			}
-			if len(list[i].Children) > 0 {
-				for _, v := range list[i].Children {
-					s, _ := strconv.ParseUint(v.FSSize, 10, 64)
-					a, _ := strconv.ParseUint(v.FSAvail, 10, 64)
-					u, _ := strconv.ParseUint(v.FSUsed, 10, 64)
-					summary.Size += s
-					summary.Avail += a
-					summary.Used += u
-				}
-			}
-
-		}
-	}
-
-	summary.Health = healthy
-
-	usbList := service.MyService.Disk().LSBLK(false)
-	usb := []model.DriveUSB{}
-	for _, v := range usbList {
-		if v.Tran == "usb" {
-			isMount := false
-			temp := model.DriveUSB{}
-			temp.Model = v.Model
-			temp.Name = v.Name
-			temp.Size = v.Size
-			for _, child := range v.Children {
-				if len(child.MountPoint) > 0 {
-					isMount = true
-					avail, _ := strconv.ParseUint(child.FSAvail, 10, 64)
-					temp.Avail += avail
-				}
-			}
-			if isMount {
-				usb = append(usb, temp)
-			}
-
-		}
-	}
 	memInfo := service.MyService.System().GetMemInfo()
 
-	service.MyService.Notify().SendAllHardwareStatusBySocket(summary, usb, memInfo, cpuData, newNet)
+	service.MyService.Notify().SendAllHardwareStatusBySocket(memInfo, cpuData, newNet)
 
 }
-func MonitoryUSB() {
-	var matcher netlink.Matcher
-
-	conn := new(netlink.UEventConn)
-	if err := conn.Connect(netlink.UdevEvent); err != nil {
-		loger.Error("udev err", zap.Any("Unable to connect to Netlink Kobject UEvent socket", err))
-	}
-	defer conn.Close()
-
-	queue := make(chan netlink.UEvent)
-	errors := make(chan error)
-	quit := conn.Monitor(queue, errors, matcher)
 
-	signals := make(chan os.Signal, 1)
-	signal.Notify(signals, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT)
-	go func() {
-		<-signals
-		close(quit)
-		os.Exit(0)
-	}()
-
-	for {
-		select {
-		case uevent := <-queue:
-			if uevent.Env["DEVTYPE"] == "disk" {
-				time.Sleep(time.Microsecond * 500)
-				SendUSBBySocket()
-				continue
-			}
-		case err := <-errors:
-			loger.Error("udev err", zap.Any("err", err))
-		}
-	}
-
-}
+// func MonitoryUSB() {
+// 	var matcher netlink.Matcher
+
+// 	conn := new(netlink.UEventConn)
+// 	if err := conn.Connect(netlink.UdevEvent); err != nil {
+// 		loger.Error("udev err", zap.Any("Unable to connect to Netlink Kobject UEvent socket", err))
+// 	}
+// 	defer conn.Close()
+
+// 	queue := make(chan netlink.UEvent)
+// 	errors := make(chan error)
+// 	quit := conn.Monitor(queue, errors, matcher)
+
+// 	signals := make(chan os.Signal, 1)
+// 	signal.Notify(signals, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT)
+// 	go func() {
+// 		<-signals
+// 		close(quit)
+// 		os.Exit(0)
+// 	}()
+
+// 	for {
+// 		select {
+// 		case uevent := <-queue:
+// 			if uevent.Env["DEVTYPE"] == "disk" {
+// 				time.Sleep(time.Microsecond * 500)
+// 				SendUSBBySocket()
+// 				continue
+// 			}
+// 		case err := <-errors:
+// 			loger.Error("udev err", zap.Any("err", err))
+// 		}
+// 	}
+
+// }

+ 59 - 75
route/route.go

@@ -1,8 +1,10 @@
 package route
 
 import (
-	jwt2 "github.com/IceWhaleTech/CasaOS-Common/utils/jwt"
-	"github.com/IceWhaleTech/CasaOS/middleware"
+	"os"
+
+	"github.com/IceWhaleTech/CasaOS-Common/middleware"
+	"github.com/IceWhaleTech/CasaOS-Common/utils/jwt"
 	"github.com/IceWhaleTech/CasaOS/pkg/config"
 	v1 "github.com/IceWhaleTech/CasaOS/route/v1"
 
@@ -11,13 +13,22 @@ import (
 )
 
 func InitRouter() *gin.Engine {
+	ginMode := gin.ReleaseMode
+	if config.ServerInfo.RunMode != "" {
+		ginMode = config.ServerInfo.RunMode
+	}
+	if os.Getenv(gin.EnvGinMode) != "" {
+		ginMode = os.Getenv(gin.EnvGinMode)
+	}
+	gin.SetMode(ginMode)
 
-	r := gin.Default()
-
+	r := gin.New()
+	r.Use(gin.Recovery())
 	r.Use(middleware.Cors())
-	r.Use(middleware.WriteLog())
 	r.Use(gzip.Gzip(gzip.DefaultCompression))
-	gin.SetMode(config.ServerInfo.RunMode)
+	if ginMode != gin.ReleaseMode {
+		r.Use(middleware.WriteLog())
+	}
 
 	// r.StaticFS("/ui", http.FS(web.Static))
 	// r.GET("/", WebUIHome)
@@ -35,15 +46,17 @@ func InitRouter() *gin.Engine {
 	// r.GET("/v1/users/image", v1.GetUserImage)
 
 	// r.GET("/v1/users/status", v1.GetUserStatus) //init/check
-	//r.GET("/v1/guide/check", v1.GetGuideCheck)         // /v1/sys/guide_check
+	// r.GET("/v1/guide/check", v1.GetGuideCheck)         // /v1/sys/guide_check
 	r.GET("/v1/sys/debug", v1.GetSystemConfigDebug) // //debug
 
 	r.GET("/v1/sys/socket-port", v1.GetSystemSocketPort) //sys/socket_port
 	r.GET("/v1/sys/version/check", v1.GetSystemCheckVersion)
-
+	r.GET("/ping", func(ctx *gin.Context) {
+		ctx.String(200, "pong")
+	})
 	v1Group := r.Group("/v1")
 
-	v1Group.Use(jwt2.JWT())
+	v1Group.Use(jwt.ExceptLocalhost())
 	{
 		// v1UsersGroup := v1Group.Group("/users")
 		// v1UsersGroup.Use()
@@ -71,32 +84,35 @@ func InitRouter() *gin.Engine {
 		v1AppsGroup := v1Group.Group("/apps")
 		v1AppsGroup.Use()
 		{
-			v1AppsGroup.GET("", v1.AppList) //list
+			v1AppsGroup.GET("", v1.AppList) // list
 			v1AppsGroup.GET("/:id", v1.AppInfo)
 		}
 		v1ContainerGroup := v1Group.Group("/container")
 		v1ContainerGroup.Use()
 		{
+
 			v1ContainerGroup.GET("", v1.MyAppList) ///my/list
 			v1ContainerGroup.GET("/usage", v1.AppUsageList)
 			v1ContainerGroup.GET("/:id", v1.ContainerUpdateInfo)    ///update/:id/info
 			v1ContainerGroup.GET("/:id/logs", v1.ContainerLog)      // /app/logs/:id
-			v1ContainerGroup.GET("/networks", v1.GetDockerNetworks) //app/install/config
+			v1ContainerGroup.GET("/networks", v1.GetDockerNetworks) // app/install/config
 
-			v1ContainerGroup.GET("/:id/state", v1.GetContainerState) //app/state/:id ?state=install_progress
+			v1ContainerGroup.GET("/:id/state", v1.GetContainerState) // app/state/:id ?state=install_progress
 			// there are problems, temporarily do not deal with
-			v1ContainerGroup.GET("/:id/terminal", v1.DockerTerminal) //app/terminal/:id
-			v1ContainerGroup.POST("", v1.InstallApp)                 //app/install
-			//v1ContainerGroup.GET("/:id", v1.ContainerInfo) // /app/info/:id
+			v1ContainerGroup.GET("/:id/terminal", v1.DockerTerminal) // app/terminal/:id
+			v1ContainerGroup.POST("", v1.InstallApp)                 // app/install
+			// v1ContainerGroup.GET("/:id", v1.ContainerInfo) // /app/info/:id
 
 			v1ContainerGroup.PUT("/:id", v1.UpdateSetting) ///update/:id/setting
 
 			v1ContainerGroup.PUT("/:id/state", v1.ChangAppState) // /app/state/:id
-			v1ContainerGroup.DELETE("/:id", v1.UnInstallApp)     //app/uninstall/:id
-			//Not used
+			v1ContainerGroup.DELETE("/:id", v1.UnInstallApp)     // app/uninstall/:id
+			// Not used
 			v1ContainerGroup.PUT("/:id/latest", v1.PutAppUpdate)
-			//Not used
+			// Not used
 			v1ContainerGroup.POST("/share", v1.ShareAppFile)
+			v1ContainerGroup.GET("/info", v1.GetDockerDaemonConfiguration)
+			v1ContainerGroup.PUT("/info", v1.PutDockerDaemonConfiguration)
 
 		}
 		v1AppCategoriesGroup := v1Group.Group("/app-categories")
@@ -108,19 +124,19 @@ func InitRouter() *gin.Engine {
 		v1SysGroup := v1Group.Group("/sys")
 		v1SysGroup.Use()
 		{
-			v1SysGroup.GET("/version", v1.GetSystemCheckVersion) //version/check
+			v1SysGroup.GET("/version", v1.GetSystemCheckVersion) // version/check
 
 			v1SysGroup.POST("/update", v1.SystemUpdate)
 
-			v1SysGroup.GET("/hardware", v1.GetSystemHardwareInfo) //hardware/info
+			v1SysGroup.GET("/hardware", v1.GetSystemHardwareInfo) // hardware/info
 
 			v1SysGroup.GET("/wsssh", v1.WsSsh)
 			v1SysGroup.POST("/ssh-login", v1.PostSshLogin)
-			//v1SysGroup.GET("/config", v1.GetSystemConfig) //delete
-			//v1SysGroup.POST("/config", v1.PostSetSystemConfig)
-			v1SysGroup.GET("/logs", v1.GetCasaOSErrorLogs) //error/logs
-			//v1SysGroup.GET("/widget/config", v1.GetWidgetConfig)//delete
-			//v1SysGroup.POST("/widget/config", v1.PostSetWidgetConfig)//delete
+			// v1SysGroup.GET("/config", v1.GetSystemConfig) //delete
+			// v1SysGroup.POST("/config", v1.PostSetSystemConfig)
+			v1SysGroup.GET("/logs", v1.GetCasaOSErrorLogs) // error/logs
+			// v1SysGroup.GET("/widget/config", v1.GetWidgetConfig)//delete
+			// v1SysGroup.POST("/widget/config", v1.PostSetWidgetConfig)//delete
 
 			v1SysGroup.POST("/stop", v1.PostKillCasaOS)
 
@@ -130,37 +146,34 @@ func InitRouter() *gin.Engine {
 			// v1SysGroup.GET("/disk", v1.GetSystemDiskInfo)
 			// v1SysGroup.GET("/network", v1.GetSystemNetInfo)
 
-			v1SysGroup.PUT("/usb-auto-mount", v1.PutSystemUSBAutoMount) ///sys/usb/:status
-			v1SysGroup.GET("/usb-auto-mount", v1.GetSystemUSBAutoMount) ///sys/usb/status
-
 			v1SysGroup.GET("/server-info", nil)
 			v1SysGroup.PUT("/server-info", nil)
 			v1SysGroup.GET("/apps-state", v1.GetSystemAppsStatus)
-			//v1SysGroup.GET("/port", v1.GetCasaOSPort)
-			//v1SysGroup.PUT("/port", v1.PutCasaOSPort)
+			// v1SysGroup.GET("/port", v1.GetCasaOSPort)
+			// v1SysGroup.PUT("/port", v1.PutCasaOSPort)
 			v1SysGroup.GET("/proxy", v1.GetSystemProxy)
 		}
 		v1PortGroup := v1Group.Group("/port")
 		v1PortGroup.Use()
 		{
-			v1PortGroup.GET("/", v1.GetPort)              //app/port
-			v1PortGroup.GET("/state/:port", v1.PortCheck) //app/check/:port
+			v1PortGroup.GET("/", v1.GetPort)              // app/port
+			v1PortGroup.GET("/state/:port", v1.PortCheck) // app/check/:port
 		}
 
 		v1FileGroup := v1Group.Group("/file")
 		v1FileGroup.Use()
 		{
-			v1FileGroup.GET("", v1.GetDownloadSingleFile) //download/:path
+			v1FileGroup.GET("", v1.GetDownloadSingleFile) // download/:path
 			v1FileGroup.POST("", v1.PostCreateFile)
 			v1FileGroup.PUT("", v1.PutFileContent)
 			v1FileGroup.PUT("/name", v1.RenamePath)
-			//file/rename
-			v1FileGroup.GET("/content", v1.GetFilerContent) //file/read
+			// file/rename
+			v1FileGroup.GET("/content", v1.GetFilerContent) // file/read
 
-			//File uploads need to be handled separately, and will not be modified here
+			// File uploads need to be handled separately, and will not be modified here
 			v1FileGroup.POST("/upload", v1.PostFileUpload)
 			v1FileGroup.GET("/upload", v1.GetFileUpload)
-			//v1FileGroup.GET("/download", v1.UserFileDownloadCommonService)
+			// v1FileGroup.GET("/download", v1.UserFileDownloadCommonService)
 		}
 		v1FolderGroup := v1Group.Group("/folder")
 		v1FolderGroup.Use()
@@ -173,9 +186,9 @@ func InitRouter() *gin.Engine {
 		v1BatchGroup.Use()
 		{
 
-			v1BatchGroup.DELETE("", v1.DeleteFile) //file/delete
+			v1BatchGroup.DELETE("", v1.DeleteFile) // file/delete
 			v1BatchGroup.DELETE("/:id/task", v1.DeleteOperateFileOrDir)
-			v1BatchGroup.POST("/task", v1.PostOperateFileOrDir) //file/operate
+			v1BatchGroup.POST("/task", v1.PostOperateFileOrDir) // file/operate
 			v1BatchGroup.GET("", v1.GetDownloadFile)
 		}
 		v1ImageGroup := v1Group.Group("/image")
@@ -183,42 +196,6 @@ func InitRouter() *gin.Engine {
 		{
 			v1ImageGroup.GET("", v1.GetFileImage)
 		}
-
-		v1DisksGroup := v1Group.Group("/disks")
-		v1DisksGroup.Use()
-		{
-			//v1DiskGroup.GET("/check", v1.GetDiskCheck) //delete
-			//v1DisksGroup.GET("", v1.GetDiskInfo)
-
-			//v1DisksGroup.POST("", v1.PostMountDisk)
-			v1DisksGroup.GET("", v1.GetDiskList)
-			v1DisksGroup.GET("/usb", v1.GetDisksUSBList)
-			v1DisksGroup.DELETE("/usb", v1.DeleteDiskUSB)
-			v1DisksGroup.DELETE("", v1.DeleteDisksUmount)
-			// //format storage
-			// v1DiskGroup.POST("/format", v1.PostDiskFormat)
-
-			// //mount SATA disk
-			// v1DiskGroup.POST("/mount", v1.PostMountDisk)
-
-			// //umount sata disk
-			// v1DiskGroup.POST("/umount", v1.PostDiskUmount)
-
-			//v1DiskGroup.GET("/type", v1.FormatDiskType)//delete
-
-			v1DisksGroup.DELETE("/part", v1.RemovePartition) //disk/delpart
-		}
-
-		v1StorageGroup := v1Group.Group("/storage")
-		v1StorageGroup.Use()
-		{
-			v1StorageGroup.POST("", v1.PostDiskAddPartition)
-
-			v1StorageGroup.PUT("", v1.PostDiskFormat)
-
-			v1StorageGroup.DELETE("", v1.PostDiskUmount)
-			v1StorageGroup.GET("", v1.GetStorageList)
-		}
 		v1SambaGroup := v1Group.Group("/samba")
 		v1SambaGroup.Use()
 		{
@@ -238,6 +215,13 @@ func InitRouter() *gin.Engine {
 				v1SharesGroup.GET("/status", v1.GetSambaStatus)
 			}
 		}
+		v1NotifyGroup := v1Group.Group("/notify")
+		v1NotifyGroup.Use()
+		{
+			v1NotifyGroup.POST("/:path", v1.PostNotifyMessage)
+			// merge to system
+			v1NotifyGroup.POST("/system_status", v1.PostSystemStatusNotify)
+		}
 	}
 	return r
 }

+ 96 - 5
route/v1/app.go

@@ -3,9 +3,12 @@ package v1
 import (
 	"encoding/json"
 	"io/ioutil"
+	"net/http"
+	"path/filepath"
 	"strconv"
 
 	"github.com/IceWhaleTech/CasaOS/model"
+	"github.com/IceWhaleTech/CasaOS/pkg/utils/command"
 	"github.com/IceWhaleTech/CasaOS/pkg/utils/common_err"
 	"github.com/IceWhaleTech/CasaOS/pkg/utils/file"
 
@@ -14,6 +17,11 @@ import (
 	"github.com/gin-gonic/gin"
 )
 
+const (
+	dockerRootDirFilePath             = "/var/lib/casaos/docker_root"
+	dockerDaemonConfigurationFilePath = "/etc/docker/daemon.json"
+)
+
 // @Summary 获取远程列表
 // @Produce  application/json
 // @Accept application/json
@@ -27,8 +35,7 @@ import (
 // @Success 200 {string} string "ok"
 // @Router /app/list [get]
 func AppList(c *gin.Context) {
-
-	//service.MyService.Docker().DockerContainerCommit("test2")
+	// service.MyService.Docker().DockerContainerCommit("test2")
 
 	index := c.DefaultQuery("index", "1")
 	size := c.DefaultQuery("size", "10000")
@@ -137,7 +144,7 @@ func MyAppList(c *gin.Context) {
 func AppUsageList(c *gin.Context) {
 	list := service.MyService.App().GetHardwareUsage()
 	c.JSON(common_err.SUCCESS, &model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: list})
-	//c.JSON(common_err.SUCCESS, &model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: nil})
+	// c.JSON(common_err.SUCCESS, &model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: nil})
 }
 
 // @Summary 应用详情
@@ -149,7 +156,6 @@ func AppUsageList(c *gin.Context) {
 // @Success 200 {string} string "ok"
 // @Router /app/appinfo/{id} [get]
 func AppInfo(c *gin.Context) {
-
 	id := c.Param("id")
 	language := c.GetHeader("Language")
 	info, err := service.MyService.Casa().GetServerAppInfo(id, "", language)
@@ -211,7 +217,7 @@ func AppInfo(c *gin.Context) {
 	// 	return c1.Type < c2.Type
 	// }
 
-	//sort
+	// sort
 	// if info.NetworkModel != "host" {
 	// 	sort.PortsSort(portOrder).Sort(info.Configures.TcpPorts)
 	// 	sort.PortsSort(portOrder).Sort(info.Configures.UdpPorts)
@@ -262,3 +268,88 @@ func ShareAppFile(c *gin.Context) {
 	content := service.MyService.Casa().ShareAppFile(str)
 	c.JSON(common_err.SUCCESS, json.RawMessage(content))
 }
+
+func GetDockerDaemonConfiguration(c *gin.Context) {
+	// info, err := service.MyService.Docker().GetDockerInfo()
+	// if err != nil {
+	// 	c.JSON(common_err.SERVICE_ERROR, &model.Result{Success: common_err.SERVICE_ERROR, Message: common_err.GetMsg(common_err.SERVICE_ERROR), Data: err.Error()})
+	// 	return
+	// }
+	data := make(map[string]interface{})
+
+	if file.Exists(dockerRootDirFilePath) {
+		buf := file.ReadFullFile(dockerRootDirFilePath)
+		err := json.Unmarshal(buf, &data)
+		if err != nil {
+			c.JSON(common_err.CLIENT_ERROR, &model.Result{Success: common_err.CLIENT_ERROR, Message: common_err.GetMsg(common_err.INVALID_PARAMS), Data: err})
+			return
+		}
+	}
+	c.JSON(common_err.SUCCESS, &model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: data})
+}
+
+func PutDockerDaemonConfiguration(c *gin.Context) {
+	request := make(map[string]interface{})
+	if err := c.BindJSON(&request); err != nil {
+		c.JSON(http.StatusBadRequest, &model.Result{Success: common_err.CLIENT_ERROR, Message: common_err.GetMsg(common_err.INVALID_PARAMS), Data: err})
+		return
+	}
+
+	value, ok := request["docker_root_dir"]
+	if !ok {
+		c.JSON(http.StatusBadRequest, &model.Result{Success: common_err.CLIENT_ERROR, Message: common_err.GetMsg(common_err.INVALID_PARAMS), Data: "`docker_root_dir` should not empty"})
+		return
+	}
+
+	dockerConfig := model.DockerDaemonConfigurationModel{}
+	if file.Exists(dockerDaemonConfigurationFilePath) {
+		byteResult := file.ReadFullFile(dockerDaemonConfigurationFilePath)
+		err := json.Unmarshal(byteResult, &dockerConfig)
+		if err != nil {
+			c.JSON(http.StatusInternalServerError, &model.Result{Success: common_err.SERVICE_ERROR, Message: "error when trying to deserialize " + dockerDaemonConfigurationFilePath, Data: err})
+			return
+		}
+	}
+
+	dockerRootDir := value.(string)
+	if dockerRootDir == "/" {
+		dockerConfig.Root = "" // omitempty - empty string will not be serialized
+	} else {
+		if !file.Exists(dockerRootDir) {
+			c.JSON(http.StatusBadRequest, &model.Result{Success: common_err.CLIENT_ERROR, Message: common_err.GetMsg(common_err.DIR_NOT_EXISTS), Data: common_err.GetMsg(common_err.DIR_NOT_EXISTS)})
+			return
+		}
+
+		dockerConfig.Root = filepath.Join(dockerRootDir, "docker")
+
+		if err := file.IsNotExistMkDir(dockerConfig.Root); err != nil {
+			c.JSON(http.StatusInternalServerError, &model.Result{Success: common_err.SERVICE_ERROR, Message: "error when trying to create " + dockerConfig.Root, Data: err})
+			return
+		}
+	}
+
+	if buf, err := json.Marshal(request); err != nil {
+		c.JSON(http.StatusBadRequest, &model.Result{Success: common_err.CLIENT_ERROR, Message: "error when trying to serialize docker root json", Data: err})
+		return
+	} else {
+		if err := file.WriteToFullPath(buf, dockerRootDirFilePath, 0o644); err != nil {
+			c.JSON(http.StatusInternalServerError, &model.Result{Success: common_err.SERVICE_ERROR, Message: "error when trying to write " + dockerRootDirFilePath, Data: err})
+			return
+		}
+	}
+
+	if buf, err := json.Marshal(dockerConfig); err != nil {
+		c.JSON(http.StatusBadRequest, &model.Result{Success: common_err.CLIENT_ERROR, Message: "error when trying to serialize docker config", Data: dockerConfig})
+		return
+	} else {
+		if err := file.WriteToFullPath(buf, dockerDaemonConfigurationFilePath, 0o644); err != nil {
+			c.JSON(http.StatusInternalServerError, &model.Result{Success: common_err.SERVICE_ERROR, Message: "error when trying to write to " + dockerDaemonConfigurationFilePath, Data: err})
+			return
+		}
+	}
+
+	println(command.ExecResultStr("systemctl daemon-reload"))
+	println(command.ExecResultStr("systemctl restart docker"))
+
+	c.JSON(http.StatusOK, &model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: request})
+}

+ 0 - 622
route/v1/disk.go

@@ -1,622 +0,0 @@
-package v1
-
-import (
-	"fmt"
-	"net/http"
-	"path/filepath"
-	"reflect"
-	"strconv"
-	"strings"
-	"time"
-
-	"github.com/IceWhaleTech/CasaOS/model"
-	"github.com/IceWhaleTech/CasaOS/model/notify"
-	"github.com/IceWhaleTech/CasaOS/pkg/utils/common_err"
-	"github.com/IceWhaleTech/CasaOS/pkg/utils/encryption"
-	"github.com/IceWhaleTech/CasaOS/pkg/utils/file"
-
-	"github.com/IceWhaleTech/CasaOS-Common/utils/jwt"
-	"github.com/IceWhaleTech/CasaOS/service"
-	model2 "github.com/IceWhaleTech/CasaOS/service/model"
-	"github.com/gin-gonic/gin"
-	"github.com/shirou/gopsutil/v3/disk"
-)
-
-var diskMap = make(map[string]string)
-
-// @Summary disk list
-// @Produce  application/json
-// @Accept application/json
-// @Tags disk
-// @Security ApiKeyAuth
-// @Success 200 {string} string "ok"
-// @Router /disk/list [get]
-func GetDiskList(c *gin.Context) {
-	path := c.Query("path")
-	if len(path) > 0 {
-		m := service.MyService.Disk().GetDiskInfo(path)
-		c.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: m})
-		return
-	}
-	t := c.DefaultQuery("type", "")
-	list := service.MyService.Disk().LSBLK(false)
-	if t == "usb" {
-		data := []model.DriveUSB{}
-		for _, v := range list {
-			if v.Tran == "usb" {
-				temp := model.DriveUSB{}
-				temp.Model = v.Model
-				temp.Name = v.Name
-				temp.Size = v.Size
-				for _, child := range v.Children {
-					if len(child.MountPoint) > 0 {
-						avail, _ := strconv.ParseUint(child.FSAvail, 10, 64)
-						temp.Avail += avail
-					}
-				}
-				data = append(data, temp)
-			}
-		}
-		c.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: data})
-		return
-	}
-
-	dbList := service.MyService.Disk().GetSerialAll()
-	part := make(map[string]int64, len(dbList))
-	for _, v := range dbList {
-		part[v.MountPoint] = v.CreatedAt
-	}
-	findSystem := 0
-
-	disks := []model.Drive{}
-	storage := []model.Storage{}
-	avail := []model.Drive{}
-	for i := 0; i < len(list); i++ {
-		disk := model.Drive{}
-		if list[i].Rota {
-			disk.DiskType = "HDD"
-		} else {
-			disk.DiskType = "SSD"
-		}
-		disk.Serial = list[i].Serial
-		disk.Name = list[i].Name
-		disk.Size = list[i].Size
-		disk.Path = list[i].Path
-		disk.Model = list[i].Model
-		disk.ChildrenNumber = len(list[i].Children)
-		if len(list[i].Children) > 0 && findSystem == 0 {
-			for j := 0; j < len(list[i].Children); j++ {
-				if len(list[i].Children[j].Children) > 0 {
-					for _, v := range list[i].Children[j].Children {
-						if v.MountPoint == "/" {
-							stor := model.Storage{}
-							stor.MountPoint = v.MountPoint
-							stor.Size = v.FSSize
-							stor.Avail = v.FSAvail
-							stor.Path = v.Path
-							stor.Type = v.FsType
-							stor.DriveName = "System"
-							disk.Model = "System"
-							if strings.Contains(v.SubSystems, "mmc") {
-								disk.DiskType = "MMC"
-							} else if strings.Contains(v.SubSystems, "usb") {
-								disk.DiskType = "USB"
-							}
-							disk.Health = "true"
-
-							disks = append(disks, disk)
-							storage = append(storage, stor)
-							findSystem = 1
-							break
-						}
-					}
-				} else {
-					if list[i].Children[j].MountPoint == "/" {
-						stor := model.Storage{}
-						stor.MountPoint = list[i].Children[j].MountPoint
-						stor.Size = list[i].Children[j].FSSize
-						stor.Avail = list[i].Children[j].FSAvail
-						stor.Path = list[i].Children[j].Path
-						stor.Type = list[i].Children[j].FsType
-						stor.DriveName = "System"
-						disk.Model = "System"
-						if strings.Contains(list[i].Children[j].SubSystems, "mmc") {
-							disk.DiskType = "MMC"
-						} else if strings.Contains(list[i].Children[j].SubSystems, "usb") {
-							disk.DiskType = "USB"
-						}
-						disk.Health = "true"
-
-						disks = append(disks, disk)
-						storage = append(storage, stor)
-						findSystem = 1
-						break
-					}
-				}
-
-			}
-		}
-		if findSystem == 1 {
-			findSystem += 1
-			continue
-		}
-
-		if list[i].Tran == "sata" || list[i].Tran == "nvme" || list[i].Tran == "spi" || list[i].Tran == "sas" || strings.Contains(list[i].SubSystems, "virtio") || (list[i].Tran == "ata" && list[i].Type == "disk") {
-			temp := service.MyService.Disk().SmartCTL(list[i].Path)
-			if reflect.DeepEqual(temp, model.SmartctlA{}) {
-				temp.SmartStatus.Passed = true
-			}
-			isAvail := true
-			for _, v := range list[i].Children {
-				if v.MountPoint != "" {
-					stor := model.Storage{}
-					stor.MountPoint = v.MountPoint
-					stor.Size = v.FSSize
-					stor.Avail = v.FSAvail
-					stor.Path = v.Path
-					stor.Type = v.FsType
-					stor.DriveName = list[i].Name
-					storage = append(storage, stor)
-					isAvail = false
-				}
-			}
-
-			if isAvail {
-				//if len(list[i].Children) == 1 && list[i].Children[0].FsType == "ext4" {
-				disk.NeedFormat = false
-				avail = append(avail, disk)
-				// } else {
-				// 	disk.NeedFormat = true
-				// 	avail = append(avail, disk)
-				// }
-			}
-
-			disk.Temperature = temp.Temperature.Current
-			disk.Health = strconv.FormatBool(temp.SmartStatus.Passed)
-
-			disks = append(disks, disk)
-		}
-	}
-	data := make(map[string]interface{}, 3)
-	data["drive"] = disks
-	data["storage"] = storage
-	data["avail"] = avail
-
-	c.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: data})
-}
-
-// @Summary disk list
-// @Produce  application/json
-// @Accept application/json
-// @Tags disk
-// @Security ApiKeyAuth
-// @Success 200 {string} string "ok"
-// @Router /disk/list [get]
-func GetDisksUSBList(c *gin.Context) {
-	list := service.MyService.Disk().LSBLK(false)
-	data := []model.DriveUSB{}
-	for _, v := range list {
-		if v.Tran == "usb" {
-			temp := model.DriveUSB{}
-			temp.Model = v.Model
-			temp.Name = v.Label
-			if temp.Name == "" {
-				temp.Name = v.Name
-			}
-			temp.Size = v.Size
-			children := []model.USBChildren{}
-			for _, child := range v.Children {
-
-				if len(child.MountPoint) > 0 {
-					tempChildren := model.USBChildren{}
-					tempChildren.MountPoint = child.MountPoint
-					tempChildren.Size, _ = strconv.ParseUint(child.FSSize, 10, 64)
-					tempChildren.Avail, _ = strconv.ParseUint(child.FSAvail, 10, 64)
-					tempChildren.Name = child.Label
-					if len(tempChildren.Name) == 0 {
-						tempChildren.Name = filepath.Base(child.MountPoint)
-					}
-					avail, _ := strconv.ParseUint(child.FSAvail, 10, 64)
-					children = append(children, tempChildren)
-					temp.Avail += avail
-				}
-			}
-
-			temp.Children = children
-			data = append(data, temp)
-		}
-	}
-	c.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: data})
-
-}
-
-func DeleteDisksUmount(c *gin.Context) {
-	js := make(map[string]string)
-	c.ShouldBind(&js)
-
-	path := js["path"]
-	pwd := js["password"]
-
-	if len(path) == 0 {
-		c.JSON(common_err.CLIENT_ERROR, model.Result{Success: common_err.INVALID_PARAMS, Message: common_err.GetMsg(common_err.INVALID_PARAMS)})
-		return
-	}
-	token := c.GetHeader("Authorization")
-	if len(token) == 0 {
-		token = c.Query("token")
-	}
-	claims, err := jwt.ParseToken(token, true)
-	if err != nil {
-		c.JSON(common_err.CLIENT_ERROR, model.Result{Success: common_err.PWD_INVALID, Message: common_err.GetMsg(common_err.PWD_INVALID)})
-		return
-	}
-
-	if encryption.GetMD5ByStr(pwd) != claims.Password {
-		c.JSON(common_err.CLIENT_ERROR, model.Result{Success: common_err.PWD_INVALID, Message: common_err.GetMsg(common_err.PWD_INVALID)})
-		return
-	}
-
-	if _, ok := diskMap[path]; ok {
-		c.JSON(common_err.SERVICE_ERROR, model.Result{Success: common_err.DISK_BUSYING, Message: common_err.GetMsg(common_err.DISK_BUSYING)})
-		return
-	}
-
-	diskInfo := service.MyService.Disk().GetDiskInfo(path)
-	for _, v := range diskInfo.Children {
-		service.MyService.Disk().UmountPointAndRemoveDir(v.Path)
-		//delete data
-		service.MyService.Disk().DeleteMountPoint(v.Path, v.MountPoint)
-
-		service.MyService.Shares().DeleteShareByPath(v.MountPoint)
-	}
-
-	service.MyService.Disk().RemoveLSBLKCache()
-
-	//send notify to client
-	msg := notify.StorageMessage{}
-	msg.Action = "REMOVED"
-	msg.Path = path
-	msg.Volume = ""
-	msg.Size = 0
-	msg.Type = ""
-	service.MyService.Notify().SendStorageBySocket(msg)
-	c.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: path})
-}
-
-func DeleteDiskUSB(c *gin.Context) {
-	js := make(map[string]string)
-	c.ShouldBind(&js)
-	mountPoint := js["mount_point"]
-	if file.CheckNotExist(mountPoint) {
-		c.JSON(common_err.CLIENT_ERROR, model.Result{Success: common_err.DIR_NOT_EXISTS, Message: common_err.GetMsg(common_err.DIR_NOT_EXISTS)})
-		return
-	}
-	service.MyService.Disk().UmountUSB(mountPoint)
-	c.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: mountPoint})
-}
-
-// @Summary get disk list
-// @Produce  application/json
-// @Accept application/json
-// @Tags disk
-// @Security ApiKeyAuth
-// @Success 200 {string} string "ok"
-// @Router /disk/lists [get]
-func GetPlugInDisks(c *gin.Context) {
-
-	list := service.MyService.Disk().LSBLK(true)
-	var result []*disk.UsageStat
-	for _, item := range list {
-		result = append(result, service.MyService.Disk().GetDiskInfoByPath(item.Path))
-	}
-	c.JSON(http.StatusOK, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: result})
-}
-
-// @Summary disk detail
-// @Produce  application/json
-// @Accept application/json
-// @Tags disk
-// @Security ApiKeyAuth
-// @Param  path query string true "for example /dev/sda"
-// @Success 200 {string} string "ok"
-// @Router /disk/info [get]
-func GetDiskInfo(c *gin.Context) {
-	path := c.Query("path")
-	if len(path) == 0 {
-		c.JSON(http.StatusOK, model.Result{Success: common_err.INVALID_PARAMS, Message: common_err.GetMsg(common_err.INVALID_PARAMS)})
-	}
-	m := service.MyService.Disk().GetDiskInfo(path)
-	c.JSON(http.StatusOK, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: m})
-}
-
-// @Summary 获取支持的格式
-// @Produce  application/json
-// @Accept application/json
-// @Tags disk
-// @Security ApiKeyAuth
-// @Success 200 {string} string "ok"
-// @Router /disk/type [get]
-func FormatDiskType(c *gin.Context) {
-	var strArr = [4]string{"fat32", "ntfs", "ext4", "exfat"}
-	c.JSON(http.StatusOK, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: strArr})
-
-}
-
-// @Summary 删除分区
-// @Produce  application/json
-// @Accept multipart/form-data
-// @Tags disk
-// @Security ApiKeyAuth
-// @Param  path formData string true "磁盘路径 例如/dev/sda1"
-// @Success 200 {string} string "ok"
-// @Router /disk/delpart [delete]
-func RemovePartition(c *gin.Context) {
-	js := make(map[string]string)
-	c.ShouldBind(&js)
-	path := js["path"]
-
-	if len(path) == 0 {
-		c.JSON(common_err.CLIENT_ERROR, model.Result{Success: common_err.INVALID_PARAMS, Message: common_err.GetMsg(common_err.INVALID_PARAMS)})
-	}
-	var p = path[:len(path)-1]
-	var n = path[len(path)-1:]
-	service.MyService.Disk().DelPartition(p, n)
-	c.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS)})
-}
-
-// @Summary  add storage
-// @Produce  application/json
-// @Accept multipart/form-data
-// @Tags disk
-// @Security ApiKeyAuth
-// @Param  path formData string true "disk path  e.g. /dev/sda"
-// @Param  serial formData string true "serial"
-// @Param  name formData string true "name"
-// @Param  format formData bool true "need format(true)"
-// @Success 200 {string} string "ok"
-// @Router /disk/storage [post]
-func PostDiskAddPartition(c *gin.Context) {
-
-	js := make(map[string]interface{})
-	c.ShouldBind(&js)
-	path := js["path"].(string)
-	name := js["name"].(string)
-	format := js["format"].(bool)
-
-	if len(path) == 0 {
-		c.JSON(common_err.CLIENT_ERROR, model.Result{Success: common_err.INVALID_PARAMS, Message: common_err.GetMsg(common_err.INVALID_PARAMS)})
-		return
-	}
-	if _, ok := diskMap[path]; ok {
-		c.JSON(common_err.SERVICE_ERROR, model.Result{Success: common_err.DISK_BUSYING, Message: common_err.GetMsg(common_err.DISK_BUSYING)})
-		return
-	}
-
-	//diskInfo := service.MyService.Disk().GetDiskInfo(path)
-
-	// if !file.CheckNotExist("/DATA/" + name) {
-	// 	// /mnt/name exist
-	// 	c.JSON(common_err.SERVICE_ERROR, model.Result{Success: common_err.NAME_NOT_AVAILABLE, Message: common_err.GetMsg(common_err.NAME_NOT_AVAILABLE)})
-	// 	return
-	// }
-	diskMap[path] = "busying"
-	currentDisk := service.MyService.Disk().GetDiskInfo(path)
-	if format {
-		// format := service.MyService.Disk().FormatDisk(path+"1", "ext4")
-		// if len(format) == 0 {
-		// 	delete(diskMap, path)
-		// 	c.JSON(common_err.SERVICE_ERROR, model.Result{Success: common_err.FORMAT_ERROR, Message: common_err.GetMsg(common_err.FORMAT_ERROR)})
-		// 	return
-		// }
-		service.MyService.Disk().AddPartition(path)
-	}
-
-	// formatBool := true
-	// for formatBool {
-	// 	currentDisk = service.MyService.Disk().GetDiskInfo(path)
-	// 	if len(currentDisk.Children) > 0 {
-	// 		formatBool = false
-	// 		break
-	// 	}
-	// 	time.Sleep(time.Second)
-	// }
-	currentDisk = service.MyService.Disk().GetDiskInfo(path)
-	// if len(currentDisk.Children) != 1 {
-	// 	c.JSON(common_err.SERVICE_ERROR, model.Result{Success: common_err.DISK_NEEDS_FORMAT, Message: common_err.GetMsg(common_err.DISK_NEEDS_FORMAT)})
-	// 	return
-	// }
-	fmt.Println(name)
-	if len(name) == 0 {
-		name = "Storage"
-	}
-	fmt.Println(name)
-	for i := 0; i < len(currentDisk.Children); i++ {
-		childrenName := currentDisk.Children[i].Label
-		if len(childrenName) == 0 {
-			//childrenName = name + "_" + currentDisk.Children[i].Name
-			childrenName = name + "_" + strconv.Itoa(i+1)
-		}
-		mountPath := "/DATA/" + childrenName
-		if !file.CheckNotExist(mountPath) {
-			ls := service.MyService.System().GetDirPath(mountPath)
-			if len(ls) > 0 {
-				// exist
-				c.JSON(common_err.SERVICE_ERROR, model.Result{Success: common_err.NAME_NOT_AVAILABLE, Message: common_err.GetMsg(common_err.NAME_NOT_AVAILABLE)})
-				return
-			}
-		}
-		m := model2.SerialDisk{}
-		m.MountPoint = mountPath
-		m.Path = currentDisk.Children[i].Path
-		m.UUID = currentDisk.Children[i].UUID
-		m.State = 0
-		m.CreatedAt = time.Now().Unix()
-		service.MyService.Disk().SaveMountPoint(m)
-		//mount dir
-		service.MyService.Disk().MountDisk(currentDisk.Children[i].Path, mountPath)
-	}
-
-	service.MyService.Disk().RemoveLSBLKCache()
-
-	delete(diskMap, path)
-
-	//send notify to client
-	msg := notify.StorageMessage{}
-	msg.Action = "ADDED"
-	msg.Path = currentDisk.Children[0].Path
-	msg.Volume = "/DATA/"
-	msg.Size = currentDisk.Children[0].Size
-	msg.Type = currentDisk.Children[0].Tran
-	service.MyService.Notify().SendStorageBySocket(msg)
-
-	c.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS)})
-}
-
-// @Param  pwd formData string true "user password"
-// @Param  volume formData string true "mount point"
-// @Success 200 {string} string "ok"
-// @Router /disk/format [post]
-func PostDiskFormat(c *gin.Context) {
-	js := make(map[string]string)
-	c.ShouldBind(&js)
-	path := js["path"]
-	t := "ext4"
-	pwd := js["password"]
-	volume := js["volume"]
-	token := c.GetHeader("Authorization")
-	if len(token) == 0 {
-		token = c.Query("token")
-	}
-	claims, err := jwt.ParseToken(token, true)
-	if err != nil {
-		c.JSON(common_err.CLIENT_ERROR, model.Result{Success: common_err.PWD_INVALID, Message: common_err.GetMsg(common_err.PWD_INVALID)})
-		return
-	}
-
-	if encryption.GetMD5ByStr(pwd) != claims.Password {
-		c.JSON(common_err.CLIENT_ERROR, model.Result{Success: common_err.PWD_INVALID, Message: common_err.GetMsg(common_err.PWD_INVALID)})
-		return
-	}
-
-	if len(path) == 0 || len(t) == 0 {
-		c.JSON(common_err.CLIENT_ERROR, model.Result{Success: common_err.INVALID_PARAMS, Message: common_err.GetMsg(common_err.INVALID_PARAMS)})
-		return
-	}
-	if _, ok := diskMap[path]; ok {
-		c.JSON(common_err.SERVICE_ERROR, model.Result{Success: common_err.DISK_BUSYING, Message: common_err.GetMsg(common_err.DISK_BUSYING)})
-		return
-	}
-	diskMap[path] = "busying"
-	service.MyService.Disk().UmountPointAndRemoveDir(path)
-	format := service.MyService.Disk().FormatDisk(path, t)
-	if len(format) == 0 {
-		delete(diskMap, path)
-		c.JSON(common_err.SERVICE_ERROR, model.Result{Success: common_err.FORMAT_ERROR, Message: common_err.GetMsg(common_err.FORMAT_ERROR)})
-		return
-	}
-	service.MyService.Disk().MountDisk(path, volume)
-	service.MyService.Disk().RemoveLSBLKCache()
-	delete(diskMap, path)
-	c.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS)})
-}
-
-// @Summary remove mount point
-// @Produce  application/json
-// @Accept multipart/form-data
-// @Tags disk
-// @Security ApiKeyAuth
-// @Param  path formData string true "e.g. /dev/sda1"
-// @Param  mount_point formData string true "e.g. /mnt/volume1"
-// @Param  pwd formData string true "user password"
-// @Success 200 {string} string "ok"
-// @Router /disk/umount [post]
-func PostDiskUmount(c *gin.Context) {
-	js := make(map[string]string)
-	c.ShouldBind(&js)
-
-	path := js["path"]
-	mountPoint := js["volume"]
-	pwd := js["password"]
-
-	if len(path) == 0 || len(mountPoint) == 0 {
-		c.JSON(common_err.CLIENT_ERROR, model.Result{Success: common_err.INVALID_PARAMS, Message: common_err.GetMsg(common_err.INVALID_PARAMS)})
-		return
-	}
-	token := c.GetHeader("Authorization")
-	if len(token) == 0 {
-		token = c.Query("token")
-	}
-	claims, err := jwt.ParseToken(token, true)
-	if err != nil {
-		c.JSON(common_err.CLIENT_ERROR, model.Result{Success: common_err.PWD_INVALID, Message: common_err.GetMsg(common_err.PWD_INVALID)})
-		return
-	}
-
-	if encryption.GetMD5ByStr(pwd) != claims.Password {
-		c.JSON(common_err.CLIENT_ERROR, model.Result{Success: common_err.PWD_INVALID, Message: common_err.GetMsg(common_err.PWD_INVALID)})
-		return
-	}
-
-	if _, ok := diskMap[path]; ok {
-		c.JSON(common_err.SERVICE_ERROR, model.Result{Success: common_err.DISK_BUSYING, Message: common_err.GetMsg(common_err.DISK_BUSYING)})
-		return
-	}
-
-	service.MyService.Disk().UmountPointAndRemoveDir(path)
-	//delete data
-	service.MyService.Disk().DeleteMountPoint(path, mountPoint)
-	service.MyService.Disk().RemoveLSBLKCache()
-
-	//send notify to client
-	msg := notify.StorageMessage{}
-	msg.Action = "REMOVED"
-	msg.Path = path
-	msg.Volume = mountPoint
-	msg.Size = 0
-	msg.Type = ""
-	service.MyService.Notify().SendStorageBySocket(msg)
-	c.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS)})
-}
-
-// @Summary confirm delete disk
-// @Produce  application/json
-// @Accept application/json
-// @Tags disk
-// @Security ApiKeyAuth
-// @Param  id path string true "id"
-// @Success 200 {string} string "ok"
-// @Router /disk/remove/{id} [delete]
-func DeleteDisk(c *gin.Context) {
-	id := c.Param("id")
-	service.MyService.Disk().DeleteMount(id)
-	c.JSON(http.StatusOK, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS)})
-}
-
-// @Summary check mount point
-// @Produce  application/json
-// @Accept application/json
-// @Tags disk
-// @Security ApiKeyAuth
-// @Success 200 {string} string "ok"
-// @Router /disk/init [get]
-func GetDiskCheck(c *gin.Context) {
-
-	dbList := service.MyService.Disk().GetSerialAll()
-	list := service.MyService.Disk().LSBLK(true)
-
-	mapList := make(map[string]string)
-
-	for _, v := range list {
-		mapList[v.Serial] = "1"
-	}
-
-	for _, v := range dbList {
-		if _, ok := mapList[v.UUID]; !ok {
-			//disk undefind
-			c.JSON(common_err.SERVICE_ERROR, model.Result{Success: common_err.SERVICE_ERROR, Message: common_err.GetMsg(common_err.SERVICE_ERROR), Data: "disk undefind"})
-			return
-		}
-	}
-
-	c.JSON(http.StatusOK, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS)})
-}

+ 2 - 2
route/v1/docker.go

@@ -761,7 +761,7 @@ func ChangAppState(c *gin.Context) {
 func ContainerLog(c *gin.Context) {
 	appId := c.Param("id")
 	log, _ := service.MyService.Docker().DockerContainerLog(appId)
-	c.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: log})
+	c.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: string(log)})
 }
 
 // @Summary 获取容器状态
@@ -877,7 +877,7 @@ func UpdateSetting(c *gin.Context) {
 	if err != nil {
 		service.MyService.Docker().DockerContainerUpdateName(m.ContainerName, id)
 		service.MyService.Docker().DockerContainerStart(id)
-		c.JSON(common_err.SERVICE_ERROR, model.Result{Success: common_err.SERVICE_ERROR, Message: common_err.GetMsg(common_err.SERVICE_ERROR)})
+		c.JSON(common_err.SERVICE_ERROR, model.Result{Success: common_err.SERVICE_ERROR, Message: common_err.GetMsg(common_err.SERVICE_ERROR), Data: err.Error()})
 		return
 	}
 	//		echo -e "hellow\nworld" >>

+ 74 - 66
route/v1/file.go

@@ -16,12 +16,13 @@ import (
 	"sync"
 
 	"github.com/IceWhaleTech/CasaOS/model"
-	"github.com/IceWhaleTech/CasaOS/pkg/config"
 	"github.com/IceWhaleTech/CasaOS/pkg/utils/common_err"
 	"github.com/IceWhaleTech/CasaOS/pkg/utils/file"
+	"github.com/IceWhaleTech/CasaOS/pkg/utils/loger"
 	"github.com/IceWhaleTech/CasaOS/service"
 	"github.com/gin-gonic/gin"
 	uuid "github.com/satori/go.uuid"
+	"go.uber.org/zap"
 )
 
 // @Summary 读取文件
@@ -48,7 +49,7 @@ func GetFilerContent(c *gin.Context) {
 		})
 		return
 	}
-	//文件读取任务是将文件内容读取到内存中。
+	// 文件读取任务是将文件内容读取到内存中。
 	info, err := ioutil.ReadFile(filePath)
 	if err != nil {
 		c.JSON(common_err.SERVICE_ERROR, model.Result{
@@ -84,7 +85,6 @@ func GetLocalFile(c *gin.Context) {
 		return
 	}
 	c.File(path)
-	return
 }
 
 // @Summary download
@@ -97,7 +97,6 @@ func GetLocalFile(c *gin.Context) {
 // @Success 200 {string} string "ok"
 // @Router /file/download [get]
 func GetDownloadFile(c *gin.Context) {
-
 	t := c.Query("format")
 
 	files := c.Query("files")
@@ -136,11 +135,11 @@ func GetDownloadFile(c *gin.Context) {
 		}
 		if !info.IsDir() {
 
-			//打开文件
+			// 打开文件
 			fileTmp, _ := os.Open(filePath)
 			defer fileTmp.Close()
 
-			//获取文件的名称
+			// 获取文件的名称
 			fileName := path.Base(filePath)
 			c.Header("Content-Disposition", "attachment; filename*=utf-8''"+url2.PathEscape(fileName))
 			c.File(filePath)
@@ -180,7 +179,6 @@ func GetDownloadFile(c *gin.Context) {
 			log.Printf("Failed to archive %s: %v", fname, err)
 		}
 	}
-
 }
 
 func GetDownloadSingleFile(c *gin.Context) {
@@ -203,7 +201,7 @@ func GetDownloadSingleFile(c *gin.Context) {
 	defer fileTmp.Close()
 
 	fileName := path.Base(filePath)
-	//c.Header("Content-Disposition", "inline")
+	// c.Header("Content-Disposition", "inline")
 	c.Header("Content-Disposition", "attachment; filename*=utf-8''"+url2.PathEscape(fileName))
 	c.File(filePath)
 }
@@ -236,33 +234,8 @@ func DirPath(c *gin.Context) {
 				info[i].Type = "application"
 			}
 		}
-	} else if path == "/DATA" {
-		disk := make(map[string]string)
-		lsblk := service.MyService.Disk().LSBLK(true)
-		for _, v := range lsblk {
-			if len(v.Children) > 0 {
-				t := v.Tran
-				for _, c := range v.Children {
-					if len(c.Children) > 0 {
-						for _, gc := range c.Children {
-							if len(gc.MountPoint) > 0 {
-								disk[gc.MountPoint] = t
-							}
-						}
-					}
-					if len(c.MountPoint) > 0 {
-						disk[c.MountPoint] = t
-					}
-				}
-
-			}
-		}
-		for i := 0; i < len(info); i++ {
-			if v, ok := disk[info[i].Path]; ok {
-				info[i].Type = v
-			}
-		}
 	}
+
 	for i := 0; i < len(info); i++ {
 		if v, ok := sharesMap[info[i].Path]; ok {
 			ex := make(map[string]interface{})
@@ -274,7 +247,7 @@ func DirPath(c *gin.Context) {
 			info[i].Extensions = ex
 		}
 	}
-	//Hide the files or folders in operation
+	// Hide the files or folders in operation
 	fileQueue := make(map[string]string)
 	if len(service.OpStrArr) > 0 {
 		for _, v := range service.OpStrArr {
@@ -292,6 +265,9 @@ func DirPath(c *gin.Context) {
 
 	pathList := []model.Path{}
 	for i := 0; i < len(info); i++ {
+		if info[i].Name == ".temp" && info[i].IsDir {
+			continue
+		}
 		if _, ok := fileQueue[info[i].Path]; !ok {
 			pathList = append(pathList, info[i])
 		}
@@ -384,7 +360,6 @@ func PostCreateFile(c *gin.Context) {
 // @Success 200 {string} string "ok"
 // @Router /file/upload [get]
 func GetFileUpload(c *gin.Context) {
-
 	relative := c.Query("relativePath")
 	fileName := c.Query("filename")
 	chunkNumber := c.Query("chunkNumber")
@@ -392,7 +367,7 @@ func GetFileUpload(c *gin.Context) {
 	path := c.Query("path")
 	dirPath := ""
 	hash := file.GetHashByContent([]byte(fileName))
-	tempDir := config.AppInfo.TempPath + "/" + hash + strconv.Itoa(totalChunks) + "/"
+	tempDir := filepath.Join(path, ".temp", hash+strconv.Itoa(totalChunks)) + "/"
 	if fileName != relative {
 		dirPath = strings.TrimSuffix(relative, fileName)
 		tempDir += dirPath
@@ -428,55 +403,91 @@ func PostFileUpload(c *gin.Context) {
 	hash := file.GetHashByContent([]byte(fileName))
 
 	if len(path) == 0 {
-		c.JSON(common_err.INVALID_PARAMS, model.Result{Success: common_err.INVALID_PARAMS, Message: common_err.GetMsg(common_err.INVALID_PARAMS)})
+		loger.Error("path should not be empty")
+		c.JSON(http.StatusBadRequest, model.Result{Success: common_err.INVALID_PARAMS, Message: common_err.GetMsg(common_err.INVALID_PARAMS)})
 		return
 	}
-	tempDir := config.AppInfo.TempPath + "/" + hash + strconv.Itoa(totalChunks) + "/"
+	tempDir := filepath.Join(path, ".temp", hash+strconv.Itoa(totalChunks)) + "/"
 
 	if fileName != relative {
 		dirPath = strings.TrimSuffix(relative, fileName)
 		tempDir += dirPath
-		file.MkDir(path + "/" + dirPath)
+		if err := file.MkDir(path + "/" + dirPath); err != nil {
+			loger.Error("error when trying to create `"+path+"/"+dirPath+"`", zap.Error(err))
+			c.JSON(http.StatusInternalServerError, model.Result{Success: common_err.SERVICE_ERROR, Message: err.Error()})
+			return
+		}
 	}
 
 	path += "/" + relative
 
 	if !file.CheckNotExist(tempDir + chunkNumber) {
-		file.RMDir(tempDir + chunkNumber)
+		if err := file.RMDir(tempDir + chunkNumber); err != nil {
+			loger.Error("error when trying to remove existing `"+tempDir+chunkNumber+"`", zap.Error(err))
+			c.JSON(http.StatusInternalServerError, model.Result{Success: common_err.SERVICE_ERROR, Message: err.Error()})
+			return
+		}
 	}
 
 	if totalChunks > 1 {
-		file.IsNotExistMkDir(tempDir)
+		if err := file.IsNotExistMkDir(tempDir); err != nil {
+			loger.Error("error when trying to create `"+tempDir+"`", zap.Error(err))
+			c.JSON(http.StatusInternalServerError, model.Result{Success: common_err.SERVICE_ERROR, Message: err.Error()})
+			return
+		}
+
+		out, err := os.OpenFile(tempDir+chunkNumber, os.O_WRONLY|os.O_CREATE, 0o644)
+		if err != nil {
+			loger.Error("error when trying to open `"+tempDir+chunkNumber+"` for creation", zap.Error(err))
+			c.JSON(http.StatusInternalServerError, model.Result{Success: common_err.SERVICE_ERROR, Message: err.Error()})
+			return
+		}
 
-		out, _ := os.OpenFile(tempDir+chunkNumber, os.O_WRONLY|os.O_CREATE, 0644)
 		defer out.Close()
-		_, err := io.Copy(out, f)
+
+		if _, err := io.Copy(out, f); err != nil { // recommend to use https://github.com/iceber/iouring-go for faster copy
+			loger.Error("error when trying to write to `"+tempDir+chunkNumber+"`", zap.Error(err))
+			c.JSON(http.StatusInternalServerError, model.Result{Success: common_err.SERVICE_ERROR, Message: err.Error()})
+			return
+		}
+
+		fileNum, err := ioutil.ReadDir(tempDir)
 		if err != nil {
-			c.JSON(common_err.SERVICE_ERROR, model.Result{Success: common_err.SERVICE_ERROR, Message: common_err.GetMsg(common_err.SERVICE_ERROR), Data: err.Error()})
+			loger.Error("error when trying to read number of files under `"+tempDir+"`", zap.Error(err))
+			c.JSON(http.StatusInternalServerError, model.Result{Success: common_err.SERVICE_ERROR, Message: err.Error()})
 			return
 		}
+
+		if totalChunks == len(fileNum) {
+			if err := file.SpliceFiles(tempDir, path, totalChunks, 1); err != nil {
+				loger.Error("error when trying to splice files under `"+tempDir+"`", zap.Error(err))
+				c.JSON(http.StatusInternalServerError, model.Result{Success: common_err.SERVICE_ERROR, Message: err.Error()})
+				return
+			}
+
+			if err := file.RMDir(tempDir); err != nil {
+				loger.Error("error when trying to remove `"+tempDir+"`", zap.Error(err))
+				c.JSON(http.StatusInternalServerError, model.Result{Success: common_err.SERVICE_ERROR, Message: err.Error()})
+				return
+			}
+		}
 	} else {
-		out, _ := os.OpenFile(path, os.O_WRONLY|os.O_CREATE, 0644)
-		defer out.Close()
-		_, err := io.Copy(out, f)
+		out, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE, 0o644)
 		if err != nil {
-			c.JSON(common_err.SERVICE_ERROR, model.Result{Success: common_err.SERVICE_ERROR, Message: common_err.GetMsg(common_err.SERVICE_ERROR), Data: err.Error()})
+			loger.Error("error when trying to open `"+path+"` for creation", zap.Error(err))
+			c.JSON(http.StatusInternalServerError, model.Result{Success: common_err.SERVICE_ERROR, Message: err.Error()})
 			return
 		}
-		c.JSON(http.StatusOK, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS)})
-		return
-	}
-	fileNum, err := ioutil.ReadDir(tempDir)
-	if err != nil {
-		c.JSON(common_err.SERVICE_ERROR, model.Result{Success: common_err.SERVICE_ERROR, Message: common_err.GetMsg(common_err.SERVICE_ERROR), Data: err.Error()})
-		return
-	}
-	if totalChunks == len(fileNum) {
-		file.SpliceFiles(tempDir, path, totalChunks, 1)
-		file.RMDir(tempDir)
-	}
 
-	c.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS)})
+		defer out.Close()
+
+		if _, err := io.Copy(out, f); err != nil { // recommend to use https://github.com/iceber/iouring-go for faster copy
+			loger.Error("error when trying to write to `"+path+"`", zap.Error(err))
+			c.JSON(http.StatusInternalServerError, model.Result{Success: common_err.SERVICE_ERROR, Message: common_err.GetMsg(common_err.SERVICE_ERROR), Data: err.Error()})
+			return
+		}
+	}
+	c.JSON(http.StatusOK, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS)})
 }
 
 // @Summary copy or move file
@@ -488,7 +499,6 @@ func PostFileUpload(c *gin.Context) {
 // @Success 200 {string} string "ok"
 // @Router /file/operate [post]
 func PostOperateFileOrDir(c *gin.Context) {
-
 	list := model.FileOperate{}
 	c.ShouldBind(&list)
 
@@ -538,7 +548,6 @@ func PostOperateFileOrDir(c *gin.Context) {
 // @Success 200 {string} string "ok"
 // @Router /file/delete [delete]
 func DeleteFile(c *gin.Context) {
-
 	paths := []string{}
 	c.ShouldBind(&paths)
 	if len(paths) == 0 {
@@ -570,7 +579,6 @@ func DeleteFile(c *gin.Context) {
 // @Success 200 {string} string "ok"
 // @Router /file/update [put]
 func PutFileContent(c *gin.Context) {
-
 	fi := model.FileUpdate{}
 	c.ShouldBind(&fi)
 
@@ -580,7 +588,7 @@ func PutFileContent(c *gin.Context) {
 		c.JSON(common_err.SERVICE_ERROR, model.Result{Success: common_err.FILE_ALREADY_EXISTS, Message: common_err.GetMsg(common_err.FILE_ALREADY_EXISTS)})
 		return
 	}
-	//err := os.Remove(path)
+	// err := os.Remove(path)
 	err := os.RemoveAll(fi.FilePath)
 	if err != nil {
 		c.JSON(common_err.SERVICE_ERROR, model.Result{Success: common_err.FILE_DELETE_ERROR, Message: common_err.GetMsg(common_err.FILE_DELETE_ERROR), Data: err})

+ 23 - 0
route/v1/notiry.go

@@ -0,0 +1,23 @@
+package v1
+
+import (
+	"github.com/IceWhaleTech/CasaOS/model"
+	"github.com/IceWhaleTech/CasaOS/pkg/utils/common_err"
+	"github.com/IceWhaleTech/CasaOS/service"
+	"github.com/gin-gonic/gin"
+)
+
+func PostNotifyMessage(c *gin.Context) {
+	path := c.Param("path")
+	message := make(map[string]interface{})
+	c.ShouldBind(&message)
+	service.MyService.Notify().SendNotify(path, message)
+	c.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS)})
+}
+
+func PostSystemStatusNotify(c *gin.Context) {
+	message := make(map[string]interface{})
+	c.ShouldBind(&message)
+	service.MyService.Notify().SettingSystemTempData(message)
+	c.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS)})
+}

+ 0 - 109
route/v1/storage.go

@@ -1,109 +0,0 @@
-/*
- * @Author: LinkLeong link@icewhale.com
- * @Date: 2022-07-11 16:02:29
- * @LastEditors: LinkLeong
- * @LastEditTime: 2022-08-17 19:14:50
- * @FilePath: /CasaOS/route/v1/storage.go
- * @Description:
- * @Website: https://www.casaos.io
- * Copyright (c) 2022 by icewhale, All Rights Reserved.
- */
-package v1
-
-import (
-	"path/filepath"
-	"reflect"
-
-	"github.com/IceWhaleTech/CasaOS/model"
-	"github.com/IceWhaleTech/CasaOS/pkg/utils/common_err"
-	"github.com/IceWhaleTech/CasaOS/service"
-	"github.com/gin-gonic/gin"
-)
-
-func GetStorageList(c *gin.Context) {
-	system := c.Query("system")
-	storages := []model.Storages{}
-	disks := service.MyService.Disk().LSBLK(false)
-	diskNumber := 1
-	children := 1
-	findSystem := 0
-	for _, d := range disks {
-		if d.Tran != "usb" {
-			tempSystemDisk := false
-			children = 1
-			tempDisk := model.Storages{
-				DiskName: d.Model,
-				Path:     d.Path,
-				Size:     d.Size,
-			}
-
-			storageArr := []model.Storage{}
-			temp := service.MyService.Disk().SmartCTL(d.Path)
-			if reflect.DeepEqual(temp, model.SmartctlA{}) {
-				temp.SmartStatus.Passed = true
-			}
-			for _, v := range d.Children {
-				if v.MountPoint != "" {
-					if findSystem == 0 {
-						if v.MountPoint == "/" {
-							tempDisk.DiskName = "System"
-							findSystem = 1
-							tempSystemDisk = true
-						}
-						if len(v.Children) > 0 {
-							for _, c := range v.Children {
-								if c.MountPoint == "/" {
-									tempDisk.DiskName = "System"
-									findSystem = 1
-									tempSystemDisk = true
-									break
-								}
-							}
-						}
-					}
-
-					stor := model.Storage{}
-					stor.MountPoint = v.MountPoint
-					stor.Size = v.FSSize
-					stor.Avail = v.FSAvail
-					stor.Path = v.Path
-					stor.Type = v.FsType
-					stor.DriveName = v.Name
-					if len(v.Label) == 0 {
-						if stor.MountPoint == "/" {
-							stor.Label = "System"
-						} else {
-							stor.Label = filepath.Base(stor.MountPoint)
-						}
-
-						children += 1
-					} else {
-						stor.Label = v.Label
-					}
-					storageArr = append(storageArr, stor)
-				}
-			}
-
-			if len(storageArr) > 0 {
-				if tempSystemDisk && len(system) > 0 {
-					tempStorageArr := []model.Storage{}
-					for i := 0; i < len(storageArr); i++ {
-						if storageArr[i].MountPoint != "/boot/efi" && storageArr[i].Type != "swap" {
-							tempStorageArr = append(tempStorageArr, storageArr[i])
-						}
-					}
-					tempDisk.Children = tempStorageArr
-					storages = append(storages, tempDisk)
-					diskNumber += 1
-				} else if !tempSystemDisk {
-					tempDisk.Children = storageArr
-					storages = append(storages, tempDisk)
-					diskNumber += 1
-				}
-
-			}
-		}
-	}
-
-	c.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: storages})
-}

+ 10 - 202
route/v1/system.go

@@ -7,7 +7,6 @@ import (
 	"io/ioutil"
 	"net/http"
 	"os"
-	"reflect"
 	"strconv"
 	"strings"
 	"time"
@@ -16,14 +15,12 @@ import (
 	"github.com/IceWhaleTech/CasaOS/model"
 	"github.com/IceWhaleTech/CasaOS/pkg/config"
 	"github.com/IceWhaleTech/CasaOS/pkg/utils/common_err"
-	"github.com/IceWhaleTech/CasaOS/pkg/utils/loger"
 	port2 "github.com/IceWhaleTech/CasaOS/pkg/utils/port"
 	"github.com/IceWhaleTech/CasaOS/pkg/utils/version"
 	"github.com/IceWhaleTech/CasaOS/service"
 	model2 "github.com/IceWhaleTech/CasaOS/service/model"
 	"github.com/IceWhaleTech/CasaOS/types"
 	"github.com/gin-gonic/gin"
-	"go.uber.org/zap"
 )
 
 // @Summary check version
@@ -79,7 +76,7 @@ func GetCasaOSErrorLogs(c *gin.Context) {
 	c.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: service.MyService.System().GetCasaOSLogs(line)})
 }
 
-//系统配置
+// 系统配置
 func GetSystemConfigDebug(c *gin.Context) {
 	array := service.MyService.System().GetSystemConfigDebug()
 	disk := service.MyService.System().GetDiskInfo()
@@ -167,101 +164,6 @@ func PostKillCasaOS(c *gin.Context) {
 	os.Exit(0)
 }
 
-// @Summary Turn off usb auto-mount
-// @Produce  application/json
-// @Accept application/json
-// @Tags sys
-// @Security ApiKeyAuth
-// @Success 200 {string} string "ok"
-// @Router /sys/usb/off [put]
-func PutSystemUSBAutoMount(c *gin.Context) {
-	js := make(map[string]string)
-	c.ShouldBind(&js)
-	status := js["state"]
-	if status == "on" {
-		service.MyService.System().UpdateUSBAutoMount("True")
-		service.MyService.System().ExecUSBAutoMountShell("True")
-	} else {
-		service.MyService.System().UpdateUSBAutoMount("False")
-		service.MyService.System().ExecUSBAutoMountShell("False")
-	}
-	go func() {
-		usbList := service.MyService.Disk().LSBLK(false)
-		usb := []model.DriveUSB{}
-		for _, v := range usbList {
-			if v.Tran == "usb" {
-				isMount := false
-				temp := model.DriveUSB{}
-				temp.Model = v.Model
-				temp.Name = v.Name
-				temp.Size = v.Size
-				for _, child := range v.Children {
-					if len(child.MountPoint) > 0 {
-						isMount = true
-						avail, _ := strconv.ParseUint(child.FSAvail, 10, 64)
-						temp.Avail += avail
-
-					}
-				}
-				if isMount {
-					usb = append(usb, temp)
-				}
-			}
-		}
-		service.MyService.Notify().SendUSBInfoBySocket(usb)
-	}()
-	c.JSON(common_err.SUCCESS,
-		model.Result{
-			Success: common_err.SUCCESS,
-			Message: common_err.GetMsg(common_err.SUCCESS),
-		})
-}
-
-// @Summary Turn off usb auto-mount
-// @Produce  application/json
-// @Accept application/json
-// @Tags sys
-// @Security ApiKeyAuth
-// @Success 200 {string} string "ok"
-// @Router /sys/usb [get]
-func GetSystemUSBAutoMount(c *gin.Context) {
-	state := "True"
-	if config.ServerInfo.USBAutoMount == "False" {
-		state = "False"
-	}
-	go func() {
-		usbList := service.MyService.Disk().LSBLK(false)
-		usb := []model.DriveUSB{}
-		for _, v := range usbList {
-			if v.Tran == "usb" {
-				isMount := false
-				temp := model.DriveUSB{}
-				temp.Model = v.Model
-				temp.Name = v.Name
-				temp.Size = v.Size
-				for _, child := range v.Children {
-					if len(child.MountPoint) > 0 {
-						isMount = true
-						avail, _ := strconv.ParseUint(child.FSAvail, 10, 64)
-						temp.Avail += avail
-
-					}
-				}
-				if isMount {
-					usb = append(usb, temp)
-				}
-			}
-		}
-		service.MyService.Notify().SendUSBInfoBySocket(usb)
-	}()
-	c.JSON(common_err.SUCCESS,
-		model.Result{
-			Success: common_err.SUCCESS,
-			Message: common_err.GetMsg(common_err.SUCCESS),
-			Data:    state,
-		})
-}
-
 func GetSystemAppsStatus(c *gin.Context) {
 	systemAppList := service.MyService.App().GetSystemAppList()
 	appList := []model2.MyAppList{}
@@ -278,12 +180,12 @@ func GetSystemAppsStatus(c *gin.Context) {
 			Id:       v.ID,
 			Port:     v.Labels["web"],
 			Index:    v.Labels["index"],
-			//Order:      m.Labels["order"],
+			// Order:      m.Labels["order"],
 			Image:  v.Image,
 			Latest: false,
-			//Type:   m.Labels["origin"],
-			//Slogan: m.Slogan,
-			//Rely:     m.Rely,
+			// Type:   m.Labels["origin"],
+			// Slogan: m.Slogan,
+			// Rely:     m.Rely,
 			Host:     v.Labels["host"],
 			Protocol: v.Labels["protocol"],
 		})
@@ -304,7 +206,6 @@ func GetSystemAppsStatus(c *gin.Context) {
 // @Success 200 {string} string "ok"
 // @Router /sys/hardware/info [get]
 func GetSystemHardwareInfo(c *gin.Context) {
-
 	data := make(map[string]string, 1)
 	data["drive_model"] = service.MyService.System().GetDeviceTree()
 	c.JSON(common_err.SUCCESS,
@@ -323,99 +224,7 @@ func GetSystemHardwareInfo(c *gin.Context) {
 // @Success 200 {string} string "ok"
 // @Router /sys/utilization [get]
 func GetSystemUtilization(c *gin.Context) {
-	var data = make(map[string]interface{}, 6)
-
-	list := service.MyService.Disk().LSBLK(true)
-
-	summary := model.Summary{}
-	healthy := true
-	findSystem := 0
-
-	for i := 0; i < len(list); i++ {
-		if len(list[i].Children) > 0 && findSystem == 0 {
-
-			for j := 0; j < len(list[i].Children); j++ {
-
-				if len(list[i].Children[j].Children) > 0 {
-					for _, v := range list[i].Children[j].Children {
-						if v.MountPoint == "/" {
-							s, _ := strconv.ParseUint(v.FSSize, 10, 64)
-							a, _ := strconv.ParseUint(v.FSAvail, 10, 64)
-							u, _ := strconv.ParseUint(v.FSUsed, 10, 64)
-							loger.Info("disk info", zap.Any("/ total:", s))
-							loger.Info("disk path", zap.Any("path", v.Path))
-							summary.Size += s
-							summary.Avail += a
-							summary.Used += u
-							findSystem = 1
-							break
-						}
-					}
-				} else {
-					if list[i].Children[j].MountPoint == "/" {
-						s, _ := strconv.ParseUint(list[i].Children[j].FSSize, 10, 64)
-						a, _ := strconv.ParseUint(list[i].Children[j].FSAvail, 10, 64)
-						u, _ := strconv.ParseUint(list[i].Children[j].FSUsed, 10, 64)
-						loger.Info("disk info", zap.Any("/ total:", s))
-						loger.Info("disk path", zap.Any("path", list[i].Path))
-						summary.Size += s
-						summary.Avail += a
-						summary.Used += u
-						findSystem = 1
-						break
-					}
-				}
-			}
-
-		}
-		if findSystem == 1 {
-			findSystem += 1
-			continue
-		}
-		if list[i].Tran == "sata" || list[i].Tran == "nvme" || list[i].Tran == "spi" || list[i].Tran == "sas" || strings.Contains(list[i].SubSystems, "virtio") || (list[i].Tran == "ata" && list[i].Type == "disk") {
-			temp := service.MyService.Disk().SmartCTL(list[i].Path)
-			if reflect.DeepEqual(temp, model.SmartctlA{}) {
-				healthy = true
-			} else {
-				healthy = temp.SmartStatus.Passed
-			}
-			if len(list[i].Children) > 0 {
-				for _, v := range list[i].Children {
-					s, _ := strconv.ParseUint(v.FSSize, 10, 64)
-					a, _ := strconv.ParseUint(v.FSAvail, 10, 64)
-					u, _ := strconv.ParseUint(v.FSUsed, 10, 64)
-					loger.Info("disk info", zap.Any("/ total:", s))
-					loger.Info("disk path", zap.Any("path", list[i].Path))
-					summary.Size += s
-					summary.Avail += a
-					summary.Used += u
-				}
-			}
-
-		}
-	}
-
-	summary.Health = healthy
-	data["disk"] = summary
-	usbList := service.MyService.Disk().LSBLK(false)
-	usb := []model.DriveUSB{}
-	for _, v := range usbList {
-		if v.Tran == "usb" {
-			temp := model.DriveUSB{}
-			temp.Model = v.Model
-			temp.Name = v.Name
-			temp.Size = v.Size
-
-			for _, child := range v.Children {
-				if len(child.MountPoint) > 0 {
-					avail, _ := strconv.ParseUint(child.FSAvail, 10, 64)
-					temp.Avail += avail
-				}
-			}
-			usb = append(usb, temp)
-		}
-	}
-	data["usb"] = usb
+	data := make(map[string]interface{})
 	cpu := service.MyService.System().GetCpuPercent()
 	num := service.MyService.System().GetCpuCoreNum()
 	cpuData := make(map[string]interface{})
@@ -427,7 +236,7 @@ func GetSystemUtilization(c *gin.Context) {
 	data["cpu"] = cpuData
 	data["mem"] = service.MyService.System().GetMemInfo()
 
-	//拼装网络信息
+	// 拼装网络信息
 	netList := service.MyService.System().GetNetInfo()
 	newNet := []model.IOCountersStat{}
 	nets := service.MyService.System().GetNet(true)
@@ -444,7 +253,9 @@ func GetSystemUtilization(c *gin.Context) {
 	}
 
 	data["net"] = newNet
-
+	for k, v := range service.MyService.Notify().GetSystemTempMap() {
+		data[k] = v
+	}
 	c.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: data})
 }
 
@@ -456,7 +267,6 @@ func GetSystemUtilization(c *gin.Context) {
 // @Success 200 {string} string "ok"
 // @Router /sys/socket/port [get]
 func GetSystemSocketPort(c *gin.Context) {
-
 	c.JSON(common_err.SUCCESS,
 		model.Result{
 			Success: common_err.SUCCESS,
@@ -479,7 +289,6 @@ func GetSystemCupInfo(c *gin.Context) {
 	data["percent"] = cpu
 	data["num"] = num
 	c.JSON(http.StatusOK, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: data})
-
 }
 
 // @Summary get mem info
@@ -492,7 +301,6 @@ func GetSystemCupInfo(c *gin.Context) {
 func GetSystemMemInfo(c *gin.Context) {
 	mem := service.MyService.System().GetMemInfo()
 	c.JSON(http.StatusOK, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: mem})
-
 }
 
 // @Summary get disk info

+ 0 - 8
service/casa.go

@@ -130,10 +130,6 @@ func (o *casaService) AsyncGetServerList() (collection model.ServerAppListCollec
 	errr := json2.Unmarshal(results, &collection)
 	if errr != nil {
 		loger.Error("marshal error", zap.Any("err", err), zap.Any("content", string(results)))
-	} else {
-		if collection.Version == o.GetCasaosVersion().Version {
-			return collection, err
-		}
 	}
 
 	head := make(map[string]string)
@@ -204,10 +200,6 @@ func (o *casaService) AsyncGetServerCategoryList() ([]model.CategoryList, error)
 	err := json2.Unmarshal(results, &list)
 	if err != nil {
 		loger.Error("marshal error", zap.Any("err", err), zap.Any("content", string(results)))
-	} else {
-		if list.Version == o.GetCasaosVersion().Version {
-			return list.Item, nil
-		}
 	}
 	item := []model.CategoryList{}
 	head := make(map[string]string)

+ 0 - 285
service/disk.go

@@ -1,285 +0,0 @@
-package service
-
-import (
-	json2 "encoding/json"
-	"fmt"
-	"reflect"
-	"strconv"
-	"strings"
-	"time"
-
-	"github.com/IceWhaleTech/CasaOS/model"
-	"github.com/IceWhaleTech/CasaOS/pkg/config"
-	command2 "github.com/IceWhaleTech/CasaOS/pkg/utils/command"
-	"github.com/IceWhaleTech/CasaOS/pkg/utils/loger"
-	model2 "github.com/IceWhaleTech/CasaOS/service/model"
-	"github.com/shirou/gopsutil/v3/disk"
-	"github.com/tidwall/gjson"
-	"go.uber.org/zap"
-	"gorm.io/gorm"
-)
-
-type DiskService interface {
-	GetPlugInDisk() []string
-	LSBLK(isUseCache bool) []model.LSBLKModel
-	SmartCTL(path string) model.SmartctlA
-	FormatDisk(path, format string) []string
-	UmountPointAndRemoveDir(path string) []string
-	GetDiskInfo(path string) model.LSBLKModel
-	DelPartition(path, num string) string
-	AddPartition(path string) string
-	GetDiskInfoByPath(path string) *disk.UsageStat
-	MountDisk(path, volume string)
-	GetSerialAll() []model2.SerialDisk
-	SaveMountPoint(m model2.SerialDisk)
-	DeleteMountPoint(path, mountPoint string)
-	DeleteMount(id string)
-	UpdateMountPoint(m model2.SerialDisk)
-	RemoveLSBLKCache()
-	UmountUSB(path string)
-}
-type diskService struct {
-	db *gorm.DB
-}
-
-func (d *diskService) RemoveLSBLKCache() {
-	key := "system_lsblk"
-	Cache.Delete(key)
-}
-func (d *diskService) UmountUSB(path string) {
-	r := command2.ExecResultStr("source " + config.AppInfo.ShellPath + "/helper.sh ;UDEVILUmount " + path)
-	fmt.Println(r)
-}
-func (d *diskService) SmartCTL(path string) model.SmartctlA {
-
-	key := "system_smart_" + path
-	if result, ok := Cache.Get(key); ok {
-
-		res, ok := result.(model.SmartctlA)
-		if ok {
-			return res
-		}
-	}
-	var m model.SmartctlA
-	str := command2.ExecSmartCTLByPath(path)
-	if str == nil {
-		loger.Error("failed to  exec shell ", zap.Any("err", "smartctl exec error"))
-		Cache.Add(key, m, time.Minute*10)
-		return m
-	}
-
-	err := json2.Unmarshal([]byte(str), &m)
-	if err != nil {
-		loger.Error("Failed to unmarshal json", zap.Any("err", err))
-	}
-	if !reflect.DeepEqual(m, model.SmartctlA{}) {
-		Cache.Add(key, m, time.Hour*24)
-	}
-	return m
-}
-
-//通过脚本获取外挂磁盘
-func (d *diskService) GetPlugInDisk() []string {
-	return command2.ExecResultStrArray("source " + config.AppInfo.ShellPath + "/helper.sh ;GetPlugInDisk")
-}
-
-//格式化硬盘
-func (d *diskService) FormatDisk(path, format string) []string {
-	r := command2.ExecResultStrArray("source " + config.AppInfo.ShellPath + "/helper.sh ;FormatDisk " + path + " " + format)
-	return r
-}
-
-//移除挂载点,删除目录
-func (d *diskService) UmountPointAndRemoveDir(path string) []string {
-	r := command2.ExecResultStrArray("source " + config.AppInfo.ShellPath + "/helper.sh ;UMountPorintAndRemoveDir " + path)
-	return r
-}
-
-//删除分区
-func (d *diskService) DelPartition(path, num string) string {
-	r := command2.ExecResultStrArray("source " + config.AppInfo.ShellPath + "/helper.sh ;DelPartition " + path + " " + num)
-	fmt.Println(r)
-	return ""
-}
-
-//part
-func (d *diskService) AddPartition(path string) string {
-	command2.ExecResultStrArray("source " + config.AppInfo.ShellPath + "/helper.sh ;AddPartition " + path)
-	return ""
-}
-
-func (d *diskService) AddAllPartition(path string) {
-
-}
-
-//获取硬盘详情
-func (d *diskService) GetDiskInfoByPath(path string) *disk.UsageStat {
-	diskInfo, err := disk.Usage(path + "1")
-
-	if err != nil {
-		fmt.Println(err)
-	}
-	diskInfo.UsedPercent, _ = strconv.ParseFloat(fmt.Sprintf("%.1f", diskInfo.UsedPercent), 64)
-	diskInfo.InodesUsedPercent, _ = strconv.ParseFloat(fmt.Sprintf("%.1f", diskInfo.InodesUsedPercent), 64)
-	return diskInfo
-}
-
-//get disk details
-func (d *diskService) LSBLK(isUseCache bool) []model.LSBLKModel {
-	key := "system_lsblk"
-	var n []model.LSBLKModel
-
-	if result, ok := Cache.Get(key); ok && isUseCache {
-
-		res, ok := result.([]model.LSBLKModel)
-		if ok {
-			return res
-		}
-	}
-
-	str := command2.ExecLSBLK()
-	if str == nil {
-		loger.Error("Failed to exec shell", zap.Any("err", "lsblk exec error"))
-		return nil
-	}
-	var m []model.LSBLKModel
-	err := json2.Unmarshal([]byte(gjson.Get(string(str), "blockdevices").String()), &m)
-	if err != nil {
-		loger.Error("Failed to unmarshal json", zap.Any("err", err))
-	}
-
-	var c []model.LSBLKModel
-
-	var fsused uint64
-
-	var health = true
-	for _, i := range m {
-		if i.Type != "loop" && !i.RO {
-			fsused = 0
-			for _, child := range i.Children {
-				if child.RM {
-					child.Health = strings.TrimSpace(command2.ExecResultStr("source " + config.AppInfo.ShellPath + "/helper.sh ;GetDiskHealthState " + child.Path))
-					if strings.ToLower(strings.TrimSpace(child.State)) != "ok" {
-						health = false
-					}
-					f, _ := strconv.ParseUint(child.FSUsed, 10, 64)
-					fsused += f
-				} else {
-					health = false
-				}
-				c = append(c, child)
-			}
-			//i.Format = strings.TrimSpace(command2.ExecResultStr("source " + config.AppInfo.ShellPath + "/helper.sh ;GetDiskType " + i.Path))
-			if health {
-				i.Health = "OK"
-			}
-			i.FSUsed = strconv.FormatUint(fsused, 10)
-			i.Children = c
-			if fsused > 0 {
-				i.UsedPercent, err = strconv.ParseFloat(fmt.Sprintf("%.4f", float64(fsused)/float64(i.Size)), 64)
-				if err != nil {
-					loger.Error("Failed to parse float", zap.Any("err", err))
-				}
-			}
-			n = append(n, i)
-			health = true
-			c = []model.LSBLKModel{}
-			fsused = 0
-		}
-	}
-	if len(n) > 0 {
-		Cache.Add(key, n, time.Second*100)
-	}
-	return n
-}
-
-func (d *diskService) GetDiskInfo(path string) model.LSBLKModel {
-	str := command2.ExecLSBLKByPath(path)
-	if str == nil {
-		loger.Error("Failed to exec shell", zap.Any("err", "lsblk exec error"))
-		return model.LSBLKModel{}
-	}
-
-	var ml []model.LSBLKModel
-	err := json2.Unmarshal([]byte(gjson.Get(string(str), "blockdevices").String()), &ml)
-	if err != nil {
-		loger.Error("Failed to unmarshal json", zap.Any("err", err))
-		return model.LSBLKModel{}
-	}
-
-	m := model.LSBLKModel{}
-	if len(ml) > 0 {
-		m = ml[0]
-	}
-	return m
-	// 下面为计算是否可以继续分区的部分,暂时不需要
-	chiArr := make(map[string]string)
-	chiList := command2.ExecResultStrArray("source " + config.AppInfo.ShellPath + "/helper.sh ;GetPartitionSectors " + m.Path)
-	if len(chiList) == 0 {
-		loger.Error("chiList length error", zap.Any("err", "chiList length error"))
-	}
-	for i := 0; i < len(chiList); i++ {
-		tempArr := strings.Split(chiList[i], ",")
-		chiArr[tempArr[0]] = chiList[i]
-	}
-	var maxSector uint64 = 0
-	for i := 0; i < len(m.Children); i++ {
-		tempArr := strings.Split(chiArr[m.Children[i].Path], ",")
-		m.Children[i].StartSector, _ = strconv.ParseUint(tempArr[1], 10, 64)
-		m.Children[i].EndSector, _ = strconv.ParseUint(tempArr[2], 10, 64)
-		if m.Children[i].EndSector > maxSector {
-			maxSector = m.Children[i].EndSector
-		}
-
-	}
-	diskEndSector := command2.ExecResultStrArray("source " + config.AppInfo.ShellPath + "/helper.sh ;GetDiskSizeAndSectors " + m.Path)
-
-	if len(diskEndSector) < 2 {
-		loger.Error("diskEndSector length error", zap.Any("err", "diskEndSector length error"))
-	}
-	diskEndSectorInt, _ := strconv.ParseUint(diskEndSector[len(diskEndSector)-1], 10, 64)
-	if (diskEndSectorInt-maxSector)*m.MinIO/1024/1024 > 100 {
-		//添加可以分区情况
-		p := model.LSBLKModel{}
-		p.Path = "可以添加"
-		m.Children = append(m.Children, p)
-	}
-	return m
-}
-
-func (d *diskService) MountDisk(path, volume string) {
-	//fmt.Println("source " + config.AppInfo.ShellPath + "/helper.sh ;do_mount " + path + " " + volume)
-	r := command2.ExecResultStr("source " + config.AppInfo.ShellPath + "/helper.sh ;do_mount " + path + " " + volume)
-	fmt.Println(r)
-}
-
-func (d *diskService) SaveMountPoint(m model2.SerialDisk) {
-	d.db.Where("uuid = ?", m.UUID).Delete(&model2.SerialDisk{})
-	d.db.Create(&m)
-}
-
-func (d *diskService) UpdateMountPoint(m model2.SerialDisk) {
-	d.db.Model(&model2.SerialDisk{}).Where("uui = ?", m.UUID).Update("mount_point", m.MountPoint)
-}
-
-func (d *diskService) DeleteMount(id string) {
-
-	d.db.Delete(&model2.SerialDisk{}).Where("id = ?", id)
-}
-
-func (d *diskService) DeleteMountPoint(path, mountPoint string) {
-
-	d.db.Where("path = ? AND mount_point = ?", path, mountPoint).Delete(&model2.SerialDisk{})
-
-	command2.OnlyExec("source " + config.AppInfo.ShellPath + "/helper.sh ;do_umount " + path)
-}
-
-func (d *diskService) GetSerialAll() []model2.SerialDisk {
-	var m []model2.SerialDisk
-	d.db.Find(&m)
-	return m
-}
-
-func NewDiskService(db *gorm.DB) DiskService {
-	return &diskService{db: db}
-}

+ 53 - 38
service/docker.go

@@ -52,13 +52,14 @@ type DockerService interface {
 	DockerContainerStop(id string) error
 	DockerContainerUpdateName(name, id string) (err error)
 	DockerContainerUpdate(m model.CustomizationPostData, id string) (err error)
-	DockerContainerLog(name string) (string, error)
+	DockerContainerLog(name string) ([]byte, error)
 	DockerContainerCommit(name string)
 	DockerContainerList() []types.Container
 	DockerNetworkModelList() []types.NetworkResource
 	DockerImageInfo(image string) (types.ImageInspect, error)
 	GetNetWorkNameByNetWorkID(id string) (string, error)
 	ContainerExecShell(container_id string) string
+	GetDockerInfo() (types.Info, error)
 }
 
 type dockerService struct {
@@ -94,7 +95,7 @@ func (ds *dockerService) ContainerExecShell(container_id string) string {
 	return exec.ID
 }
 
-//创建默认网络
+// 创建默认网络
 func DockerNetwork() {
 
 	cli, _ := client2.NewClientWithOpts(client2.FromEnv)
@@ -109,7 +110,7 @@ func DockerNetwork() {
 	cli.NetworkCreate(context.Background(), docker.NETWORKNAME, types.NetworkCreate{})
 }
 
-//根据网络id获取网络名
+// 根据网络id获取网络名
 func (ds *dockerService) GetNetWorkNameByNetWorkID(id string) (string, error) {
 	cli, _ := client2.NewClientWithOpts(client2.FromEnv)
 	defer cli.Close()
@@ -122,7 +123,7 @@ func (ds *dockerService) GetNetWorkNameByNetWorkID(id string) (string, error) {
 	return "", err
 }
 
-//拉取镜像
+// 拉取镜像
 func DockerPull() {
 
 	cli, _ := client2.NewClientWithOpts(client2.FromEnv)
@@ -141,7 +142,7 @@ func DockerPull() {
 
 }
 
-//拉取镜像
+// 拉取镜像
 func DockerEx() {
 
 	cli, _ := client2.NewClientWithOpts(client2.FromEnv)
@@ -292,7 +293,7 @@ func DockerLogs() {
 
 //正式内容
 
-//检查镜像是否存在
+// 检查镜像是否存在
 func (ds *dockerService) IsExistImage(imageName string) bool {
 	cli, err := client2.NewClientWithOpts(client2.FromEnv)
 	if err != nil {
@@ -311,7 +312,7 @@ func (ds *dockerService) IsExistImage(imageName string) bool {
 	return false
 }
 
-//安装镜像
+// 安装镜像
 func (ds *dockerService) DockerPullImage(imageName string, icon, name string) error {
 	cli, err := client2.NewClientWithOpts(client2.FromEnv)
 	if err != nil {
@@ -365,12 +366,12 @@ func (ds *dockerService) DockerContainerCopyCreate(info *types.ContainerJSON) (c
 	return container.ID, err
 }
 
-//param imageName 镜像名称
-//param containerDbId 数据库的id
-//param port 容器内部主端口
-//param mapPort 容器主端口映射到外部的端口
-//param tcp 容器其他tcp端口
-//param udp 容器其他udp端口
+// param imageName 镜像名称
+// param containerDbId 数据库的id
+// param port 容器内部主端口
+// param mapPort 容器主端口映射到外部的端口
+// param tcp 容器其他tcp端口
+// param udp 容器其他udp端口
 func (ds *dockerService) DockerContainerCreate(m model.CustomizationPostData, id string) (containerId string, err error) {
 	if len(m.NetworkModel) == 0 {
 		m.NetworkModel = "bridge"
@@ -581,7 +582,7 @@ func (ds *dockerService) DockerContainerCreate(m model.CustomizationPostData, id
 	return containerDb.ID, err
 }
 
-//删除容器
+// 删除容器
 func (ds *dockerService) DockerContainerRemove(name string, update bool) error {
 	cli, err := client2.NewClientWithOpts(client2.FromEnv)
 	if err != nil {
@@ -605,7 +606,7 @@ func (ds *dockerService) DockerContainerRemove(name string, update bool) error {
 	return err
 }
 
-//删除镜像
+// 删除镜像
 func (ds *dockerService) DockerImageRemove(name string) error {
 	cli, err := client2.NewClientWithOpts(client2.FromEnv)
 	if err != nil {
@@ -653,7 +654,7 @@ Loop:
 	return err
 }
 
-//停止镜像
+// 停止镜像
 func (ds *dockerService) DockerContainerStop(id string) error {
 	cli, err := client2.NewClientWithOpts(client2.FromEnv)
 	if err != nil {
@@ -664,7 +665,7 @@ func (ds *dockerService) DockerContainerStop(id string) error {
 	return err
 }
 
-//启动容器
+// 启动容器
 func (ds *dockerService) DockerContainerStart(name string) error {
 	cli, err := client2.NewClientWithOpts(client2.FromEnv)
 	if err != nil {
@@ -675,24 +676,27 @@ func (ds *dockerService) DockerContainerStart(name string) error {
 	return err
 }
 
-//查看日志
-func (ds *dockerService) DockerContainerLog(name string) (string, error) {
+// 查看日志
+func (ds *dockerService) DockerContainerLog(name string) ([]byte, error) {
 	cli, err := client2.NewClientWithOpts(client2.FromEnv)
 	if err != nil {
-		return "", err
+		return []byte(""), err
 	}
 	defer cli.Close()
-	body, err := cli.ContainerLogs(context.Background(), name, types.ContainerLogsOptions{ShowStderr: true, ShowStdout: true})
+	//body, err := cli.ContainerAttach(context.Background(), name, types.ContainerAttachOptions{Logs: true, Stream: false, Stdin: false, Stdout: false, Stderr: false})
+	body, err := cli.ContainerLogs(context.Background(), name, types.ContainerLogsOptions{ShowStdout: true, ShowStderr: true})
+
 	if err != nil {
-		return "", err
+		return []byte(""), err
 	}
 
 	defer body.Close()
 	content, err := ioutil.ReadAll(body)
+	//content, err := ioutil.ReadAll(body)
 	if err != nil {
-		return "", err
+		return []byte(""), err
 	}
-	return string(content), nil
+	return content, nil
 }
 
 func DockerContainerStats1() error {
@@ -714,7 +718,7 @@ func DockerContainerStats1() error {
 	return nil
 }
 
-//获取容器状态
+// 获取容器状态
 func (ds *dockerService) DockerContainerStats(name string) (string, error) {
 	cli, err := client2.NewClientWithOpts(client2.FromEnv)
 	if err != nil {
@@ -733,7 +737,7 @@ func (ds *dockerService) DockerContainerStats(name string) (string, error) {
 	return string(sts), nil
 }
 
-//备份容器
+// 备份容器
 func (ds *dockerService) DockerContainerCommit(name string) {
 	cli, err := client2.NewClientWithOpts(client2.FromEnv)
 	if err != nil {
@@ -778,7 +782,7 @@ func (ds *dockerService) DockerListByImage(image, version string) (*types.Contai
 	return &containers[0], nil
 }
 
-//获取容器详情
+// 获取容器详情
 func (ds *dockerService) DockerContainerInfo(name string) (*types.ContainerJSON, error) {
 
 	cli, err := client2.NewClientWithOpts(client2.FromEnv)
@@ -793,13 +797,13 @@ func (ds *dockerService) DockerContainerInfo(name string) (*types.ContainerJSON,
 	return &d, nil
 }
 
-//更新容器
-//param shares cpu优先级
-//param containerDbId 数据库的id
-//param port 容器内部主端口
-//param mapPort 容器主端口映射到外部的端口
-//param tcp 容器其他tcp端口
-//param udp 容器其他udp端口
+// 更新容器
+// param shares cpu优先级
+// param containerDbId 数据库的id
+// param port 容器内部主端口
+// param mapPort 容器主端口映射到外部的端口
+// param tcp 容器其他tcp端口
+// param udp 容器其他udp端口
 func (ds *dockerService) DockerContainerUpdate(m model.CustomizationPostData, id string) (err error) {
 	cli, err := client2.NewClientWithOpts(client2.FromEnv)
 	if err != nil {
@@ -834,9 +838,9 @@ func (ds *dockerService) DockerContainerUpdate(m model.CustomizationPostData, id
 	return
 }
 
-//更新容器名称
-//param name 容器名称
-//param id 老的容器名称
+// 更新容器名称
+// param name 容器名称
+// param id 老的容器名称
 func (ds *dockerService) DockerContainerUpdateName(name, id string) (err error) {
 	cli, err := client2.NewClientWithOpts(client2.FromEnv)
 	if err != nil {
@@ -851,7 +855,7 @@ func (ds *dockerService) DockerContainerUpdateName(name, id string) (err error)
 	return
 }
 
-//获取网络列表
+// 获取网络列表
 func (ds *dockerService) DockerNetworkModelList() []types.NetworkResource {
 
 	cli, _ := client2.NewClientWithOpts(client2.FromEnv)
@@ -863,6 +867,17 @@ func NewDockerService() DockerService {
 	return &dockerService{rootDir: command2.ExecResultStr(`source ./shell/helper.sh ;GetDockerRootDir`)}
 }
 
+func (ds *dockerService) GetDockerInfo() (types.Info, error) {
+	cli, err := client2.NewClientWithOpts(client2.FromEnv)
+	if err != nil {
+		return types.Info{}, err
+	}
+	defer cli.Close()
+
+	return cli.Info(context.Background())
+
+}
+
 //   ---------------------------------------test------------------------------------
 //func ServiceCreate() {
 //	cli, err := client2.NewClientWithOpts(client2.FromEnv)

+ 0 - 25
service/model/o_disk.go

@@ -1,25 +0,0 @@
-/*
- * @Author: LinkLeong link@icewhale.org
- * @Date: 2021-12-07 17:14:41
- * @LastEditors: LinkLeong
- * @LastEditTime: 2022-08-17 18:46:43
- * @FilePath: /CasaOS/service/model/o_disk.go
- * @Description:
- * @Website: https://www.casaos.io
- * Copyright (c) 2022 by icewhale, All Rights Reserved.
- */
-package model
-
-//SerialAdvanced Technology Attachment (STAT)
-type SerialDisk struct {
-	Id         uint   `gorm:"column:id;primary_key" json:"id"`
-	UUID       string `json:"uuid"`
-	Path       string `json:"path"`
-	State      int    `json:"state"`
-	MountPoint string `json:"mount_point"`
-	CreatedAt  int64  `json:"created_at"`
-}
-
-func (p *SerialDisk) TableName() string {
-	return "o_disk"
-}

+ 36 - 41
service/notify.go

@@ -31,16 +31,38 @@ type NotifyServer interface {
 	SendNetInfoBySocket(netList []model2.IOCountersStat)
 	SendCPUInfoBySocket(cpu map[string]interface{})
 	SendMemInfoBySocket(mem map[string]interface{})
-	SendUSBInfoBySocket(list []model2.DriveUSB)
-	SendDiskInfoBySocket(disk model2.Summary)
 	SendFileOperateNotify(nowSend bool)
 	SendInstallAppBySocket(app notify.Application)
-	SendAllHardwareStatusBySocket(disk model2.Summary, list []model2.DriveUSB, mem map[string]interface{}, cpu map[string]interface{}, netList []model2.IOCountersStat)
+	SendAllHardwareStatusBySocket(mem map[string]interface{}, cpu map[string]interface{}, netList []model2.IOCountersStat)
 	SendStorageBySocket(message notify.StorageMessage)
+	SendNotify(path string, message map[string]interface{})
+	SettingSystemTempData(message map[string]interface{})
+	GetSystemTempMap() map[string]interface{}
 }
 
 type notifyServer struct {
-	db *gorm.DB
+	db            *gorm.DB
+	SystemTempMap map[string]interface{}
+}
+
+func (i *notifyServer) SettingSystemTempData(message map[string]interface{}) {
+	for k, v := range message {
+		i.SystemTempMap[k] = v
+	}
+}
+
+func (i *notifyServer) SendNotify(path string, message map[string]interface{}) {
+	msg := gosf.Message{}
+	msg.Body = message
+	msg.Success = true
+	msg.Text = path
+
+	notify := notify.Message{}
+	notify.Path = path
+	notify.Msg = msg
+
+	NotifyMsg <- notify
+
 }
 
 func (i *notifyServer) SendStorageBySocket(message notify.StorageMessage) {
@@ -58,12 +80,9 @@ func (i *notifyServer) SendStorageBySocket(message notify.StorageMessage) {
 
 	NotifyMsg <- notify
 }
-func (i *notifyServer) SendAllHardwareStatusBySocket(disk model2.Summary, list []model2.DriveUSB, mem map[string]interface{}, cpu map[string]interface{}, netList []model2.IOCountersStat) {
+func (i *notifyServer) SendAllHardwareStatusBySocket(mem map[string]interface{}, cpu map[string]interface{}, netList []model2.IOCountersStat) {
 
 	body := make(map[string]interface{})
-	body["sys_disk"] = disk
-
-	body["sys_usb"] = list
 
 	body["sys_mem"] = mem
 
@@ -71,6 +90,10 @@ func (i *notifyServer) SendAllHardwareStatusBySocket(disk model2.Summary, list [
 
 	body["sys_net"] = netList
 
+	for k, v := range i.SystemTempMap {
+		body[k] = v
+	}
+
 	msg := gosf.Message{}
 	msg.Body = body
 	msg.Success = true
@@ -239,38 +262,6 @@ func (i *notifyServer) SendFileOperateNotify(nowSend bool) {
 
 }
 
-func (i *notifyServer) SendDiskInfoBySocket(disk model2.Summary) {
-	body := make(map[string]interface{})
-	body["data"] = disk
-
-	msg := gosf.Message{}
-	msg.Body = body
-	msg.Success = true
-	msg.Text = "sys_disk"
-
-	notify := notify.Message{}
-	notify.Path = "sys_disk"
-	notify.Msg = msg
-
-	NotifyMsg <- notify
-}
-
-func (i *notifyServer) SendUSBInfoBySocket(list []model2.DriveUSB) {
-	body := make(map[string]interface{})
-	body["data"] = list
-
-	msg := gosf.Message{}
-	msg.Body = body
-	msg.Success = true
-	msg.Text = "sys_usb"
-
-	notify := notify.Message{}
-	notify.Path = "sys_usb"
-	notify.Msg = msg
-
-	NotifyMsg <- notify
-}
-
 func (i *notifyServer) SendMemInfoBySocket(mem map[string]interface{}) {
 	body := make(map[string]interface{})
 	body["data"] = mem
@@ -452,7 +443,11 @@ func SendMeg() {
 // 	}
 
 // }
+func (i *notifyServer) GetSystemTempMap() map[string]interface{} {
 
+	return i.SystemTempMap
+
+}
 func NewNotifyService(db *gorm.DB) NotifyServer {
-	return &notifyServer{db: db}
+	return &notifyServer{db: db, SystemTempMap: make(map[string]interface{})}
 }

+ 0 - 7
service/service.go

@@ -30,7 +30,6 @@ type Repository interface {
 	//User() UserService
 	Docker() DockerService
 	Casa() CasaService
-	Disk() DiskService
 	Notify() NotifyServer
 	Rely() RelyService
 	System() SystemService
@@ -51,7 +50,6 @@ func NewService(db *gorm.DB, RuntimePath string) Repository {
 		app:         NewAppService(db),
 		docker:      NewDockerService(),
 		casa:        NewCasaService(),
-		disk:        NewDiskService(db),
 		notify:      NewNotifyService(db),
 		rely:        NewRelyService(db),
 		system:      NewSystemService(),
@@ -65,7 +63,6 @@ type store struct {
 	app         AppService
 	docker      DockerService
 	casa        CasaService
-	disk        DiskService
 	notify      NotifyServer
 	rely        RelyService
 	system      SystemService
@@ -107,7 +104,3 @@ func (c *store) Docker() DockerService {
 func (c *store) Casa() CasaService {
 	return c.casa
 }
-
-func (c *store) Disk() DiskService {
-	return c.disk
-}

+ 20 - 23
service/system.go

@@ -30,8 +30,6 @@ type SystemService interface {
 	UpdateAssist()
 	UpSystemPort(port string)
 	GetTimeZone() string
-	UpdateUSBAutoMount(state string)
-	ExecUSBAutoMountShell(state string)
 	UpAppOrderFile(str, id string)
 	GetAppOrderFile(id string) []byte
 	GetNet(physics bool) []string
@@ -53,14 +51,7 @@ type SystemService interface {
 	GetCPUTemperature() int
 	GetCPUPower() map[string]string
 }
-type systemService struct {
-}
-
-func (s *systemService) UpdateUSBAutoMount(state string) {
-	config.ServerInfo.USBAutoMount = state
-	config.Cfg.Section("server").Key("USBAutoMount").SetValue(state)
-	config.Cfg.SaveTo(config.SystemConfigInfo.ConfigPath)
-}
+type systemService struct{}
 
 func (c *systemService) MkdirAll(path string) (int, error) {
 	_, err := os.Stat(path)
@@ -76,8 +67,8 @@ func (c *systemService) MkdirAll(path string) (int, error) {
 	}
 	return common_err.SERVICE_ERROR, err
 }
-func (c *systemService) RenameFile(oldF, newF string) (int, error) {
 
+func (c *systemService) RenameFile(oldF, newF string) (int, error) {
 	_, err := os.Stat(newF)
 	if err == nil {
 		return common_err.DIR_ALREADY_EXISTS, nil
@@ -92,6 +83,7 @@ func (c *systemService) RenameFile(oldF, newF string) (int, error) {
 	}
 	return common_err.SERVICE_ERROR, err
 }
+
 func (c *systemService) CreateFile(path string) (int, error) {
 	_, err := os.Stat(path)
 	if err == nil {
@@ -104,9 +96,11 @@ func (c *systemService) CreateFile(path string) (int, error) {
 	}
 	return common_err.SERVICE_ERROR, err
 }
+
 func (c *systemService) GetDeviceTree() string {
 	return command2.ExecResultStr("source " + config.AppInfo.ShellPath + "/helper.sh ;GetDeviceTree")
 }
+
 func (c *systemService) GetSysInfo() host.InfoStat {
 	info, _ := host.Info()
 	return *info
@@ -128,9 +122,7 @@ func (c *systemService) GetNetState(name string) string {
 }
 
 func (c *systemService) GetDirPathOne(path string) (m model.Path) {
-
 	f, err := os.Stat(path)
-
 	if err != nil {
 		return
 	}
@@ -175,6 +167,7 @@ func (c *systemService) GetDirPath(path string) []model.Path {
 	}
 	return dirs
 }
+
 func (c *systemService) GetCpuInfo() []cpu.InfoStat {
 	info, _ := cpu.Info()
 	return info
@@ -207,6 +200,7 @@ func (c *systemService) GetNetInfo() []net.IOCountersStat {
 	parts, _ := net.IOCounters(true)
 	return parts
 }
+
 func (c *systemService) GetNet(physics bool) []string {
 	t := "1"
 	if physics {
@@ -221,10 +215,16 @@ func (s *systemService) UpdateSystemVersion(version string) {
 	}
 	file.CreateFile(config.AppInfo.LogPath + "/upgrade.log")
 	//go command2.OnlyExec("curl -fsSL https://raw.githubusercontent.com/LinkLeong/casaos-alpha/main/update.sh | bash")
-	go command2.OnlyExec("curl -fsSL https://raw.githubusercontent.com/IceWhaleTech/get/main/update.sh | bash")
+	if len(config.ServerInfo.UpdateUrl) > 0 {
+		go command2.OnlyExec("curl -fsSL " + config.ServerInfo.UpdateUrl + " | bash")
+	} else {
+		go command2.OnlyExec("curl -fsSL https://raw.githubusercontent.com/IceWhaleTech/get/main/update.sh | bash")
+	}
+
 	//s.log.Error(config.AppInfo.ProjectPath + "/shell/tool.sh -r " + version)
 	//s.log.Error(command2.ExecResultStr(config.AppInfo.ProjectPath + "/shell/tool.sh -r " + version))
 }
+
 func (s *systemService) UpdateAssist() {
 	command2.ExecResultStrArray("source " + config.AppInfo.ShellPath + "/assist.sh")
 }
@@ -233,14 +233,6 @@ func (s *systemService) GetTimeZone() string {
 	return command2.ExecResultStr("source " + config.AppInfo.ShellPath + "/helper.sh ;GetTimeZone")
 }
 
-func (s *systemService) ExecUSBAutoMountShell(state string) {
-	if state == "False" {
-		command2.OnlyExec("source " + config.AppInfo.ShellPath + "/helper.sh ;USB_Stop_Auto")
-	} else {
-		command2.OnlyExec("source " + config.AppInfo.ShellPath + "/helper.sh ;USB_Start_Auto")
-	}
-}
-
 func (s *systemService) GetSystemConfigDebug() []string {
 	return command2.ExecResultStrArray("source " + config.AppInfo.ShellPath + "/helper.sh ;GetSysInfo")
 }
@@ -248,9 +240,11 @@ func (s *systemService) GetSystemConfigDebug() []string {
 func (s *systemService) UpAppOrderFile(str, id string) {
 	file.WriteToPath([]byte(str), config.AppInfo.DBPath+"/"+id, "app_order.json")
 }
+
 func (s *systemService) GetAppOrderFile(id string) []byte {
 	return file.ReadFullFile(config.AppInfo.UserDataPath + "/" + id + "/app_order.json")
 }
+
 func (s *systemService) UpSystemPort(port string) {
 	if len(port) > 0 && port != config.ServerInfo.HttpPort {
 		config.Cfg.Section("server").Key("HttpPort").SetValue(port)
@@ -258,6 +252,7 @@ func (s *systemService) UpSystemPort(port string) {
 	}
 	config.Cfg.SaveTo(config.SystemConfigInfo.ConfigPath)
 }
+
 func (s *systemService) GetCasaOSLogs(lineNumber int) string {
 	file, err := os.Open(filepath.Join(config.AppInfo.LogPath, fmt.Sprintf("%s.%s",
 		config.AppInfo.LogSaveName,
@@ -294,8 +289,8 @@ func GetDeviceAllIP() []string {
 func (s *systemService) IsServiceRunning(name string) bool {
 	status := command2.ExecResultStr("source " + config.AppInfo.ShellPath + "/helper.sh ;CheckServiceStatus smbd")
 	return strings.TrimSpace(status) == "running"
-
 }
+
 func (s *systemService) GetCPUTemperature() int {
 	outPut := ""
 	if file.Exists("/sys/class/thermal/thermal_zone0/temp") {
@@ -313,6 +308,7 @@ func (s *systemService) GetCPUTemperature() int {
 	}
 	return celsius
 }
+
 func (s *systemService) GetCPUPower() map[string]string {
 	data := make(map[string]string, 2)
 	data["timestamp"] = strconv.FormatInt(time.Now().Unix(), 10)
@@ -323,6 +319,7 @@ func (s *systemService) GetCPUPower() map[string]string {
 	}
 	return data
 }
+
 func NewSystemService() SystemService {
 	return &systemService{}
 }

+ 9 - 10
types/system.go

@@ -1,15 +1,14 @@
-/*
- * @Author: LinkLeong link@icewhale.com
- * @Date: 2022-02-17 18:53:22
- * @LastEditors: LinkLeong
- * @LastEditTime: 2022-09-06 14:27:42
- * @FilePath: /CasaOS/types/system.go
- * @Description:
- * @Website: https://www.casaos.io
- * Copyright (c) 2022 by icewhale, All Rights Reserved.
+/*@Author: LinkLeong link@icewhale.com
+ *@Date: 2022-02-17 18:53:22
+ *@LastEditors: LinkLeong
+ *@LastEditTime: 2022-09-06 14:27:42
+ *@FilePath: /CasaOS/types/system.go
+ *@Description:
+ *@Website: https://www.casaos.io
+ *Copyright (c) 2022 by icewhale, All Rights Reserved.
  */
 package types
 
-const CURRENTVERSION = "0.3.6"
+const CURRENTVERSION = "0.3.7"
 
 const BODY = " "