Compare commits

...

34 Commits

Author SHA1 Message Date
LinkLeong
2beb1c0d82 update changelog 2022-10-19 09:08:11 +01:00
LinkLeong
772c3e0bc0 Merge branch 'v0.3.7' of https://github.com/IceWhaleTech/CasaOS into v0.3.7 2022-10-19 09:00:57 +01:00
LinkLeong
bcda992322 add change log 2022-10-19 09:00:45 +01:00
Tiger Wang
87de9cec0a wip 2022-10-18 18:58:26 -04:00
Tiger Wang
6d47d4ff18 wip 2022-10-18 17:30:00 -04:00
LinkLeong
4bb81e4669 Merge branch 'v0.3.7' of https://github.com/IceWhaleTech/CasaOS into v0.3.7 2022-10-17 06:54:34 +01:00
LinkLeong
c05d837350 add update url 2022-10-17 06:53:23 +01:00
Tiger Wang
8908c39969 wip 2022-10-13 19:33:18 -04:00
Tiger Wang
df0f015944 wip 2022-10-13 16:09:19 -04:00
LinkLeong
46a37f0510 fix upload file 2022-10-13 11:32:30 +01:00
LinkLeong
6ea3cdb364 Utilization interface to supplement disk information 2022-10-13 04:45:17 +01:00
LinkLeong
be80d0cd95 Merge branch 'v0.3.7' of https://github.com/IceWhaleTech/CasaOS into v0.3.7 2022-10-13 04:32:13 +01:00
a624669980@163.com
296e88d099 Merge branch 'v0.3.7' of ssh://github.com/IceWhaleTech/CasaOS into v0.3.7 2022-10-13 11:16:52 +08:00
Tiger Wang
b61a3db611 wip 2022-10-12 16:12:14 -04:00
Tiger Wang
0f3d3e82f5 wip 2022-10-11 23:33:58 -04:00
Tiger Wang
dd66f73157 wip 2022-10-11 23:33:58 -04:00
Tiger Wang
cbbb907d6a wip 2022-10-11 23:33:58 -04:00
Tiger Wang
ff6cdb6fda wip 2022-10-11 23:33:58 -04:00
Tiger Wang
2eac040875 update CasaOS-Common to fix runtime error 2022-10-11 23:33:54 -04:00
Tiger Wang
b41d855f73 change service type to notify for systemd so its status is OK only when service is initialized successfully 2022-10-11 23:31:42 -04:00
Tiger Wang
182bc25343 wip 2022-10-11 23:31:42 -04:00
Tiger Wang
12d5e5db03 update goreleaser configuration 2022-10-11 23:31:42 -04:00
Tiger Wang
455d226dcd remove /DATA directory initialization - moved to local-storage (#578) 2022-10-11 23:31:42 -04:00
LinkLeong
f0448cd1b9 remove temp path 2022-10-11 23:31:42 -04:00
LinkLeong
aff18fa091 add share function to common 2022-10-11 23:31:42 -04:00
LinkLeong
80c347ac01 update http status 2022-10-11 23:31:42 -04:00
LinkLeong
8113f51cf7 remove disk and test common package 2022-10-11 23:31:42 -04:00
LinkLeong
4f491fa22f add system notiry 2022-10-11 23:31:42 -04:00
LinkLeong
3935489d8b add shell script 2022-10-11 23:31:37 -04:00
LinkLeong
d14381e6a2 add send notify function 2022-10-11 23:28:25 -04:00
LinkLeong
466350dd21 update CasaOS-Common 2022-09-13 07:02:21 +01:00
LinkLeong
fb39529e8f update common package 2022-09-10 01:00:01 +01:00
LinkLeong
4434ba522b update upgrade script address 2022-09-09 07:36:49 +01:00
LinkLeong
aac8fe85ba update the way environment variables are displayed 2022-09-09 06:46:51 +01:00
24 changed files with 489 additions and 493 deletions

View File

@@ -18,6 +18,20 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Fixed ### 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 ## [0.3.6-alpha.1] - 2022-09-06

View File

@@ -60,8 +60,6 @@ BUILD_PATH=$(dirname "${BASH_SOURCE[0]}")/../../..
SOURCE_ROOT=${BUILD_PATH}/sysroot SOURCE_ROOT=${BUILD_PATH}/sysroot
APP_NAME="casaos" APP_NAME="casaos"
APP_NAME_FORMAL="CasaOS"
#APP_NAME_FORMAL="casaos-alpha"
# check if migration is needed # check if migration is needed
SOURCE_BIN_PATH=${SOURCE_ROOT}/usr/bin SOURCE_BIN_PATH=${SOURCE_ROOT}/usr/bin
@@ -85,45 +83,6 @@ if [ "${NEED_MIGRATION}" = "false" ]; then
exit 0 exit 0
fi fi
MIGRATION_SERVICE_DIR=${1}
if [ -z "${MIGRATION_SERVICE_DIR}" ]; then
MIGRATION_SERVICE_DIR=${BUILD_PATH}/scripts/migration/service.d/${APP_NAME}
fi
MIGRATION_LIST_FILE=${MIGRATION_SERVICE_DIR}/migration.list
MIGRATION_PATH=()
CURRENT_VERSION_FOUND="false"
# a VERSION_PAIR looks like "v0.3.5 v0.3.6-alpha2"
#
# - "v0.3.5" is the current version installed on this host
# - "v0.3.6-alpha2" is the version of the migration tool from GitHub
while read -r VERSION_PAIR; do
if [ -z "${VERSION_PAIR}" ]; then
continue
fi
# 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)
if [ "${CURRENT_VERSION}" = "${VER1// /}" ] || [ "${CURRENT_VERSION}" = "LEGACY_WITHOUT_VERSION" ]; then
CURRENT_VERSION_FOUND="true"
fi
if [ "${CURRENT_VERSION_FOUND}" = "true" ]; then
MIGRATION_PATH+=("${VER2// /}")
fi
done < "${MIGRATION_LIST_FILE}"
if [ ${#MIGRATION_PATH[@]} -eq 0 ]; then
__warning "No migration path found from ${CURRENT_VERSION} to ${SOURCE_VERSION}"
exit 0
fi
ARCH="unknown" ARCH="unknown"
case $(uname -m) in case $(uname -m) in
@@ -141,22 +100,59 @@ case $(uname -m) in
;; ;;
esac esac
__info "ARCH: ${ARCH}"
MIGRATION_SERVICE_DIR=${1}
if [ -z "${MIGRATION_SERVICE_DIR}" ]; then
MIGRATION_SERVICE_DIR=${BUILD_PATH}/scripts/migration/service.d/${APP_NAME}
fi
MIGRATION_LIST_FILE=${MIGRATION_SERVICE_DIR}/migration.list
MIGRATION_PATH=()
CURRENT_VERSION_FOUND="false"
# a VERSION_PAIR looks like "v0.3.5 <url>"
#
# - "v0.3.5" is the current version installed on this host
# - "<url>" is the url of the migration tool
while read -r VERSION_PAIR; do
if [ -z "${VERSION_PAIR}" ]; then
continue
fi
# obtain "v0.3.5" from "v0.3.5 v0.3.6-alpha2"
VER1=$(echo "${VERSION_PAIR}" | cut -d' ' -f1)
# 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+=("${URL// /}")
fi
done < "${MIGRATION_LIST_FILE}"
if [ ${#MIGRATION_PATH[@]} -eq 0 ]; then
__warning "No migration path found from ${CURRENT_VERSION} to ${SOURCE_VERSION}"
exit 0
fi
pushd "${MIGRATION_SERVICE_DIR}" pushd "${MIGRATION_SERVICE_DIR}"
{ for VER2 in "${MIGRATION_PATH[@]}"; do { for URL in "${MIGRATION_PATH[@]}"; do
MIGRATION_TOOL_FILE=$(basename "${URL}")
MIGRATION_TOOL_FILE=linux-"${ARCH}"-"${APP_NAME}"-migration-tool-"${VER2}".tar.gz
if [ -f "${MIGRATION_TOOL_FILE}" ]; then if [ -f "${MIGRATION_TOOL_FILE}" ]; then
__info "Migration tool ${MIGRATION_TOOL_FILE} exists. Skip downloading." __info "Migration tool ${MIGRATION_TOOL_FILE} exists. Skip downloading."
continue continue
fi fi
# MIGRATION_TOOL_URL=http://192.168.2.197:8000/v1/package/migration?type=release&name="${APP_NAME_FORMAL}"&version=${VER2}&arch=${ARCH} __info "Dowloading ${URL}..."
MIGRATION_TOOL_URL=https://github.com/IceWhaleTech/"${APP_NAME_FORMAL}"/releases/download/"${VER2}"/linux-"${ARCH}"-"${APP_NAME}"-migration-tool-"${VER2}".tar.gz curl -fsSL -o "${MIGRATION_TOOL_FILE}" -O "${URL}"
echo "Dowloading ${MIGRATION_TOOL_URL}..."
curl -sL -O "${MIGRATION_TOOL_URL}"
done done
} || { } || {
popd popd
@@ -164,8 +160,8 @@ pushd "${MIGRATION_SERVICE_DIR}"
} }
{ {
for VER2 in "${MIGRATION_PATH[@]}"; do for URL in "${MIGRATION_PATH[@]}"; do
MIGRATION_TOOL_FILE=linux-"${ARCH}"-"${APP_NAME}"-migration-tool-"${VER2}".tar.gz MIGRATION_TOOL_FILE=$(basename "${URL}")
__info "Extracting ${MIGRATION_TOOL_FILE}..." __info "Extracting ${MIGRATION_TOOL_FILE}..."
tar zxvf "${MIGRATION_TOOL_FILE}" || __error "Failed to extract ${MIGRATION_TOOL_FILE}" tar zxvf "${MIGRATION_TOOL_FILE}" || __error "Failed to extract ${MIGRATION_TOOL_FILE}"

View File

@@ -1,4 +1,3 @@
LEGACY_WITHOUT_VERSION 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 v0.3.6 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 v0.3.6 v0.3.5.1 https://github.com/IceWhaleTech/CasaOS/releases/download/v0.3.6/linux-${ARCH}-casaos-migration-tool-v0.3.6.tar.gz
v0.3.6 v0.3.7

View File

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

View File

@@ -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}"

View File

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

View File

@@ -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

View File

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

View File

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

View File

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

View File

@@ -83,8 +83,7 @@ func main() {
} }
migrationTools := []interfaces.MigrationTool{ migrationTools := []interfaces.MigrationTool{
NewMigrationToolFor_035(), // nothing to migrate from last version
NewMigrationToolFor_036(),
} }
var selectedMigrationTool interfaces.MigrationTool var selectedMigrationTool interfaces.MigrationTool
@@ -115,8 +114,7 @@ func main() {
panic(err) panic(err)
} }
selectedMigrationTool.PostMigrate() if err := selectedMigrationTool.PostMigrate(); err != nil {
_logger.Info("casaos migration ok") _logger.Error("Migration succeeded, but post-migration failed: %s", err)
// panic(err) }
} }

View File

@@ -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 migrationTool036 struct{}
func (u *migrationTool036) 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 *migrationTool036) PreMigrate() error {
return nil
}
func (u *migrationTool036) 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 *migrationTool036) PostMigrate() error {
return nil
}
func NewMigrationToolFor_035() interfaces.MigrationTool {
return &migrationTool{}
}

View File

@@ -11,18 +11,13 @@
package main package main
import ( import (
"strings"
interfaces "github.com/IceWhaleTech/CasaOS-Common" interfaces "github.com/IceWhaleTech/CasaOS-Common"
"github.com/IceWhaleTech/CasaOS-Common/utils/version" "github.com/IceWhaleTech/CasaOS-Common/utils/version"
"github.com/IceWhaleTech/CasaOS/pkg/config"
"github.com/IceWhaleTech/CasaOS/service"
) )
type migrationTool struct{} type migrationTool struct{}
func (u *migrationTool) IsMigrationNeeded() (bool, error) { func (u *migrationTool) IsMigrationNeeded() (bool, error) {
majorVersion, minorVersion, patchVersion, err := version.DetectLegacyVersion() majorVersion, minorVersion, patchVersion, err := version.DetectLegacyVersion()
if err != nil { if err != nil {
if err == version.ErrLegacyVersionNotFound { if err == version.ErrLegacyVersionNotFound {
@@ -46,22 +41,13 @@ func (u *migrationTool) IsMigrationNeeded() (bool, error) {
_logger.Info("Migration is needed for a CasaOS version 0.3.5 and older...") _logger.Info("Migration is needed for a CasaOS version 0.3.5 and older...")
return true, nil return true, nil
} }
func (u *migrationTool) PreMigrate() error { func (u *migrationTool) PreMigrate() error {
return nil return nil
} }
func (u *migrationTool) Migrate() error { 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")
}
_logger.Info("update done")
return nil return nil
} }

View File

@@ -1,64 +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"
"runtime/debug"
"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)
debug.PrintStack()
}
}()
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()
}
}
}

View File

@@ -26,6 +26,7 @@ type ServerModel struct {
Token string Token string
USBAutoMount string USBAutoMount string
SocketPort string SocketPort string
UpdateUrl string
} }
// 服务配置 // 服务配置

View File

@@ -362,21 +362,27 @@ func WriteToFullPath(data []byte, fullPath string, perm fs.FileMode) error {
func SpliceFiles(dir, path string, length int, startPoint int) error { func SpliceFiles(dir, path string, length int, startPoint int) error {
fullPath := path fullPath := path
IsNotExistCreateFile(fullPath) if err := IsNotExistCreateFile(fullPath); err != nil {
return err
}
file, _ := os.OpenFile(fullPath, file, _ := os.OpenFile(fullPath,
os.O_WRONLY|os.O_TRUNC|os.O_CREATE, os.O_WRONLY|os.O_TRUNC|os.O_CREATE,
0o666, 0o666,
) )
defer file.Close() defer file.Close()
bufferedWriter := bufio.NewWriter(file) 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)) data, err := ioutil.ReadFile(dir + "/" + strconv.Itoa(i+startPoint))
if err != nil { if err != nil {
return err return err
} }
_, err = bufferedWriter.Write(data) if _, err := bufferedWriter.Write(data); err != nil { // recommend to use https://github.com/iceber/iouring-go for faster write
if err != nil {
return err return err
} }
} }

View File

@@ -1,8 +1,10 @@
package route package route
import ( import (
"os"
"github.com/IceWhaleTech/CasaOS-Common/middleware"
"github.com/IceWhaleTech/CasaOS-Common/utils/jwt" "github.com/IceWhaleTech/CasaOS-Common/utils/jwt"
"github.com/IceWhaleTech/CasaOS/middleware"
"github.com/IceWhaleTech/CasaOS/pkg/config" "github.com/IceWhaleTech/CasaOS/pkg/config"
v1 "github.com/IceWhaleTech/CasaOS/route/v1" v1 "github.com/IceWhaleTech/CasaOS/route/v1"
@@ -11,12 +13,22 @@ import (
) )
func InitRouter() *gin.Engine { func InitRouter() *gin.Engine {
r := gin.Default() 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.New()
r.Use(gin.Recovery())
r.Use(middleware.Cors()) r.Use(middleware.Cors())
r.Use(middleware.WriteLog())
r.Use(gzip.Gzip(gzip.DefaultCompression)) 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.StaticFS("/ui", http.FS(web.Static))
// r.GET("/", WebUIHome) // r.GET("/", WebUIHome)
@@ -134,9 +146,6 @@ func InitRouter() *gin.Engine {
// v1SysGroup.GET("/disk", v1.GetSystemDiskInfo) // v1SysGroup.GET("/disk", v1.GetSystemDiskInfo)
// v1SysGroup.GET("/network", v1.GetSystemNetInfo) // 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.GET("/server-info", nil)
v1SysGroup.PUT("/server-info", nil) v1SysGroup.PUT("/server-info", nil)
v1SysGroup.GET("/apps-state", v1.GetSystemAppsStatus) v1SysGroup.GET("/apps-state", v1.GetSystemAppsStatus)

View File

@@ -18,6 +18,7 @@ import (
) )
const ( const (
dockerRootDirFilePath = "/var/lib/casaos/docker_root"
dockerDaemonConfigurationFilePath = "/etc/docker/daemon.json" dockerDaemonConfigurationFilePath = "/etc/docker/daemon.json"
) )
@@ -274,36 +275,27 @@ func GetDockerDaemonConfiguration(c *gin.Context) {
// c.JSON(common_err.SERVICE_ERROR, &model.Result{Success: common_err.SERVICE_ERROR, Message: common_err.GetMsg(common_err.SERVICE_ERROR), Data: err.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 // return
// } // }
dockerConfig := model.DockerDaemonConfigurationModel{} data := make(map[string]interface{})
data := make(map[string]interface{}, 1)
data["docker_root_dir"] = ""
// TODO read dockerRootDir from /etc/casaos/casaos.conf if file.Exists(dockerRootDirFilePath) {
if file.Exists(dockerDaemonConfigurationFilePath) { buf := file.ReadFullFile(dockerRootDirFilePath)
byteResult := file.ReadFullFile(dockerDaemonConfigurationFilePath) err := json.Unmarshal(buf, &data)
err := json.Unmarshal(byteResult, &dockerConfig)
if err != nil { 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.Error()}) c.JSON(common_err.CLIENT_ERROR, &model.Result{Success: common_err.CLIENT_ERROR, Message: common_err.GetMsg(common_err.INVALID_PARAMS), Data: err})
return return
} }
if dockerConfig.Root != "" {
data["docker_root_dir"] = dockerConfig.Root
} else {
data["docker_root_dir"] = "/var/lib/docker"
}
} }
c.JSON(common_err.SUCCESS, &model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: data}) 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) { func PutDockerDaemonConfiguration(c *gin.Context) {
js := make(map[string]interface{}) request := make(map[string]interface{})
if err := c.BindJSON(&js); err != nil { 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.Error()}) c.JSON(http.StatusBadRequest, &model.Result{Success: common_err.CLIENT_ERROR, Message: common_err.GetMsg(common_err.INVALID_PARAMS), Data: err})
return return
} }
value, ok := js["docker_root_dir"] value, ok := request["docker_root_dir"]
if !ok { 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"}) 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 return
@@ -314,7 +306,7 @@ func PutDockerDaemonConfiguration(c *gin.Context) {
byteResult := file.ReadFullFile(dockerDaemonConfigurationFilePath) byteResult := file.ReadFullFile(dockerDaemonConfigurationFilePath)
err := json.Unmarshal(byteResult, &dockerConfig) err := json.Unmarshal(byteResult, &dockerConfig)
if err != nil { if err != nil {
c.JSON(http.StatusInternalServerError, &model.Result{Success: common_err.SERVICE_ERROR, Message: "error when trying to deserialize " + dockerDaemonConfigurationFilePath, Data: err.Error()}) c.JSON(http.StatusInternalServerError, &model.Result{Success: common_err.SERVICE_ERROR, Message: "error when trying to deserialize " + dockerDaemonConfigurationFilePath, Data: err})
return return
} }
} }
@@ -331,26 +323,33 @@ func PutDockerDaemonConfiguration(c *gin.Context) {
dockerConfig.Root = filepath.Join(dockerRootDir, "docker") dockerConfig.Root = filepath.Join(dockerRootDir, "docker")
if err := file.IsNotExistMkDir(dockerConfig.Root); err != nil { 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.Error()}) c.JSON(http.StatusInternalServerError, &model.Result{Success: common_err.SERVICE_ERROR, Message: "error when trying to create " + dockerConfig.Root, Data: err})
return return
} }
} }
byteMode, err := json.Marshal(dockerConfig) if buf, err := json.Marshal(request); err != nil {
if 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}) c.JSON(http.StatusBadRequest, &model.Result{Success: common_err.CLIENT_ERROR, Message: "error when trying to serialize docker config", Data: dockerConfig})
return 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
}
} }
if err := file.WriteToFullPath(byteMode, 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.Error()})
return
}
// TODO also write dockerRootDir to /etc/casaos/casaos.conf
println(command.ExecResultStr("systemctl daemon-reload")) println(command.ExecResultStr("systemctl daemon-reload"))
println(command.ExecResultStr("systemctl restart docker")) println(command.ExecResultStr("systemctl restart docker"))
c.JSON(http.StatusOK, &model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: js}) c.JSON(http.StatusOK, &model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: request})
} }

View File

@@ -1126,7 +1126,7 @@ func ContainerUpdateInfo(c *gin.Context) {
} }
} }
for _, v := range info.Config.Env { for _, v := range info.Config.Env {
if len(showENVList) > 0 { if len(showENVList) > 0 && info.Config.Labels["origin"] != "local" {
if _, ok := showENVMap[strings.Split(v, "=")[0]]; ok { if _, ok := showENVMap[strings.Split(v, "=")[0]]; ok {
temp := model.Env{ temp := model.Env{
Name: strings.Split(v, "=")[0], Name: strings.Split(v, "=")[0],

View File

@@ -18,9 +18,11 @@ import (
"github.com/IceWhaleTech/CasaOS/model" "github.com/IceWhaleTech/CasaOS/model"
"github.com/IceWhaleTech/CasaOS/pkg/utils/common_err" "github.com/IceWhaleTech/CasaOS/pkg/utils/common_err"
"github.com/IceWhaleTech/CasaOS/pkg/utils/file" "github.com/IceWhaleTech/CasaOS/pkg/utils/file"
"github.com/IceWhaleTech/CasaOS/pkg/utils/loger"
"github.com/IceWhaleTech/CasaOS/service" "github.com/IceWhaleTech/CasaOS/service"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
uuid "github.com/satori/go.uuid" uuid "github.com/satori/go.uuid"
"go.uber.org/zap"
) )
// @Summary 读取文件 // @Summary 读取文件
@@ -47,7 +49,7 @@ func GetFilerContent(c *gin.Context) {
}) })
return return
} }
//文件读取任务是将文件内容读取到内存中。 // 文件读取任务是将文件内容读取到内存中。
info, err := ioutil.ReadFile(filePath) info, err := ioutil.ReadFile(filePath)
if err != nil { if err != nil {
c.JSON(common_err.SERVICE_ERROR, model.Result{ c.JSON(common_err.SERVICE_ERROR, model.Result{
@@ -83,7 +85,6 @@ func GetLocalFile(c *gin.Context) {
return return
} }
c.File(path) c.File(path)
return
} }
// @Summary download // @Summary download
@@ -96,7 +97,6 @@ func GetLocalFile(c *gin.Context) {
// @Success 200 {string} string "ok" // @Success 200 {string} string "ok"
// @Router /file/download [get] // @Router /file/download [get]
func GetDownloadFile(c *gin.Context) { func GetDownloadFile(c *gin.Context) {
t := c.Query("format") t := c.Query("format")
files := c.Query("files") files := c.Query("files")
@@ -135,11 +135,11 @@ func GetDownloadFile(c *gin.Context) {
} }
if !info.IsDir() { if !info.IsDir() {
//打开文件 // 打开文件
fileTmp, _ := os.Open(filePath) fileTmp, _ := os.Open(filePath)
defer fileTmp.Close() defer fileTmp.Close()
//获取文件的名称 // 获取文件的名称
fileName := path.Base(filePath) fileName := path.Base(filePath)
c.Header("Content-Disposition", "attachment; filename*=utf-8''"+url2.PathEscape(fileName)) c.Header("Content-Disposition", "attachment; filename*=utf-8''"+url2.PathEscape(fileName))
c.File(filePath) c.File(filePath)
@@ -179,7 +179,6 @@ func GetDownloadFile(c *gin.Context) {
log.Printf("Failed to archive %s: %v", fname, err) log.Printf("Failed to archive %s: %v", fname, err)
} }
} }
} }
func GetDownloadSingleFile(c *gin.Context) { func GetDownloadSingleFile(c *gin.Context) {
@@ -202,7 +201,7 @@ func GetDownloadSingleFile(c *gin.Context) {
defer fileTmp.Close() defer fileTmp.Close()
fileName := path.Base(filePath) 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.Header("Content-Disposition", "attachment; filename*=utf-8''"+url2.PathEscape(fileName))
c.File(filePath) c.File(filePath)
} }
@@ -248,7 +247,7 @@ func DirPath(c *gin.Context) {
info[i].Extensions = ex info[i].Extensions = ex
} }
} }
//Hide the files or folders in operation // Hide the files or folders in operation
fileQueue := make(map[string]string) fileQueue := make(map[string]string)
if len(service.OpStrArr) > 0 { if len(service.OpStrArr) > 0 {
for _, v := range service.OpStrArr { for _, v := range service.OpStrArr {
@@ -361,7 +360,6 @@ func PostCreateFile(c *gin.Context) {
// @Success 200 {string} string "ok" // @Success 200 {string} string "ok"
// @Router /file/upload [get] // @Router /file/upload [get]
func GetFileUpload(c *gin.Context) { func GetFileUpload(c *gin.Context) {
relative := c.Query("relativePath") relative := c.Query("relativePath")
fileName := c.Query("filename") fileName := c.Query("filename")
chunkNumber := c.Query("chunkNumber") chunkNumber := c.Query("chunkNumber")
@@ -405,7 +403,8 @@ func PostFileUpload(c *gin.Context) {
hash := file.GetHashByContent([]byte(fileName)) hash := file.GetHashByContent([]byte(fileName))
if len(path) == 0 { 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 return
} }
tempDir := filepath.Join(path, ".temp", hash+strconv.Itoa(totalChunks)) + "/" tempDir := filepath.Join(path, ".temp", hash+strconv.Itoa(totalChunks)) + "/"
@@ -413,47 +412,82 @@ func PostFileUpload(c *gin.Context) {
if fileName != relative { if fileName != relative {
dirPath = strings.TrimSuffix(relative, fileName) dirPath = strings.TrimSuffix(relative, fileName)
tempDir += dirPath 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 path += "/" + relative
if !file.CheckNotExist(tempDir + chunkNumber) { 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 { if totalChunks > 1 {
file.IsNotExistMkDir(tempDir) if err := file.IsNotExistMkDir(tempDir); err != nil {
loger.Error("error when trying to create `"+tempDir+"`", zap.Error(err))
out, _ := os.OpenFile(tempDir+chunkNumber, os.O_WRONLY|os.O_CREATE, 0644) c.JSON(http.StatusInternalServerError, model.Result{Success: common_err.SERVICE_ERROR, Message: err.Error()})
defer out.Close()
_, err := io.Copy(out, f)
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 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
}
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 `"+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 {
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 { } else {
out, _ := os.OpenFile(path, os.O_WRONLY|os.O_CREATE, 0644) out, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE, 0o644)
defer out.Close()
_, err := io.Copy(out, f)
if err != nil { 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 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 // @Summary copy or move file
@@ -465,7 +499,6 @@ func PostFileUpload(c *gin.Context) {
// @Success 200 {string} string "ok" // @Success 200 {string} string "ok"
// @Router /file/operate [post] // @Router /file/operate [post]
func PostOperateFileOrDir(c *gin.Context) { func PostOperateFileOrDir(c *gin.Context) {
list := model.FileOperate{} list := model.FileOperate{}
c.ShouldBind(&list) c.ShouldBind(&list)
@@ -515,7 +548,6 @@ func PostOperateFileOrDir(c *gin.Context) {
// @Success 200 {string} string "ok" // @Success 200 {string} string "ok"
// @Router /file/delete [delete] // @Router /file/delete [delete]
func DeleteFile(c *gin.Context) { func DeleteFile(c *gin.Context) {
paths := []string{} paths := []string{}
c.ShouldBind(&paths) c.ShouldBind(&paths)
if len(paths) == 0 { if len(paths) == 0 {
@@ -547,7 +579,6 @@ func DeleteFile(c *gin.Context) {
// @Success 200 {string} string "ok" // @Success 200 {string} string "ok"
// @Router /file/update [put] // @Router /file/update [put]
func PutFileContent(c *gin.Context) { func PutFileContent(c *gin.Context) {
fi := model.FileUpdate{} fi := model.FileUpdate{}
c.ShouldBind(&fi) c.ShouldBind(&fi)
@@ -557,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)}) c.JSON(common_err.SERVICE_ERROR, model.Result{Success: common_err.FILE_ALREADY_EXISTS, Message: common_err.GetMsg(common_err.FILE_ALREADY_EXISTS)})
return return
} }
//err := os.Remove(path) // err := os.Remove(path)
err := os.RemoveAll(fi.FilePath) err := os.RemoveAll(fi.FilePath)
if err != nil { 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}) 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})

View File

@@ -164,51 +164,6 @@ func PostKillCasaOS(c *gin.Context) {
os.Exit(0) 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")
}
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"
}
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) { func GetSystemAppsStatus(c *gin.Context) {
systemAppList := service.MyService.App().GetSystemAppList() systemAppList := service.MyService.App().GetSystemAppList()
appList := []model2.MyAppList{} appList := []model2.MyAppList{}
@@ -225,12 +180,12 @@ func GetSystemAppsStatus(c *gin.Context) {
Id: v.ID, Id: v.ID,
Port: v.Labels["web"], Port: v.Labels["web"],
Index: v.Labels["index"], Index: v.Labels["index"],
//Order: m.Labels["order"], // Order: m.Labels["order"],
Image: v.Image, Image: v.Image,
Latest: false, Latest: false,
//Type: m.Labels["origin"], // Type: m.Labels["origin"],
//Slogan: m.Slogan, // Slogan: m.Slogan,
//Rely: m.Rely, // Rely: m.Rely,
Host: v.Labels["host"], Host: v.Labels["host"],
Protocol: v.Labels["protocol"], Protocol: v.Labels["protocol"],
}) })
@@ -251,7 +206,6 @@ func GetSystemAppsStatus(c *gin.Context) {
// @Success 200 {string} string "ok" // @Success 200 {string} string "ok"
// @Router /sys/hardware/info [get] // @Router /sys/hardware/info [get]
func GetSystemHardwareInfo(c *gin.Context) { func GetSystemHardwareInfo(c *gin.Context) {
data := make(map[string]string, 1) data := make(map[string]string, 1)
data["drive_model"] = service.MyService.System().GetDeviceTree() data["drive_model"] = service.MyService.System().GetDeviceTree()
c.JSON(common_err.SUCCESS, c.JSON(common_err.SUCCESS,
@@ -270,7 +224,7 @@ func GetSystemHardwareInfo(c *gin.Context) {
// @Success 200 {string} string "ok" // @Success 200 {string} string "ok"
// @Router /sys/utilization [get] // @Router /sys/utilization [get]
func GetSystemUtilization(c *gin.Context) { func GetSystemUtilization(c *gin.Context) {
var data = make(map[string]interface{}, 6) data := make(map[string]interface{})
cpu := service.MyService.System().GetCpuPercent() cpu := service.MyService.System().GetCpuPercent()
num := service.MyService.System().GetCpuCoreNum() num := service.MyService.System().GetCpuCoreNum()
cpuData := make(map[string]interface{}) cpuData := make(map[string]interface{})
@@ -282,7 +236,7 @@ func GetSystemUtilization(c *gin.Context) {
data["cpu"] = cpuData data["cpu"] = cpuData
data["mem"] = service.MyService.System().GetMemInfo() data["mem"] = service.MyService.System().GetMemInfo()
//拼装网络信息 // 拼装网络信息
netList := service.MyService.System().GetNetInfo() netList := service.MyService.System().GetNetInfo()
newNet := []model.IOCountersStat{} newNet := []model.IOCountersStat{}
nets := service.MyService.System().GetNet(true) nets := service.MyService.System().GetNet(true)
@@ -299,7 +253,9 @@ func GetSystemUtilization(c *gin.Context) {
} }
data["net"] = newNet 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}) c.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: data})
} }
@@ -311,7 +267,6 @@ func GetSystemUtilization(c *gin.Context) {
// @Success 200 {string} string "ok" // @Success 200 {string} string "ok"
// @Router /sys/socket/port [get] // @Router /sys/socket/port [get]
func GetSystemSocketPort(c *gin.Context) { func GetSystemSocketPort(c *gin.Context) {
c.JSON(common_err.SUCCESS, c.JSON(common_err.SUCCESS,
model.Result{ model.Result{
Success: common_err.SUCCESS, Success: common_err.SUCCESS,
@@ -334,7 +289,6 @@ func GetSystemCupInfo(c *gin.Context) {
data["percent"] = cpu data["percent"] = cpu
data["num"] = num data["num"] = num
c.JSON(http.StatusOK, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: data}) c.JSON(http.StatusOK, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: data})
} }
// @Summary get mem info // @Summary get mem info
@@ -347,7 +301,6 @@ func GetSystemCupInfo(c *gin.Context) {
func GetSystemMemInfo(c *gin.Context) { func GetSystemMemInfo(c *gin.Context) {
mem := service.MyService.System().GetMemInfo() mem := service.MyService.System().GetMemInfo()
c.JSON(http.StatusOK, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: mem}) c.JSON(http.StatusOK, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: mem})
} }
// @Summary get disk info // @Summary get disk info

View File

@@ -37,6 +37,7 @@ type NotifyServer interface {
SendStorageBySocket(message notify.StorageMessage) SendStorageBySocket(message notify.StorageMessage)
SendNotify(path string, message map[string]interface{}) SendNotify(path string, message map[string]interface{})
SettingSystemTempData(message map[string]interface{}) SettingSystemTempData(message map[string]interface{})
GetSystemTempMap() map[string]interface{}
} }
type notifyServer struct { type notifyServer struct {
@@ -442,7 +443,11 @@ func SendMeg() {
// } // }
// } // }
func (i *notifyServer) GetSystemTempMap() map[string]interface{} {
return i.SystemTempMap
}
func NewNotifyService(db *gorm.DB) NotifyServer { func NewNotifyService(db *gorm.DB) NotifyServer {
return &notifyServer{db: db, SystemTempMap: make(map[string]interface{})} return &notifyServer{db: db, SystemTempMap: make(map[string]interface{})}
} }

View File

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