Compare commits

..

7 Commits

Author SHA1 Message Date
LinkLeong
9d6381d7ac Update file route 2023-07-12 07:57:13 +01:00
LinkLeong
e5b172627a update action 2023-07-10 07:59:46 +01:00
LinkLeong
bbbb3b2f29 update action 2023-07-10 07:58:24 +01:00
LinkLeong
1453eac570 update gorelease version 2023-07-10 07:57:22 +01:00
LinkLeong
c649b67c20 update 401 2023-07-03 09:34:09 +01:00
LinkLeong
93262dc549 Update logs 2023-06-16 07:24:35 +01:00
LinkLeong
a106abc8ba Fixed compression error 2023-05-15 11:40:52 +01:00
73 changed files with 3672 additions and 2559 deletions

View File

@@ -8,57 +8,39 @@ assignees: ''
--- ---
**Describe the bug** **Describe the bug**
A clear and concise description of what the bug is.
> A clear and concise description of what the bug is.
**To Reproduce** **To Reproduce**
Steps to reproduce the behavior:
> Steps to reproduce the behavior:
1. Go to '...' 1. Go to '...'
2. Click on '....' 2. Click on '....'
3. Scroll down to '....' 3. Scroll down to '....'
4. See error 4. See error
**Expected behavior** **Expected behavior**
A clear and concise description of what you expected to happen.
> A clear and concise description of what you expected to happen.
**Screenshots** **Screenshots**
If applicable, add screenshots to help explain your problem.
> If applicable, add screenshots to help explain your problem.
**Desktop (please complete the following information):** **Desktop (please complete the following information):**
```
- OS: [e.g. iOS] - OS: [e.g. iOS]
- Browser [e.g. chrome, safari] - Browser [e.g. chrome, safari]
- Version [e.g. 22] - Version [e.g. 22]
```
**System Time**
> Run `timedatectl` and share the output
```
(timedatectl output here)
```
**Logs** **Logs**
> Run following command to collect corresponding logs: run following command to collect corresponding logs:
```bash ```bash
sudo journalctl -xef -u casaos-gateway sudo journalctl -xef -u casaos-gateway
sudo journalctl -xef -u casaos-user-service sudo journalctl -xef -u casaos-user-service
sudo journalctl -xef -u casaos-local-storage sudo journalctl -xef -u casaos-local-storage
sudo journalctl -xef -u casaos-app-management
sudo journalctl -xef -u casaos.service sudo journalctl -xef -u casaos.service
``` ```
**Additional context**
> Add any other context about the problem here.
> **Additional context**
> If you are a Zimaboard user, make it explicit with when you got your Zimaboard. Add any other context about the problem here.

23
.github/ISSUE_TEMPLATE/feedback.yml vendored Normal file
View File

@@ -0,0 +1,23 @@
name: "Feedback"
description: Feedback, showcases, thoughts, needs and questions, etc.
title: "[Feedback] "
labels: ["feedback"]
body:
- type: markdown
attributes:
value: |
### ❤️ Thanks for your feedback!
> Come join our [Discord community](https://discord.gg/knqAbbBbeX) and paint the ideal home cloud with us.
- type: textarea
id: description
attributes:
label: Description
placeholder: What do you want to tell us?
validations:
required: true
- type: textarea
id: additional
attributes:
label: Additional Information
description: Please add logs/files/screenshots if you have them to help us better understanding.

View File

@@ -0,0 +1,15 @@
---
name: Submit application
about: Add an app to this project
title: ''
labels: ''
assignees: LinkLeong
---
Tested platform
e.g. linux/amd64,linux/arm-v7,linux-arm64
Please export and upload the configuration file of this application

View File

@@ -65,7 +65,7 @@ jobs:
# ls # ls
- name: Set environment for github-release - name: Set enviroment for github-release
run: | run: |
echo "VERSION=$(cat types/system.go | grep CURRENTVERSION | awk '$2 == "CURRENTVERSION"{print $4}' | sed 's/"//g')" >>$GITHUB_ENV echo "VERSION=$(cat types/system.go | grep CURRENTVERSION | awk '$2 == "CURRENTVERSION"{print $4}' | sed 's/"//g')" >>$GITHUB_ENV
echo "BODY=$(cat types/system.go | grep BODY | awk -F= '{print $2}' | sed 's/"//g')" >>$GITHUB_ENV echo "BODY=$(cat types/system.go | grep BODY | awk -F= '{print $2}' | sed 's/"//g')" >>$GITHUB_ENV

View File

@@ -20,8 +20,6 @@ jobs:
uses: actions/setup-go@v4 uses: actions/setup-go@v4
with: with:
go-version: "1.20" go-version: "1.20"
- name: generate OPENAPI
run: go generate
- name: Run coverage - name: Run coverage
run: go test -race -failfast -coverprofile=coverage.txt -covermode=atomic -v ./... run: go test -race -failfast -coverprofile=coverage.txt -covermode=atomic -v ./...
- name: Upload coverage to Codecov - name: Upload coverage to Codecov

View File

@@ -33,9 +33,8 @@ jobs:
- name: Get old instance and snapshot name, create new instance name - name: Get old instance and snapshot name, create new instance name
run: | run: |
echo "OLD_INSTANCE_SNAPSHOT_NAME=CasaOS-v0.4.4-3-Demo-1700132299" >> $GITHUB_ENV echo "OLD_INSTANCE_SNAPSHOT_NAME=$(aws lightsail get-instance-snapshots | grep '"name": "updateto_to_0.4.1-1676285322' | sed 's/ //g' | sed 's/"//g' | sed 's/,//g' | sed 's/name://g')" >> $GITHUB_ENV
echo "OLD_INSTANCE_NAME=$(aws lightsail get-instances | grep '"name": "CasaOS-Demo-[0-9]' | tail -1 | sed 's/ //g' | sed 's/"//g' | sed 's/,//g' | sed 's/name://g')" >> $GITHUB_ENV echo "OLD_INSTANCE_NAME=$(aws lightsail get-instances | grep '"name": "CasaOS-Demo-[0-9]' | sed 's/ //g' | sed 's/"//g' | sed 's/,//g' | sed 's/name://g')" >> $GITHUB_ENV
# echo "OLD_INSTANCE_NAME=CasaOS-Demo-1687680295" >> $GITHUB_ENV
echo "NEW_INSTANCE_NAME= CasaOS-Demo-$(date +%s)" >> $GITHUB_ENV echo "NEW_INSTANCE_NAME= CasaOS-Demo-$(date +%s)" >> $GITHUB_ENV
- name: Create instances from snapshot - name: Create instances from snapshot
@@ -76,9 +75,5 @@ jobs:
run: | run: |
aws lightsail delete-instance \ aws lightsail delete-instance \
--instance-name ${{ env.OLD_INSTANCE_NAME }} --instance-name ${{ env.OLD_INSTANCE_NAME }}
- name: Demo Reset Error Handling
if: ${{ failure() }}
run: |
curl -X POST -H "Content-Type: application/json" -d '{"msg_type":"text","content":{"text":"Demo Reset Error"}}' ${{ secrets.SSH_ROBOT_URL }}

View File

@@ -1,46 +0,0 @@
name: publish npm
on:
push:
tags:
- v*.*.*
workflow_dispatch:
permissions:
contents: write
jobs:
publish-npm:
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 0
- uses: actions/setup-node@v3
with:
node-version: 16
registry-url: https://registry.npmjs.org/
- run: git tag --sort=-creatordate | head -n 1
- name: Get version
id: get_version
run: echo "VERSION=$(git tag --sort=-creatordate | head -n 1)" >> $GITHUB_OUTPUT
- name: Get commit id
id: get_commit_id
run: echo "COMMIT_ID=$( git rev-parse --short "$GITHUB_SHA" )" >> $GITHUB_OUTPUT
- run: echo "${{ steps.get_version.outputs.VERSION }}-${{ steps.get_commit_id.outputs.COMMIT_ID }}"
- name: Set version
run: |
sudo apt-get install jq
jq '.version="${{ steps.get_version.outputs.VERSION }}-${{ steps.get_commit_id.outputs.COMMIT_ID }}"' package.json > package.json.new
mv package.json.new package.json
- name: Generate SDK
run: |
npm cache clean --force
npm install @openapitools/openapi-generator-cli -g
- run: npm i
- run: npm run start
- run: npm publish --access public
env:
NODE_AUTH_TOKEN: ${{secrets.npm_token}}

View File

@@ -40,3 +40,9 @@ jobs:
uses: joseph-montanez/forward-event-action@v3.0.0 uses: joseph-montanez/forward-event-action@v3.0.0
with: with:
webhook: ${{ secrets.Discord_CasaOS_Bug_Webhook }} webhook: ${{ secrets.Discord_CasaOS_Bug_Webhook }}
- name: Alpha Issues & Comments
if: ${{ ( github.event_name == 'issues' || github.event_name == 'issue_comment' ) && contains(github.event.issue.labels.*.name, 'alpha') }}
uses: joseph-montanez/forward-event-action@v3.0.0
with:
webhook: ${{ secrets.Discord_CasaOS_Alpha_Webhook }}

View File

@@ -2,9 +2,7 @@ name: Auto Publish Website
on: on:
push: push:
branches: branches:
- main - community
workflow_dispatch:
permissions: permissions:
contents: write contents: write
jobs: jobs:
@@ -50,12 +48,6 @@ jobs:
args: release --rm-dist --snapshot args: release --rm-dist --snapshot
env: env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GoogleID: ${{ secrets.GoogleID }}
GoogleSecret: ${{ secrets.GoogleSecret }}
DropboxKey: ${{ secrets.DropboxKey }}
DropboxSecret: ${{ secrets.DropboxSecret }}
OneDriveID: ${{ secrets.OneDriveID }}
OneDriveSecret: ${{ secrets.OneDriveSecret }}
# Your GoReleaser Pro key, if you are using the 'goreleaser-pro' distribution # Your GoReleaser Pro key, if you are using the 'goreleaser-pro' distribution
# GORELEASER_KEY: ${{ secrets.GORELEASER_KEY }} # GORELEASER_KEY: ${{ secrets.GORELEASER_KEY }}

View File

@@ -7,19 +7,57 @@ on:
permissions: permissions:
contents: write contents: write
jobs: jobs:
call-workflow-passing-data: goreleaser:
uses: IceWhaleTech/github/.github/workflows/go_release.yml@main runs-on: ubuntu-22.04
with: steps:
project-name: CasaOS - name: Install dependencies for cross-compiling
file-name: casaos run: |
secrets: sudo apt update
GoogleID: ${{ secrets.GoogleID }} sudo apt-get --no-install-recommends --yes install \
GoogleSecret: ${{ secrets.GoogleSecret }} upx libc6-dev-amd64-cross \
DropboxKey: ${{ secrets.DropboxKey }} gcc-aarch64-linux-gnu libc6-dev-arm64-cross \
DropboxSecret: ${{ secrets.DropboxSecret }} gcc-arm-linux-gnueabihf libc6-dev-armhf-cross
OneDriveID: ${{ secrets.OneDriveID }} - name: Checkout
OneDriveSecret: ${{ secrets.OneDriveSecret }} uses: actions/checkout@v3
OneDrivePublic: ${{ secrets.OneDrivePublic }} with:
OSS_KEY_ID: ${{ secrets.OSS_KEY_ID }} fetch-depth: 0
OSS_KEY_SECRET: ${{ secrets.OSS_KEY_SECRET }} - name: Fetch all tags
run: git fetch --force --tags
- name: Get version
id: get_version
run: echo ::set-output name=VERSION::${GITHUB_REF/refs\/tags\//}
- name: Set up Go
uses: actions/setup-go@v4
with:
go-version: "1.20"
- name: Run GoReleaser
uses: goreleaser/goreleaser-action@v4
with:
# either 'goreleaser' (default) or 'goreleaser-pro'
distribution: goreleaser
version: 1.14.1
args: release --rm-dist
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
# Your GoReleaser Pro key, if you are using the 'goreleaser-pro' distribution
# GORELEASER_KEY: ${{ secrets.GORELEASER_KEY }}
- name: Upload to oss
id: upload_to_oss
uses: tvrcgo/upload-to-oss@master
with:
key-id: ${{ secrets.OSS_KEY_ID }}
key-secret: ${{ secrets.OSS_KEY_SECRET }}
region: oss-cn-shanghai
bucket: casaos
assets: |
dist/checksums.txt:/IceWhaleTech/CasaOS/releases/download/${{ steps.get_version.outputs.VERSION }}/checksums.txt
dist/linux-arm-7-casaos-${{ steps.get_version.outputs.VERSION }}.tar.gz:/IceWhaleTech/CasaOS/releases/download/${{ steps.get_version.outputs.VERSION }}/linux-arm-7-casaos-${{ steps.get_version.outputs.VERSION }}.tar.gz
dist/linux-arm64-casaos-${{ steps.get_version.outputs.VERSION }}.tar.gz:/IceWhaleTech/CasaOS/releases/download/${{ steps.get_version.outputs.VERSION }}/linux-arm64-casaos-${{ steps.get_version.outputs.VERSION }}.tar.gz
dist/linux-amd64-casaos-${{ steps.get_version.outputs.VERSION }}.tar.gz:/IceWhaleTech/CasaOS/releases/download/${{ steps.get_version.outputs.VERSION }}/linux-amd64-casaos-${{ steps.get_version.outputs.VERSION }}.tar.gz
dist/linux-arm-7-casaos-migration-tool-${{ steps.get_version.outputs.VERSION }}.tar.gz:/IceWhaleTech/CasaOS/releases/download/${{ steps.get_version.outputs.VERSION }}/linux-arm-7-casaos-migration-tool-${{ steps.get_version.outputs.VERSION }}.tar.gz
dist/linux-arm64-casaos-migration-tool-${{ steps.get_version.outputs.VERSION }}.tar.gz:/IceWhaleTech/CasaOS/releases/download/${{ steps.get_version.outputs.VERSION }}/linux-arm64-casaos-migration-tool-${{ steps.get_version.outputs.VERSION }}.tar.gz
dist/linux-amd64-casaos-migration-tool-${{ steps.get_version.outputs.VERSION }}.tar.gz:/IceWhaleTech/CasaOS/releases/download/${{ steps.get_version.outputs.VERSION }}/linux-amd64-casaos-migration-tool-${{ steps.get_version.outputs.VERSION }}.tar.gz

1
.gitignore vendored
View File

@@ -37,7 +37,6 @@ github.com
.all-contributorsrc .all-contributorsrc
dist dist
CasaOS CasaOS
/codegen
# System Files # System Files
.DS_Store .DS_Store

View File

@@ -113,22 +113,24 @@ builds:
goarm: goarm:
- "7" - "7"
archives: archives:
- name_template: >- - name_template: "{{ .Os }}-{{ .Arch }}-{{ .ProjectName }}-v{{ .Version }}"
{{ .Os }}-{{- if eq .Arch "arm" }}arm-7{{- else }}{{ .Arch }}{{- end }}-{{ .ProjectName }}-v{{ .Version }}
id: casaos id: casaos
builds: builds:
- casaos-amd64 - casaos-amd64
- casaos-arm64 - casaos-arm64
- casaos-arm-7 - casaos-arm-7
replacements:
arm: arm-7
files: files:
- build/**/* - build/**/*
- name_template: >- - name_template: "{{ .Os }}-{{ .Arch }}-{{ .ProjectName }}-migration-tool-v{{ .Version }}"
{{ .Os }}-{{- if eq .Arch "arm" }}arm-7{{- else }}{{ .Arch }}{{- end }}-{{ .ProjectName }}-migration-tool-v{{ .Version }}
id: casaos-migration-tool id: casaos-migration-tool
builds: builds:
- casaos-migration-tool-amd64 - casaos-migration-tool-amd64
- casaos-migration-tool-arm64 - casaos-migration-tool-arm64
- casaos-migration-tool-arm-7 - casaos-migration-tool-arm-7
replacements:
arm: arm-7
files: files:
- build/sysroot/etc/**/* - build/sysroot/etc/**/*
checksum: checksum:

View File

@@ -19,12 +19,6 @@ builds:
ldflags: ldflags:
- -X main.commit={{.Commit}} - -X main.commit={{.Commit}}
- -X main.date={{.Date}} - -X main.date={{.Date}}
- -X github.com/IceWhaleTech/CasaOS/drivers/google_drive.client_id={{.Env.GoogleID}}
- -X github.com/IceWhaleTech/CasaOS/drivers/google_drive.client_secret={{.Env.GoogleSecret}}
- -X github.com/IceWhaleTech/CasaOS/drivers/onedrive.client_id={{.Env.OneDriveID}}
- -X github.com/IceWhaleTech/CasaOS/drivers/onedrive.client_secret={{.Env.OneDriveSecret}}
- -X github.com/IceWhaleTech/CasaOS/drivers/dropbox.app_key={{.Env.DropboxKey}}
- -X github.com/IceWhaleTech/CasaOS/drivers/dropbox.app_secret={{.Env.DropboxSecret}}
- -s - -s
- -w - -w
- -extldflags "-static" - -extldflags "-static"
@@ -38,20 +32,14 @@ builds:
- amd64 - amd64
- id: casaos-arm64 - id: casaos-arm64
binary: build/sysroot/usr/bin/casaos binary: build/sysroot/usr/bin/casaos
# hooks: hooks:
# post: post:
# - upx --best --lzma -v --no-progress "{{ .Path }}" - upx --best --lzma -v --no-progress "{{ .Path }}"
env: env:
- CC=aarch64-linux-gnu-gcc - CC=aarch64-linux-gnu-gcc
ldflags: ldflags:
- -X main.commit={{.Commit}} - -X main.commit={{.Commit}}
- -X main.date={{.Date}} - -X main.date={{.Date}}
- -X github.com/IceWhaleTech/CasaOS/drivers/google_drive.client_id={{.Env.GoogleID}}
- -X github.com/IceWhaleTech/CasaOS/drivers/google_drive.client_secret={{.Env.GoogleSecret}}
- -X github.com/IceWhaleTech/CasaOS/drivers/onedrive.client_id={{.Env.OneDriveID}}
- -X github.com/IceWhaleTech/CasaOS/drivers/onedrive.client_secret={{.Env.OneDriveSecret}}
- -X github.com/IceWhaleTech/CasaOS/drivers/dropbox.app_key={{.Env.DropboxKey}}
- -X github.com/IceWhaleTech/CasaOS/drivers/dropbox.app_secret={{.Env.DropboxSecret}}
- -s - -s
- -w - -w
- -extldflags "-static" - -extldflags "-static"
@@ -73,12 +61,6 @@ builds:
ldflags: ldflags:
- -X main.commit={{.Commit}} - -X main.commit={{.Commit}}
- -X main.date={{.Date}} - -X main.date={{.Date}}
- -X github.com/IceWhaleTech/CasaOS/drivers/google_drive.client_id={{.Env.GoogleID}}
- -X github.com/IceWhaleTech/CasaOS/drivers/google_drive.client_secret={{.Env.GoogleSecret}}
- -X github.com/IceWhaleTech/CasaOS/drivers/onedrive.client_id={{.Env.OneDriveID}}
- -X github.com/IceWhaleTech/CasaOS/drivers/onedrive.client_secret={{.Env.OneDriveSecret}}
- -X github.com/IceWhaleTech/CasaOS/drivers/dropbox.app_key={{.Env.DropboxKey}}
- -X github.com/IceWhaleTech/CasaOS/drivers/dropbox.app_secret={{.Env.DropboxSecret}}
- -s - -s
- -w - -w
- -extldflags "-static" - -extldflags "-static"
@@ -116,9 +98,9 @@ builds:
- amd64 - amd64
- id: casaos-migration-tool-arm64 - id: casaos-migration-tool-arm64
binary: build/sysroot/usr/bin/casaos-migration-tool binary: build/sysroot/usr/bin/casaos-migration-tool
# hooks: hooks:
# post: post:
# - upx --best --lzma -v --no-progress "{{ .Path }}" - upx --best --lzma -v --no-progress "{{ .Path }}"
main: ./cmd/migration-tool main: ./cmd/migration-tool
env: env:
- CC=aarch64-linux-gnu-gcc - CC=aarch64-linux-gnu-gcc
@@ -161,22 +143,24 @@ builds:
goarm: goarm:
- "7" - "7"
archives: archives:
- name_template: >- - name_template: "{{ .Os }}-{{ .Arch }}-{{ .ProjectName }}-v{{ .Version }}"
{{ .Os }}-{{- if eq .Arch "arm" }}arm-7{{- else }}{{ .Arch }}{{- end }}-{{ .ProjectName }}-v{{ .Version }}
id: casaos id: casaos
builds: builds:
- casaos-amd64 - casaos-amd64
- casaos-arm64 - casaos-arm64
- casaos-arm-7 - casaos-arm-7
replacements:
arm: arm-7
files: files:
- build/**/* - build/**/*
- name_template: >- - name_template: "{{ .Os }}-{{ .Arch }}-{{ .ProjectName }}-migration-tool-v{{ .Version }}"
{{ .Os }}-{{- if eq .Arch "arm" }}arm-7{{- else }}{{ .Arch }}{{- end }}-{{ .ProjectName }}-migration-tool-v{{ .Version }}
id: casaos-migration-tool id: casaos-migration-tool
builds: builds:
- casaos-migration-tool-amd64 - casaos-migration-tool-amd64
- casaos-migration-tool-arm64 - casaos-migration-tool-arm64
- casaos-migration-tool-arm-7 - casaos-migration-tool-arm-7
replacements:
arm: arm-7
files: files:
- build/sysroot/etc/**/* - build/sysroot/etc/**/*
checksum: checksum:

View File

@@ -46,11 +46,6 @@
<!-- ALL-CONTRIBUTORS-BADGE:START - Do not remove or modify this section --> <!-- ALL-CONTRIBUTORS-BADGE:START - Do not remove or modify this section -->
<a href="#credits"><img alt="All Contributors" src="https://img.shields.io/static/v1?label=All%20Contributors&message=15&color=162453&style=flat-square&logo=Handshake&logoColor=fff" /></a> <a href="#credits"><img alt="All Contributors" src="https://img.shields.io/static/v1?label=All%20Contributors&message=15&color=162453&style=flat-square&logo=Handshake&logoColor=fff" /></a>
<!-- ALL-CONTRIBUTORS-BADGE:END --> <!-- ALL-CONTRIBUTORS-BADGE:END -->
<br/>
<!-- CasaOS YouTube -->
<a href="https://www.youtube.com/channel/UC2zMrUYT17AJhIl9XWZzT8g" target="_blank">
<img alt="YouTube Tutorial Views" src="https://img.shields.io/youtube/channel/views/UC2zMrUYT17AJhIl9XWZzT8g?style=for-the-badge&logo=youtube&logoColor=red&label=YouTube%20Tutorial%20Views" />
</a>
<br/> <br/>
<!-- CasaOS Links --> <!-- CasaOS Links -->
<a href="https://www.casaos.io" target="_blank">Website</a> | <a href="https://www.casaos.io" target="_blank">Website</a> |
@@ -88,7 +83,7 @@ Furthermore, the personal cloud could combine personal data to train personalize
- Multiple hardware and base system support - Multiple hardware and base system support
- ZimaBoard, NUC, RPi, old computers, whatever is available. - ZimaBoard, NUC, RPi, old computers, whatever is available.
- Selected apps in the app store, one-click installation - Selected apps in the app store, one-click installation
- Nextcloud, HomeAssistant, AdGuard, Jellyfin, *arr and more! - Nextcloud, HomeAssiant, AdGuard, Jellyfin, *arr and more!
- Easily install numerous Docker apps - Easily install numerous Docker apps
- Over 100,000 apps from the Docker ecosystem can be easily installed - Over 100,000 apps from the Docker ecosystem can be easily installed
- Elegant drive and file management - Elegant drive and file management
@@ -109,7 +104,7 @@ CasaOS fully supports ZimaBoard, Intel NUC, and Raspberry Pi. Also, more compute
### System Compatibility ### System Compatibility
Official Support Official Support
- Debian 12 (✅ Tested, Recommended) - Debian 11 (✅ Tested, Recommended)
- Ubuntu Server 20.04 (✅ Tested) - Ubuntu Server 20.04 (✅ Tested)
- Raspberry Pi OS (✅ Tested) - Raspberry Pi OS (✅ Tested)
@@ -134,30 +129,6 @@ or
curl -fsSL https://get.casaos.io | sudo bash curl -fsSL https://get.casaos.io | sudo bash
``` ```
### Update CasaOS
CasaOS can be updated from the User Interface (UI), via `Settings ... Update`.
Alternatively it can be updated from a terminal session. To update from a terminal session, it must be done either from a secure shell (ssh) session to the device or from a directly attached terminal and keyboard to the device running CasaOS, this cannot be done from the terminal via the CasaOS User Interface (UI). To update to the latest release of CasaOS from a terminal session run this command:
```sh
wget -qO- https://get.casaos.io/update | sudo bash
```
or
```sh
curl -fsSL https://get.casaos.io/update | sudo bash
```
To determine version of CasaOS from a terminal session run this command:
```sh
casaos -v
```
### Uninstall CasaOS ### Uninstall CasaOS
@@ -175,13 +146,13 @@ curl -fsSL https://get.icewhale.io/casaos-uninstall.sh | sudo bash
## Community ## Community
The word Casa comes from the Spanish word for "home". Project CasaOS originated as a pre-installed system for the crowdfunded product [ZimaBoard](https://www.zimaboard.com) on Kickstarter. The word Casa comes from the Spanish word for "home". Project CasaOS originated as a pre-installed system for crowdfunded product [ZimaBoard](https://www.zimaboard.com) on Kickstarter.
After looking at many systems and software on the market, the team found no server system designed for home scenarios, sadly true. After looking at many systems and software on the market, the team found no server system designed for home scenarios, sadly true.
So, we set out to build this open-source project to develop CasaOS with our own hands, everyone in the community, and you. So, we set out to build this open source project to develop CasaOS with our own hands, everyone in the community, and you.
We believe that through community-driven collaborative innovation and open communication with global developers, we can reshape the digital home experience like never before. We believes that through community-driven collaborative innovation and open communication with global developers, we can reshape the digital home experience like never before.
**A warm welcome for you to get help or share great ideas in the [Discord](https://discord.gg/knqAbbBbeX)!** **A warm welcome for you to get help or share great ideas in the [Discord](https://discord.gg/knqAbbBbeX)!**
@@ -191,8 +162,8 @@ We believe that through community-driven collaborative innovation and open commu
CasaOS is a community-driven open source project and the people involved are CasaOS users. That means CasaOS will always need contributions from community members just like you! CasaOS is a community-driven open source project and the people involved are CasaOS users. That means CasaOS will always need contributions from community members just like you!
- See <https://wiki.casaos.io/en/contribute> for ways of contributing to CasaOS - See <https://wiki.casaos.io/en/contribute> for ways of contribution to CasaOS
- See <https://wiki.casaos.io/en/contribute/development> if you want to be involved in code contribution specifically - See <https://wiki.casaos.io/en/contribute/development> if you want to be involved in code contribution specificially
## Donate ## Donate
<p ><a href="https://www.buymeacoffee.com/icewhaletech"> <img align="center" src="https://cdn.buymeacoffee.com/buttons/v2/default-yellow.png" height="50" width="210" alt="bappi2097" target="_blank" /></a></p> <p ><a href="https://www.buymeacoffee.com/icewhaletech"> <img align="center" src="https://cdn.buymeacoffee.com/buttons/v2/default-yellow.png" height="50" width="210" alt="bappi2097" target="_blank" /></a></p>
@@ -228,8 +199,6 @@ Everyone's contribution is greatly appreciated. ([Emoji Key](https://allcontribu
</tr> </tr>
<tr> <tr>
<td align="center"><a href="https://github.com/llwaini"><img src="https://avatars.githubusercontent.com/u/59589857?v=4?s=100" width="100px;" alt=""/><br /><sub><b>llwaini</b></sub></a><br /><a href="#projectManagement-llwaini" title="Project Management">📆</a> <a href="https://github.com/IceWhaleTech/CasaOS/commits?author=llwaini" title="Tests">⚠️</a> <a href="#tutorial-llwaini" title="Tutorials">✅</a></td> <td align="center"><a href="https://github.com/llwaini"><img src="https://avatars.githubusercontent.com/u/59589857?v=4?s=100" width="100px;" alt=""/><br /><sub><b>llwaini</b></sub></a><br /><a href="#projectManagement-llwaini" title="Project Management">📆</a> <a href="https://github.com/IceWhaleTech/CasaOS/commits?author=llwaini" title="Tests">⚠️</a> <a href="#tutorial-llwaini" title="Tutorials">✅</a></td>
<td align="center"><a href="https://github.com/CorrectRoadH"><img src="https://avatars.githubusercontent.com/u/29306285?v=4?s=100" width="100px;" alt=""/><br /><sub><b>CorrectRoadH</b></sub></a><br /><a href="https://github.com/IceWhaleTech/CasaOS/commits?author=correctroadh" title="Code">💻</a> <a href="https://github.com/IceWhaleTech/CasaOS/commits?author=correctroadh" title="Documentation">📖</a></td>
<td align="center"><a href="https://github.com/zhanghengxin"><img src="https://avatars.githubusercontent.com/u/24197448?v=4?s=100" width="100px;" alt=""/><br /><sub><b>zhanghengxin</b></sub></a><br /><a href="https://github.com/IceWhaleTech/CasaOS/commits?author=zhanghengxin" title="Code">💻</a> <a href="https://github.com/IceWhaleTech/CasaOS/commits?author=zhanghengxin" title="Documentation">📖</a></td>
</tr> </tr>
</table> </table>
@@ -238,7 +207,7 @@ Everyone's contribution is greatly appreciated. ([Emoji Key](https://allcontribu
<!-- ALL-CONTRIBUTORS-LIST:END --> <!-- ALL-CONTRIBUTORS-LIST:END -->
This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind are welcome! This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome!
## Changelog ## Changelog

View File

@@ -20,11 +20,10 @@ servers:
tags: tags:
- name: Health methods - name: Health methods
description: |- description: |-
These methods are used to check the health and status of the CasaOS API and associated services. (TODO)
- name: File methods - name: File methods
description: |- description: |-
The File methods allow you to interact with files and directories on the CasaOS system. (TODO)
x-tagGroups: x-tagGroups:
- name: Methods - name: Methods
@@ -60,6 +59,7 @@ paths:
$ref: "#/components/responses/GetHealthPortsOK" $ref: "#/components/responses/GetHealthPortsOK"
"500": "500":
$ref: "#/components/responses/ResponseInternalServerError" $ref: "#/components/responses/ResponseInternalServerError"
/health/logs: /health/logs:
get: get:
tags: tags:
@@ -76,7 +76,6 @@ paths:
format: binary format: binary
"500": "500":
$ref: "#/components/responses/ResponseInternalServerError" $ref: "#/components/responses/ResponseInternalServerError"
/file/test: /file/test:
get: get:
tags: tags:
@@ -90,153 +89,6 @@ paths:
$ref: "#/components/responses/ResponseOK" $ref: "#/components/responses/ResponseOK"
"500": "500":
$ref: "#/components/responses/ResponseInternalServerError" $ref: "#/components/responses/ResponseInternalServerError"
/file/upload:
get:
tags:
- File
summary: Check upload chunk
parameters:
- name: path
in: query
description: File path
required: true
example: "/DATA/test.log"
schema:
type: string
- name: relativePath
in: query
description: File path
required: true
example: "/DATA/test.log"
schema:
type: string
- name: filename
in: query
description: File name
required: true
example: "test.log"
schema:
type: string
- name: chunkNumber
in: query
description: chunk number
required: true
example: 1
schema:
type: string
- name: totalChunks
in: query
description: total chunks
example: 2
required: true
schema:
type: integer
description: Check if the file block has been uploaded (needs to be modified later)
operationId: checkUploadChunk
responses:
"200":
$ref: "#/components/responses/ResponseStringOK"
"400":
$ref: "#/components/responses/ResponseClientError"
"500":
$ref: "#/components/responses/ResponseInternalServerError"
post:
tags:
- File
summary: Upload file
description: Upload file
operationId: postUploadFile
requestBody:
content:
multipart/form-data:
schema:
type: object
properties:
relativePath:
type: string
example: "/DATA/test.log"
filename:
type: string
example: "/DATA/test2.log"
totalChunks:
type: string
example: "2"
chunkNumber:
type: string
example: "20"
path:
type: string
example: "/DATA"
file:
type: string
format: binary
chunkSize:
type: string
example: "1024"
currentChunkSize:
type: string
example: "1024"
totalSize:
type: string
example: "1024"
identifier:
type: string
example: "test.log"
responses:
"200":
$ref: "#/components/responses/ResponseStringOK"
"400":
$ref: "#/components/responses/ResponseClientError"
"500":
$ref: "#/components/responses/ResponseInternalServerError"
/zt/info:
get:
tags:
- Zerotier methods
summary: Get Zerotier info
description: |-
Get Zerotier info.
operationId: getZerotierInfo
responses:
"200":
$ref: "#/components/responses/GetZTInfoOK"
"500":
$ref: "#/components/responses/ResponseInternalServerError"
/zt/{network_id}/status:
put:
tags:
- Zerotier methods
summary: Set Zerotier network status
description: |-
Set Zerotier network status.
operationId: setZerotierNetworkStatus
parameters:
- name: network_id
in: path
description: network id
required: true
schema:
type: string
requestBody:
content:
application/json:
schema:
type: object
properties:
status:
enum:
- online
- offline
type: string
example: "online"
responses:
"200":
$ref: "#/components/responses/GetZTInfoOK"
"500":
$ref: "#/components/responses/ResponseInternalServerError"
components: components:
securitySchemes: securitySchemes:
access_token: access_token:
@@ -252,20 +104,6 @@ components:
schema: schema:
$ref: "#/components/schemas/BaseResponse" $ref: "#/components/schemas/BaseResponse"
ResponseStringOK:
description: OK
content:
application/json:
schema:
$ref: "#/components/schemas/SuccessResponseString"
ResponseClientError:
description: Client Error
content:
application/json:
schema:
$ref: "#/components/schemas/BaseResponse"
ResponseInternalServerError: ResponseInternalServerError:
description: Internal Server Error description: Internal Server Error
content: content:
@@ -294,13 +132,6 @@ components:
- properties: - properties:
data: data:
$ref: "#/components/schemas/HealthPorts" $ref: "#/components/schemas/HealthPorts"
GetZTInfoOK:
description: OK
content:
application/json:
schema:
$ref: "#/components/schemas/ZTInfo"
schemas: schemas:
BaseResponse: BaseResponse:
@@ -311,14 +142,6 @@ components:
type: string type: string
example: "" example: ""
SuccessResponseString:
allOf:
- $ref: "#/components/schemas/BaseResponse"
- properties:
data:
type: string
description: When the interface returns success, this field is the specific success information
HealthServices: HealthServices:
properties: properties:
running: running:
@@ -346,14 +169,3 @@ components:
type: integer type: integer
example: 53 example: 53
x-go-name: UDP x-go-name: UDP
ZTInfo:
properties:
id:
type: string
example: "1234567890"
name:
type: string
example: "CasaOS"
status:
type: string
example: "online"

View File

@@ -1,6 +1,7 @@
[Unit] [Unit]
After=casaos-message-bus.service After=casaos-message-bus.service
After=rclone.service After=rclone.service
ConditionFileNotEmpty=/etc/casaos/casaos.conf
Description=CasaOS Main Service Description=CasaOS Main Service
[Service] [Service]

View File

@@ -1,28 +0,0 @@
package main
import (
"github.com/IceWhaleTech/CasaOS-Common/external"
"github.com/IceWhaleTech/CasaOS/codegen/message_bus"
"github.com/IceWhaleTech/CasaOS/common"
"github.com/samber/lo"
)
func main() {
eventTypes := lo.Map(common.EventTypes, func(item message_bus.EventType, index int) external.EventType {
return external.EventType{
Name: item.Name,
SourceID: item.SourceID,
PropertyTypeList: lo.Map(
item.PropertyTypeList, func(item message_bus.PropertyType, index int) external.PropertyType {
return external.PropertyType{
Name: item.Name,
Description: item.Description,
Example: item.Example,
}
},
),
}
})
external.PrintEventTypesAsMarkdown(common.SERVICENAME, common.VERSION, eventTypes)
}

View File

@@ -77,7 +77,7 @@ func init() {
} }
} }
config.InitSetup(configFlag, "") config.InitSetup(configFlag)
if len(dbFlag) == 0 { if len(dbFlag) == 0 {
dbFlag = config.AppInfo.DBPath + "/db" dbFlag = config.AppInfo.DBPath + "/db"

257
codegen/casaos_api.go Normal file
View File

@@ -0,0 +1,257 @@
// Package codegen provides primitives to interact with the openapi HTTP API.
//
// Code generated by github.com/deepmap/oapi-codegen version v1.12.4 DO NOT EDIT.
package codegen
import (
"bytes"
"compress/gzip"
"encoding/base64"
"fmt"
"net/url"
"path"
"strings"
"github.com/getkin/kin-openapi/openapi3"
"github.com/labstack/echo/v4"
)
const (
Access_tokenScopes = "access_token.Scopes"
)
// BaseResponse defines model for BaseResponse.
type BaseResponse struct {
// Message message returned by server side if there is any
Message *string `json:"message,omitempty"`
}
// HealthPorts defines model for HealthPorts.
type HealthPorts struct {
TCP *[]int `json:"tcp,omitempty"`
UDP *[]int `json:"udp,omitempty"`
}
// HealthServices defines model for HealthServices.
type HealthServices struct {
NotRunning *[]string `json:"not_running,omitempty"`
Running *[]string `json:"running,omitempty"`
}
// GetHealthPortsOK defines model for GetHealthPortsOK.
type GetHealthPortsOK struct {
Data *HealthPorts `json:"data,omitempty"`
// Message message returned by server side if there is any
Message *string `json:"message,omitempty"`
}
// GetHealthServicesOK defines model for GetHealthServicesOK.
type GetHealthServicesOK struct {
Data *HealthServices `json:"data,omitempty"`
// Message message returned by server side if there is any
Message *string `json:"message,omitempty"`
}
// ResponseInternalServerError defines model for ResponseInternalServerError.
type ResponseInternalServerError = BaseResponse
// ResponseOK defines model for ResponseOK.
type ResponseOK = BaseResponse
// ServerInterface represents all server handlers.
type ServerInterface interface {
// Test file methods
// (GET /file/test)
GetFileTest(ctx echo.Context) error
// Get log
// (GET /health/logs)
GetHealthlogs(ctx echo.Context) error
// Get port in use
// (GET /health/ports)
GetHealthPorts(ctx echo.Context) error
// Get service status
// (GET /health/services)
GetHealthServices(ctx echo.Context) error
}
// ServerInterfaceWrapper converts echo contexts to parameters.
type ServerInterfaceWrapper struct {
Handler ServerInterface
}
// GetFileTest converts echo context to params.
func (w *ServerInterfaceWrapper) GetFileTest(ctx echo.Context) error {
var err error
ctx.Set(Access_tokenScopes, []string{""})
// Invoke the callback with all the unmarshalled arguments
err = w.Handler.GetFileTest(ctx)
return err
}
// GetHealthlogs converts echo context to params.
func (w *ServerInterfaceWrapper) GetHealthlogs(ctx echo.Context) error {
var err error
ctx.Set(Access_tokenScopes, []string{""})
// Invoke the callback with all the unmarshalled arguments
err = w.Handler.GetHealthlogs(ctx)
return err
}
// GetHealthPorts converts echo context to params.
func (w *ServerInterfaceWrapper) GetHealthPorts(ctx echo.Context) error {
var err error
ctx.Set(Access_tokenScopes, []string{""})
// Invoke the callback with all the unmarshalled arguments
err = w.Handler.GetHealthPorts(ctx)
return err
}
// GetHealthServices converts echo context to params.
func (w *ServerInterfaceWrapper) GetHealthServices(ctx echo.Context) error {
var err error
ctx.Set(Access_tokenScopes, []string{""})
// Invoke the callback with all the unmarshalled arguments
err = w.Handler.GetHealthServices(ctx)
return err
}
// This is a simple interface which specifies echo.Route addition functions which
// are present on both echo.Echo and echo.Group, since we want to allow using
// either of them for path registration
type EchoRouter interface {
CONNECT(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route
DELETE(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route
GET(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route
HEAD(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route
OPTIONS(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route
PATCH(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route
POST(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route
PUT(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route
TRACE(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route
}
// RegisterHandlers adds each server route to the EchoRouter.
func RegisterHandlers(router EchoRouter, si ServerInterface) {
RegisterHandlersWithBaseURL(router, si, "")
}
// Registers handlers, and prepends BaseURL to the paths, so that the paths
// can be served under a prefix.
func RegisterHandlersWithBaseURL(router EchoRouter, si ServerInterface, baseURL string) {
wrapper := ServerInterfaceWrapper{
Handler: si,
}
router.GET(baseURL+"/file/test", wrapper.GetFileTest)
router.GET(baseURL+"/health/logs", wrapper.GetHealthlogs)
router.GET(baseURL+"/health/ports", wrapper.GetHealthPorts)
router.GET(baseURL+"/health/services", wrapper.GetHealthServices)
}
// Base64 encoded, gzipped, json marshaled Swagger object
var swaggerSpec = []string{
"H4sIAAAAAAAC/8xX3W7bRhN9lcV+30VcUKIQI0BAIBf5aRwjKGQ0LlrAMpTVckRuQu5uZ4aKVYPvXuyS",
"smhJEeykKXola3/OnHM8szO6ldrV3lmwTDK7lQjknSWIX86A34GquLxwyDR9H9a0swyWw5/K+8poxcbZ",
"9BM5G9ZIl1CruFtV06XMrm7l/xGWMpP/S7eh0u4cpa8Uwa99TNkmt9Kj84BsOga54gh2DGJAUbZte922",
"bSJzII3GB24yk9P3sk22cj4AroyG/7iiDcvjojahzi0DWlWFW4A/Izp8lLiHS9pnsoktuuCiiz4g90ij",
"v4dLcKVNerDo+L0b2e7/owYiVcSN+0D9hkDgBi3kYrEW1Okjk4MwS8ElIAhDQtm1TCTcqNpXIDMpE4mg",
"8qmt1jJjbCCRvPZhhxiNLTriw8Td48Xahw/DUMfvd+DPJ3dgxjIUEJ3uVxSiClRuRoUbWVWHtcvXF+FE",
"k38F8NnpIwF/e3MxFHCXp3sarOM5NtYGxQdDS61IORpTByH3bNrh0SbyIXijQjF8UeuH40Y5BLpBw+sP",
"IXc6BUprIJqz+wwxR03IjBJUDigT2fvxsuHSofkrpvM2lvLmPaw7p4xduv0UmzWTyan2RnODEL/AzAoh",
"RLdBrkENoobcqBcz+cQjLAFppF3lcBQzHDKRK/x8MpOCUBPwi5ksmT1laYrqy7gwXDaLhgD74htrV6fn",
"Gn4vVQWXoMu0coVLa2Vs2pnXf8wXylrAeYCfW1OUPH8+mfibsbfFTH4r2SoA/UC2/MXEEPNF1cBxwqYu",
"hKoChdeK1PRDR+rfZ9SxSXeyYGY7VuLlxbnw6FYmBxK1IQ1VpSy4hkQNXLqcxNKhyM1yCQiWBWmwCo2j",
"cUB561AYogbCI5WL3JBuiIyzlAhfgSIQK0OGw1smrs4Mv2sWAsE7Muxwff1k40bnxL78juaJcCg+OWPF",
"lWtQvDGkHebb23m3MC6K9LP98+Vi8WoBf5yMZ7FcDMfa3QqWiVwBUlckq6ehXJ0Hq7yRmTwdT8anMpFe",
"cRlrNF2aClIGip2lAN4vtEsgFuHYxrOxjJAYS/Y8l1kYDt6aoIk4vt6DMejpZPK1rnR3Lh20ujaRzx5z",
"5VDrju9RU9cK14f4B9tUQTK7km+Hy9fhXlrGdzlkJg0s2dPbPd/x1GHFX2nYTjPwiBhB1fcb99JhrVhm",
"cmFsYH6w7R2aYv5hv86AReWKgUud1sM++U0HPm5U16i/JTf25ugfozjoEMaKhuCBymnQug8WToDtO64g",
"VtyQcEsBSpfiY99rf/ooepiDRbUzI3yXfYO5/cc42AvppR41cTAvxJ8E9yeFq+v2OhwIwSjuN1jJTKar",
"p31/kOFAD7/r+pPL6ZvpyXbA2IkeflQcv3DvTQiBbkasijN0je/i9ed+2XtN9oRet38HAAD///s5WXsj",
"DgAA",
}
// GetSwagger returns the content of the embedded swagger specification file
// or error if failed to decode
func decodeSpec() ([]byte, error) {
zipped, err := base64.StdEncoding.DecodeString(strings.Join(swaggerSpec, ""))
if err != nil {
return nil, fmt.Errorf("error base64 decoding spec: %s", err)
}
zr, err := gzip.NewReader(bytes.NewReader(zipped))
if err != nil {
return nil, fmt.Errorf("error decompressing spec: %s", err)
}
var buf bytes.Buffer
_, err = buf.ReadFrom(zr)
if err != nil {
return nil, fmt.Errorf("error decompressing spec: %s", err)
}
return buf.Bytes(), nil
}
var rawSpec = decodeSpecCached()
// a naive cached of a decoded swagger spec
func decodeSpecCached() func() ([]byte, error) {
data, err := decodeSpec()
return func() ([]byte, error) {
return data, err
}
}
// Constructs a synthetic filesystem for resolving external references when loading openapi specifications.
func PathToRawSpec(pathToFile string) map[string]func() ([]byte, error) {
var res = make(map[string]func() ([]byte, error))
if len(pathToFile) > 0 {
res[pathToFile] = rawSpec
}
return res
}
// GetSwagger returns the Swagger specification corresponding to the generated code
// in this file. The external references of Swagger specification are resolved.
// The logic of resolving external references is tightly connected to "import-mapping" feature.
// Externally referenced files must be embedded in the corresponding golang packages.
// Urls can be supported but this task was out of the scope.
func GetSwagger() (swagger *openapi3.T, err error) {
var resolvePath = PathToRawSpec("")
loader := openapi3.NewLoader()
loader.IsExternalRefsAllowed = true
loader.ReadFromURIFunc = func(loader *openapi3.Loader, url *url.URL) ([]byte, error) {
var pathToFile = url.String()
pathToFile = path.Clean(pathToFile)
getSpec, ok := resolvePath[pathToFile]
if !ok {
err1 := fmt.Errorf("path not found: %s", pathToFile)
return nil, err1
}
return getSpec()
}
var specData []byte
specData, err = rawSpec()
if err != nil {
return
}
swagger, err = loader.LoadFromData(specData)
if err != nil {
return
}
return
}

2254
codegen/message_bus/api.go Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -2,7 +2,6 @@ package common
const ( const (
SERVICENAME = "casaos" SERVICENAME = "casaos"
VERSION = "0.4.11" VERSION = "0.4.4"
BODY = " " BODY = " "
RANW_NAME = "IceWhale-RemoteAccess"
) )

View File

@@ -1,12 +1,23 @@
package common package common
import ( import (
"fmt"
"github.com/IceWhaleTech/CasaOS/codegen/message_bus" "github.com/IceWhaleTech/CasaOS/codegen/message_bus"
) )
// devtype -> action -> event var (
var EventTypes = []message_bus.EventType{ // devtype -> action -> event
{Name: "casaos:system:utilization", SourceID: SERVICENAME, PropertyTypeList: []message_bus.PropertyType{}}, EventTypes map[string]map[string]message_bus.EventType
{Name: "casaos:file:recover", SourceID: SERVICENAME, PropertyTypeList: []message_bus.PropertyType{}},
{Name: "casaos:file:operate", SourceID: SERVICENAME, PropertyTypeList: []message_bus.PropertyType{}}, PropertyNameLookupMaps = map[string]map[string]string{
} "system": {
fmt.Sprintf("%s:%s", SERVICENAME, "utilization"): "ID_BUS",
},
}
ActionPastTense = map[string]string{
"add": "added",
"remove": "removed",
}
)

View File

@@ -3,7 +3,6 @@ package drivers
import ( import (
_ "github.com/IceWhaleTech/CasaOS/drivers/dropbox" _ "github.com/IceWhaleTech/CasaOS/drivers/dropbox"
_ "github.com/IceWhaleTech/CasaOS/drivers/google_drive" _ "github.com/IceWhaleTech/CasaOS/drivers/google_drive"
_ "github.com/IceWhaleTech/CasaOS/drivers/onedrive"
) )
// All do nothing,just for import // All do nothing,just for import

View File

@@ -96,8 +96,5 @@ func (d *Dropbox) Remove(ctx context.Context, obj model.Obj) error {
func (d *Dropbox) Put(ctx context.Context, dstDir model.Obj, stream model.FileStreamer, up driver.UpdateProgress) error { func (d *Dropbox) Put(ctx context.Context, dstDir model.Obj, stream model.FileStreamer, up driver.UpdateProgress) error {
return nil return nil
} }
func (d *Dropbox) GetInfo(ctx context.Context) (string, string, string, error) {
return "", "", "", nil
}
var _ driver.Driver = (*Dropbox)(nil) var _ driver.Driver = (*Dropbox)(nil)

View File

@@ -2,9 +2,12 @@ package dropbox
import ( import (
"github.com/IceWhaleTech/CasaOS/internal/driver" "github.com/IceWhaleTech/CasaOS/internal/driver"
"github.com/IceWhaleTech/CasaOS/internal/op"
) )
const ICONURL = "./img/driver/Dropbox.svg" const ICONURL = "./img/driver/Dropbox.svg"
const APPKEY = "tciqajyazzdygt9"
const APPSECRET = "e7gtmv441cwdf0n"
type Addition struct { type Addition struct {
driver.RootID driver.RootID
@@ -12,7 +15,7 @@ type Addition struct {
AppKey string `json:"app_key" type:"string" default:"tciqajyazzdygt9" omit:"true"` AppKey string `json:"app_key" type:"string" default:"tciqajyazzdygt9" omit:"true"`
AppSecret string `json:"app_secret" type:"string" default:"e7gtmv441cwdf0n" omit:"true"` AppSecret string `json:"app_secret" type:"string" default:"e7gtmv441cwdf0n" omit:"true"`
OrderDirection string `json:"order_direction" type:"select" options:"asc,desc" omit:"true"` OrderDirection string `json:"order_direction" type:"select" options:"asc,desc" omit:"true"`
AuthUrl string `json:"auth_url" type:"string" default:""` AuthUrl string `json:"auth_url" type:"string" default:"https://www.dropbox.com/oauth2/authorize?client_id=tciqajyazzdygt9&redirect_uri=https://cloudoauth.files.casaos.app&response_type=code&token_access_type=offline&state=${HOST}%2Fv1%2Frecover%2FDropbox&&force_reapprove=true&force_reauthentication=true"`
Icon string `json:"icon" type:"string" default:"./img/driver/Dropbox.svg"` Icon string `json:"icon" type:"string" default:"./img/driver/Dropbox.svg"`
Code string `json:"code" type:"string" help:"code from auth_url" omit:"true"` Code string `json:"code" type:"string" help:"code from auth_url" omit:"true"`
} }
@@ -22,3 +25,9 @@ var config = driver.Config{
OnlyProxy: true, OnlyProxy: true,
DefaultRoot: "root", DefaultRoot: "root",
} }
func init() {
op.RegisterDriver(func() driver.Driver {
return &Dropbox{}
})
}

View File

@@ -10,11 +10,6 @@ import (
"go.uber.org/zap" "go.uber.org/zap"
) )
var (
app_key = "private build"
app_secret = "private build"
)
func (d *Dropbox) getRefreshToken() error { func (d *Dropbox) getRefreshToken() error {
url := "https://api.dropbox.com/oauth2/token" url := "https://api.dropbox.com/oauth2/token"
var resp base.TokenResp var resp base.TokenResp
@@ -105,12 +100,3 @@ func (d *Dropbox) getFiles(path string) ([]File, error) {
return res, nil return res, nil
} }
func GetConfig() Dropbox {
dp := Dropbox{}
dp.RootFolderID = ""
dp.AuthUrl = "https://www.dropbox.com/oauth2/authorize?client_id=" + app_key + "&redirect_uri=https://cloudoauth.files.casaos.app&response_type=code&token_access_type=offline&state=${HOST}%2Fv1%2Frecover%2FDropbox&&force_reapprove=true&force_reauthentication=true"
dp.AppKey = app_key
dp.AppSecret = app_secret
dp.Icon = "./img/driver/Dropbox.svg"
return dp
}

View File

@@ -80,9 +80,6 @@ func (d *GoogleDrive) GetUserInfo(ctx context.Context) (string, error) {
return user.User.EmailAddress, nil return user.User.EmailAddress, nil
} }
func (d *GoogleDrive) GetInfo(ctx context.Context) (string, string, string, error) {
return "", "", "", nil
}
func (d *GoogleDrive) MakeDir(ctx context.Context, parentDir model.Obj, dirName string) error { func (d *GoogleDrive) MakeDir(ctx context.Context, parentDir model.Obj, dirName string) error {
data := base.Json{ data := base.Json{
"name": dirName, "name": dirName,

View File

@@ -2,19 +2,22 @@ package google_drive
import ( import (
"github.com/IceWhaleTech/CasaOS/internal/driver" "github.com/IceWhaleTech/CasaOS/internal/driver"
"github.com/IceWhaleTech/CasaOS/internal/op"
) )
const ICONURL = "./img/driver/GoogleDrive.svg" const ICONURL = "./img/driver/GoogleDrive.svg"
const CLIENTID = "921743327851-urr4f7jjfp4ts639evqb3i4m4qb4u4cc.apps.googleusercontent.com"
const CLIENTSECRET = "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"
type Addition struct { type Addition struct {
driver.RootID driver.RootID
RefreshToken string `json:"refresh_token" required:"true" omit:"true"` RefreshToken string `json:"refresh_token" required:"true" omit:"true"`
OrderBy string `json:"order_by" type:"string" help:"such as: folder,name,modifiedTime" omit:"true"` OrderBy string `json:"order_by" type:"string" help:"such as: folder,name,modifiedTime" omit:"true"`
OrderDirection string `json:"order_direction" type:"select" options:"asc,desc" omit:"true"` OrderDirection string `json:"order_direction" type:"select" options:"asc,desc" omit:"true"`
ClientID string `json:"client_id" required:"true" default:"" omit:"true"` ClientID string `json:"client_id" required:"true" default:"921743327851-urr4f7jjfp4ts639evqb3i4m4qb4u4cc.apps.googleusercontent.com" omit:"true"`
ClientSecret string `json:"client_secret" required:"true" default:"" omit:"true"` ClientSecret string `json:"client_secret" required:"true" default:"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" omit:"true"`
ChunkSize int64 `json:"chunk_size" type:"number" help:"chunk size while uploading (unit: MB)" omit:"true"` ChunkSize int64 `json:"chunk_size" type:"number" help:"chunk size while uploading (unit: MB)" omit:"true"`
AuthUrl string `json:"auth_url" type:"string" default:""` AuthUrl string `json:"auth_url" type:"string" default:"https://accounts.google.com/o/oauth2/auth/oauthchooseaccount?response_type=code&client_id=921743327851-urr4f7jjfp4ts639evqb3i4m4qb4u4cc.apps.googleusercontent.com&redirect_uri=https%3A%2F%2Fcloudoauth.files.casaos.app&scope=https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fdrive&access_type=offline&approval_prompt=force&state=${HOST}%2Fv1%2Frecover%2FGoogleDrive&service=lso&o2v=1&flowName=GeneralOAuthFlow"`
Icon string `json:"icon" type:"string" default:"./img/driver/GoogleDrive.svg"` Icon string `json:"icon" type:"string" default:"./img/driver/GoogleDrive.svg"`
Code string `json:"code" type:"string" help:"code from auth_url" omit:"true"` Code string `json:"code" type:"string" help:"code from auth_url" omit:"true"`
} }
@@ -24,3 +27,9 @@ var config = driver.Config{
OnlyProxy: true, OnlyProxy: true,
DefaultRoot: "root", DefaultRoot: "root",
} }
func init() {
op.RegisterDriver(func() driver.Driver {
return &GoogleDrive{}
})
}

View File

@@ -16,11 +16,6 @@ import (
"go.uber.org/zap" "go.uber.org/zap"
) )
var (
client_id = "private build"
client_secret = "private build"
)
// do others that not defined in Driver interface // do others that not defined in Driver interface
func (d *GoogleDrive) getRefreshToken() error { func (d *GoogleDrive) getRefreshToken() error {
@@ -155,13 +150,3 @@ func (d *GoogleDrive) chunkUpload(ctx context.Context, stream model.FileStreamer
} }
return nil return nil
} }
func GetConfig() GoogleDrive {
config := GoogleDrive{}
config.ClientID = client_id
config.ClientSecret = client_secret
config.RootFolderID = "root"
config.AuthUrl = "https://accounts.google.com/o/oauth2/auth/oauthchooseaccount?response_type=code&client_id=" + client_id + "&redirect_uri=https%3A%2F%2Fcloudoauth.files.casaos.app&scope=https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fdrive&access_type=offline&approval_prompt=force&state=${HOST}%2Fv1%2Frecover%2FGoogleDrive&service=lso&o2v=1&flowName=GeneralOAuthFlow"
config.Icon = "./img/driver/GoogleDrive.svg"
return config
}

View File

@@ -1,70 +0,0 @@
package onedrive
import (
"context"
"fmt"
"net/http"
"strconv"
"github.com/IceWhaleTech/CasaOS-Common/utils/logger"
"github.com/IceWhaleTech/CasaOS/internal/driver"
"github.com/IceWhaleTech/CasaOS/model"
"go.uber.org/zap"
)
type Onedrive struct {
model.StorageA
Addition
AccessToken string
}
func (d *Onedrive) Config() driver.Config {
return config
}
func (d *Onedrive) GetAddition() driver.Additional {
return &d.Addition
}
func (d *Onedrive) Init(ctx context.Context) error {
if d.ChunkSize < 1 {
d.ChunkSize = 5
}
if len(d.RefreshToken) == 0 {
return d.getRefreshToken()
}
return d.refreshToken()
}
func (d *Onedrive) GetUserInfo(ctx context.Context) (string, error) {
return "", nil
}
func (d *Onedrive) GetInfo(ctx context.Context) (string, string, string, error) {
url := d.GetMetaUrl(false, "/")
user := Info{}
resp, err := d.Request(url, http.MethodGet, nil, &user)
if err != nil {
return "", "", "", err
}
logger.Info("resp", zap.Any("resp", resp))
return user.LastModifiedBy.User.DisplayName, user.ParentReference.DriveID, user.ParentReference.DriveType, nil
}
func (d *Onedrive) GetSpaceSize(ctx context.Context) (used string, total string, err error) {
host := onedriveHostMap[d.Region]
url := fmt.Sprintf("%s/v1.0/me/drive/quota", host.Api)
size := About{}
resp, err := d.Request(url, http.MethodGet, nil, &size)
if err != nil {
return used, total, err
}
logger.Info("resp", zap.Any("resp", resp))
used = strconv.Itoa(size.Used)
total = strconv.Itoa(size.Total)
return
}
func (d *Onedrive) Drop(ctx context.Context) error {
return nil
}
var _ driver.Driver = (*Onedrive)(nil)

View File

@@ -1,69 +0,0 @@
package onedrive
import (
"github.com/IceWhaleTech/CasaOS/internal/driver"
)
const ICONURL = "./img/driver/OneDrive.svg"
type Host struct {
Oauth string
Api string
}
type TokenErr struct {
Error string `json:"error"`
ErrorDescription string `json:"error_description"`
}
type RespErr struct {
Error struct {
Code string `json:"code"`
Message string `json:"message"`
} `json:"error"`
}
type Addition struct {
Region string `json:"region" type:"select" required:"true" options:"global,cn,us,de" default:"global"`
IsSharepoint bool `json:"is_sharepoint"`
ClientID string `json:"client_id" required:"true"`
ClientSecret string `json:"client_secret" required:"true"`
RedirectUri string `json:"redirect_uri" required:"true" default:""`
RefreshToken string `json:"refresh_token" required:"true"`
SiteId string `json:"site_id"`
ChunkSize int64 `json:"chunk_size" type:"number" default:"5"`
RootFolderID string `json:"root_folder_id"`
AuthUrl string `json:"auth_url" type:"string" default:""`
Icon string `json:"icon" type:"string" default:""`
Code string `json:"code" type:"string" help:"code from auth_url" omit:"true"`
}
type About struct {
Total int `json:"total"`
Used int `json:"used"`
State string `json:"state"`
}
type Info struct {
LastModifiedBy struct {
Application struct {
DisplayName string `json:"displayName"`
ID string `json:"id"`
} `json:"application"`
Device struct {
ID string `json:"id"`
} `json:"device"`
User struct {
DisplayName string `json:"displayName"`
ID string `json:"id"`
} `json:"user"`
} `json:"lastModifiedBy"`
ParentReference struct {
DriveID string `json:"driveId"`
DriveType string `json:"driveType"`
} `json:"parentReference"`
}
var config = driver.Config{
Name: "Onedrive",
LocalSort: true,
DefaultRoot: "/",
}

View File

@@ -1,182 +0,0 @@
package onedrive
import (
"errors"
"fmt"
"net/url"
"strings"
"github.com/IceWhaleTech/CasaOS-Common/utils/logger"
"github.com/IceWhaleTech/CasaOS/drivers/base"
"go.uber.org/zap"
)
var (
client_id = "private build"
client_secret = "private build"
)
var onedriveHostMap = map[string]Host{
"global": {
Oauth: "https://login.microsoftonline.com",
Api: "https://graph.microsoft.com",
},
"cn": {
Oauth: "https://login.chinacloudapi.cn",
Api: "https://microsoftgraph.chinacloudapi.cn",
},
"us": {
Oauth: "https://login.microsoftonline.us",
Api: "https://graph.microsoft.us",
},
"de": {
Oauth: "https://login.microsoftonline.de",
Api: "https://graph.microsoft.de",
},
}
func EncodePath(path string, all ...bool) string {
seg := strings.Split(path, "/")
toReplace := []struct {
Src string
Dst string
}{
{Src: "%", Dst: "%25"},
{"%", "%25"},
{"?", "%3F"},
{"#", "%23"},
}
for i := range seg {
if len(all) > 0 && all[0] {
seg[i] = url.PathEscape(seg[i])
} else {
for j := range toReplace {
seg[i] = strings.ReplaceAll(seg[i], toReplace[j].Src, toReplace[j].Dst)
}
}
}
return strings.Join(seg, "/")
}
func (d *Onedrive) GetMetaUrl(auth bool, path string) string {
host := onedriveHostMap[d.Region]
path = EncodePath(path, true)
if auth {
return host.Oauth
}
if d.IsSharepoint {
if path == "/" || path == "\\" {
return fmt.Sprintf("%s/v1.0/sites/%s/drive/root", host.Api, d.SiteId)
} else {
return fmt.Sprintf("%s/v1.0/sites/%s/drive/root:%s:", host.Api, d.SiteId, path)
}
} else {
if path == "/" || path == "\\" {
return fmt.Sprintf("%s/v1.0/me/drive/root", host.Api)
} else {
return fmt.Sprintf("%s/v1.0/me/drive/root:%s:", host.Api, path)
}
}
}
func (d *Onedrive) refreshToken() error {
var err error
for i := 0; i < 3; i++ {
err = d._refreshToken()
if err == nil {
break
}
}
return err
}
func (d *Onedrive) getRefreshToken() error {
url := d.GetMetaUrl(true, "") + "/common/oauth2/v2.0/token"
var resp base.TokenResp
var e TokenErr
res, err := base.RestyClient.R().SetResult(&resp).SetError(&e).SetFormData(map[string]string{
"grant_type": "authorization_code",
"client_id": d.ClientID,
"client_secret": d.ClientSecret,
"code": d.Code,
"redirect_uri": d.RedirectUri,
}).Post(url)
if err != nil {
return err
}
logger.Info("get refresh token", zap.String("res", res.String()))
if e.Error != "" {
return fmt.Errorf("%s", e.ErrorDescription)
}
if resp.RefreshToken == "" {
return errors.New("refresh token is empty")
}
d.RefreshToken, d.AccessToken = resp.RefreshToken, resp.AccessToken
return nil
}
func (d *Onedrive) _refreshToken() error {
url := d.GetMetaUrl(true, "") + "/common/oauth2/v2.0/token"
var resp base.TokenResp
var e TokenErr
res, err := base.RestyClient.R().SetResult(&resp).SetError(&e).SetFormData(map[string]string{
"grant_type": "refresh_token",
"client_id": d.ClientID,
"client_secret": d.ClientSecret,
"redirect_uri": d.RedirectUri,
"refresh_token": d.RefreshToken,
}).Post(url)
if err != nil {
return err
}
logger.Info("get refresh token", zap.String("res", res.String()))
if e.Error != "" {
return fmt.Errorf("%s", e.ErrorDescription)
}
if resp.RefreshToken == "" {
return errors.New("refresh token is empty")
}
d.RefreshToken, d.AccessToken = resp.RefreshToken, resp.AccessToken
return nil
}
func (d *Onedrive) Request(url string, method string, callback base.ReqCallback, resp interface{}) ([]byte, error) {
req := base.RestyClient.R()
req.SetHeader("Authorization", "Bearer "+d.AccessToken)
if callback != nil {
callback(req)
}
if resp != nil {
req.SetResult(resp)
}
var e RespErr
req.SetError(&e)
res, err := req.Execute(method, url)
if err != nil {
return nil, err
}
if e.Error.Code != "" {
if e.Error.Code == "InvalidAuthenticationToken" {
err = d.refreshToken()
if err != nil {
return nil, err
}
return d.Request(url, method, callback, resp)
}
return nil, errors.New(e.Error.Message)
}
return res.Body(), nil
}
func GetConfig() Onedrive {
config := Onedrive{}
config.ClientID = client_id
config.ClientSecret = client_secret
config.RootFolderID = "/"
config.AuthUrl = "https://login.microsoftonline.com/common/oauth2/v2.0/authorize?client_id=" + client_id + "&response_type=code&redirect_uri=https%3A%2F%2Fcloudoauth.files.casaos.app&scope=offline_access+files.readwrite.all&state=${HOST}%2Fv1%2Frecover%2FOnedrive"
config.Icon = "./img/driver/OneDrive.svg"
config.Region = "global"
config.RedirectUri = "https://cloudoauth.files.casaos.app"
return config
}

75
go.mod
View File

@@ -1,29 +1,30 @@
module github.com/IceWhaleTech/CasaOS module github.com/IceWhaleTech/CasaOS
go 1.21 go 1.20
require ( require (
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
github.com/IceWhaleTech/CasaOS-Common v0.4.9-alpha6 github.com/IceWhaleTech/CasaOS-Common v0.4.4-alpha8
github.com/coreos/go-systemd v0.0.0-20191104093116-d3cd4ed1dbcf github.com/coreos/go-systemd v0.0.0-20191104093116-d3cd4ed1dbcf
github.com/deckarep/golang-set/v2 v2.3.0 github.com/deckarep/golang-set/v2 v2.3.0
github.com/deepmap/oapi-codegen v1.12.4 github.com/deepmap/oapi-codegen v1.12.4
github.com/disintegration/imaging v1.6.2 github.com/disintegration/imaging v1.6.2
github.com/dsoprea/go-exif/v3 v3.0.1 github.com/dsoprea/go-exif/v3 v3.0.0-20221012082141-d21ac8e2de85
github.com/getkin/kin-openapi v0.117.0 github.com/getkin/kin-openapi v0.115.0
github.com/glebarez/sqlite v1.8.0 github.com/gin-contrib/gzip v0.0.6
github.com/gin-gonic/gin v1.9.0
github.com/glebarez/sqlite v1.7.0
github.com/go-ini/ini v1.67.0 github.com/go-ini/ini v1.67.0
github.com/go-resty/resty/v2 v2.7.0 github.com/go-resty/resty/v2 v2.7.0
github.com/golang/mock v1.6.0 github.com/golang/mock v1.6.0
github.com/gomodule/redigo v1.8.9 github.com/gomodule/redigo v1.8.9
github.com/google/go-github/v36 v36.0.0 github.com/google/go-github/v36 v36.0.0
github.com/google/uuid v1.3.0
github.com/googollee/go-socket.io v1.7.0 github.com/googollee/go-socket.io v1.7.0
github.com/gorilla/websocket v1.5.0 github.com/gorilla/websocket v1.5.0
github.com/h2non/filetype v1.1.3 github.com/h2non/filetype v1.1.3
github.com/hirochachacha/go-smb2 v1.1.0 github.com/hirochachacha/go-smb2 v1.1.0
github.com/json-iterator/go v1.1.12 github.com/json-iterator/go v1.1.12
github.com/labstack/echo/v4 v4.12.0 github.com/labstack/echo/v4 v4.10.2
github.com/maruel/natural v1.1.0 github.com/maruel/natural v1.1.0
github.com/mholt/archiver/v3 v3.5.1 github.com/mholt/archiver/v3 v3.5.1
github.com/mileusna/useragent v1.2.1 github.com/mileusna/useragent v1.2.1
@@ -32,25 +33,27 @@ require (
github.com/patrickmn/go-cache v2.1.0+incompatible github.com/patrickmn/go-cache v2.1.0+incompatible
github.com/pkg/errors v0.9.1 github.com/pkg/errors v0.9.1
github.com/robfig/cron/v3 v3.0.1 github.com/robfig/cron/v3 v3.0.1
github.com/samber/lo v1.38.1 github.com/satori/go.uuid v1.2.0
github.com/shirou/gopsutil/v3 v3.23.2 github.com/shirou/gopsutil/v3 v3.23.2
github.com/sirupsen/logrus v1.9.3 github.com/sirupsen/logrus v1.9.0
github.com/stretchr/testify v1.9.0 github.com/stretchr/testify v1.8.2
github.com/tidwall/gjson v1.17.0 github.com/tidwall/gjson v1.14.4
go.uber.org/goleak v1.2.1 go.uber.org/goleak v1.2.1
go.uber.org/zap v1.24.0 go.uber.org/zap v1.24.0
golang.org/x/crypto v0.23.0 golang.org/x/crypto v0.8.0
golang.org/x/oauth2 v0.7.0 golang.org/x/oauth2 v0.6.0
golang.org/x/sync v0.3.0 golang.org/x/sync v0.1.0
golang.org/x/sys v0.20.0 golang.org/x/sys v0.7.0
gorm.io/gorm v1.25.0 gorm.io/gorm v1.24.6
gotest.tools v2.2.0+incompatible gotest.tools v2.2.0+incompatible
) )
require ( require (
github.com/andybalholm/brotli v1.0.5 // indirect github.com/andybalholm/brotli v1.0.5 // indirect
github.com/apapsch/go-jsonmerge/v2 v2.0.0 // indirect github.com/apapsch/go-jsonmerge/v2 v2.0.0 // indirect
github.com/benbjohnson/clock v1.3.1 // indirect github.com/benbjohnson/clock v1.3.0 // indirect
github.com/bytedance/sonic v1.8.5 // indirect
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect
github.com/coreos/go-systemd/v22 v22.5.0 // indirect github.com/coreos/go-systemd/v22 v22.5.0 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect github.com/davecgh/go-spew v1.1.1 // indirect
github.com/dsnet/compress v0.0.2-0.20210315054119-f66993602bf5 // indirect github.com/dsnet/compress v0.0.2-0.20210315054119-f66993602bf5 // indirect
@@ -58,47 +61,57 @@ require (
github.com/dsoprea/go-utility/v2 v2.0.0-20221003172846-a3e1774ef349 // indirect github.com/dsoprea/go-utility/v2 v2.0.0-20221003172846-a3e1774ef349 // indirect
github.com/dustin/go-humanize v1.0.1 // indirect github.com/dustin/go-humanize v1.0.1 // indirect
github.com/geoffgarside/ber v1.1.0 // indirect github.com/geoffgarside/ber v1.1.0 // indirect
github.com/glebarez/go-sqlite v1.21.1 // indirect github.com/gin-contrib/sse v0.1.0 // indirect
github.com/glebarez/go-sqlite v1.21.0 // indirect
github.com/go-errors/errors v1.4.2 // indirect github.com/go-errors/errors v1.4.2 // indirect
github.com/go-ole/go-ole v1.2.6 // indirect github.com/go-ole/go-ole v1.2.6 // indirect
github.com/go-openapi/jsonpointer v0.19.6 // indirect github.com/go-openapi/jsonpointer v0.19.6 // indirect
github.com/go-openapi/swag v0.22.3 // indirect github.com/go-openapi/swag v0.22.3 // indirect
github.com/go-playground/locales v0.14.1 // indirect
github.com/go-playground/universal-translator v0.18.1 // indirect
github.com/go-playground/validator/v10 v10.12.0 // indirect
github.com/goccy/go-json v0.10.2 // indirect
github.com/godbus/dbus/v5 v5.1.0 // indirect github.com/godbus/dbus/v5 v5.1.0 // indirect
github.com/gofrs/uuid v4.4.0+incompatible // indirect github.com/gofrs/uuid v4.4.0+incompatible // indirect
github.com/golang-jwt/jwt v3.2.2+incompatible // indirect github.com/golang-jwt/jwt v3.2.2+incompatible // indirect
github.com/golang-jwt/jwt/v5 v5.0.0 // indirect github.com/golang-jwt/jwt/v4 v4.5.0 // indirect
github.com/golang/geo v0.0.0-20210211234256-740aa86cb551 // indirect github.com/golang/geo v0.0.0-20210211234256-740aa86cb551 // indirect
github.com/golang/protobuf v1.5.3 // indirect github.com/golang/protobuf v1.5.3 // indirect
github.com/golang/snappy v0.0.4 // indirect github.com/golang/snappy v0.0.4 // indirect
github.com/google/go-cmp v0.6.0 // indirect github.com/google/go-cmp v0.5.9 // indirect
github.com/google/go-querystring v1.1.0 // indirect github.com/google/go-querystring v1.1.0 // indirect
github.com/google/safetext v0.0.0-20240104143208-7a7d9b3d812f // indirect github.com/google/uuid v1.3.0 // indirect
github.com/gorilla/mux v1.8.0 // indirect github.com/gorilla/mux v1.8.0 // indirect
github.com/invopop/yaml v0.2.0 // indirect github.com/invopop/yaml v0.2.0 // indirect
github.com/jinzhu/inflection v1.0.0 // indirect github.com/jinzhu/inflection v1.0.0 // indirect
github.com/jinzhu/now v1.1.5 // indirect github.com/jinzhu/now v1.1.5 // indirect
github.com/josharian/intern v1.0.0 // indirect github.com/josharian/intern v1.0.0 // indirect
github.com/klauspost/compress v1.16.5 // indirect github.com/klauspost/compress v1.16.5 // indirect
github.com/klauspost/cpuid/v2 v2.2.4 // indirect
github.com/klauspost/pgzip v1.2.5 // indirect github.com/klauspost/pgzip v1.2.5 // indirect
github.com/labstack/echo-jwt/v4 v4.2.0 // indirect github.com/kr/pretty v0.3.1 // indirect
github.com/labstack/gommon v0.4.2 // indirect github.com/labstack/gommon v0.4.0 // indirect
github.com/leodido/go-urn v1.2.3 // indirect
github.com/lufia/plan9stats v0.0.0-20230110061619-bbe2e5e100de // indirect github.com/lufia/plan9stats v0.0.0-20230110061619-bbe2e5e100de // indirect
github.com/mailru/easyjson v0.7.7 // indirect github.com/mailru/easyjson v0.7.7 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect github.com/mattn/go-isatty v0.0.18 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect
github.com/nwaples/rardecode v1.1.3 // indirect github.com/nwaples/rardecode v1.1.3 // indirect
github.com/pelletier/go-toml/v2 v2.0.7 // indirect
github.com/perimeterx/marshmallow v1.1.4 // indirect github.com/perimeterx/marshmallow v1.1.4 // indirect
github.com/pierrec/lz4/v4 v4.1.17 // indirect github.com/pierrec/lz4/v4 v4.1.17 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/power-devops/perfstat v0.0.0-20221212215047-62379fc7944b // indirect github.com/power-devops/perfstat v0.0.0-20221212215047-62379fc7944b // indirect
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
github.com/samber/lo v1.38.1 // indirect
github.com/tidwall/match v1.1.1 // indirect github.com/tidwall/match v1.1.1 // indirect
github.com/tidwall/pretty v1.2.1 // indirect github.com/tidwall/pretty v1.2.1 // indirect
github.com/tklauser/go-sysconf v0.3.11 // indirect github.com/tklauser/go-sysconf v0.3.11 // indirect
github.com/tklauser/numcpus v0.6.0 // indirect github.com/tklauser/numcpus v0.6.0 // indirect
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
github.com/ugorji/go/codec v1.2.11 // indirect github.com/ugorji/go/codec v1.2.11 // indirect
github.com/ulikunitz/xz v0.5.11 // indirect github.com/ulikunitz/xz v0.5.11 // indirect
github.com/valyala/bytebufferpool v1.0.0 // indirect github.com/valyala/bytebufferpool v1.0.0 // indirect
@@ -107,19 +120,19 @@ require (
github.com/yusufpapurcu/wmi v1.2.2 // indirect github.com/yusufpapurcu/wmi v1.2.2 // indirect
go.uber.org/atomic v1.10.0 // indirect go.uber.org/atomic v1.10.0 // indirect
go.uber.org/multierr v1.11.0 // indirect go.uber.org/multierr v1.11.0 // indirect
golang.org/x/exp v0.0.0-20230713183714-613f0c0eb8a1 // indirect golang.org/x/arch v0.3.0 // indirect
golang.org/x/exp v0.0.0-20220303212507-bbda1eaf7a17 // indirect
golang.org/x/image v0.6.0 // indirect golang.org/x/image v0.6.0 // indirect
golang.org/x/net v0.25.0 // indirect golang.org/x/net v0.9.0 // indirect
golang.org/x/text v0.15.0 // indirect golang.org/x/text v0.9.0 // indirect
golang.org/x/time v0.5.0 // indirect golang.org/x/time v0.3.0 // indirect
google.golang.org/appengine v1.6.7 // indirect google.golang.org/appengine v1.6.7 // indirect
google.golang.org/protobuf v1.30.0 // indirect google.golang.org/protobuf v1.30.0 // indirect
gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect
modernc.org/libc v1.22.4 // indirect modernc.org/libc v1.22.3 // indirect
modernc.org/mathutil v1.5.0 // indirect modernc.org/mathutil v1.5.0 // indirect
modernc.org/memory v1.5.0 // indirect modernc.org/memory v1.5.0 // indirect
modernc.org/sqlite v1.21.2 // indirect modernc.org/sqlite v1.21.0 // indirect
mvdan.cc/sh/v3 v3.7.0 // indirect
) )

174
go.sum
View File

@@ -1,16 +1,22 @@
github.com/Curtis-Milo/nat-type-identifier-go v0.0.0-20220215191915-18d42168c63d h1:62lEBImTxZ83pgzywgDNIrPPuQ+j4ep9QjqrWBn1hrU= github.com/Curtis-Milo/nat-type-identifier-go v0.0.0-20220215191915-18d42168c63d h1:62lEBImTxZ83pgzywgDNIrPPuQ+j4ep9QjqrWBn1hrU=
github.com/Curtis-Milo/nat-type-identifier-go v0.0.0-20220215191915-18d42168c63d/go.mod h1:lW9x+yEjqKdPbE3+cf2fGPJXCw/hChX3Omi9QHTLFsQ= github.com/Curtis-Milo/nat-type-identifier-go v0.0.0-20220215191915-18d42168c63d/go.mod h1:lW9x+yEjqKdPbE3+cf2fGPJXCw/hChX3Omi9QHTLFsQ=
github.com/IceWhaleTech/CasaOS-Common v0.4.9-alpha6 h1:ojExdb1fZDieTBYgNwopHAsW4FMGKkat4id8YwyyE0g= github.com/IceWhaleTech/CasaOS-Common v0.4.4-alpha8 h1:UhCg3d9Cxhx7KVmqh8oUrUl1qFmFdcHee3Zkk4+P2JA=
github.com/IceWhaleTech/CasaOS-Common v0.4.9-alpha6/go.mod h1:W/768nPd9BJXh+a72y8hUJNcmjDvyMqlXxlT+lOT3t4= github.com/IceWhaleTech/CasaOS-Common v0.4.4-alpha8/go.mod h1:2IuYyy5qW1BE6jqC6M+tOU+WtUec1K565rLATBJ9p/0=
github.com/RaveNoX/go-jsoncommentstrip v1.0.0/go.mod h1:78ihd09MekBnJnxpICcwzCMzGrKSKYe4AqU6PDYYpjk= github.com/RaveNoX/go-jsoncommentstrip v1.0.0/go.mod h1:78ihd09MekBnJnxpICcwzCMzGrKSKYe4AqU6PDYYpjk=
github.com/andybalholm/brotli v1.0.1/go.mod h1:loMXtMfwqflxFJPmdbJO0a3KNoPuLBgiu3qAvBg8x/Y= github.com/andybalholm/brotli v1.0.1/go.mod h1:loMXtMfwqflxFJPmdbJO0a3KNoPuLBgiu3qAvBg8x/Y=
github.com/andybalholm/brotli v1.0.5 h1:8uQZIdzKmjc/iuPu7O2ioW48L81FgatrcpfFmiq/cCs= github.com/andybalholm/brotli v1.0.5 h1:8uQZIdzKmjc/iuPu7O2ioW48L81FgatrcpfFmiq/cCs=
github.com/andybalholm/brotli v1.0.5/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= github.com/andybalholm/brotli v1.0.5/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
github.com/apapsch/go-jsonmerge/v2 v2.0.0 h1:axGnT1gRIfimI7gJifB699GoE/oq+F2MU7Dml6nw9rQ= github.com/apapsch/go-jsonmerge/v2 v2.0.0 h1:axGnT1gRIfimI7gJifB699GoE/oq+F2MU7Dml6nw9rQ=
github.com/apapsch/go-jsonmerge/v2 v2.0.0/go.mod h1:lvDnEdqiQrp0O42VQGgmlKpxL1AP2+08jFMw88y4klk= github.com/apapsch/go-jsonmerge/v2 v2.0.0/go.mod h1:lvDnEdqiQrp0O42VQGgmlKpxL1AP2+08jFMw88y4klk=
github.com/benbjohnson/clock v1.3.1 h1:Heo0FGXzOxUHquZbraxt+tT7UXVDhesUQH5ISbsOkCQ= github.com/benbjohnson/clock v1.3.0 h1:ip6w0uFQkncKQ979AypyG0ER7mqUSBdKLOgAle/AT8A=
github.com/benbjohnson/clock v1.3.1/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/benbjohnson/clock v1.3.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
github.com/bmatcuk/doublestar v1.1.1/go.mod h1:UD6OnuiIn0yFxxA2le/rnRU1G4RaI4UvFv1sNto9p6w= github.com/bmatcuk/doublestar v1.1.1/go.mod h1:UD6OnuiIn0yFxxA2le/rnRU1G4RaI4UvFv1sNto9p6w=
github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM=
github.com/bytedance/sonic v1.8.5 h1:kjX0/vo5acEQ/sinD/18SkA/lDDUk23F0RcaHvI7omc=
github.com/bytedance/sonic v1.8.5/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U=
github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY=
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 h1:qSGYFH7+jGhDF8vLC+iwCD4WpbV1EBDSzWkJODFLams=
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk=
github.com/coreos/go-systemd v0.0.0-20191104093116-d3cd4ed1dbcf h1:iW4rZ826su+pqaw19uhpSCzhj44qo35pNgKFGqzDKkU= github.com/coreos/go-systemd v0.0.0-20191104093116-d3cd4ed1dbcf h1:iW4rZ826su+pqaw19uhpSCzhj44qo35pNgKFGqzDKkU=
github.com/coreos/go-systemd v0.0.0-20191104093116-d3cd4ed1dbcf/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/go-systemd v0.0.0-20191104093116-d3cd4ed1dbcf/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs= github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs=
@@ -33,8 +39,8 @@ github.com/dsoprea/go-exif/v3 v3.0.0-20200717053412-08f1b6708903/go.mod h1:0nsO1
github.com/dsoprea/go-exif/v3 v3.0.0-20210625224831-a6301f85c82b/go.mod h1:cg5SNYKHMmzxsr9X6ZeLh/nfBRHHp5PngtEPcujONtk= github.com/dsoprea/go-exif/v3 v3.0.0-20210625224831-a6301f85c82b/go.mod h1:cg5SNYKHMmzxsr9X6ZeLh/nfBRHHp5PngtEPcujONtk=
github.com/dsoprea/go-exif/v3 v3.0.0-20221003160559-cf5cd88aa559/go.mod h1:rW6DMEv25U9zCtE5ukC7ttBRllXj7g7TAHl7tQrT5No= github.com/dsoprea/go-exif/v3 v3.0.0-20221003160559-cf5cd88aa559/go.mod h1:rW6DMEv25U9zCtE5ukC7ttBRllXj7g7TAHl7tQrT5No=
github.com/dsoprea/go-exif/v3 v3.0.0-20221003171958-de6cb6e380a8/go.mod h1:akyZEJZ/k5bmbC9gA612ZLQkcED8enS9vuTiuAkENr0= github.com/dsoprea/go-exif/v3 v3.0.0-20221003171958-de6cb6e380a8/go.mod h1:akyZEJZ/k5bmbC9gA612ZLQkcED8enS9vuTiuAkENr0=
github.com/dsoprea/go-exif/v3 v3.0.1 h1:/IE4iW7gvY7BablV1XY0unqhMv26EYpOquVMwoBo/wc= github.com/dsoprea/go-exif/v3 v3.0.0-20221012082141-d21ac8e2de85 h1:vZkWA0Lduu9QB6qRBtsLy7m5uO/RFNCDH2pzMLTxGts=
github.com/dsoprea/go-exif/v3 v3.0.1/go.mod h1:10HkA1Wz3h398cDP66L+Is9kKDmlqlIJGPv8pk4EWvc= github.com/dsoprea/go-exif/v3 v3.0.0-20221012082141-d21ac8e2de85/go.mod h1:10HkA1Wz3h398cDP66L+Is9kKDmlqlIJGPv8pk4EWvc=
github.com/dsoprea/go-logging v0.0.0-20190624164917-c4f10aab7696/go.mod h1:Nm/x2ZUNRW6Fe5C3LxdY1PyZY5wmDv/s5dkPJ/VB3iA= github.com/dsoprea/go-logging v0.0.0-20190624164917-c4f10aab7696/go.mod h1:Nm/x2ZUNRW6Fe5C3LxdY1PyZY5wmDv/s5dkPJ/VB3iA=
github.com/dsoprea/go-logging v0.0.0-20200517223158-a10564966e9d/go.mod h1:7I+3Pe2o/YSU88W0hWlm9S22W7XI1JFNJ86U0zPKMf8= github.com/dsoprea/go-logging v0.0.0-20200517223158-a10564966e9d/go.mod h1:7I+3Pe2o/YSU88W0hWlm9S22W7XI1JFNJ86U0zPKMf8=
github.com/dsoprea/go-logging v0.0.0-20200710184922-b02d349568dd h1:l+vLbuxptsC6VQyQsfD7NnEC8BZuFpz45PgY+pH8YTg= github.com/dsoprea/go-logging v0.0.0-20200710184922-b02d349568dd h1:l+vLbuxptsC6VQyQsfD7NnEC8BZuFpz45PgY+pH8YTg=
@@ -47,16 +53,21 @@ github.com/dsoprea/go-utility/v2 v2.0.0-20221003172846-a3e1774ef349 h1:DilThiXje
github.com/dsoprea/go-utility/v2 v2.0.0-20221003172846-a3e1774ef349/go.mod h1:4GC5sXji84i/p+irqghpPFZBF8tRN/Q7+700G0/DLe8= github.com/dsoprea/go-utility/v2 v2.0.0-20221003172846-a3e1774ef349/go.mod h1:4GC5sXji84i/p+irqghpPFZBF8tRN/Q7+700G0/DLe8=
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
github.com/frankban/quicktest v1.14.5 h1:dfYrrRyLtiqT9GyKXgdh+k4inNeTvmGbuSgZ3lx3GhA=
github.com/frankban/quicktest v1.14.5/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
github.com/geoffgarside/ber v1.1.0 h1:qTmFG4jJbwiSzSXoNJeHcOprVzZ8Ulde2Rrrifu5U9w= github.com/geoffgarside/ber v1.1.0 h1:qTmFG4jJbwiSzSXoNJeHcOprVzZ8Ulde2Rrrifu5U9w=
github.com/geoffgarside/ber v1.1.0/go.mod h1:jVPKeCbj6MvQZhwLYsGwaGI52oUorHoHKNecGT85ZCc= github.com/geoffgarside/ber v1.1.0/go.mod h1:jVPKeCbj6MvQZhwLYsGwaGI52oUorHoHKNecGT85ZCc=
github.com/getkin/kin-openapi v0.117.0 h1:QT2DyGujAL09F4NrKDHJGsUoIprlIcFVHWDVDcUFE8A= github.com/getkin/kin-openapi v0.115.0 h1:c8WHRLVY3G8m9jQTy0/DnIuljgRwTCB5twZytQS4JyU=
github.com/getkin/kin-openapi v0.117.0/go.mod h1:l5e9PaFUo9fyLJCPGQeXI2ML8c3P8BHOEV2VaAVf/pc= github.com/getkin/kin-openapi v0.115.0/go.mod h1:l5e9PaFUo9fyLJCPGQeXI2ML8c3P8BHOEV2VaAVf/pc=
github.com/glebarez/go-sqlite v1.21.1 h1:7MZyUPh2XTrHS7xNEHQbrhfMZuPSzhkm2A1qgg0y5NY= github.com/gin-contrib/gzip v0.0.6 h1:NjcunTcGAj5CO1gn4N8jHOSIeRFHIbn51z6K+xaN4d4=
github.com/glebarez/go-sqlite v1.21.1/go.mod h1:ISs8MF6yk5cL4n/43rSOmVMGJJjHYr7L2MbZZ5Q4E2E= github.com/gin-contrib/gzip v0.0.6/go.mod h1:QOJlmV2xmayAjkNS2Y8NQsMneuRShOU/kjovCXNuzzk=
github.com/glebarez/sqlite v1.8.0 h1:02X12E2I/4C1n+v90yTqrjRa8yuo7c3KeHI3FRznCvc= github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
github.com/glebarez/sqlite v1.8.0/go.mod h1:bpET16h1za2KOOMb8+jCp6UBP/iahDpfPQqSaYLTLx8= github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
github.com/gin-gonic/gin v1.8.1/go.mod h1:ji8BvRH1azfM+SYow9zQ6SZMvR8qOMZHmsCuWR9tTTk=
github.com/gin-gonic/gin v1.9.0 h1:OjyFBKICoexlu99ctXNR2gg+c5pKrKMuyjgARg9qeY8=
github.com/gin-gonic/gin v1.9.0/go.mod h1:W1Me9+hsUSyj3CePGrd1/QrKJMSJ1Tu/0hFEH89961k=
github.com/glebarez/go-sqlite v1.21.0 h1:b8MHPtBagkSD2gntImZPsG3o3QEXgMDxguW/GLUonHQ=
github.com/glebarez/go-sqlite v1.21.0/go.mod h1:GodsA6yGSa3eKbvpr7dS+JaqazzVfMcjIXvx6KHhW/c=
github.com/glebarez/sqlite v1.7.0 h1:A7Xj/KN2Lvie4Z4rrgQHY8MsbebX3NyWsL3n2i82MVI=
github.com/glebarez/sqlite v1.7.0/go.mod h1:PkeevrRlF/1BhQBCnzcMWzgrIk7IOop+qS2jUYLfHhk=
github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q=
github.com/go-errors/errors v1.0.2/go.mod h1:psDX2osz5VnTOnFWbDeWwS7yejl+uV3FEWEp4lssFEs= github.com/go-errors/errors v1.0.2/go.mod h1:psDX2osz5VnTOnFWbDeWwS7yejl+uV3FEWEp4lssFEs=
github.com/go-errors/errors v1.1.1/go.mod h1:psDX2osz5VnTOnFWbDeWwS7yejl+uV3FEWEp4lssFEs= github.com/go-errors/errors v1.1.1/go.mod h1:psDX2osz5VnTOnFWbDeWwS7yejl+uV3FEWEp4lssFEs=
@@ -72,10 +83,24 @@ github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaL
github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
github.com/go-openapi/swag v0.22.3 h1:yMBqmnQ0gyZvEb/+KzuWZOXgllrXT4SADYbvDaXHv/g= github.com/go-openapi/swag v0.22.3 h1:yMBqmnQ0gyZvEb/+KzuWZOXgllrXT4SADYbvDaXHv/g=
github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14=
github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
github.com/go-playground/locales v0.14.0/go.mod h1:sawfccIbzZTqEDETgFXqTho0QybSa7l++s0DH+LDiLs=
github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
github.com/go-playground/universal-translator v0.18.0/go.mod h1:UvRDBj+xPUEGrFYl+lu/H90nyDXpg0fqeB/AQUGNTVA=
github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
github.com/go-playground/validator/v10 v10.10.0/go.mod h1:74x4gJWsvQexRdW8Pn3dXSGrTK4nAUsbPlLADvpJkos=
github.com/go-playground/validator/v10 v10.12.0 h1:E4gtWgxWxp8YSxExrQFv5BpCahla0PVF2oTTEYaWQGI=
github.com/go-playground/validator/v10 v10.12.0/go.mod h1:hCAPuzYvKdP33pxWa+2+6AIKXEKqjIUyqsNCtbsSJrA=
github.com/go-resty/resty/v2 v2.7.0 h1:me+K9p3uhSmXtrBZ4k9jcEAfJmuC8IivWHwaLZwPrFY= github.com/go-resty/resty/v2 v2.7.0 h1:me+K9p3uhSmXtrBZ4k9jcEAfJmuC8IivWHwaLZwPrFY=
github.com/go-resty/resty/v2 v2.7.0/go.mod h1:9PWDzw47qPphMRFfhsyk0NnSgvluHcljSMVIq3w7q0I= github.com/go-resty/resty/v2 v2.7.0/go.mod h1:9PWDzw47qPphMRFfhsyk0NnSgvluHcljSMVIq3w7q0I=
github.com/go-test/deep v1.0.8 h1:TDsG77qcSprGbC6vTN8OuXp5g+J+b5Pcguhf7Zt61VM= github.com/go-test/deep v1.0.8 h1:TDsG77qcSprGbC6vTN8OuXp5g+J+b5Pcguhf7Zt61VM=
github.com/go-test/deep v1.0.8/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE= github.com/go-test/deep v1.0.8/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE=
github.com/goccy/go-json v0.9.7/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk= github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk=
github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
@@ -84,8 +109,8 @@ github.com/gofrs/uuid v4.4.0+incompatible h1:3qXRTX8/NbyulANqlc0lchS1gqAVxRgsuW1
github.com/gofrs/uuid v4.4.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/gofrs/uuid v4.4.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY= github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY=
github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I= github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I=
github.com/golang-jwt/jwt/v5 v5.0.0 h1:1n1XNM9hk7O9mnQoNBGolZvzebBQ7p93ULHRc28XJUE= github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg=
github.com/golang-jwt/jwt/v5 v5.0.0/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
github.com/golang/geo v0.0.0-20190916061304-5b978397cfec/go.mod h1:QZ0nwyI2jOfgRAoBvP+ab5aRr7c9x7lhGEJrKvBwjWI= github.com/golang/geo v0.0.0-20190916061304-5b978397cfec/go.mod h1:QZ0nwyI2jOfgRAoBvP+ab5aRr7c9x7lhGEJrKvBwjWI=
github.com/golang/geo v0.0.0-20200319012246-673a6f80352d/go.mod h1:QZ0nwyI2jOfgRAoBvP+ab5aRr7c9x7lhGEJrKvBwjWI= github.com/golang/geo v0.0.0-20200319012246-673a6f80352d/go.mod h1:QZ0nwyI2jOfgRAoBvP+ab5aRr7c9x7lhGEJrKvBwjWI=
github.com/golang/geo v0.0.0-20210211234256-740aa86cb551 h1:gtexQ/VGyN+VVFRXSFiguSNcXmS6rkKT+X7FdIrTtfo= github.com/golang/geo v0.0.0-20210211234256-740aa86cb551 h1:gtexQ/VGyN+VVFRXSFiguSNcXmS6rkKT+X7FdIrTtfo=
@@ -106,9 +131,8 @@ github.com/gomodule/redigo v1.8.9/go.mod h1:7ArFNvsTjH8GMMzB4uy1snslv2BwmginuMs0
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/go-github/v36 v36.0.0 h1:ndCzM616/oijwufI7nBRa+5eZHLldT+4yIB68ib5ogs= github.com/google/go-github/v36 v36.0.0 h1:ndCzM616/oijwufI7nBRa+5eZHLldT+4yIB68ib5ogs=
github.com/google/go-github/v36 v36.0.0/go.mod h1:LFlKC047IOqiglRGNqNb9s/iAPTnnjtlshm+bxp+kwk= github.com/google/go-github/v36 v36.0.0/go.mod h1:LFlKC047IOqiglRGNqNb9s/iAPTnnjtlshm+bxp+kwk=
github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
@@ -116,9 +140,6 @@ github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD
github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU= github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26 h1:Xim43kblpZXfIBQsbuBVKCudVG457BR2GZFIz3uw3hQ= github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26 h1:Xim43kblpZXfIBQsbuBVKCudVG457BR2GZFIz3uw3hQ=
github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26/go.mod h1:dDKJzRmX4S37WGHujM7tX//fmj1uioxKzKxz3lo4HJo=
github.com/google/safetext v0.0.0-20240104143208-7a7d9b3d812f h1:o2yGZLlsOj5H5uvtQNEdi6DeA0GbUP3lm0gWW5RvY0s=
github.com/google/safetext v0.0.0-20240104143208-7a7d9b3d812f/go.mod h1:H3K1Iu/utuCfa10JO+GsmKUYSWi7ug57Rk6GaDRHaaQ=
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/googollee/go-socket.io v1.7.0 h1:ODcQSAvVIPvKozXtUGuJDV3pLwdpBLDs1Uoq/QHIlY8= github.com/googollee/go-socket.io v1.7.0 h1:ODcQSAvVIPvKozXtUGuJDV3pLwdpBLDs1Uoq/QHIlY8=
@@ -151,22 +172,27 @@ github.com/klauspost/compress v1.11.4/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYs
github.com/klauspost/compress v1.16.5 h1:IFV2oUNUzZaz+XyusxpLzpzS8Pt5rh0Z16For/djlyI= github.com/klauspost/compress v1.16.5 h1:IFV2oUNUzZaz+XyusxpLzpzS8Pt5rh0Z16For/djlyI=
github.com/klauspost/compress v1.16.5/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= github.com/klauspost/compress v1.16.5/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE=
github.com/klauspost/cpuid v1.2.0/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= github.com/klauspost/cpuid v1.2.0/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
github.com/klauspost/cpuid/v2 v2.2.4 h1:acbojRNwl3o09bUq+yDCtZFc1aiwaAAxtcn8YkZXnvk=
github.com/klauspost/cpuid/v2 v2.2.4/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY=
github.com/klauspost/pgzip v1.2.5 h1:qnWYvvKqedOF2ulHpMG72XQol4ILEJ8k2wwRl/Km8oE= github.com/klauspost/pgzip v1.2.5 h1:qnWYvvKqedOF2ulHpMG72XQol4ILEJ8k2wwRl/Km8oE=
github.com/klauspost/pgzip v1.2.5/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs= github.com/klauspost/pgzip v1.2.5/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/labstack/echo-jwt/v4 v4.2.0 h1:odSISV9JgcSCuhgQSV/6Io3i7nUmfM/QkBeR5GVJj5c= github.com/labstack/echo/v4 v4.10.2 h1:n1jAhnq/elIFTHr1EYpiYtyKgx4RW9ccVgkqByZaN2M=
github.com/labstack/echo-jwt/v4 v4.2.0/go.mod h1:MA2RqdXdEn4/uEglx0HcUOgQSyBaTh5JcaHIan3biwU= github.com/labstack/echo/v4 v4.10.2/go.mod h1:OEyqf2//K1DFdE57vw2DRgWY0M7s65IVQO2FzvI4J5k=
github.com/labstack/echo/v4 v4.12.0 h1:IKpw49IMryVB2p1a4dzwlhP1O2Tf2E0Ir/450lH+kI0= github.com/labstack/gommon v0.4.0 h1:y7cvthEAEbU0yHOf4axH8ZG2NH8knB9iNSoTO8dyIk8=
github.com/labstack/echo/v4 v4.12.0/go.mod h1:UP9Cr2DJXbOK3Kr9ONYzNowSh7HP0aG0ShAyycHSJvM= github.com/labstack/gommon v0.4.0/go.mod h1:uW6kP17uPlLJsD3ijUYn3/M5bAxtlZhMI6m3MFxTMTM=
github.com/labstack/gommon v0.4.2 h1:F8qTUNXgG1+6WQmqoUWnz8WiEU60mXVVw0P4ht1WRA0= github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY=
github.com/labstack/gommon v0.4.2/go.mod h1:QlUFxVM+SNXhDL/Z7YhocGIBYOiwB0mXm1+1bAPHPyU= github.com/leodido/go-urn v1.2.3 h1:6BE2vPT0lqoz3fmOesHZiaiFh7889ssCo2GMvLCfiuA=
github.com/leodido/go-urn v1.2.3/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4=
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I= github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I=
github.com/lufia/plan9stats v0.0.0-20230110061619-bbe2e5e100de h1:V53FWzU6KAZVi1tPp5UIsMoUWJ2/PNwYIDXnu7QuBCE= github.com/lufia/plan9stats v0.0.0-20230110061619-bbe2e5e100de h1:V53FWzU6KAZVi1tPp5UIsMoUWJ2/PNwYIDXnu7QuBCE=
github.com/lufia/plan9stats v0.0.0-20230110061619-bbe2e5e100de/go.mod h1:JKx41uQRwqlTZabZc+kILPrO/3jlKnQ2Z8b7YiVw5cE= github.com/lufia/plan9stats v0.0.0-20230110061619-bbe2e5e100de/go.mod h1:JKx41uQRwqlTZabZc+kILPrO/3jlKnQ2Z8b7YiVw5cE=
@@ -176,11 +202,13 @@ github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
github.com/maruel/natural v1.1.0 h1:2z1NgP/Vae+gYrtC0VuvrTJ6U35OuyUqDdfluLqMWuQ= github.com/maruel/natural v1.1.0 h1:2z1NgP/Vae+gYrtC0VuvrTJ6U35OuyUqDdfluLqMWuQ=
github.com/maruel/natural v1.1.0/go.mod h1:eFVhYCcUOfZFxXoDZam8Ktya72wa79fNC3lc/leA0DQ= github.com/maruel/natural v1.1.0/go.mod h1:eFVhYCcUOfZFxXoDZam8Ktya72wa79fNC3lc/leA0DQ=
github.com/mattn/go-colorable v0.1.11/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.18 h1:DOKFKCQ7FNG2L1rbrmstDN4QVRdS89Nkh85u68Uwp98=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-isatty v0.0.18/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mholt/archiver/v3 v3.5.1 h1:rDjOBX9JSF5BvoJGvjqK479aL70qh9DIpZCl+k7Clwo= github.com/mholt/archiver/v3 v3.5.1 h1:rDjOBX9JSF5BvoJGvjqK479aL70qh9DIpZCl+k7Clwo=
github.com/mholt/archiver/v3 v3.5.1/go.mod h1:e3dqJ7H78uzsRSEACH1joayhuSyhnonssnDhppzS1L4= github.com/mholt/archiver/v3 v3.5.1/go.mod h1:e3dqJ7H78uzsRSEACH1joayhuSyhnonssnDhppzS1L4=
github.com/mileusna/useragent v1.2.1 h1:p3RJWhi3LfuI6BHdddojREyK3p6qX67vIfOVMnUIVr0= github.com/mileusna/useragent v1.2.1 h1:p3RJWhi3LfuI6BHdddojREyK3p6qX67vIfOVMnUIVr0=
@@ -201,11 +229,15 @@ github.com/nwaples/rardecode v1.1.3 h1:cWCaZwfM5H7nAD6PyEdcVnczzV8i/JtotnyW/dD9l
github.com/nwaples/rardecode v1.1.3/go.mod h1:5DzqNKiOdpKKBH87u8VlvAnPZMXcGRhxWkRpHbbfGS0= github.com/nwaples/rardecode v1.1.3/go.mod h1:5DzqNKiOdpKKBH87u8VlvAnPZMXcGRhxWkRpHbbfGS0=
github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc= github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc=
github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ= github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ=
github.com/pelletier/go-toml/v2 v2.0.1/go.mod h1:r9LEWfGN8R5k0VXJ+0BkIe7MYkRdwZOjgMj2KwnJFUo=
github.com/pelletier/go-toml/v2 v2.0.7 h1:muncTPStnKRos5dpVKULv2FVd4bMOhNePj9CjgDb8Us=
github.com/pelletier/go-toml/v2 v2.0.7/go.mod h1:eumQOmlWiOPt5WriQQqoM5y18pDHwha2N+QD+EUNTek=
github.com/perimeterx/marshmallow v1.1.4 h1:pZLDH9RjlLGGorbXhcaQLhfuV0pFMNfPO55FuFkxqLw= github.com/perimeterx/marshmallow v1.1.4 h1:pZLDH9RjlLGGorbXhcaQLhfuV0pFMNfPO55FuFkxqLw=
github.com/perimeterx/marshmallow v1.1.4/go.mod h1:dsXbUu8CRzfYP5a87xpp0xq9S3u0Vchtcl8we9tYaXw= github.com/perimeterx/marshmallow v1.1.4/go.mod h1:dsXbUu8CRzfYP5a87xpp0xq9S3u0Vchtcl8we9tYaXw=
github.com/pierrec/lz4/v4 v4.1.2/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= github.com/pierrec/lz4/v4 v4.1.2/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
github.com/pierrec/lz4/v4 v4.1.17 h1:kV4Ip+/hUBC+8T6+2EgburRtkE9ef4nbY3f4dFhGjMc= github.com/pierrec/lz4/v4 v4.1.17 h1:kV4Ip+/hUBC+8T6+2EgburRtkE9ef4nbY3f4dFhGjMc=
github.com/pierrec/lz4/v4 v4.1.17/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= github.com/pierrec/lz4/v4 v4.1.17/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
@@ -218,29 +250,33 @@ github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs= github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs=
github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro= github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro=
github.com/rogpeppe/go-internal v1.10.1-0.20230524175051-ec119421bb97 h1:3RPlVWzZ/PDqmVuf/FKHARG5EMid/tl7cv54Sw/QRVY= github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
github.com/rogpeppe/go-internal v1.10.1-0.20230524175051-ec119421bb97/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA= github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE=
github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
github.com/samber/lo v1.38.1 h1:j2XEAqXKb09Am4ebOg31SpvzUTTs6EN3VfgeLUhPdXM= github.com/samber/lo v1.38.1 h1:j2XEAqXKb09Am4ebOg31SpvzUTTs6EN3VfgeLUhPdXM=
github.com/samber/lo v1.38.1/go.mod h1:+m/ZKRl6ClXCE2Lgf3MsQlWfh4bn1bz6CXEOxnEXnEA= github.com/samber/lo v1.38.1/go.mod h1:+m/ZKRl6ClXCE2Lgf3MsQlWfh4bn1bz6CXEOxnEXnEA=
github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww=
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
github.com/shirou/gopsutil/v3 v3.23.2 h1:PAWSuiAszn7IhPMBtXsbSCafej7PqUOvY6YywlQUExU= github.com/shirou/gopsutil/v3 v3.23.2 h1:PAWSuiAszn7IhPMBtXsbSCafej7PqUOvY6YywlQUExU=
github.com/shirou/gopsutil/v3 v3.23.2/go.mod h1:gv0aQw33GLo3pG8SiWKiQrbDzbRY1K80RyZJ7V4Th1M= github.com/shirou/gopsutil/v3 v3.23.2/go.mod h1:gv0aQw33GLo3pG8SiWKiQrbDzbRY1K80RyZJ7V4Th1M=
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0=
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
github.com/spkg/bom v0.0.0-20160624110644-59b7046e48ad/go.mod h1:qLr4V1qq6nMqFKkMo8ZTx3f+BZEkzsRUY10Xsm2mwU0= github.com/spkg/bom v0.0.0-20160624110644-59b7046e48ad/go.mod h1:qLr4V1qq6nMqFKkMo8ZTx3f+BZEkzsRUY10Xsm2mwU0=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8=
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= github.com/tidwall/gjson v1.14.4 h1:uo0p8EbA09J7RQaflQ1aBRffTR7xedD2bcIVSYxLnkM=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/tidwall/gjson v1.14.4/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
github.com/tidwall/gjson v1.17.0 h1:/Jocvlh98kcTfpN2+JzGQWQcqrPQwDrVEMApx/M5ZwM=
github.com/tidwall/gjson v1.17.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA= github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA=
github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM=
github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
@@ -250,6 +286,8 @@ github.com/tklauser/go-sysconf v0.3.11 h1:89WgdJhk5SNwJfu+GKyYveZ4IaJ7xAkecBo+Kd
github.com/tklauser/go-sysconf v0.3.11/go.mod h1:GqXfhXY3kiPa0nAXPDIQIWzJbMCB7AmcWpGR8lSZfqI= github.com/tklauser/go-sysconf v0.3.11/go.mod h1:GqXfhXY3kiPa0nAXPDIQIWzJbMCB7AmcWpGR8lSZfqI=
github.com/tklauser/numcpus v0.6.0 h1:kebhY2Qt+3U6RNK7UqpYNA+tJ23IBEGKkB7JQBfDYms= github.com/tklauser/numcpus v0.6.0 h1:kebhY2Qt+3U6RNK7UqpYNA+tJ23IBEGKkB7JQBfDYms=
github.com/tklauser/numcpus v0.6.0/go.mod h1:FEZLMke0lhOUG6w2JadTzp0a+Nl8PF/GFkQ5UVIcaL4= github.com/tklauser/numcpus v0.6.0/go.mod h1:FEZLMke0lhOUG6w2JadTzp0a+Nl8PF/GFkQ5UVIcaL4=
github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI=
github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08=
github.com/ugorji/go v1.2.7/go.mod h1:nF9osbDWLy6bDVv/Rtoh6QgnvNDpmCalQV5urGCCS6M= github.com/ugorji/go v1.2.7/go.mod h1:nF9osbDWLy6bDVv/Rtoh6QgnvNDpmCalQV5urGCCS6M=
github.com/ugorji/go/codec v1.2.7/go.mod h1:WGN1fab3R1fzQlVQTkfxVtIBhWDRqOviHU95kRgeqEY= github.com/ugorji/go/codec v1.2.7/go.mod h1:WGN1fab3R1fzQlVQTkfxVtIBhWDRqOviHU95kRgeqEY=
github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU= github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU=
@@ -260,6 +298,7 @@ github.com/ulikunitz/xz v0.5.11 h1:kpFauv27b6ynzBNT/Xy+1k+fK4WswhN/6PN5WhFAGw8=
github.com/ulikunitz/xz v0.5.11/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= github.com/ulikunitz/xz v0.5.11/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ=
github.com/valyala/fasttemplate v1.2.2 h1:lxLXG0uE3Qnshl9QyaK6XJxMXlQZELvChBOCmQD0Loo= github.com/valyala/fasttemplate v1.2.2 h1:lxLXG0uE3Qnshl9QyaK6XJxMXlQZELvChBOCmQD0Loo=
github.com/valyala/fasttemplate v1.2.2/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= github.com/valyala/fasttemplate v1.2.2/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ=
github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 h1:nIPpBwaJSVYIxUFsDv3M8ofmx9yWTog9BfvIu0q41lo= github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 h1:nIPpBwaJSVYIxUFsDv3M8ofmx9yWTog9BfvIu0q41lo=
@@ -276,14 +315,18 @@ go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
go.uber.org/zap v1.24.0 h1:FiJd5l1UOLj0wCgbSE0rwwXHzEdAZS6hiiSnxJN/D60= go.uber.org/zap v1.24.0 h1:FiJd5l1UOLj0wCgbSE0rwwXHzEdAZS6hiiSnxJN/D60=
go.uber.org/zap v1.24.0/go.mod h1:2kMP+WWQ8aoFoedH3T2sq6iJ2yDWpHbP0f6MQbS9Gkg= go.uber.org/zap v1.24.0/go.mod h1:2kMP+WWQ8aoFoedH3T2sq6iJ2yDWpHbP0f6MQbS9Gkg=
golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
golang.org/x/arch v0.3.0 h1:02VY4/ZcO/gBOH6PUaoiptASxtXU10jazRCP865E97k=
golang.org/x/arch v0.3.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI= golang.org/x/crypto v0.8.0 h1:pd9TJtTueMTVQXzk8E2XESSMQDj/U7OUu0PqJqPXQjQ=
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8= golang.org/x/crypto v0.8.0/go.mod h1:mRqEX+O9/h5TFCrQhkgjo2yKi0yYA+9ecGkdQoHrywE=
golang.org/x/exp v0.0.0-20230713183714-613f0c0eb8a1 h1:MGwJjxBy0HJshjDNfLsYO8xppfqWlA5ZT9OhtUUhTNw= golang.org/x/exp v0.0.0-20220303212507-bbda1eaf7a17 h1:3MTrJm4PyNL9NBqvYDSj3DHl46qQakyfqfWo4jgfaEM=
golang.org/x/exp v0.0.0-20230713183714-613f0c0eb8a1/go.mod h1:FXUEEKJgO7OQYeo8N01OfiKP8RXMtf6e8aTskBGqWdc= golang.org/x/exp v0.0.0-20220303212507-bbda1eaf7a17/go.mod h1:lgLbSvA5ygNOMpwM/9anMpWVlVJ7Z+cHWq/eFuinpGE=
golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/image v0.6.0 h1:bR8b5okrPI3g/gyZakLZHeWxAR8Dn5CyxXv1hLH5g/4= golang.org/x/image v0.6.0 h1:bR8b5okrPI3g/gyZakLZHeWxAR8Dn5CyxXv1hLH5g/4=
golang.org/x/image v0.6.0/go.mod h1:MXLdDR43H7cDJq5GEGXEVeeNhPgi+YYEQ2pC1byI1x0= golang.org/x/image v0.6.0/go.mod h1:MXLdDR43H7cDJq5GEGXEVeeNhPgi+YYEQ2pC1byI1x0=
@@ -304,17 +347,16 @@ golang.org/x/net v0.0.0-20211029224645-99673261e6eb/go.mod h1:9nx3DQGgdP8bBQD5qx
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.0.0-20221002022538-bcab6841153b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= golang.org/x/net v0.0.0-20221002022538-bcab6841153b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac= golang.org/x/net v0.9.0 h1:aWJ/m6xSmxWBx+V0XRHTlrYrPG56jKsLdTFmsSsCzOM=
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.7.0 h1:qe6s0zUXlPX80/dITx3440hWZ7GwMwgDDyrSGTPJG/g= golang.org/x/oauth2 v0.6.0 h1:Lh8GPgSKBfWSwFvtuWOfeI3aAAnbXTSutYxJiOJFgIw=
golang.org/x/oauth2 v0.7.0/go.mod h1:hPLQkd9LyjfXTiRohC/41GhcFqxisoUQ99sCUOHO9x4= golang.org/x/oauth2 v0.6.0/go.mod h1:ycmewcwgD4Rpr3eZJLSB4Kyyljb3qDh40vJ8STE5HKw=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o=
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E=
golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -326,7 +368,12 @@ golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211103235746-7861aae1554b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
@@ -335,13 +382,12 @@ golang.org/x/sys v0.0.0-20220928140112-f11e5e49a4ec/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y= golang.org/x/sys v0.7.0 h1:3jlCCIQZPdOYu1h8BkNvLz8Kgwtae2cagcG/VamtZRU=
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
golang.org/x/term v0.20.0 h1:VnkxpohqXaOBYJtBmEppKUG6mXpi+4O6purfc2+sMhw= golang.org/x/term v0.7.0 h1:BEvjmm5fURWqcfbSKTdpkDXYBrUS1c0m8agp14W48vQ=
golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
@@ -349,10 +395,10 @@ golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk= golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE=
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4=
golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
@@ -367,12 +413,14 @@ google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6
google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng= google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng=
google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc= gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc=
gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc= gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
@@ -382,20 +430,20 @@ gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gorm.io/gorm v1.25.0 h1:+KtYtb2roDz14EQe4bla8CbQlmb9dN3VejSai3lprfU= gorm.io/gorm v1.24.6 h1:wy98aq9oFEetsc4CAbKD2SoBCdMzsbSIvSUUFJuHi5s=
gorm.io/gorm v1.25.0/go.mod h1:L4uxeKpfBml98NYqVqwAdmV1a2nBtAec/cf3fpucW/k= gorm.io/gorm v1.24.6/go.mod h1:L4uxeKpfBml98NYqVqwAdmV1a2nBtAec/cf3fpucW/k=
gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo= gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo=
gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw=
modernc.org/libc v1.22.4 h1:wymSbZb0AlrjdAVX3cjreCHTPCpPARbQXNz6BHPzdwQ= modernc.org/libc v1.22.3 h1:D/g6O5ftAfavceqlLOFwaZuA5KYafKwmr30A6iSqoyY=
modernc.org/libc v1.22.4/go.mod h1:jj+Z7dTNX8fBScMVNRAYZ/jF91K8fdT2hYMThc3YjBY= modernc.org/libc v1.22.3/go.mod h1:MQrloYP209xa2zHome2a8HLiLm6k0UT8CoHpV74tOFw=
modernc.org/mathutil v1.5.0 h1:rV0Ko/6SfM+8G+yKiyI830l3Wuz1zRutdslNoQ0kfiQ= modernc.org/mathutil v1.5.0 h1:rV0Ko/6SfM+8G+yKiyI830l3Wuz1zRutdslNoQ0kfiQ=
modernc.org/mathutil v1.5.0/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E= modernc.org/mathutil v1.5.0/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E=
modernc.org/memory v1.5.0 h1:N+/8c5rE6EqugZwHii4IFsaJ7MUhoWX07J5tC/iI5Ds= modernc.org/memory v1.5.0 h1:N+/8c5rE6EqugZwHii4IFsaJ7MUhoWX07J5tC/iI5Ds=
modernc.org/memory v1.5.0/go.mod h1:PkUhL0Mugw21sHPeskwZW4D6VscE/GQJOnIpCnW6pSU= modernc.org/memory v1.5.0/go.mod h1:PkUhL0Mugw21sHPeskwZW4D6VscE/GQJOnIpCnW6pSU=
modernc.org/sqlite v1.21.2 h1:ixuUG0QS413Vfzyx6FWx6PYTmHaOegTY+hjzhn7L+a0= modernc.org/sqlite v1.21.0 h1:4aP4MdUf15i3R3M2mx6Q90WHKz3nZLoz96zlB6tNdow=
modernc.org/sqlite v1.21.2/go.mod h1:cxbLkB5WS32DnQqeH4h4o1B0eMr8W/y8/RGuxQ3JsC0= modernc.org/sqlite v1.21.0/go.mod h1:XwQ0wZPIh1iKb5mkvCJ3szzbhk+tykC8ZWqTRTgYRwI=
mvdan.cc/sh/v3 v3.7.0 h1:lSTjdP/1xsddtaKfGg7Myu7DnlHItd3/M2tomOcNNBg= rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=
mvdan.cc/sh/v3 v3.7.0/go.mod h1:K2gwkaesF/D7av7Kxl0HbF5kGOd2ArupNTX3X44+8l8=

View File

@@ -34,16 +34,14 @@ type Reader interface {
// List files in the path // List files in the path
// if identify files by path, need to set ID with path,like path.Join(dir.GetID(), obj.GetName()) // if identify files by path, need to set ID with path,like path.Join(dir.GetID(), obj.GetName())
// if identify files by id, need to set ID with corresponding id // if identify files by id, need to set ID with corresponding id
// List(ctx context.Context, dir model.Obj, args model.ListArgs) ([]model.Obj, error) List(ctx context.Context, dir model.Obj, args model.ListArgs) ([]model.Obj, error)
// Link get url/filepath/reader of file // Link get url/filepath/reader of file
// Link(ctx context.Context, file model.Obj, args model.LinkArgs) (*model.Link, error) Link(ctx context.Context, file model.Obj, args model.LinkArgs) (*model.Link, error)
} }
type User interface { type User interface {
// GetRoot get root directory of user // GetRoot get root directory of user
GetUserInfo(ctx context.Context) (string, error) GetUserInfo(ctx context.Context) (string, error)
GetInfo(ctx context.Context) (string, string, string, error)
} }
type Getter interface { type Getter interface {
GetRoot(ctx context.Context) (model.Obj, error) GetRoot(ctx context.Context) (model.Obj, error)
} }

26
main.go
View File

@@ -13,16 +13,17 @@ import (
"time" "time"
"github.com/IceWhaleTech/CasaOS-Common/model" "github.com/IceWhaleTech/CasaOS-Common/model"
"github.com/IceWhaleTech/CasaOS-Common/utils/command"
"github.com/IceWhaleTech/CasaOS-Common/utils/constants" "github.com/IceWhaleTech/CasaOS-Common/utils/constants"
"github.com/IceWhaleTech/CasaOS-Common/utils/logger" "github.com/IceWhaleTech/CasaOS-Common/utils/logger"
util_http "github.com/IceWhaleTech/CasaOS-Common/utils/http" util_http "github.com/IceWhaleTech/CasaOS-Common/utils/http"
"github.com/IceWhaleTech/CasaOS/codegen/message_bus"
"github.com/IceWhaleTech/CasaOS/common" "github.com/IceWhaleTech/CasaOS/common"
"github.com/IceWhaleTech/CasaOS/pkg/cache" "github.com/IceWhaleTech/CasaOS/pkg/cache"
"github.com/IceWhaleTech/CasaOS/pkg/config" "github.com/IceWhaleTech/CasaOS/pkg/config"
"github.com/IceWhaleTech/CasaOS/pkg/sqlite" "github.com/IceWhaleTech/CasaOS/pkg/sqlite"
"github.com/IceWhaleTech/CasaOS/pkg/utils/command"
"github.com/IceWhaleTech/CasaOS/pkg/utils/file" "github.com/IceWhaleTech/CasaOS/pkg/utils/file"
"github.com/IceWhaleTech/CasaOS/route" "github.com/IceWhaleTech/CasaOS/route"
"github.com/IceWhaleTech/CasaOS/service" "github.com/IceWhaleTech/CasaOS/service"
@@ -47,9 +48,6 @@ var (
//go:embed api/casaos/openapi.yaml //go:embed api/casaos/openapi.yaml
_docYAML string _docYAML string
//go:embed build/sysroot/etc/casaos/casaos.conf.sample
_confSample string
configFlag = flag.String("c", "", "config address") configFlag = flag.String("c", "", "config address")
dbFlag = flag.String("db", "", "db path") dbFlag = flag.String("db", "", "db path")
versionFlag = flag.Bool("v", false, "version") versionFlag = flag.Bool("v", false, "version")
@@ -65,7 +63,7 @@ func init() {
println("git commit:", commit) println("git commit:", commit)
println("build date:", date) println("build date:", date)
config.InitSetup(*configFlag, _confSample) config.InitSetup(*configFlag)
logger.LogInit(config.AppInfo.LogPath, config.AppInfo.LogSaveName, config.AppInfo.LogFileExt) logger.LogInit(config.AppInfo.LogPath, config.AppInfo.LogSaveName, config.AppInfo.LogFileExt)
if len(*dbFlag) == 0 { if len(*dbFlag) == 0 {
@@ -83,7 +81,6 @@ func init() {
route.InitFunction() route.InitFunction()
//service.MyService.System().GenreateSystemEntry()
/// ///
//service.MountLists = make(map[string]*mountlib.MountPoint) //service.MountLists = make(map[string]*mountlib.MountPoint)
//configfile.Install() //configfile.Install()
@@ -104,17 +101,20 @@ func main() {
if *versionFlag { if *versionFlag {
return return
} }
v1Router := route.InitV1Router() v1Router := route.InitV1Router()
v2Router := route.InitV2Router() v2Router := route.InitV2Router()
v2DocRouter := route.InitV2DocRouter(_docHTML, _docYAML) v2DocRouter := route.InitV2DocRouter(_docHTML, _docYAML)
v3File := route.InitFile() v3file := route.InitFile()
v4dir := route.InitDir()
mux := &util_http.HandlerMultiplexer{ mux := &util_http.HandlerMultiplexer{
HandlerMap: map[string]http.Handler{ HandlerMap: map[string]http.Handler{
"v1": v1Router, "v1": v1Router,
"v2": v2Router, "v2": v2Router,
"v3": v3File,
"doc": v2DocRouter, "doc": v2DocRouter,
"v3": v3file,
"v4": v4dir,
}, },
} }
@@ -143,8 +143,6 @@ func main() {
"/v1/cloud", "/v1/cloud",
"/v1/recover", "/v1/recover",
"/v1/other", "/v1/other",
"/v1/zt",
"/v1/test",
route.V2APIPath, route.V2APIPath,
route.V2DocPath, route.V2DocPath,
route.V3FilePath, route.V3FilePath,
@@ -154,15 +152,19 @@ func main() {
Path: apiPath, Path: apiPath,
Target: "http://" + listener.Addr().String(), Target: "http://" + listener.Addr().String(),
}) })
if err != nil { if err != nil {
fmt.Println("err", err) fmt.Println("err", err)
panic(err) panic(err)
} }
} }
var events []message_bus.EventType
events = append(events, message_bus.EventType{Name: "casaos:system:utilization", SourceID: common.SERVICENAME, PropertyTypeList: []message_bus.PropertyType{}})
events = append(events, message_bus.EventType{Name: "casaos:file:recover", SourceID: common.SERVICENAME, PropertyTypeList: []message_bus.PropertyType{}})
events = append(events, message_bus.EventType{Name: "casaos:file:operate", SourceID: common.SERVICENAME, PropertyTypeList: []message_bus.PropertyType{}})
// register at message bus // register at message bus
for i := 0; i < 10; i++ { for i := 0; i < 10; i++ {
response, err := service.MyService.MessageBus().RegisterEventTypesWithResponse(context.Background(), common.EventTypes) response, err := service.MyService.MessageBus().RegisterEventTypesWithResponse(context.Background(), events)
if err != nil { if err != nil {
logger.Error("error when trying to register one or more event types - some event type will not be discoverable", zap.Error(err)) logger.Error("error when trying to register one or more event types - some event type will not be discoverable", zap.Error(err))
} }

View File

@@ -1,7 +0,0 @@
package model
type Drive struct {
Name string `json:"name"`
Icon string `json:"icon"`
AuthUrl string `json:"auth_url"`
}

View File

@@ -70,8 +70,7 @@ type FileSetting struct {
DownloadDir string `json:"download_dir"` DownloadDir string `json:"download_dir"`
} }
type BaseInfo struct { type BaseInfo struct {
Hash string `json:"i"` Hash string `json:"i"`
Version string `json:"v"` Version string `json:"v"`
Channel string `json:"c,omitempty"` Channel string `json:"c,omitempty"`
DriveModel string `json:"m,omitempty"`
} }

View File

@@ -23,14 +23,3 @@ type Path struct {
Write bool `json:"write"` Write bool `json:"write"`
Extensions map[string]interface{} `json:"extensions"` Extensions map[string]interface{} `json:"extensions"`
} }
type DeviceInfo struct {
LanIpv4 []string `json:"lan_ipv4"`
Port int `json:"port"`
DeviceName string `json:"device_name"`
DeviceModel string `json:"device_model"`
DeviceSN string `json:"device_sn"`
Initialized bool `json:"initialized"`
OS_Version string `json:"os_version"`
Hash string `json:"hash"`
}

View File

@@ -1,39 +0,0 @@
{
"name": "@icewhale/casaos-openapi",
"version": "0.0.1",
"scripts": {
"clean": "rm -rf generate",
"build": "rm -rf dist && tsc && yarn clean",
"generate:local": "openapi-generator-cli generate -g typescript-axios -i ./api/casaos/openapi.yaml -o ./generate",
"generate:npx": "npx @openapitools/openapi-generator-cli generate -g typescript-axios -i ./api/casaos/openapi.yaml -o ./generate",
"generate:ts": "npx openapi-typescript-codegen --input ./api/casaos/openapi.yaml --output ./generate",
"start": "yarn generate:local && yarn build"
},
"homepage": "https://github.com/IceWhaleTech/CasaOS#readme",
"description": "Casaos Typescript+Axios SDK",
"keywords": [
"CasaOS",
"SDK",
"CasaOS Axios"
],
"main": "dist/index.js",
"files": [
"LICENSE",
"README.md",
"dist",
"generate"
],
"dependencies": {
"axios": "^1.1.0"
},
"devDependencies": {
"all-contributors-cli": "^6.24.0",
"@openapitools/openapi-generator-cli": "2.5.2",
"@types/node": "^18.8.3",
"openapi-typescript-codegen": "^0.23.0",
"typescript": "^4.9.5"
},
"author": "casaos",
"license": "Apache-2.0"
}

View File

@@ -10,10 +10,6 @@
*/ */
package config package config
import ( const (
"path/filepath" USERCONFIGURL = "/etc/casaos/casaos.conf"
"github.com/IceWhaleTech/CasaOS-Common/utils/constants"
) )
var CasaOSConfigFilePath = filepath.Join(constants.DefaultConfigPath, "casaos.conf")

View File

@@ -14,72 +14,80 @@ import (
"fmt" "fmt"
"log" "log"
"os" "os"
"path"
"path/filepath" "path/filepath"
"runtime"
"strings"
"github.com/IceWhaleTech/CasaOS-Common/utils/constants"
"github.com/IceWhaleTech/CasaOS/common"
"github.com/IceWhaleTech/CasaOS/model" "github.com/IceWhaleTech/CasaOS/model"
"github.com/go-ini/ini" "github.com/go-ini/ini"
) )
var ( // 系统配置
SysInfo = &model.SysInfoModel{} var SysInfo = &model.SysInfoModel{}
AppInfo = &model.APPModel{
DBPath: constants.DefaultDataPath,
LogPath: constants.DefaultLogPath,
LogSaveName: common.SERVICENAME,
LogFileExt: "log",
ShellPath: "/usr/share/casaos/shell",
UserDataPath: filepath.Join(constants.DefaultDataPath, "conf"),
}
CommonInfo = &model.CommonModel{
RuntimePath: constants.DefaultRuntimePath,
}
ServerInfo = &model.ServerModel{}
SystemConfigInfo = &model.SystemConfig{}
FileSettingInfo = &model.FileSetting{}
Cfg *ini.File // 用户相关
ConfigFilePath string var AppInfo = &model.APPModel{}
)
var CommonInfo = &model.CommonModel{}
// var RedisInfo = &model.RedisModel{}
// server相关
var ServerInfo = &model.ServerModel{}
var SystemConfigInfo = &model.SystemConfig{}
var FileSettingInfo = &model.FileSetting{}
var Cfg *ini.File
// 初始化设置,获取系统的部分信息。 // 初始化设置,获取系统的部分信息。
func InitSetup(config string, sample string) { func InitSetup(config string) {
ConfigFilePath = CasaOSConfigFilePath configDir := USERCONFIGURL
if len(config) > 0 { if len(config) > 0 {
ConfigFilePath = config configDir = config
} }
if runtime.GOOS == "darwin" {
// create default config file if not exist configDir = "./conf/conf.conf"
if _, err := os.Stat(ConfigFilePath); os.IsNotExist(err) {
fmt.Println("config file not exist, create it")
// create config file
file, err := os.Create(ConfigFilePath)
if err != nil {
panic(err)
}
defer file.Close()
// write default config
_, err = file.WriteString(sample)
if err != nil {
panic(err)
}
} }
var err error var err error
// 读取文件 // 读取文件
Cfg, err = ini.Load(ConfigFilePath) Cfg, err = ini.Load(configDir)
if err != nil { if err != nil {
panic(err) Cfg, err = ini.Load("/etc/casaos.conf")
if err != nil {
Cfg, err = ini.Load("/casaOS/server/conf/conf.ini")
if err != nil {
fmt.Printf("Fail to read file: %v", err)
os.Exit(1)
}
}
} }
mapTo("app", AppInfo) mapTo("app", AppInfo)
// mapTo("redis", RedisInfo)
mapTo("server", ServerInfo) mapTo("server", ServerInfo)
mapTo("system", SystemConfigInfo) mapTo("system", SystemConfigInfo)
mapTo("file", FileSettingInfo) mapTo("file", FileSettingInfo)
mapTo("common", CommonInfo) mapTo("common", CommonInfo)
SystemConfigInfo.ConfigPath = configDir
if len(AppInfo.DBPath) == 0 {
AppInfo.DBPath = "/var/lib/casaos"
}
if len(AppInfo.LogPath) == 0 {
AppInfo.LogPath = "/var/log/casaos/"
}
if len(AppInfo.ShellPath) == 0 {
AppInfo.ShellPath = "/usr/share/casaos/shell"
}
if len(AppInfo.UserDataPath) == 0 {
AppInfo.UserDataPath = "/var/lib/casaos/conf"
}
if len(CommonInfo.RuntimePath) == 0 {
CommonInfo.RuntimePath = "/var/run/casaos"
}
Cfg.SaveTo(configDir)
// AppInfo.ProjectPath = getCurrentDirectory() //os.Getwd()
} }
// 映射 // 映射
@@ -89,3 +97,21 @@ func mapTo(section string, v interface{}) {
log.Fatalf("Cfg.MapTo %s err: %v", section, err) log.Fatalf("Cfg.MapTo %s err: %v", section, err)
} }
} }
// 获取当前执行文件绝对路径go run
func getCurrentAbPathByCaller() string {
var abPath string
_, filename, _, ok := runtime.Caller(0)
if ok {
abPath = path.Dir(filename)
}
return abPath
}
func getCurrentDirectory() string {
dir, err := filepath.Abs(filepath.Dir(os.Args[0]))
if err != nil {
log.Fatal(err)
}
return strings.Replace(dir, "\\", "/", -1)
}

View File

@@ -0,0 +1,159 @@
package command
import (
"bufio"
"fmt"
"io/ioutil"
"os"
"os/exec"
"path/filepath"
"strings"
)
func OnlyExec(cmdStr string) {
cmd := exec.Command("/bin/bash", "-c", cmdStr)
stdout, err := cmd.StdoutPipe()
if err != nil {
fmt.Println(err)
return
}
defer stdout.Close()
if err := cmd.Start(); err != nil {
fmt.Println(err)
return
}
if err := cmd.Wait(); err != nil {
fmt.Println(err)
}
}
func ExecResultStrArray(cmdStr string) []string {
cmd := exec.Command("/bin/bash", "-c", cmdStr)
stdout, err := cmd.StdoutPipe()
if err != nil {
fmt.Println(err)
return nil
}
defer stdout.Close()
if err = cmd.Start(); err != nil {
fmt.Println(err)
return nil
}
// str, err := ioutil.ReadAll(stdout)
networklist := []string{}
outputBuf := bufio.NewReader(stdout)
for {
output, _, err := outputBuf.ReadLine()
if err != nil {
if err.Error() != "EOF" {
fmt.Printf("Error :%s\n", err)
}
break
}
networklist = append(networklist, string(output))
}
if err := cmd.Wait(); err != nil {
fmt.Println(err)
}
return networklist
}
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)
return ""
}
defer stdout.Close()
if err := cmd.Start(); err != nil {
fmt.Println(err)
return ""
}
str, err := ioutil.ReadAll(stdout)
if err != nil {
fmt.Println(err)
return ""
}
if err := cmd.Wait(); err != nil {
fmt.Println(err)
}
return string(str)
}
// 执行 lsblk 命令
func ExecLSBLK() []byte {
output, err := exec.Command("lsblk", "-O", "-J", "-b").Output()
if err != nil {
fmt.Println("lsblk", err)
return nil
}
return output
}
// 执行 lsblk 命令
func ExecLSBLKByPath(path string) []byte {
output, err := exec.Command("lsblk", path, "-O", "-J", "-b").Output()
if err != nil {
fmt.Println("lsblk", err)
return nil
}
return output
}
func ExecuteScripts(scriptDirectory string) {
if _, err := os.Stat(scriptDirectory); os.IsNotExist(err) {
fmt.Printf("No post-start scripts at %s\n", scriptDirectory)
return
}
files, err := os.ReadDir(scriptDirectory)
if err != nil {
fmt.Printf("Failed to read from script directory %s: %s\n", scriptDirectory, err.Error())
return
}
for _, file := range files {
if file.IsDir() {
continue
}
scriptFilepath := filepath.Join(scriptDirectory, file.Name())
f, err := os.Open(scriptFilepath)
if err != nil {
fmt.Printf("Failed to open script file %s: %s\n", scriptFilepath, err.Error())
continue
}
f.Close()
scanner := bufio.NewScanner(f)
scanner.Scan()
shebang := scanner.Text()
interpreter := "/bin/sh"
if strings.HasPrefix(shebang, "#!") {
interpreter = shebang[2:]
}
cmd := exec.Command(interpreter, scriptFilepath)
fmt.Printf("Executing post-start script %s using %s\n", scriptFilepath, interpreter)
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
err = cmd.Run()
if err != nil {
fmt.Printf("Failed to execute post-start script %s: %s\n", scriptFilepath, err.Error())
}
}
fmt.Println("Finished executing post-start scripts.")
}

View File

@@ -0,0 +1,33 @@
package command_test
import (
"os"
"testing"
"github.com/IceWhaleTech/CasaOS/pkg/utils/command"
"go.uber.org/goleak"
"gotest.tools/assert"
)
func TestExecuteScripts(t *testing.T) {
goleak.VerifyNone(t)
// make a temp directory
tmpDir, err := os.MkdirTemp("", "casaos-test-*")
assert.NilError(t, err)
defer os.RemoveAll(tmpDir)
command.ExecuteScripts(tmpDir)
// create a sample script under tmpDir
script := tmpDir + "/test.sh"
f, err := os.Create(script)
assert.NilError(t, err)
defer f.Close()
// write a sample script
_, err = f.WriteString("#!/bin/bash\necho 123")
assert.NilError(t, err)
command.ExecuteScripts(tmpDir)
}

View File

@@ -1,11 +0,0 @@
package utils
import "github.com/labstack/echo/v4"
func DefaultPostForm(ctx echo.Context, key, defaultValue string) string {
value := ctx.Request().Form.Get(key)
if value == "" {
return defaultValue
}
return value
}

View File

@@ -1,11 +0,0 @@
package utils
import "github.com/labstack/echo/v4"
func DefaultQuery(ctx echo.Context, key string, defaultValue string) string {
if value := ctx.QueryParam(key); value != "" {
return value
}
return defaultValue
}

View File

@@ -77,22 +77,6 @@ func RMDir(src string) error {
return nil return nil
} }
func RemoveAll(dir string) error {
err := filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}
if !info.IsDir() {
return os.Remove(path)
}
return nil
})
if err != nil {
return err
}
return os.Remove(dir)
}
// Open a file according to a specific mode // Open a file according to a specific mode
func Open(name string, flag int, perm os.FileMode) (*os.File, error) { func Open(name string, flag int, perm os.FileMode) (*os.File, error) {
f, err := os.OpenFile(name, flag, perm) f, err := os.OpenFile(name, flag, perm)

View File

@@ -1,78 +0,0 @@
package httper
import (
"fmt"
"io/ioutil"
"net/http"
"strings"
)
func ZTGet(url string) ([]byte, error) {
port, err := ioutil.ReadFile("/var/lib/zerotier-one/zerotier-one.port")
if err != nil {
return nil, err
}
// Build the target URL
targetURL := fmt.Sprintf("http://localhost:%s%s", strings.TrimSpace(string(port)), url)
// Create a new request
req, err := http.NewRequest("GET", targetURL, nil)
if err != nil {
return nil, err
}
// Add the X-ZT1-AUTH header
authToken, err := ioutil.ReadFile("/var/lib/zerotier-one/authtoken.secret")
if err != nil {
return nil, err
}
req.Header.Set("X-ZT1-AUTH", strings.TrimSpace(string(authToken)))
client := http.Client{}
resp, err := client.Do(req)
if err != nil {
return nil, err
}
defer resp.Body.Close()
respBody, err := ioutil.ReadAll(resp.Body)
if err != nil {
return nil, err
}
return respBody, nil
}
func ZTPost(url string, body string) ([]byte, error) {
port, err := ioutil.ReadFile("/var/lib/zerotier-one/zerotier-one.port")
if err != nil {
return nil, err
}
// Build the target URL
targetURL := fmt.Sprintf("http://localhost:%s%s", strings.TrimSpace(string(port)), url)
// Create a new request
req, err := http.NewRequest("POST", targetURL, strings.NewReader(body))
if err != nil {
return nil, err
}
// Add the X-ZT1-AUTH header
authToken, err := ioutil.ReadFile("/var/lib/zerotier-one/authtoken.secret")
if err != nil {
return nil, err
}
req.Header.Set("X-ZT1-AUTH", strings.TrimSpace(string(authToken)))
client := http.Client{}
resp, err := client.Do(req)
if err != nil {
return nil, err
}
defer resp.Body.Close()
respBody, err := ioutil.ReadAll(resp.Body)
if err != nil {
return nil, err
}
return respBody, nil
}

View File

@@ -1,7 +1,6 @@
package ip_helper package ip_helper
import ( import (
"fmt"
"net" "net"
"strings" "strings"
@@ -57,30 +56,7 @@ func GetDeviceAllIP(port string) []string {
} }
return address return address
} }
func GetDeviceAllIPv4() map[string]string {
address := make(map[string]string)
addrs, err := net.Interfaces()
if err != nil {
return address
}
for _, a := range addrs {
if a.Flags&net.FlagLoopback != 0 || a.Flags&net.FlagUp == 0 {
continue
}
addrs, err := a.Addrs()
if err != nil {
fmt.Println("Error:", err)
continue
}
for _, addr := range addrs {
if ipnet, ok := addr.(*net.IPNet); ok && !ipnet.IP.IsLoopback() && ipnet.IP.To4() != nil {
address[a.Name] = ipnet.IP.String()
}
}
}
return address
}
func HasLocalIP(ip net.IP) bool { func HasLocalIP(ip net.IP) bool {
if ip.IsLoopback() { if ip.IsLoopback() {
return true return true

View File

@@ -17,7 +17,6 @@ import (
"strings" "strings"
"time" "time"
file1 "github.com/IceWhaleTech/CasaOS-Common/utils/file"
"github.com/IceWhaleTech/CasaOS-Common/utils/logger" "github.com/IceWhaleTech/CasaOS-Common/utils/logger"
"github.com/IceWhaleTech/CasaOS/common" "github.com/IceWhaleTech/CasaOS/common"
"github.com/IceWhaleTech/CasaOS/model" "github.com/IceWhaleTech/CasaOS/model"
@@ -25,7 +24,6 @@ import (
"github.com/IceWhaleTech/CasaOS/pkg/samba" "github.com/IceWhaleTech/CasaOS/pkg/samba"
"github.com/IceWhaleTech/CasaOS/pkg/utils/encryption" "github.com/IceWhaleTech/CasaOS/pkg/utils/encryption"
"github.com/IceWhaleTech/CasaOS/pkg/utils/file" "github.com/IceWhaleTech/CasaOS/pkg/utils/file"
v1 "github.com/IceWhaleTech/CasaOS/route/v1"
"github.com/IceWhaleTech/CasaOS/service" "github.com/IceWhaleTech/CasaOS/service"
"go.uber.org/zap" "go.uber.org/zap"
) )
@@ -33,7 +31,6 @@ import (
func InitFunction() { func InitFunction() {
go InitNetworkMount() go InitNetworkMount()
go InitInfo() go InitInfo()
//go InitZerotier()
} }
func InitInfo() { func InitInfo() {
@@ -54,12 +51,6 @@ func InitInfo() {
} }
mb.Hash = encryption.GetMD5ByStr(mac) mb.Hash = encryption.GetMD5ByStr(mac)
mb.Version = common.VERSION mb.Version = common.VERSION
osRelease, _ := file1.ReadOSRelease()
mb.DriveModel = osRelease["MODEL"]
if len(mb.DriveModel) == 0 {
mb.DriveModel = "Casa"
}
os.Remove(config.AppInfo.DBPath + "/baseinfo.conf") os.Remove(config.AppInfo.DBPath + "/baseinfo.conf")
by, err := json.Marshal(mb) by, err := json.Marshal(mb)
if err != nil { if err != nil {
@@ -107,6 +98,3 @@ func InitNetworkMount() {
logger.Error("mount storage err", zap.Any("err", err)) logger.Error("mount storage err", zap.Any("err", err))
} }
} }
func InitZerotier() {
v1.CheckNetwork()
}

View File

@@ -2,68 +2,50 @@ package route
import ( import (
"crypto/ecdsa" "crypto/ecdsa"
"net/http" "os"
"strconv"
"github.com/IceWhaleTech/CasaOS-Common/external" "github.com/IceWhaleTech/CasaOS-Common/external"
"github.com/IceWhaleTech/CasaOS-Common/middleware"
"github.com/IceWhaleTech/CasaOS-Common/utils/jwt" "github.com/IceWhaleTech/CasaOS-Common/utils/jwt"
"github.com/IceWhaleTech/CasaOS/common"
"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"
"github.com/labstack/echo/v4"
echo_middleware "github.com/labstack/echo/v4/middleware" "github.com/gin-contrib/gzip"
"github.com/gin-gonic/gin"
) )
func InitV1Router() http.Handler { func InitV1Router() *gin.Engine {
e := echo.New() ginMode := gin.ReleaseMode
if config.ServerInfo.RunMode != "" {
ginMode = config.ServerInfo.RunMode
}
if os.Getenv(gin.EnvGinMode) != "" {
ginMode = os.Getenv(gin.EnvGinMode)
}
gin.SetMode(ginMode)
e.Use((echo_middleware.CORSWithConfig(echo_middleware.CORSConfig{ r := gin.New()
AllowOrigins: []string{"*"}, r.Use(gin.Recovery())
AllowMethods: []string{echo.POST, echo.GET, echo.OPTIONS, echo.PUT, echo.DELETE}, r.Use(middleware.Cors())
AllowHeaders: []string{echo.HeaderAuthorization, echo.HeaderContentLength, echo.HeaderXCSRFToken, echo.HeaderContentType, echo.HeaderAccessControlAllowOrigin, echo.HeaderAccessControlAllowHeaders, echo.HeaderAccessControlAllowMethods, echo.HeaderConnection, echo.HeaderOrigin, echo.HeaderXRequestedWith}, r.Use(gzip.Gzip(gzip.DefaultCompression))
ExposeHeaders: []string{echo.HeaderContentLength, echo.HeaderAccessControlAllowOrigin, echo.HeaderAccessControlAllowHeaders}, if ginMode != gin.ReleaseMode {
MaxAge: 172800, r.Use(middleware.WriteLog())
AllowCredentials: true, }
})))
e.Use(echo_middleware.Gzip())
e.Use(echo_middleware.Recover())
e.Use(echo_middleware.Logger())
e.GET("/v1/sys/debug", v1.GetSystemConfigDebug) // //debug r.GET("/v1/sys/debug", v1.GetSystemConfigDebug) // //debug
e.GET("/v1/sys/version/check", v1.GetSystemCheckVersion) r.GET("/v1/sys/version/check", v1.GetSystemCheckVersion)
e.GET("/v1/sys/version/current", func(ctx echo.Context) error { r.GET("/ping", func(ctx *gin.Context) {
return ctx.String(200, common.VERSION) ctx.String(200, "pong")
}) })
e.GET("/ping", func(ctx echo.Context) error { r.GET("/v1/recover/:type", v1.GetRecoverStorage)
return ctx.String(200, "pong") v1Group := r.Group("/v1")
})
e.GET("/v1/recover/:type", v1.GetRecoverStorage)
v1Group := e.Group("/v1")
// e.Any("/v1/test", v1.CheckNetwork)
v1Group.Use(echo_middleware.JWTWithConfig(echo_middleware.JWTConfig{
Skipper: func(c echo.Context) bool {
return c.RealIP() == "::1" || c.RealIP() == "127.0.0.1"
},
ParseTokenFunc: func(token string, c echo.Context) (interface{}, error) {
valid, claims, err := jwt.Validate(token, func() (*ecdsa.PublicKey, error) { return external.GetPublicKey(config.CommonInfo.RuntimePath) })
if err != nil || !valid {
return nil, echo.ErrUnauthorized
}
c.Request().Header.Set("user_id", strconv.Itoa(claims.ID)) v1Group.Use(jwt.ExceptLocalhost(
func() (*ecdsa.PublicKey, error) {
return claims, nil return external.GetPublicKey(config.CommonInfo.RuntimePath)
}, },
TokenLookupFuncs: []echo_middleware.ValuesExtractor{ ))
func(ctx echo.Context) ([]string, error) {
if len(ctx.Request().Header.Get(echo.HeaderAuthorization)) > 0 {
return []string{ctx.Request().Header.Get(echo.HeaderAuthorization)}, nil
}
return []string{ctx.QueryParam("token")}, nil
},
},
}))
{ {
v1SysGroup := v1Group.Group("/sys") v1SysGroup := v1Group.Group("/sys")
@@ -97,7 +79,6 @@ func InitV1Router() http.Handler {
// v1SysGroup.PUT("/port", v1.PutCasaOSPort) // v1SysGroup.PUT("/port", v1.PutCasaOSPort)
v1SysGroup.GET("/proxy", v1.GetSystemProxy) v1SysGroup.GET("/proxy", v1.GetSystemProxy)
v1SysGroup.PUT("/state/:state", v1.PutSystemState) v1SysGroup.PUT("/state/:state", v1.PutSystemState)
v1SysGroup.GET("/entry", v1.GetSystemEntry)
} }
v1PortGroup := v1Group.Group("/port") v1PortGroup := v1Group.Group("/port")
v1PortGroup.Use() v1PortGroup.Use()
@@ -105,6 +86,7 @@ func InitV1Router() http.Handler {
v1PortGroup.GET("/", v1.GetPort) // app/port v1PortGroup.GET("/", v1.GetPort) // app/port
v1PortGroup.GET("/state/:port", v1.PortCheck) // app/check/:port v1PortGroup.GET("/state/:port", v1.PortCheck) // app/check/:port
} }
v1FileGroup := v1Group.Group("/file") v1FileGroup := v1Group.Group("/file")
v1FileGroup.Use() v1FileGroup.Use()
{ {
@@ -116,7 +98,7 @@ func InitV1Router() http.Handler {
v1FileGroup.GET("/content", v1.GetFilerContent) // file/read 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.POST("/upload", v1.PostFileUpload)
v1FileGroup.POST("/upload", v1.PostFileUpload) v1FileGroup.POST("/upload", v1.PostFileUpload)
v1FileGroup.GET("/upload", v1.GetFileUpload) v1FileGroup.GET("/upload", v1.GetFileUpload)
// v1FileGroup.GET("/download", v1.UserFileDownloadCommonService) // v1FileGroup.GET("/download", v1.UserFileDownloadCommonService)
@@ -189,13 +171,9 @@ func InitV1Router() http.Handler {
v1OtherGroup.Use() v1OtherGroup.Use()
{ {
v1OtherGroup.GET("/search", v1.GetSearchResult) v1OtherGroup.GET("/search", v1.GetSearchResult)
}
v1ZerotierGroup := v1Group.Group("/zt")
v1ZerotierGroup.Use()
{
v1ZerotierGroup.Any("/*url", v1.ZerotierProxy)
} }
} }
return e return r
} }

View File

@@ -6,36 +6,37 @@ import (
"github.com/IceWhaleTech/CasaOS-Common/utils/logger" "github.com/IceWhaleTech/CasaOS-Common/utils/logger"
"github.com/IceWhaleTech/CasaOS/drivers/dropbox" "github.com/IceWhaleTech/CasaOS/drivers/dropbox"
"github.com/IceWhaleTech/CasaOS/drivers/google_drive" "github.com/IceWhaleTech/CasaOS/drivers/google_drive"
"github.com/IceWhaleTech/CasaOS/drivers/onedrive"
"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/httper" "github.com/IceWhaleTech/CasaOS/pkg/utils/httper"
"github.com/IceWhaleTech/CasaOS/service" "github.com/IceWhaleTech/CasaOS/service"
"github.com/labstack/echo/v4" "github.com/gin-gonic/gin"
"go.uber.org/zap" "go.uber.org/zap"
) )
func ListStorages(ctx echo.Context) error { func ListStorages(c *gin.Context) {
// var req model.PageReq // var req model.PageReq
// if err := ctx.Bind(&req); err != nil { // if err := c.ShouldBind(&req); err != nil {
// return ctx.JSON(common_err.SUCCESS, model.Result{Success: common_err.CLIENT_ERROR, Message: common_err.GetMsg(common_err.CLIENT_ERROR), Data: err.Error()}) // c.JSON(common_err.SUCCESS, model.Result{Success: common_err.CLIENT_ERROR, Message: common_err.GetMsg(common_err.CLIENT_ERROR), Data: err.Error()})
// return // return
// } // }
// req.Validate() // req.Validate()
// logger.Info("ListStorages", zap.Any("req", req)) //logger.Info("ListStorages", zap.Any("req", req))
// storages, total, err := service.MyService.Storage().GetStorages(req.Page, req.PerPage) //storages, total, err := service.MyService.Storage().GetStorages(req.Page, req.PerPage)
// if err != nil { // if err != nil {
// return ctx.JSON(common_err.SUCCESS, model.Result{Success: common_err.SERVICE_ERROR, Message: common_err.GetMsg(common_err.SERVICE_ERROR), Data: err.Error()}) // c.JSON(common_err.SUCCESS, model.Result{Success: common_err.SERVICE_ERROR, Message: common_err.GetMsg(common_err.SERVICE_ERROR), Data: err.Error()})
// return // return
// } // }
// return ctx.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: model.PageResp{ // c.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: model.PageResp{
// Content: storages, // Content: storages,
// Total: total, // Total: total,
// }}) // }})
r, err := service.MyService.Storage().GetStorages() r, err := service.MyService.Storage().GetStorages()
if err != nil { if err != nil {
return ctx.JSON(common_err.SUCCESS, model.Result{Success: common_err.SERVICE_ERROR, Message: common_err.GetMsg(common_err.SERVICE_ERROR), Data: err.Error()}) c.JSON(common_err.SUCCESS, model.Result{Success: common_err.SERVICE_ERROR, Message: common_err.GetMsg(common_err.SERVICE_ERROR), Data: err.Error()})
return
} }
for i := 0; i < len(r.MountPoints); i++ { for i := 0; i < len(r.MountPoints); i++ {
@@ -50,9 +51,6 @@ func ListStorages(ctx echo.Context) error {
if dataMap["type"] == "dropbox" { if dataMap["type"] == "dropbox" {
r.MountPoints[i].Icon = dropbox.ICONURL r.MountPoints[i].Icon = dropbox.ICONURL
} }
if dataMap["type"] == "onedrive" {
r.MountPoints[i].Icon = onedrive.ICONURL
}
r.MountPoints[i].Name = dataMap["username"] r.MountPoints[i].Name = dataMap["username"]
} }
list := []httper.MountPoint{} list := []httper.MountPoint{}
@@ -66,36 +64,38 @@ func ListStorages(ctx echo.Context) error {
}) })
} }
return ctx.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: list})
} }
func UmountStorage(ctx echo.Context) error { func UmountStorage(c *gin.Context) {
json := make(map[string]string) json := make(map[string]string)
ctx.Bind(&json) c.ShouldBind(&json)
mountPoint := json["mount_point"] mountPoint := json["mount_point"]
if mountPoint == "" { if mountPoint == "" {
return ctx.JSON(common_err.CLIENT_ERROR, model.Result{Success: common_err.CLIENT_ERROR, Message: common_err.GetMsg(common_err.CLIENT_ERROR), Data: "mount_point is empty"}) c.JSON(common_err.CLIENT_ERROR, model.Result{Success: common_err.CLIENT_ERROR, Message: common_err.GetMsg(common_err.CLIENT_ERROR), Data: "mount_point is empty"})
return
} }
err := service.MyService.Storage().UnmountStorage(mountPoint) err := service.MyService.Storage().UnmountStorage(mountPoint)
if err != nil { if err != nil {
return ctx.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
} }
service.MyService.Storage().DeleteConfigByName(strings.ReplaceAll(mountPoint, "/mnt/", "")) service.MyService.Storage().DeleteConfigByName(strings.ReplaceAll(mountPoint, "/mnt/", ""))
return ctx.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: "success"}) c.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: "success"})
} }
func GetStorage(ctx echo.Context) error { func GetStorage(c *gin.Context) {
// idStr := ctx.QueryParam("id")
// idStr := c.Query("id")
// id, err := strconv.Atoi(idStr) // id, err := strconv.Atoi(idStr)
// if err != nil { // if err != nil {
// return ctx.JSON(common_err.SUCCESS, model.Result{Success: common_err.CLIENT_ERROR, Message: common_err.GetMsg(common_err.CLIENT_ERROR), Data: err.Error()}) // c.JSON(common_err.SUCCESS, model.Result{Success: common_err.CLIENT_ERROR, Message: common_err.GetMsg(common_err.CLIENT_ERROR), Data: err.Error()})
// return // return
// } // }
// storage, err := service.MyService.Storage().GetStorageById(uint(id)) // storage, err := service.MyService.Storage().GetStorageById(uint(id))
// if err != nil { // if err != nil {
// return ctx.JSON(common_err.SUCCESS, model.Result{Success: common_err.SERVICE_ERROR, Message: common_err.GetMsg(common_err.SERVICE_ERROR), Data: err.Error()}) // c.JSON(common_err.SUCCESS, model.Result{Success: common_err.SERVICE_ERROR, Message: common_err.GetMsg(common_err.SERVICE_ERROR), Data: err.Error()})
// return // return
// } // }
// return ctx.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: storage}) // c.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: storage})
return nil
} }

View File

@@ -1,34 +1,12 @@
package v1 package v1
import ( import (
"github.com/IceWhaleTech/CasaOS-Common/model"
"github.com/IceWhaleTech/CasaOS-Common/utils/common_err" "github.com/IceWhaleTech/CasaOS-Common/utils/common_err"
"github.com/IceWhaleTech/CasaOS/drivers/dropbox" "github.com/IceWhaleTech/CasaOS/internal/op"
"github.com/IceWhaleTech/CasaOS/drivers/google_drive" "github.com/gin-gonic/gin"
"github.com/IceWhaleTech/CasaOS/drivers/onedrive"
"github.com/IceWhaleTech/CasaOS/model"
"github.com/labstack/echo/v4"
) )
func ListDriverInfo(ctx echo.Context) error { func ListDriverInfo(c *gin.Context) {
list := []model.Drive{} c.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: op.GetDriverInfoMap()})
google := google_drive.GetConfig()
list = append(list, model.Drive{
Name: "Google Drive",
Icon: google.Icon,
AuthUrl: google.AuthUrl,
})
dp := dropbox.GetConfig()
list = append(list, model.Drive{
Name: "Dropbox",
Icon: dp.Icon,
AuthUrl: dp.AuthUrl,
})
od := onedrive.GetConfig()
list = append(list, model.Drive{
Name: "OneDrive",
Icon: od.Icon,
AuthUrl: od.AuthUrl,
})
return ctx.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: list})
} }

View File

@@ -20,17 +20,16 @@ import (
"github.com/IceWhaleTech/CasaOS-Common/utils/logger" "github.com/IceWhaleTech/CasaOS-Common/utils/logger"
"github.com/IceWhaleTech/CasaOS/model" "github.com/IceWhaleTech/CasaOS/model"
"github.com/gorilla/websocket" "github.com/gorilla/websocket"
"github.com/labstack/echo/v4"
"github.com/robfig/cron/v3" "github.com/robfig/cron/v3"
"github.com/tidwall/gjson" "github.com/tidwall/gjson"
"github.com/IceWhaleTech/CasaOS/pkg/utils"
"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/service" "github.com/IceWhaleTech/CasaOS/service"
model2 "github.com/IceWhaleTech/CasaOS/service/model" model2 "github.com/IceWhaleTech/CasaOS/service/model"
"github.com/google/uuid" "github.com/gin-gonic/gin"
uuid "github.com/satori/go.uuid"
"go.uber.org/zap" "go.uber.org/zap"
"github.com/h2non/filetype" "github.com/h2non/filetype"
@@ -39,9 +38,8 @@ import (
type ListReq struct { type ListReq struct {
model.PageReq model.PageReq
Path string `json:"path" form:"path"` Path string `json:"path" form:"path"`
// Refresh bool `json:"refresh"` //Refresh bool `json:"refresh"`
} }
type ObjResp struct { type ObjResp struct {
Name string `json:"name"` Name string `json:"name"`
Size int64 `json:"size"` Size int64 `json:"size"`
@@ -84,53 +82,58 @@ var (
// @Param path query string true "路径" // @Param path query string true "路径"
// @Success 200 {string} string "ok" // @Success 200 {string} string "ok"
// @Router /file/read [get] // @Router /file/read [get]
func GetFilerContent(ctx echo.Context) error { func GetFilerContent(c *gin.Context) {
filePath := ctx.QueryParam("path") filePath := c.Query("path")
if len(filePath) == 0 { if len(filePath) == 0 {
return ctx.JSON(common_err.CLIENT_ERROR, model.Result{ c.JSON(common_err.CLIENT_ERROR, model.Result{
Success: common_err.INVALID_PARAMS, Success: common_err.INVALID_PARAMS,
Message: common_err.GetMsg(common_err.INVALID_PARAMS), Message: common_err.GetMsg(common_err.INVALID_PARAMS),
}) })
return
} }
if !file.Exists(filePath) { if !file.Exists(filePath) {
return ctx.JSON(common_err.SERVICE_ERROR, model.Result{ c.JSON(common_err.SERVICE_ERROR, model.Result{
Success: common_err.FILE_DOES_NOT_EXIST, Success: common_err.FILE_DOES_NOT_EXIST,
Message: common_err.GetMsg(common_err.FILE_DOES_NOT_EXIST), Message: common_err.GetMsg(common_err.FILE_DOES_NOT_EXIST),
}) })
return
} }
// 文件读取任务是将文件内容读取到内存中。 // 文件读取任务是将文件内容读取到内存中。
info, err := ioutil.ReadFile(filePath) info, err := ioutil.ReadFile(filePath)
if err != nil { if err != nil {
return ctx.JSON(common_err.SERVICE_ERROR, model.Result{ c.JSON(common_err.SERVICE_ERROR, model.Result{
Success: common_err.FILE_READ_ERROR, Success: common_err.FILE_READ_ERROR,
Message: common_err.GetMsg(common_err.FILE_READ_ERROR), Message: common_err.GetMsg(common_err.FILE_READ_ERROR),
Data: err.Error(), Data: err.Error(),
}) })
return
} }
result := string(info) result := string(info)
return ctx.JSON(common_err.SUCCESS, model.Result{ c.JSON(common_err.SUCCESS, model.Result{
Success: common_err.SUCCESS, Success: common_err.SUCCESS,
Message: common_err.GetMsg(common_err.SUCCESS), Message: common_err.GetMsg(common_err.SUCCESS),
Data: result, Data: result,
}) })
} }
func GetLocalFile(ctx echo.Context) error { func GetLocalFile(c *gin.Context) {
path := ctx.QueryParam("path") path := c.Query("path")
if len(path) == 0 { if len(path) == 0 {
return ctx.JSON(http.StatusOK, model.Result{ c.JSON(http.StatusOK, model.Result{
Success: common_err.INVALID_PARAMS, Success: common_err.INVALID_PARAMS,
Message: common_err.GetMsg(common_err.INVALID_PARAMS), Message: common_err.GetMsg(common_err.INVALID_PARAMS),
}) })
return
} }
if !file.Exists(path) { if !file.Exists(path) {
return ctx.JSON(http.StatusOK, model.Result{ c.JSON(http.StatusOK, model.Result{
Success: common_err.FILE_DOES_NOT_EXIST, Success: common_err.FILE_DOES_NOT_EXIST,
Message: common_err.GetMsg(common_err.FILE_DOES_NOT_EXIST), Message: common_err.GetMsg(common_err.FILE_DOES_NOT_EXIST),
}) })
return
} }
return ctx.File(path) c.File(path)
} }
// @Summary download // @Summary download
@@ -142,39 +145,42 @@ func GetLocalFile(ctx echo.Context) error {
// @Param files query string true "file list eg: filename1,filename2,filename3 " // @Param files query string true "file list eg: filename1,filename2,filename3 "
// @Success 200 {string} string "ok" // @Success 200 {string} string "ok"
// @Router /file/download [get] // @Router /file/download [get]
func GetDownloadFile(ctx echo.Context) error { func GetDownloadFile(c *gin.Context) {
t := ctx.QueryParam("format") t := c.Query("format")
files := ctx.QueryParam("files") files := c.Query("files")
if len(files) == 0 { if len(files) == 0 {
return ctx.JSON(common_err.CLIENT_ERROR, model.Result{ c.JSON(common_err.CLIENT_ERROR, model.Result{
Success: common_err.INVALID_PARAMS, Success: common_err.INVALID_PARAMS,
Message: common_err.GetMsg(common_err.INVALID_PARAMS), Message: common_err.GetMsg(common_err.INVALID_PARAMS),
}) })
return
} }
list := strings.Split(files, ",") list := strings.Split(files, ",")
for _, v := range list { for _, v := range list {
if !file.Exists(v) { if !file.Exists(v) {
return ctx.JSON(common_err.SERVICE_ERROR, model.Result{ c.JSON(common_err.SERVICE_ERROR, model.Result{
Success: common_err.FILE_DOES_NOT_EXIST, Success: common_err.FILE_DOES_NOT_EXIST,
Message: common_err.GetMsg(common_err.FILE_DOES_NOT_EXIST), Message: common_err.GetMsg(common_err.FILE_DOES_NOT_EXIST),
}) })
return
} }
} }
ctx.Request().Header.Add("Content-Type", "application/octet-stream") c.Header("Content-Type", "application/octet-stream")
ctx.Request().Header.Add("Content-Transfer-Encoding", "binary") c.Header("Content-Transfer-Encoding", "binary")
ctx.Request().Header.Add("Cache-Control", "no-cache") c.Header("Cache-Control", "no-cache")
// handles only single files not folders and multiple files // handles only single files not folders and multiple files
if len(list) == 1 { if len(list) == 1 {
filePath := list[0] filePath := list[0]
info, err := os.Stat(filePath) info, err := os.Stat(filePath)
if err != nil { if err != nil {
return ctx.JSON(http.StatusOK, model.Result{ c.JSON(http.StatusOK, model.Result{
Success: common_err.FILE_DOES_NOT_EXIST, Success: common_err.FILE_DOES_NOT_EXIST,
Message: common_err.GetMsg(common_err.FILE_DOES_NOT_EXIST), Message: common_err.GetMsg(common_err.FILE_DOES_NOT_EXIST),
}) })
return
} }
if !info.IsDir() { if !info.IsDir() {
@@ -184,26 +190,29 @@ func GetDownloadFile(ctx echo.Context) error {
// 获取文件的名称 // 获取文件的名称
fileName := path.Base(filePath) fileName := path.Base(filePath)
ctx.Response().Header().Add("Content-Disposition", "attachment; filename*=utf-8''"+url2.PathEscape(fileName)) c.Header("Content-Disposition", "attachment; filename*=utf-8''"+url2.PathEscape(fileName))
ctx.File(filePath) c.File(filePath)
return
} }
} }
extension, ar, err := file.GetCompressionAlgorithm(t) extension, ar, err := file.GetCompressionAlgorithm(t)
if err != nil { if err != nil {
return ctx.JSON(common_err.CLIENT_ERROR, model.Result{ c.JSON(common_err.CLIENT_ERROR, model.Result{
Success: common_err.INVALID_PARAMS, Success: common_err.INVALID_PARAMS,
Message: common_err.GetMsg(common_err.INVALID_PARAMS), Message: common_err.GetMsg(common_err.INVALID_PARAMS),
}) })
return
} }
err = ar.Create(ctx.Response().Writer) err = ar.Create(c.Writer)
if err != nil { if err != nil {
return ctx.JSON(common_err.SERVICE_ERROR, model.Result{ c.JSON(common_err.SERVICE_ERROR, model.Result{
Success: common_err.SERVICE_ERROR, Success: common_err.SERVICE_ERROR,
Message: common_err.GetMsg(common_err.SERVICE_ERROR), Message: common_err.GetMsg(common_err.SERVICE_ERROR),
Data: err.Error(), Data: err.Error(),
}) })
return
} }
defer ar.Close() defer ar.Close()
commonDir := file.CommonPrefix(filepath.Separator, list...) commonDir := file.CommonPrefix(filepath.Separator, list...)
@@ -212,27 +221,27 @@ func GetDownloadFile(ctx echo.Context) error {
name := "_" + currentPath name := "_" + currentPath
name += extension name += extension
ctx.Request().Header.Add("Content-Disposition", "attachment; filename*=utf-8''"+url.PathEscape(name)) c.Header("Content-Disposition", "attachment; filename*=utf-8''"+url.PathEscape(name))
for _, fname := range list { for _, fname := range list {
err = file.AddFile(ar, fname, commonDir) err = file.AddFile(ar, fname, commonDir)
if err != nil { if err != nil {
log.Printf("Failed to archive %s: %v", fname, err) log.Printf("Failed to archive %s: %v", fname, err)
} }
} }
return nil
} }
func GetDownloadSingleFile(ctx echo.Context) error { func GetDownloadSingleFile(c *gin.Context) {
filePath := ctx.QueryParam("path") filePath := c.Query("path")
if len(filePath) == 0 { if len(filePath) == 0 {
return ctx.JSON(common_err.CLIENT_ERROR, model.Result{ c.JSON(common_err.CLIENT_ERROR, model.Result{
Success: common_err.INVALID_PARAMS, Success: common_err.INVALID_PARAMS,
Message: common_err.GetMsg(common_err.INVALID_PARAMS), Message: common_err.GetMsg(common_err.INVALID_PARAMS),
}) })
return
} }
fileName := path.Base(filePath) fileName := path.Base(filePath)
// c.Header("Content-Disposition", "inline") // c.Header("Content-Disposition", "inline")
ctx.Request().Header.Add("Content-Disposition", "attachment; filename*=utf-8''"+url2.PathEscape(fileName)) c.Header("Content-Disposition", "attachment; filename*=utf-8''"+url2.PathEscape(fileName))
fi, err := os.Open(filePath) fi, err := os.Open(filePath)
if err != nil { if err != nil {
@@ -246,29 +255,31 @@ func GetDownloadSingleFile(ctx echo.Context) error {
kind, _ := filetype.Match(buffer) kind, _ := filetype.Match(buffer)
if kind != filetype.Unknown { if kind != filetype.Unknown {
ctx.Request().Header.Add("Content-Type", kind.MIME.Value) c.Header("Content-Type", kind.MIME.Value)
} }
node, err := os.Stat(filePath) node, err := os.Stat(filePath)
// Set the Last-Modified header to the timestamp // Set the Last-Modified header to the timestamp
ctx.Request().Header.Add("Last-Modified", node.ModTime().UTC().Format(http.TimeFormat)) c.Header("Last-Modified", node.ModTime().UTC().Format(http.TimeFormat))
knownSize := node.Size() >= 0 knownSize := node.Size() >= 0
if knownSize { if knownSize {
ctx.Request().Header.Add("Content-Length", strconv.FormatInt(node.Size(), 10)) c.Header("Content-Length", strconv.FormatInt(node.Size(), 10))
} }
http.ServeContent(ctx.Response().Writer, ctx.Request(), fileName, node.ModTime(), fi) http.ServeContent(c.Writer, c.Request, fileName, node.ModTime(), fi)
// http.ServeFile(c.Writer, ctx.Request(), filePath) //http.ServeFile(c.Writer, c.Request, filePath)
defer fi.Close() defer fi.Close()
return
fileTmp, err := os.Open(filePath) fileTmp, err := os.Open(filePath)
if err != nil { if err != nil {
return ctx.JSON(common_err.SERVICE_ERROR, model.Result{ c.JSON(common_err.SERVICE_ERROR, model.Result{
Success: common_err.FILE_DOES_NOT_EXIST, Success: common_err.FILE_DOES_NOT_EXIST,
Message: common_err.GetMsg(common_err.FILE_DOES_NOT_EXIST), Message: common_err.GetMsg(common_err.FILE_DOES_NOT_EXIST),
}) })
return
} }
defer fileTmp.Close() defer fileTmp.Close()
return ctx.File(filePath) c.File(filePath)
} }
// @Summary 获取目录列表 // @Summary 获取目录列表
@@ -279,14 +290,17 @@ func GetDownloadSingleFile(ctx echo.Context) error {
// @Param path query string false "路径" // @Param path query string false "路径"
// @Success 200 {string} string "ok" // @Success 200 {string} string "ok"
// @Router /file/dirpath [get] // @Router /file/dirpath [get]
func DirPath(ctx echo.Context) error { func DirPath(c *gin.Context) {
var req ListReq var req ListReq
path := ctx.QueryParam("path") if err := c.ShouldBind(&req); err != nil {
req.Path = path c.JSON(common_err.CLIENT_ERROR, model.Result{Success: common_err.CLIENT_ERROR, Message: common_err.GetMsg(common_err.CLIENT_ERROR), Data: err.Error()})
return
}
req.Validate() req.Validate()
info, err := service.MyService.System().GetDirPath(req.Path) info, err := service.MyService.System().GetDirPath(req.Path)
if err != nil { if err != nil {
return ctx.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
} }
shares := service.MyService.Shares().GetSharesList() shares := service.MyService.Shares().GetSharesList()
sharesMap := make(map[string]string) sharesMap := make(map[string]string)
@@ -294,7 +308,7 @@ func DirPath(ctx echo.Context) error {
sharesMap[v.Path] = fmt.Sprint(v.ID) sharesMap[v.Path] = fmt.Sprint(v.ID)
} }
// if len(info) <= (req.Page-1)*req.Size { // if len(info) <= (req.Page-1)*req.Size {
// return ctx.JSON(common_err.CLIENT_ERROR, model.Result{Success: common_err.CLIENT_ERROR, Message: common_err.GetMsg(common_err.INVALID_PARAMS), Data: "page out of range"}) // c.JSON(common_err.CLIENT_ERROR, model.Result{Success: common_err.CLIENT_ERROR, Message: common_err.GetMsg(common_err.INVALID_PARAMS), Data: "page out of range"})
// return // return
// } // }
forEnd := req.Index * req.Size forEnd := req.Index * req.Size
@@ -366,7 +380,7 @@ func DirPath(ctx echo.Context) error {
Index: req.Index, Index: req.Index,
Size: req.Size, Size: req.Size,
} }
return ctx.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: flist}) c.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: flist})
} }
// @Summary rename file or dir // @Summary rename file or dir
@@ -378,21 +392,23 @@ func DirPath(ctx echo.Context) error {
// @Param newpath body string true "path of new" // @Param newpath body string true "path of new"
// @Success 200 {string} string "ok" // @Success 200 {string} string "ok"
// @Router /file/rename [put] // @Router /file/rename [put]
func RenamePath(ctx echo.Context) error { func RenamePath(c *gin.Context) {
json := make(map[string]string) json := make(map[string]string)
ctx.Bind(&json) c.ShouldBind(&json)
op := json["old_path"] op := json["old_path"]
np := json["new_path"] np := json["new_path"]
if len(op) == 0 || len(np) == 0 { if len(op) == 0 || len(np) == 0 {
return ctx.JSON(common_err.CLIENT_ERROR, model.Result{Success: common_err.INVALID_PARAMS, Message: common_err.GetMsg(common_err.INVALID_PARAMS)}) c.JSON(common_err.CLIENT_ERROR, model.Result{Success: common_err.INVALID_PARAMS, Message: common_err.GetMsg(common_err.INVALID_PARAMS)})
return
} }
mounted := service.IsMounted(op) mounted := service.IsMounted(op)
if mounted { if mounted {
return ctx.JSON(common_err.SERVICE_ERROR, model.Result{Success: common_err.MOUNTED_DIRECTIORIES, Message: common_err.GetMsg(common_err.MOUNTED_DIRECTIORIES), Data: common_err.GetMsg(common_err.MOUNTED_DIRECTIORIES)}) c.JSON(common_err.SERVICE_ERROR, model.Result{Success: common_err.MOUNTED_DIRECTIORIES, Message: common_err.GetMsg(common_err.MOUNTED_DIRECTIORIES), Data: common_err.GetMsg(common_err.MOUNTED_DIRECTIORIES)})
return
} }
success, err := service.MyService.System().RenameFile(op, np) success, err := service.MyService.System().RenameFile(op, np)
return ctx.JSON(common_err.SUCCESS, model.Result{Success: success, Message: common_err.GetMsg(success), Data: err}) c.JSON(common_err.SUCCESS, model.Result{Success: success, Message: common_err.GetMsg(success), Data: err})
} }
// @Summary create folder // @Summary create folder
@@ -403,21 +419,22 @@ func RenamePath(ctx echo.Context) error {
// @Param path body string true "path of folder" // @Param path body string true "path of folder"
// @Success 200 {string} string "ok" // @Success 200 {string} string "ok"
// @Router /file/mkdir [post] // @Router /file/mkdir [post]
func MkdirAll(ctx echo.Context) error { func MkdirAll(c *gin.Context) {
json := make(map[string]string) json := make(map[string]string)
ctx.Bind(&json) c.ShouldBind(&json)
path := json["path"] path := json["path"]
var code int var code int
if len(path) == 0 { if len(path) == 0 {
return ctx.JSON(common_err.CLIENT_ERROR, model.Result{Success: common_err.INVALID_PARAMS, Message: common_err.GetMsg(common_err.INVALID_PARAMS)}) c.JSON(common_err.CLIENT_ERROR, model.Result{Success: common_err.INVALID_PARAMS, Message: common_err.GetMsg(common_err.INVALID_PARAMS)})
return
} }
// decodedPath, err := url.QueryUnescape(path) // decodedPath, err := url.QueryUnescape(path)
// if err != nil { // if err != nil {
// return ctx.JSON(http.StatusOK, model.Result{Success: common_err.INVALID_PARAMS, Message: common_err.GetMsg(common_err.INVALID_PARAMS)}) // c.JSON(http.StatusOK, model.Result{Success: common_err.INVALID_PARAMS, Message: common_err.GetMsg(common_err.INVALID_PARAMS)})
// return // return
// } // }
code, _ = service.MyService.System().MkdirAll(path) code, _ = service.MyService.System().MkdirAll(path)
return ctx.JSON(common_err.SUCCESS, model.Result{Success: code, Message: common_err.GetMsg(code)}) c.JSON(common_err.SUCCESS, model.Result{Success: code, Message: common_err.GetMsg(code)})
} }
// @Summary create file // @Summary create file
@@ -428,21 +445,22 @@ func MkdirAll(ctx echo.Context) error {
// @Param path body string true "path of folder (path need to url encode)" // @Param path body string true "path of folder (path need to url encode)"
// @Success 200 {string} string "ok" // @Success 200 {string} string "ok"
// @Router /file/create [post] // @Router /file/create [post]
func PostCreateFile(ctx echo.Context) error { func PostCreateFile(c *gin.Context) {
json := make(map[string]string) json := make(map[string]string)
ctx.Bind(&json) c.ShouldBind(&json)
path := json["path"] path := json["path"]
var code int var code int
if len(path) == 0 { if len(path) == 0 {
return ctx.JSON(common_err.CLIENT_ERROR, model.Result{Success: common_err.INVALID_PARAMS, Message: common_err.GetMsg(common_err.INVALID_PARAMS)}) c.JSON(common_err.CLIENT_ERROR, model.Result{Success: common_err.INVALID_PARAMS, Message: common_err.GetMsg(common_err.INVALID_PARAMS)})
return
} }
// decodedPath, err := url.QueryUnescape(path) // decodedPath, err := url.QueryUnescape(path)
// if err != nil { // if err != nil {
// return ctx.JSON(http.StatusOK, model.Result{Success: common_err.INVALID_PARAMS, Message: common_err.GetMsg(common_err.INVALID_PARAMS)}) // c.JSON(http.StatusOK, model.Result{Success: common_err.INVALID_PARAMS, Message: common_err.GetMsg(common_err.INVALID_PARAMS)})
// return // return
// } // }
code, _ = service.MyService.System().CreateFile(path) code, _ = service.MyService.System().CreateFile(path)
return ctx.JSON(common_err.SUCCESS, model.Result{Success: code, Message: common_err.GetMsg(code)}) c.JSON(common_err.SUCCESS, model.Result{Success: code, Message: common_err.GetMsg(code)})
} }
// @Summary upload file // @Summary upload file
@@ -454,17 +472,14 @@ func PostCreateFile(ctx echo.Context) error {
// @Param file formData file true "file" // @Param file formData file true "file"
// @Success 200 {string} string "ok" // @Success 200 {string} string "ok"
// @Router /file/upload [get] // @Router /file/upload [get]
func GetFileUpload(ctx echo.Context) error { func GetFileUpload(c *gin.Context) {
relative := ctx.QueryParam("relativePath") relative := c.Query("relativePath")
fileName := ctx.QueryParam("filename") fileName := c.Query("filename")
chunkNumber := ctx.QueryParam("chunkNumber") chunkNumber := c.Query("chunkNumber")
totalChunks, _ := strconv.Atoi(utils.DefaultQuery(ctx, "totalChunks", "0")) totalChunks, _ := strconv.Atoi(c.DefaultQuery("totalChunks", "0"))
path := ctx.QueryParam("path") path := c.Query("path")
dirPath := "" dirPath := ""
hash := file.GetHashByContent([]byte(fileName)) hash := file.GetHashByContent([]byte(fileName))
if file.Exists(path + "/" + relative) {
return ctx.JSON(http.StatusConflict, model.Result{Success: http.StatusConflict, Message: common_err.GetMsg(common_err.FILE_ALREADY_EXISTS)})
}
tempDir := filepath.Join(path, ".temp", hash+strconv.Itoa(totalChunks)) + "/" tempDir := filepath.Join(path, ".temp", hash+strconv.Itoa(totalChunks)) + "/"
if fileName != relative { if fileName != relative {
dirPath = strings.TrimSuffix(relative, fileName) dirPath = strings.TrimSuffix(relative, fileName)
@@ -473,10 +488,11 @@ func GetFileUpload(ctx echo.Context) error {
} }
tempDir += chunkNumber tempDir += chunkNumber
if !file.CheckNotExist(tempDir) { if !file.CheckNotExist(tempDir) {
return ctx.JSON(200, model.Result{Success: 200, Message: common_err.GetMsg(common_err.FILE_ALREADY_EXISTS)}) c.JSON(200, model.Result{Success: 200, Message: common_err.GetMsg(common_err.FILE_ALREADY_EXISTS)})
return
} }
return ctx.JSON(204, model.Result{Success: 204, Message: common_err.GetMsg(common_err.SUCCESS)}) c.JSON(204, model.Result{Success: 204, Message: common_err.GetMsg(common_err.SUCCESS)})
} }
// @Summary upload file // @Summary upload file
@@ -488,20 +504,21 @@ func GetFileUpload(ctx echo.Context) error {
// @Param file formData file true "file" // @Param file formData file true "file"
// @Success 200 {string} string "ok" // @Success 200 {string} string "ok"
// @Router /file/upload [post] // @Router /file/upload [post]
func PostFileUpload(ctx echo.Context) error { func PostFileUpload(c *gin.Context) {
f, _, _ := ctx.Request().FormFile("file") f, _, _ := c.Request.FormFile("file")
relative := ctx.FormValue("relativePath") relative := c.PostForm("relativePath")
fileName := ctx.FormValue("filename") fileName := c.PostForm("filename")
totalChunks, _ := strconv.Atoi(utils.DefaultPostForm(ctx, "totalChunks", "0")) totalChunks, _ := strconv.Atoi(c.DefaultPostForm("totalChunks", "0"))
chunkNumber := ctx.FormValue("chunkNumber") chunkNumber := c.PostForm("chunkNumber")
dirPath := "" dirPath := ""
path := ctx.FormValue("path") path := c.PostForm("path")
hash := file.GetHashByContent([]byte(fileName)) hash := file.GetHashByContent([]byte(fileName))
if len(path) == 0 { if len(path) == 0 {
logger.Error("path should not be empty") logger.Error("path should not be empty")
return ctx.JSON(http.StatusBadRequest, model.Result{Success: common_err.INVALID_PARAMS, Message: common_err.GetMsg(common_err.INVALID_PARAMS)}) c.JSON(http.StatusBadRequest, model.Result{Success: common_err.INVALID_PARAMS, Message: common_err.GetMsg(common_err.INVALID_PARAMS)})
return
} }
tempDir := filepath.Join(path, ".temp", hash+strconv.Itoa(totalChunks)) + "/" tempDir := filepath.Join(path, ".temp", hash+strconv.Itoa(totalChunks)) + "/"
@@ -510,7 +527,8 @@ func PostFileUpload(ctx echo.Context) error {
tempDir += dirPath tempDir += dirPath
if err := file.MkDir(path + "/" + dirPath); err != nil { if err := file.MkDir(path + "/" + dirPath); err != nil {
logger.Error("error when trying to create `"+path+"/"+dirPath+"`", zap.Error(err)) logger.Error("error when trying to create `"+path+"/"+dirPath+"`", zap.Error(err))
return ctx.JSON(http.StatusInternalServerError, model.Result{Success: common_err.SERVICE_ERROR, Message: err.Error()}) c.JSON(http.StatusInternalServerError, model.Result{Success: common_err.SERVICE_ERROR, Message: err.Error()})
return
} }
} }
@@ -519,94 +537,108 @@ func PostFileUpload(ctx echo.Context) error {
if !file.CheckNotExist(tempDir + chunkNumber) { if !file.CheckNotExist(tempDir + chunkNumber) {
if err := file.RMDir(tempDir + chunkNumber); err != nil { if err := file.RMDir(tempDir + chunkNumber); err != nil {
logger.Error("error when trying to remove existing `"+tempDir+chunkNumber+"`", zap.Error(err)) logger.Error("error when trying to remove existing `"+tempDir+chunkNumber+"`", zap.Error(err))
return ctx.JSON(http.StatusInternalServerError, model.Result{Success: common_err.SERVICE_ERROR, Message: err.Error()}) c.JSON(http.StatusInternalServerError, model.Result{Success: common_err.SERVICE_ERROR, Message: err.Error()})
return
} }
} }
if totalChunks > 1 { if totalChunks > 1 {
if err := file.IsNotExistMkDir(tempDir); err != nil { if err := file.IsNotExistMkDir(tempDir); err != nil {
logger.Error("error when trying to create `"+tempDir+"`", zap.Error(err)) logger.Error("error when trying to create `"+tempDir+"`", zap.Error(err))
return ctx.JSON(http.StatusInternalServerError, model.Result{Success: common_err.SERVICE_ERROR, Message: err.Error()}) 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) out, err := os.OpenFile(tempDir+chunkNumber, os.O_WRONLY|os.O_CREATE, 0o644)
if err != nil { if err != nil {
logger.Error("error when trying to open `"+tempDir+chunkNumber+"` for creation", zap.Error(err)) logger.Error("error when trying to open `"+tempDir+chunkNumber+"` for creation", zap.Error(err))
return ctx.JSON(http.StatusInternalServerError, model.Result{Success: common_err.SERVICE_ERROR, Message: err.Error()}) c.JSON(http.StatusInternalServerError, model.Result{Success: common_err.SERVICE_ERROR, Message: err.Error()})
return
} }
defer out.Close() defer out.Close()
if _, err := io.Copy(out, f); err != nil { // recommend to use https://github.com/iceber/iouring-go for faster copy if _, err := io.Copy(out, f); err != nil { // recommend to use https://github.com/iceber/iouring-go for faster copy
logger.Error("error when trying to write to `"+tempDir+chunkNumber+"`", zap.Error(err)) logger.Error("error when trying to write to `"+tempDir+chunkNumber+"`", zap.Error(err))
return ctx.JSON(http.StatusInternalServerError, model.Result{Success: common_err.SERVICE_ERROR, Message: err.Error()}) c.JSON(http.StatusInternalServerError, model.Result{Success: common_err.SERVICE_ERROR, Message: err.Error()})
return
} }
fileNum, err := ioutil.ReadDir(tempDir) fileNum, err := ioutil.ReadDir(tempDir)
if err != nil { if err != nil {
logger.Error("error when trying to read number of files under `"+tempDir+"`", zap.Error(err)) logger.Error("error when trying to read number of files under `"+tempDir+"`", zap.Error(err))
return ctx.JSON(http.StatusInternalServerError, model.Result{Success: common_err.SERVICE_ERROR, Message: err.Error()}) c.JSON(http.StatusInternalServerError, model.Result{Success: common_err.SERVICE_ERROR, Message: err.Error()})
return
} }
if totalChunks == len(fileNum) { if totalChunks == len(fileNum) {
if err := file.SpliceFiles(tempDir, path, totalChunks, 1); err != nil { if err := file.SpliceFiles(tempDir, path, totalChunks, 1); err != nil {
logger.Error("error when trying to splice files under `"+tempDir+"`", zap.Error(err)) logger.Error("error when trying to splice files under `"+tempDir+"`", zap.Error(err))
return ctx.JSON(http.StatusInternalServerError, model.Result{Success: common_err.SERVICE_ERROR, Message: err.Error()}) c.JSON(http.StatusInternalServerError, model.Result{Success: common_err.SERVICE_ERROR, Message: err.Error()})
return
}
if err := file.RMDir(tempDir); err != nil {
logger.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
} }
go func() {
time.Sleep(11 * time.Second)
if err := file.RMDir(tempDir); err != nil {
logger.Error("error when trying to remove `"+tempDir+"`", zap.Error(err))
}
}()
} }
} else { } else {
out, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE, 0o644) out, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE, 0o644)
if err != nil { if err != nil {
logger.Error("error when trying to open `"+path+"` for creation", zap.Error(err)) logger.Error("error when trying to open `"+path+"` for creation", zap.Error(err))
return ctx.JSON(http.StatusInternalServerError, model.Result{Success: common_err.SERVICE_ERROR, Message: err.Error()}) c.JSON(http.StatusInternalServerError, model.Result{Success: common_err.SERVICE_ERROR, Message: err.Error()})
return
} }
defer out.Close() defer out.Close()
if _, err := io.Copy(out, f); err != nil { // recommend to use https://github.com/iceber/iouring-go for faster copy if _, err := io.Copy(out, f); err != nil { // recommend to use https://github.com/iceber/iouring-go for faster copy
logger.Error("error when trying to write to `"+path+"`", zap.Error(err)) logger.Error("error when trying to write to `"+path+"`", zap.Error(err))
return ctx.JSON(http.StatusInternalServerError, model.Result{Success: common_err.SERVICE_ERROR, Message: common_err.GetMsg(common_err.SERVICE_ERROR), Data: err.Error()}) c.JSON(http.StatusInternalServerError, model.Result{Success: common_err.SERVICE_ERROR, Message: common_err.GetMsg(common_err.SERVICE_ERROR), Data: err.Error()})
return
} }
} }
return ctx.JSON(http.StatusOK, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS)}) c.JSON(http.StatusOK, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS)})
} }
func PostFileOctet(ctx echo.Context) error { func PostFileOctet(c *gin.Context) {
content_length := ctx.Request().ContentLength
content_length := c.Request.ContentLength
if content_length <= 0 || content_length > 1024*1024*1024*2*1024 { if content_length <= 0 || content_length > 1024*1024*1024*2*1024 {
log.Printf("content_length error\n") log.Printf("content_length error\n")
return ctx.JSON(http.StatusBadRequest, model.Result{Success: common_err.CLIENT_ERROR, Message: common_err.GetMsg(common_err.CLIENT_ERROR), Data: "content_length error"}) c.JSON(http.StatusBadRequest, model.Result{Success: common_err.CLIENT_ERROR, Message: common_err.GetMsg(common_err.CLIENT_ERROR), Data: "content_length error"})
return
} }
content_type_, has_key := ctx.Request().Header["Content-Type"] content_type_, has_key := c.Request.Header["Content-Type"]
if !has_key { if !has_key {
log.Printf("Content-Type error\n") log.Printf("Content-Type error\n")
return ctx.JSON(http.StatusBadRequest, model.Result{Success: common_err.CLIENT_ERROR, Message: common_err.GetMsg(common_err.CLIENT_ERROR), Data: "Content-Type error"}) c.JSON(http.StatusBadRequest, model.Result{Success: common_err.CLIENT_ERROR, Message: common_err.GetMsg(common_err.CLIENT_ERROR), Data: "Content-Type error"})
return
} }
if len(content_type_) != 1 { if len(content_type_) != 1 {
log.Printf("Content-Type count error\n") log.Printf("Content-Type count error\n")
return ctx.JSON(http.StatusBadRequest, model.Result{Success: common_err.CLIENT_ERROR, Message: common_err.GetMsg(common_err.CLIENT_ERROR), Data: "Content-Type count error"}) c.JSON(http.StatusBadRequest, model.Result{Success: common_err.CLIENT_ERROR, Message: common_err.GetMsg(common_err.CLIENT_ERROR), Data: "Content-Type count error"})
return
} }
content_type := content_type_[0] content_type := content_type_[0]
const BOUNDARY string = "; boundary=" const BOUNDARY string = "; boundary="
loc := strings.Index(content_type, BOUNDARY) loc := strings.Index(content_type, BOUNDARY)
if loc == -1 { if loc == -1 {
log.Printf("Content-Type error, no boundary\n") log.Printf("Content-Type error, no boundary\n")
return ctx.JSON(http.StatusBadRequest, model.Result{Success: common_err.CLIENT_ERROR, Message: common_err.GetMsg(common_err.CLIENT_ERROR), Data: "Content-Type error, no boundary"}) c.JSON(http.StatusBadRequest, model.Result{Success: common_err.CLIENT_ERROR, Message: common_err.GetMsg(common_err.CLIENT_ERROR), Data: "Content-Type error, no boundary"})
return
} }
boundary := []byte(content_type[(loc + len(BOUNDARY)):]) boundary := []byte(content_type[(loc + len(BOUNDARY)):])
log.Printf("[%s]\n\n", boundary) log.Printf("[%s]\n\n", boundary)
read_data := make([]byte, 1024*24) read_data := make([]byte, 1024*24)
var read_total int = 0 var read_total int = 0
for { for {
file_header, file_data, err := file.ParseFromHead(read_data, read_total, append(boundary, []byte("\r\n")...), ctx.Request().Body) file_header, file_data, err := file.ParseFromHead(read_data, read_total, append(boundary, []byte("\r\n")...), c.Request.Body)
if err != nil { if err != nil {
log.Printf("%v", err) log.Printf("%v", err)
return
} }
log.Printf("file :%s\n", file_header) log.Printf("file :%s\n", file_header)
// //
@@ -614,14 +646,16 @@ func PostFileOctet(ctx echo.Context) error {
f, err := os.OpenFile(file_header["path"]+"/"+file_header["filename"], os.O_WRONLY|os.O_CREATE, 0o644) f, err := os.OpenFile(file_header["path"]+"/"+file_header["filename"], os.O_WRONLY|os.O_CREATE, 0o644)
if err != nil { if err != nil {
log.Printf("create file fail:%v\n", err) log.Printf("create file fail:%v\n", err)
return
} }
f.Write(file_data) f.Write(file_data)
file_data = nil file_data = nil
temp_data, reach_end, err := file.ReadToBoundary(boundary, ctx.Request().Body, f) temp_data, reach_end, err := file.ReadToBoundary(boundary, c.Request.Body, f)
f.Close() f.Close()
if err != nil { if err != nil {
log.Printf("%v\n", err) log.Printf("%v\n", err)
return
} }
if reach_end { if reach_end {
break break
@@ -631,7 +665,7 @@ func PostFileOctet(ctx echo.Context) error {
continue continue
} }
} }
return ctx.JSON(http.StatusOK, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS)}) 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
@@ -642,15 +676,17 @@ func PostFileOctet(ctx echo.Context) error {
// @Param body body model.FileOperate true "type:move,copy" // @Param body body model.FileOperate true "type:move,copy"
// @Success 200 {string} string "ok" // @Success 200 {string} string "ok"
// @Router /file/operate [post] // @Router /file/operate [post]
func PostOperateFileOrDir(ctx echo.Context) error { func PostOperateFileOrDir(c *gin.Context) {
list := model.FileOperate{} list := model.FileOperate{}
ctx.Bind(&list) c.ShouldBind(&list)
if len(list.Item) == 0 { if len(list.Item) == 0 {
return ctx.JSON(common_err.CLIENT_ERROR, model.Result{Success: common_err.INVALID_PARAMS, Message: common_err.GetMsg(common_err.INVALID_PARAMS)}) c.JSON(common_err.CLIENT_ERROR, model.Result{Success: common_err.INVALID_PARAMS, Message: common_err.GetMsg(common_err.INVALID_PARAMS)})
return
} }
if list.To == list.Item[0].From[:strings.LastIndex(list.Item[0].From, "/")] { if list.To == list.Item[0].From[:strings.LastIndex(list.Item[0].From, "/")] {
return ctx.JSON(common_err.SERVICE_ERROR, model.Result{Success: common_err.SOURCE_DES_SAME, Message: common_err.GetMsg(common_err.SOURCE_DES_SAME)}) c.JSON(common_err.SERVICE_ERROR, model.Result{Success: common_err.SOURCE_DES_SAME, Message: common_err.GetMsg(common_err.SOURCE_DES_SAME)})
return
} }
var total int64 = 0 var total int64 = 0
@@ -665,7 +701,8 @@ func PostOperateFileOrDir(ctx echo.Context) error {
if list.Type == "move" { if list.Type == "move" {
mounted := service.IsMounted(list.Item[i].From) mounted := service.IsMounted(list.Item[i].From)
if mounted { if mounted {
return ctx.JSON(common_err.SERVICE_ERROR, model.Result{Success: common_err.MOUNTED_DIRECTIORIES, Message: common_err.GetMsg(common_err.MOUNTED_DIRECTIORIES), Data: common_err.GetMsg(common_err.MOUNTED_DIRECTIORIES)}) c.JSON(common_err.SERVICE_ERROR, model.Result{Success: common_err.MOUNTED_DIRECTIORIES, Message: common_err.GetMsg(common_err.MOUNTED_DIRECTIORIES), Data: common_err.GetMsg(common_err.MOUNTED_DIRECTIORIES)})
return
} }
} }
} }
@@ -673,7 +710,7 @@ func PostOperateFileOrDir(ctx echo.Context) error {
list.TotalSize = total list.TotalSize = total
list.ProcessedSize = 0 list.ProcessedSize = 0
uid := uuid.NewString() uid := uuid.NewV4().String()
service.FileQueue.Store(uid, list) service.FileQueue.Store(uid, list)
service.OpStrArr = append(service.OpStrArr, uid) service.OpStrArr = append(service.OpStrArr, uid)
if len(service.OpStrArr) == 1 { if len(service.OpStrArr) == 1 {
@@ -684,7 +721,7 @@ func PostOperateFileOrDir(ctx echo.Context) error {
} }
return ctx.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS)}) c.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS)})
} }
// @Summary delete file // @Summary delete file
@@ -695,30 +732,33 @@ func PostOperateFileOrDir(ctx echo.Context) error {
// @Param body body string true "paths eg ["/a/b/c","/d/e/f"]" // @Param body body string true "paths eg ["/a/b/c","/d/e/f"]"
// @Success 200 {string} string "ok" // @Success 200 {string} string "ok"
// @Router /file/delete [delete] // @Router /file/delete [delete]
func DeleteFile(ctx echo.Context) error { func DeleteFile(c *gin.Context) {
paths := []string{} paths := []string{}
ctx.Bind(&paths) c.ShouldBind(&paths)
if len(paths) == 0 { if len(paths) == 0 {
return ctx.JSON(common_err.CLIENT_ERROR, model.Result{Success: common_err.INVALID_PARAMS, Message: common_err.GetMsg(common_err.INVALID_PARAMS)}) c.JSON(common_err.CLIENT_ERROR, model.Result{Success: common_err.INVALID_PARAMS, Message: common_err.GetMsg(common_err.INVALID_PARAMS)})
return
} }
// path := ctx.QueryParam("path") // path := c.Query("path")
// paths := strings.Split(path, ",") // paths := strings.Split(path, ",")
for _, v := range paths { for _, v := range paths {
mounted := service.IsMounted(v) mounted := service.IsMounted(v)
if mounted { if mounted {
return ctx.JSON(common_err.SERVICE_ERROR, model.Result{Success: common_err.MOUNTED_DIRECTIORIES, Message: common_err.GetMsg(common_err.MOUNTED_DIRECTIORIES), Data: common_err.GetMsg(common_err.MOUNTED_DIRECTIORIES)}) c.JSON(common_err.SERVICE_ERROR, model.Result{Success: common_err.MOUNTED_DIRECTIORIES, Message: common_err.GetMsg(common_err.MOUNTED_DIRECTIORIES), Data: common_err.GetMsg(common_err.MOUNTED_DIRECTIORIES)})
return
} }
} }
for _, v := range paths { for _, v := range paths {
err := os.RemoveAll(v) err := os.RemoveAll(v)
if err != nil { if err != nil {
return ctx.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})
return
} }
} }
return ctx.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS)}) c.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS)})
} }
// @Summary update file // @Summary update file
@@ -730,30 +770,34 @@ func DeleteFile(ctx echo.Context) error {
// @Param content body string true "content" // @Param content body string true "content"
// @Success 200 {string} string "ok" // @Success 200 {string} string "ok"
// @Router /file/update [put] // @Router /file/update [put]
func PutFileContent(ctx echo.Context) error { func PutFileContent(c *gin.Context) {
fi := model.FileUpdate{} fi := model.FileUpdate{}
ctx.Bind(&fi) c.ShouldBind(&fi)
// path := ctx.FormValue("path") // path := c.PostForm("path")
// content := ctx.FormValue("content") // content := c.PostForm("content")
if !file.Exists(fi.FilePath) { if !file.Exists(fi.FilePath) {
return ctx.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
} }
// err := os.Remove(path) // err := os.Remove(path)
f, err := os.Stat(fi.FilePath) f, err := os.Stat(fi.FilePath)
if err != nil { if err != nil {
return ctx.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
} }
fm := f.Mode() fm := f.Mode()
if err != nil { if err != nil {
return ctx.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})
return
} }
os.OpenFile(fi.FilePath, os.O_CREATE, fm) os.OpenFile(fi.FilePath, os.O_CREATE, fm)
err = file.WriteToFullPath([]byte(fi.FileContent), fi.FilePath, fm) err = file.WriteToFullPath([]byte(fi.FileContent), fi.FilePath, fm)
if err != nil { if err != nil {
return ctx.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 ctx.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS)}) c.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS)})
} }
// @Summary image thumbnail/original image // @Summary image thumbnail/original image
@@ -765,34 +809,38 @@ func PutFileContent(ctx echo.Context) error {
// @Param type query string false "original,thumbnail" Enums(original,thumbnail) // @Param type query string false "original,thumbnail" Enums(original,thumbnail)
// @Success 200 {string} string "ok" // @Success 200 {string} string "ok"
// @Router /file/image [get] // @Router /file/image [get]
func GetFileImage(ctx echo.Context) error { func GetFileImage(c *gin.Context) {
t := ctx.QueryParam("type") t := c.Query("type")
path := ctx.QueryParam("path") path := c.Query("path")
if !file.Exists(path) { if !file.Exists(path) {
return ctx.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
} }
if t == "thumbnail" { if t == "thumbnail" {
f, err := file.GetImage(path, 100, 0) f, err := file.GetImage(path, 100, 0)
if err != nil { if err != nil {
return ctx.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
} }
ctx.Response().Writer.Write(f) c.Writer.WriteString(string(f))
return
} }
f, err := os.Open(path) f, err := os.Open(path)
if err != nil { if err != nil {
return ctx.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
} }
defer f.Close() defer f.Close()
data, err := ioutil.ReadAll(f) data, err := ioutil.ReadAll(f)
if err != nil { if err != nil {
return ctx.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
} }
ctx.Response().Writer.Write(data) c.Writer.WriteString(string(data))
return nil
} }
func DeleteOperateFileOrDir(ctx echo.Context) error { func DeleteOperateFileOrDir(c *gin.Context) {
id := ctx.Param("id") id := c.Param("id")
if id == "0" { if id == "0" {
service.FileQueue = sync.Map{} service.FileQueue = sync.Map{}
service.OpStrArr = []string{} service.OpStrArr = []string{}
@@ -810,29 +858,30 @@ func DeleteOperateFileOrDir(ctx echo.Context) error {
} }
go service.MyService.Notify().SendFileOperateNotify(true) go service.MyService.Notify().SendFileOperateNotify(true)
return ctx.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS)}) c.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS)})
} }
func GetSize(c *gin.Context) {
func GetSize(ctx echo.Context) error {
json := make(map[string]string) json := make(map[string]string)
ctx.Bind(&json) c.ShouldBind(&json)
path := json["path"] path := json["path"]
size, err := file.GetFileOrDirSize(path) size, err := file.GetFileOrDirSize(path)
if err != nil { if err != nil {
return ctx.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 ctx.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: size}) c.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: size})
} }
func GetFileCount(ctx echo.Context) error { func GetFileCount(c *gin.Context) {
json := make(map[string]string) json := make(map[string]string)
ctx.Bind(&json) c.ShouldBind(&json)
path := json["path"] path := json["path"]
list, err := ioutil.ReadDir(path) list, err := ioutil.ReadDir(path)
if err != nil { if err != nil {
return ctx.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 ctx.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: len(list)}) c.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: len(list)})
} }
type CenterHandler struct { type CenterHandler struct {
@@ -865,16 +914,17 @@ type PeerModel struct {
RtcSupported bool `json:"rtcSupported"` RtcSupported bool `json:"rtcSupported"`
} }
func ConnectWebSocket(ctx echo.Context) error { func ConnectWebSocket(c *gin.Context) {
peerId := ctx.QueryParam("peer") peerId := c.Query("peer")
writer := ctx.Response().Writer writer := c.Writer
request := ctx.Request() request := c.Request
key := uuid.NewString() key := uuid.NewV4().String()
// peerModel := service.MyService.Peer().GetPeerByUserAgent(ctx.Request().UserAgent()) //peerModel := service.MyService.Peer().GetPeerByUserAgent(c.Request.UserAgent())
peerModel := model2.PeerDriveDBModel{} peerModel := model2.PeerDriveDBModel{}
name := service.GetName(request) name := service.GetName(request)
if conn, err = upgraderFile.Upgrade(writer, request, writer.Header()); err != nil { if conn, err = upgraderFile.Upgrade(writer, request, writer.Header()); err != nil {
log.Println(err) log.Println(err)
return
} }
client := &Client{handler: &handler, conn: conn, send: make(chan []byte, 256), ID: service.GetPeerId(request, key), IP: service.GetIP(request), Name: name, RtcSupported: true, TimerId: 0, LastBeat: time.Now()} client := &Client{handler: &handler, conn: conn, send: make(chan []byte, 256), ID: service.GetPeerId(request, key), IP: service.GetIP(request), Name: name, RtcSupported: true, TimerId: 0, LastBeat: time.Now()}
if peerId != "" || len(peerModel.ID) > 0 { if peerId != "" || len(peerModel.ID) > 0 {
@@ -887,7 +937,7 @@ func ConnectWebSocket(ctx echo.Context) error {
client.Name = service.GetNameByDB(peerModel) client.Name = service.GetNameByDB(peerModel)
} }
} }
list := service.MyService.Peer().GetPeers() var list = service.MyService.Peer().GetPeers()
if len(peerModel.ID) == 0 { if len(peerModel.ID) == 0 {
peerModel.ID = key peerModel.ID = key
peerModel.DisplayName = name.DisplayName peerModel.DisplayName = name.DisplayName
@@ -895,7 +945,7 @@ func ConnectWebSocket(ctx echo.Context) error {
peerModel.Model = name.Model peerModel.Model = name.Model
peerModel.OS = name.OS peerModel.OS = name.OS
peerModel.Browser = name.Browser peerModel.Browser = name.Browser
peerModel.UserAgent = ctx.Request().UserAgent() peerModel.UserAgent = c.Request.UserAgent()
peerModel.IP = client.IP peerModel.IP = client.IP
service.MyService.Peer().CreatePeer(&peerModel) service.MyService.Peer().CreatePeer(&peerModel)
list = append(list, peerModel) list = append(list, peerModel)
@@ -939,7 +989,7 @@ func ConnectWebSocket(ctx echo.Context) error {
for _, v := range handler.clients { for _, v := range handler.clients {
v.send <- pby v.send <- pby
} }
// client.handler.broadcast <- pby //client.handler.broadcast <- pby
clients := []PeerModel{} clients := []PeerModel{}
for _, v := range client.handler.clients { for _, v := range client.handler.clients {
if _, ok := handler.clients[v.ID]; ok { if _, ok := handler.clients[v.ID]; ok {
@@ -972,34 +1022,31 @@ func ConnectWebSocket(ctx echo.Context) error {
// 每个 client 都挂起 2 个新的协程,监控读、写状态 // 每个 client 都挂起 2 个新的协程,监控读、写状态
go client.writePump() go client.writePump()
go client.readPump() go client.readPump()
return ctx.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS)}) c.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS)})
} }
var handler = CenterHandler{ var handler = CenterHandler{broadcast: make(chan []byte),
broadcast: make(chan []byte),
register: make(chan *Client), register: make(chan *Client),
unregister: make(chan *Client), unregister: make(chan *Client),
clients: make(map[string]*Client), clients: make(map[string]*Client)}
}
func init() { func init() {
// 起个协程跑起来,监听注册、注销、消息 3 个 channel // 起个协程跑起来,监听注册、注销、消息 3 个 channel
go handler.monitoring() go handler.monitoring()
crontab := cron.New(cron.WithSeconds()) // 精确到秒 crontab := cron.New(cron.WithSeconds()) //精确到秒
// 定义定时器调用的任务函数 //定义定时器调用的任务函数
task := func() { task := func() {
handler.broadcast <- []byte(`{"type":"ping"}`) handler.broadcast <- []byte(`{"type":"ping"}`)
} }
// 定时任务 //定时任务
spec := "*/30 * * * * ?" // cron表达式每五秒一次 spec := "*/30 * * * * ?" //cron表达式每五秒一次
// 添加定时任务, // 添加定时任务,
crontab.AddFunc(spec, task) crontab.AddFunc(spec, task)
// 启动定时器 // 启动定时器
crontab.Start() crontab.Start()
} }
func (c *Client) writePump() { func (c *Client) writePump() {
defer func() { defer func() {
c.handler.unregister <- c c.handler.unregister <- c
@@ -1054,7 +1101,7 @@ func (c *Client) readPump() {
// otherBy, err := json.Marshal(other) // otherBy, err := json.Marshal(other)
// fmt.Println(err) // fmt.Println(err)
c.handler.broadcast <- []byte(`{"type":"peer-left","peerId":"` + c.ID + `"}`) c.handler.broadcast <- []byte(`{"type":"peer-left","peerId":"` + c.ID + `"}`)
// c.handler.broadcast <- otherBy //c.handler.broadcast <- otherBy
break break
} else if t.String() == "pong" { } else if t.String() == "pong" {
c.LastBeat = time.Now() c.LastBeat = time.Now()
@@ -1079,7 +1126,6 @@ func (c *Client) readPump() {
c.handler.broadcast <- message c.handler.broadcast <- message
} }
} }
func (ch *CenterHandler) monitoring() { func (ch *CenterHandler) monitoring() {
for { for {
select { select {
@@ -1099,13 +1145,12 @@ func (ch *CenterHandler) monitoring() {
} }
} }
} }
func GetPeers(c *gin.Context) {
func GetPeers(ctx echo.Context) error {
peers := service.MyService.Peer().GetPeers() peers := service.MyService.Peer().GetPeers()
for i := 0; i < len(peers); i++ { for i := 0; i < len(peers); i++ {
if _, ok := handler.clients[peers[i].ID]; ok { if _, ok := handler.clients[peers[i].ID]; ok {
peers[i].Online = true peers[i].Online = true
} }
} }
return ctx.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: peers}) c.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: peers})
} }

View File

@@ -6,26 +6,28 @@ 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/service" "github.com/IceWhaleTech/CasaOS/service"
"github.com/labstack/echo/v4" "github.com/gin-gonic/gin"
) )
func PostNotifyMessage(ctx echo.Context) error { func PostNotifyMessage(c *gin.Context) {
name := ctx.Param("name") name := c.Param("name")
message := make(map[string]interface{}) message := make(map[string]interface{})
if err := ctx.Bind(&message); err != nil { if err := c.ShouldBind(&message); err != nil {
return ctx.JSON(http.StatusBadRequest, model.Result{Success: common_err.INVALID_PARAMS, Message: err.Error()}) c.JSON(http.StatusBadRequest, model.Result{Success: common_err.INVALID_PARAMS, Message: err.Error()})
return
} }
service.MyService.Notify().SendNotify(name, message) service.MyService.Notify().SendNotify(name, message)
return ctx.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS)}) c.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS)})
} }
func PostSystemStatusNotify(ctx echo.Context) error { func PostSystemStatusNotify(c *gin.Context) {
message := make(map[string]interface{}) message := make(map[string]interface{})
if err := ctx.Bind(&message); err != nil { if err := c.ShouldBind(&message); err != nil {
return ctx.JSON(http.StatusBadRequest, model.Result{Success: common_err.INVALID_PARAMS, Message: err.Error()}) c.JSON(http.StatusBadRequest, model.Result{Success: common_err.INVALID_PARAMS, Message: err.Error()})
return
} }
service.MyService.Notify().SettingSystemTempData(message) service.MyService.Notify().SettingSystemTempData(message)
return ctx.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS)}) c.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS)})
} }

View File

@@ -6,8 +6,8 @@ import (
"github.com/IceWhaleTech/CasaOS/service" "github.com/IceWhaleTech/CasaOS/service"
"github.com/IceWhaleTech/CasaOS/types" "github.com/IceWhaleTech/CasaOS/types"
"github.com/gin-gonic/gin"
"github.com/gorilla/websocket" "github.com/gorilla/websocket"
"github.com/labstack/echo/v4"
) )
var upGrader = websocket.Upgrader{ var upGrader = websocket.Upgrader{
@@ -24,11 +24,11 @@ var upGrader = websocket.Upgrader{
// @Param token path string true "token" // @Param token path string true "token"
// @Success 200 {string} string "ok" // @Success 200 {string} string "ok"
// @Router /notify/ws [get] // @Router /notify/ws [get]
func NotifyWS(ctx echo.Context) error { func NotifyWS(c *gin.Context) {
// 升级get请求为webSocket协议 //升级get请求为webSocket协议
ws, err := upGrader.Upgrade(ctx.Response().Writer, ctx.Request(), nil) ws, err := upGrader.Upgrade(c.Writer, c.Request, nil)
if err != nil { if err != nil {
return nil return
} }
defer ws.Close() defer ws.Close()
service.WebSocketConns = append(service.WebSocketConns, ws) service.WebSocketConns = append(service.WebSocketConns, ws)
@@ -41,6 +41,7 @@ func NotifyWS(ctx echo.Context) error {
mt, message, err := ws.ReadMessage() mt, message, err := ws.ReadMessage()
fmt.Println(mt, message, err) fmt.Println(mt, message, err)
} }
} }
// @Summary 标记notify已读 // @Summary 标记notify已读
@@ -50,13 +51,12 @@ func NotifyWS(ctx echo.Context) error {
// @Security ApiKeyAuth // @Security ApiKeyAuth
// @Success 200 {string} string "ok" // @Success 200 {string} string "ok"
// @Router /notify/read/{id} [put] // @Router /notify/read/{id} [put]
func PutNotifyRead(ctx echo.Context) error { func PutNotifyRead(c *gin.Context) {
id := ctx.Param("id") id := c.Param("id")
// if len(id) == 0 { // if len(id) == 0 {
// return ctx.JSON(http.StatusOK, model.Result{Success: oasis_err.INVALID_PARAMS, Message: oasis_err.GetMsg(oasis_err.INVALID_PARAMS)}) // c.JSON(http.StatusOK, model.Result{Success: oasis_err.INVALID_PARAMS, Message: oasis_err.GetMsg(oasis_err.INVALID_PARAMS)})
// return // return
// } // }
fmt.Println(id) fmt.Println(id)
service.MyService.Notify().MarkRead(id, types.NOTIFY_READ) service.MyService.Notify().MarkRead(id, types.NOTIFY_READ)
return nil
} }

View File

@@ -6,23 +6,25 @@ 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/service" "github.com/IceWhaleTech/CasaOS/service"
"github.com/labstack/echo/v4" "github.com/gin-gonic/gin"
) )
func GetSearchResult(ctx echo.Context) error { func GetSearchResult(c *gin.Context) {
json := make(map[string]string) json := make(map[string]string)
ctx.Bind(&json) c.ShouldBind(&json)
url := json["url"] url := json["url"]
if url == "" { if url == "" {
return ctx.JSON(common_err.CLIENT_ERROR, model.Result{Success: common_err.INVALID_PARAMS, Message: common_err.GetMsg(common_err.INVALID_PARAMS), Data: "key is empty"}) c.JSON(common_err.CLIENT_ERROR, model.Result{Success: common_err.INVALID_PARAMS, Message: common_err.GetMsg(common_err.INVALID_PARAMS), Data: "key is empty"})
return
} }
// data, err := service.MyService.Other().Search(key) //data, err := service.MyService.Other().Search(key)
data, err := service.MyService.Other().AgentSearch(url) data, err := service.MyService.Other().AgentSearch(url)
if err != nil { if err != nil {
fmt.Println(err) fmt.Println(err)
return ctx.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 ctx.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})
} }

View File

@@ -8,56 +8,64 @@ import (
"github.com/IceWhaleTech/CasaOS-Common/utils/logger" "github.com/IceWhaleTech/CasaOS-Common/utils/logger"
"github.com/IceWhaleTech/CasaOS/drivers/dropbox" "github.com/IceWhaleTech/CasaOS/drivers/dropbox"
"github.com/IceWhaleTech/CasaOS/drivers/google_drive" "github.com/IceWhaleTech/CasaOS/drivers/google_drive"
"github.com/IceWhaleTech/CasaOS/drivers/onedrive"
"github.com/IceWhaleTech/CasaOS/service" "github.com/IceWhaleTech/CasaOS/service"
"github.com/labstack/echo/v4" "github.com/gin-gonic/gin"
"go.uber.org/zap" "go.uber.org/zap"
) )
func GetRecoverStorage(ctx echo.Context) error { func GetRecoverStorage(c *gin.Context) {
ctx.Request().Header.Add("Content-Type", "text/html; charset=utf-8") c.Header("Content-Type", "text/html; charset=utf-8")
t := ctx.Param("type") t := c.Param("type")
currentTime := time.Now().UTC() currentTime := time.Now().UTC()
currentDate := time.Now().UTC().Format("2006-01-02") currentDate := time.Now().UTC().Format("2006-01-02")
notify := make(map[string]interface{}) notify := make(map[string]interface{})
if t == "GoogleDrive" { if t == "GoogleDrive" {
google_drive := google_drive.GetConfig() add := google_drive.Addition{}
google_drive.Code = ctx.QueryParam("code") add.Code = c.Query("code")
if len(google_drive.Code) == 0 { if len(add.Code) == 0 {
ctx.String(200, `<p>Code cannot be empty</p><script>window.close()</script>`) c.String(200, `<p>Code cannot be empty</p><script>window.close()</script>`)
notify["status"] = "fail" notify["status"] = "fail"
notify["message"] = "Code cannot be empty" notify["message"] = "Code cannot be empty"
logger.Error("Then code is empty: ", zap.String("code", google_drive.Code), zap.Any("name", "google_drive")) logger.Error("Then code is empty: ", zap.String("code", add.Code), zap.Any("name", "google_drive"))
service.MyService.Notify().SendNotify("casaos:file:recover", notify) service.MyService.Notify().SendNotify("casaos:file:recover", notify)
return
} }
err := google_drive.Init(ctx.Request().Context()) add.RootFolderID = "root"
add.ClientID = google_drive.CLIENTID
add.ClientSecret = google_drive.CLIENTSECRET
var google_drive google_drive.GoogleDrive
google_drive.Addition = add
err := google_drive.Init(c)
if err != nil { if err != nil {
ctx.String(200, `<p>Initialization failure:`+err.Error()+`</p><script>window.close()</script>`) c.String(200, `<p>Initialization failure:`+err.Error()+`</p><script>window.close()</script>`)
notify["status"] = "fail" notify["status"] = "fail"
notify["message"] = "Initialization failure" notify["message"] = "Initialization failure"
logger.Error("Then init error: ", zap.Error(err), zap.Any("name", "google_drive")) logger.Error("Then init error: ", zap.Error(err), zap.Any("name", "google_drive"))
service.MyService.Notify().SendNotify("casaos:file:recover", notify) service.MyService.Notify().SendNotify("casaos:file:recover", notify)
return
} }
username, err := google_drive.GetUserInfo(ctx.Request().Context()) username, err := google_drive.GetUserInfo(c)
if err != nil { if err != nil {
ctx.String(200, `<p>Failed to get user information:`+err.Error()+`</p><script>window.close()</script>`) c.String(200, `<p>Failed to get user information:`+err.Error()+`</p><script>window.close()</script>`)
notify["status"] = "fail" notify["status"] = "fail"
notify["message"] = "Failed to get user information" notify["message"] = "Failed to get user information"
logger.Error("Then get user info error: ", zap.Error(err), zap.Any("name", "google_drive")) logger.Error("Then get user info error: ", zap.Error(err), zap.Any("name", "google_drive"))
service.MyService.Notify().SendNotify("casaos:file:recover", notify) service.MyService.Notify().SendNotify("casaos:file:recover", notify)
return
} }
dmap := make(map[string]string) dmap := make(map[string]string)
dmap["username"] = username dmap["username"] = username
configs, err := service.MyService.Storage().GetConfig() configs, err := service.MyService.Storage().GetConfig()
if err != nil { if err != nil {
ctx.String(200, `<p>Failed to get rclone config:`+err.Error()+`</p><script>window.close()</script>`) c.String(200, `<p>Failed to get rclone config:`+err.Error()+`</p><script>window.close()</script>`)
notify["status"] = "fail" notify["status"] = "fail"
notify["message"] = "Failed to get rclone config" notify["message"] = "Failed to get rclone config"
logger.Error("Then get config error: ", zap.Error(err), zap.Any("name", "google_drive")) logger.Error("Then get config error: ", zap.Error(err), zap.Any("name", "google_drive"))
service.MyService.Notify().SendNotify("casaos:file:recover", notify) service.MyService.Notify().SendNotify("casaos:file:recover", notify)
return
} }
for _, v := range configs.Remotes { for _, v := range configs.Remotes {
cf, err := service.MyService.Storage().GetConfigByName(v) cf, err := service.MyService.Storage().GetConfigByName(v)
@@ -66,7 +74,7 @@ func GetRecoverStorage(ctx echo.Context) error {
continue continue
} }
if cf["type"] == "drive" && cf["username"] == dmap["username"] { if cf["type"] == "drive" && cf["username"] == dmap["username"] {
ctx.String(200, `<p>The same configuration has been added</p><script>window.close()</script>`) c.String(200, `<p>The same configuration has been added</p><script>window.close()</script>`)
err := service.MyService.Storage().CheckAndMountByName(v) err := service.MyService.Storage().CheckAndMountByName(v)
if err != nil { if err != nil {
logger.Error("check and mount by name error: ", zap.Error(err), zap.Any("name", cf["username"])) logger.Error("check and mount by name error: ", zap.Error(err), zap.Any("name", cf["username"]))
@@ -74,6 +82,7 @@ func GetRecoverStorage(ctx echo.Context) error {
notify["status"] = "warn" notify["status"] = "warn"
notify["message"] = "The same configuration has been added" notify["message"] = "The same configuration has been added"
service.MyService.Notify().SendNotify("casaos:file:recover", notify) service.MyService.Notify().SendNotify("casaos:file:recover", notify)
return
} }
} }
if len(username) > 0 { if len(username) > 0 {
@@ -81,11 +90,11 @@ func GetRecoverStorage(ctx echo.Context) error {
username = a[0] username = a[0]
} }
// username = fileutil.NameAccumulation(username, "/mnt") //username = fileutil.NameAccumulation(username, "/mnt")
username += "_google_drive_" + strconv.FormatInt(time.Now().Unix(), 10) username += "_google_drive_" + strconv.FormatInt(time.Now().Unix(), 10)
dmap["client_id"] = google_drive.ClientID dmap["client_id"] = add.ClientID
dmap["client_secret"] = google_drive.ClientSecret dmap["client_secret"] = add.ClientSecret
dmap["scope"] = "drive" dmap["scope"] = "drive"
dmap["mount_point"] = "/mnt/" + username dmap["mount_point"] = "/mnt/" + username
dmap["token"] = `{"access_token":"` + google_drive.AccessToken + `","token_type":"Bearer","refresh_token":"` + google_drive.RefreshToken + `","expiry":"` + currentDate + `T` + currentTime.Add(time.Hour*1).Add(time.Minute*50).Format("15:04:05") + `Z"}` dmap["token"] = `{"access_token":"` + google_drive.AccessToken + `","token_type":"Bearer","refresh_token":"` + google_drive.RefreshToken + `","expiry":"` + currentDate + `T` + currentTime.Add(time.Hour*1).Add(time.Minute*50).Format("15:04:05") + `Z"}`
@@ -97,42 +106,50 @@ func GetRecoverStorage(ctx echo.Context) error {
notify["driver"] = "GoogleDrive" notify["driver"] = "GoogleDrive"
service.MyService.Notify().SendNotify("casaos:file:recover", notify) service.MyService.Notify().SendNotify("casaos:file:recover", notify)
} else if t == "Dropbox" { } else if t == "Dropbox" {
dropbox := dropbox.GetConfig() add := dropbox.Addition{}
dropbox.Code = ctx.QueryParam("code") add.Code = c.Query("code")
if len(dropbox.Code) == 0 { if len(add.Code) == 0 {
ctx.String(200, `<p>Code cannot be empty</p><script>window.close()</script>`) c.String(200, `<p>Code cannot be empty</p><script>window.close()</script>`)
notify["status"] = "fail" notify["status"] = "fail"
notify["message"] = "Code cannot be empty" notify["message"] = "Code cannot be empty"
logger.Error("Then code is empty error: ", zap.String("code", dropbox.Code), zap.Any("name", "dropbox")) logger.Error("Then code is empty error: ", zap.String("code", add.Code), zap.Any("name", "dropbox"))
service.MyService.Notify().SendNotify("casaos:file:recover", notify) service.MyService.Notify().SendNotify("casaos:file:recover", notify)
return
} }
add.RootFolderID = ""
err := dropbox.Init(ctx.Request().Context()) add.AppKey = dropbox.APPKEY
add.AppSecret = dropbox.APPSECRET
var dropbox dropbox.Dropbox
dropbox.Addition = add
err := dropbox.Init(c)
if err != nil { if err != nil {
ctx.String(200, `<p>Initialization failure:`+err.Error()+`</p><script>window.close()</script>`) c.String(200, `<p>Initialization failure:`+err.Error()+`</p><script>window.close()</script>`)
notify["status"] = "fail" notify["status"] = "fail"
notify["message"] = "Initialization failure" notify["message"] = "Initialization failure"
logger.Error("Then init error: ", zap.Error(err), zap.Any("name", "dropbox")) logger.Error("Then init error: ", zap.Error(err), zap.Any("name", "dropbox"))
service.MyService.Notify().SendNotify("casaos:file:recover", notify) service.MyService.Notify().SendNotify("casaos:file:recover", notify)
return
} }
username, err := dropbox.GetUserInfo(ctx.Request().Context()) username, err := dropbox.GetUserInfo(c)
if err != nil { if err != nil {
ctx.String(200, `<p>Failed to get user information:`+err.Error()+`</p><script>window.close()</script>`) c.String(200, `<p>Failed to get user information:`+err.Error()+`</p><script>window.close()</script>`)
notify["status"] = "fail" notify["status"] = "fail"
notify["message"] = "Failed to get user information" notify["message"] = "Failed to get user information"
logger.Error("Then get user information: ", zap.Error(err), zap.Any("name", "dropbox")) logger.Error("Then get user information: ", zap.Error(err), zap.Any("name", "dropbox"))
service.MyService.Notify().SendNotify("casaos:file:recover", notify) service.MyService.Notify().SendNotify("casaos:file:recover", notify)
return
} }
dmap := make(map[string]string) dmap := make(map[string]string)
dmap["username"] = username dmap["username"] = username
configs, err := service.MyService.Storage().GetConfig() configs, err := service.MyService.Storage().GetConfig()
if err != nil { if err != nil {
ctx.String(200, `<p>Failed to get rclone config:`+err.Error()+`</p><script>window.close()</script>`) c.String(200, `<p>Failed to get rclone config:`+err.Error()+`</p><script>window.close()</script>`)
notify["status"] = "fail" notify["status"] = "fail"
notify["message"] = "Failed to get rclone config" notify["message"] = "Failed to get rclone config"
logger.Error("Then get config error: ", zap.Error(err), zap.Any("name", "dropbox")) logger.Error("Then get config error: ", zap.Error(err), zap.Any("name", "dropbox"))
service.MyService.Notify().SendNotify("casaos:file:recover", notify) service.MyService.Notify().SendNotify("casaos:file:recover", notify)
return
} }
for _, v := range configs.Remotes { for _, v := range configs.Remotes {
cf, err := service.MyService.Storage().GetConfigByName(v) cf, err := service.MyService.Storage().GetConfigByName(v)
@@ -141,7 +158,7 @@ func GetRecoverStorage(ctx echo.Context) error {
continue continue
} }
if cf["type"] == "dropbox" && cf["username"] == dmap["username"] { if cf["type"] == "dropbox" && cf["username"] == dmap["username"] {
ctx.String(200, `<p>The same configuration has been added</p><script>window.close()</script>`) c.String(200, `<p>The same configuration has been added</p><script>window.close()</script>`)
err := service.MyService.Storage().CheckAndMountByName(v) err := service.MyService.Storage().CheckAndMountByName(v)
if err != nil { if err != nil {
logger.Error("check and mount by name error: ", zap.Error(err), zap.Any("name", cf["username"])) logger.Error("check and mount by name error: ", zap.Error(err), zap.Any("name", cf["username"]))
@@ -150,6 +167,7 @@ func GetRecoverStorage(ctx echo.Context) error {
notify["status"] = "warn" notify["status"] = "warn"
notify["message"] = "The same configuration has been added" notify["message"] = "The same configuration has been added"
service.MyService.Notify().SendNotify("casaos:file:recover", notify) service.MyService.Notify().SendNotify("casaos:file:recover", notify)
return
} }
} }
if len(username) > 0 { if len(username) > 0 {
@@ -158,8 +176,8 @@ func GetRecoverStorage(ctx echo.Context) error {
} }
username += "_dropbox_" + strconv.FormatInt(time.Now().Unix(), 10) username += "_dropbox_" + strconv.FormatInt(time.Now().Unix(), 10)
dmap["client_id"] = dropbox.AppKey dmap["client_id"] = add.AppKey
dmap["client_secret"] = dropbox.AppSecret dmap["client_secret"] = add.AppSecret
dmap["token"] = `{"access_token":"` + dropbox.AccessToken + `","token_type":"bearer","refresh_token":"` + dropbox.Addition.RefreshToken + `","expiry":"` + currentDate + `T` + currentTime.Add(time.Hour*3).Add(time.Minute*50).Format("15:04:05") + `.780385354Z"}` dmap["token"] = `{"access_token":"` + dropbox.AccessToken + `","token_type":"bearer","refresh_token":"` + dropbox.Addition.RefreshToken + `","expiry":"` + currentDate + `T` + currentTime.Add(time.Hour*3).Add(time.Minute*50).Format("15:04:05") + `.780385354Z"}`
dmap["mount_point"] = "/mnt/" + username dmap["mount_point"] = "/mnt/" + username
// data.SetValue(username, "type", "dropbox") // data.SetValue(username, "type", "dropbox")
@@ -170,7 +188,7 @@ func GetRecoverStorage(ctx echo.Context) error {
// data.SetValue(username, "token", `{"access_token":"`+dropbox.AccessToken+`","token_type":"bearer","refresh_token":"`+dropbox.Addition.RefreshToken+`","expiry":"`+currentDate+`T`+currentTime.Add(time.Hour*3).Format("15:04:05")+`.780385354Z"}`) // data.SetValue(username, "token", `{"access_token":"`+dropbox.AccessToken+`","token_type":"bearer","refresh_token":"`+dropbox.Addition.RefreshToken+`","expiry":"`+currentDate+`T`+currentTime.Add(time.Hour*3).Format("15:04:05")+`.780385354Z"}`)
// e = data.Save() // e = data.Save()
// if e != nil { // if e != nil {
// return ctx.String(200, `<p>保存配置失败:`+e.Error()+`</p>`) // c.String(200, `<p>保存配置失败:`+e.Error()+`</p>`)
// return // return
// } // }
@@ -181,94 +199,7 @@ func GetRecoverStorage(ctx echo.Context) error {
notify["message"] = "Success" notify["message"] = "Success"
notify["driver"] = "Dropbox" notify["driver"] = "Dropbox"
service.MyService.Notify().SendNotify("casaos:file:recover", notify) service.MyService.Notify().SendNotify("casaos:file:recover", notify)
} else if t == "Onedrive" {
onedrive := onedrive.GetConfig()
onedrive.Code = ctx.QueryParam("code")
if len(onedrive.Code) == 0 {
ctx.String(200, `<p>Code cannot be empty</p><script>window.close()</script>`)
notify["status"] = "fail"
notify["message"] = "Code cannot be empty"
logger.Error("Then code is empty error: ", zap.String("code", onedrive.Code), zap.Any("name", "onedrive"))
service.MyService.Notify().SendNotify("casaos:file:recover", notify)
}
err := onedrive.Init(ctx.Request().Context())
if err != nil {
ctx.String(200, `<p>Initialization failure:`+err.Error()+`</p><script>window.close()</script>`)
notify["status"] = "fail"
notify["message"] = "Initialization failure"
logger.Error("Then init error: ", zap.Error(err), zap.Any("name", "onedrive"))
service.MyService.Notify().SendNotify("casaos:file:recover", notify)
}
username, driveId, driveType, err := onedrive.GetInfo(ctx.Request().Context())
if err != nil {
ctx.String(200, `<p>Failed to get user information:`+err.Error()+`</p><script>window.close()</script>`)
notify["status"] = "fail"
notify["message"] = "Failed to get user information"
logger.Error("Then get user information: ", zap.Error(err), zap.Any("name", "onedrive"))
service.MyService.Notify().SendNotify("casaos:file:recover", notify)
}
dmap := make(map[string]string)
dmap["username"] = username
configs, err := service.MyService.Storage().GetConfig()
if err != nil {
ctx.String(200, `<p>Failed to get rclone config:`+err.Error()+`</p><script>window.close()</script>`)
notify["status"] = "fail"
notify["message"] = "Failed to get rclone config"
logger.Error("Then get config error: ", zap.Error(err), zap.Any("name", "onedrive"))
service.MyService.Notify().SendNotify("casaos:file:recover", notify)
}
for _, v := range configs.Remotes {
cf, err := service.MyService.Storage().GetConfigByName(v)
if err != nil {
logger.Error("then get config by name error: ", zap.Error(err), zap.Any("name", v))
continue
}
if cf["type"] == "onedrive" && cf["username"] == dmap["username"] {
ctx.String(200, `<p>The same configuration has been added</p><script>window.close()</script>`)
err := service.MyService.Storage().CheckAndMountByName(v)
if err != nil {
logger.Error("check and mount by name error: ", zap.Error(err), zap.Any("name", cf["username"]))
}
notify["status"] = "warn"
notify["message"] = "The same configuration has been added"
service.MyService.Notify().SendNotify("casaos:file:recover", notify)
}
}
if len(username) > 0 {
a := strings.Split(username, "@")
username = a[0]
}
username += "_onedrive_" + strconv.FormatInt(time.Now().Unix(), 10)
dmap["client_id"] = onedrive.ClientID
dmap["client_secret"] = onedrive.ClientSecret
dmap["token"] = `{"access_token":"` + onedrive.AccessToken + `","token_type":"bearer","refresh_token":"` + onedrive.RefreshToken + `","expiry":"` + currentDate + `T` + currentTime.Add(time.Hour*3).Add(time.Minute*50).Format("15:04:05") + `.780385354Z"}`
dmap["mount_point"] = "/mnt/" + username
dmap["drive_id"] = driveId
dmap["drive_type"] = driveType
// data.SetValue(username, "type", "dropbox")
// data.SetValue(username, "client_id", add.AppKey)
// data.SetValue(username, "client_secret", add.AppSecret)
// data.SetValue(username, "mount_point", "/mnt/"+username)
// data.SetValue(username, "token", `{"access_token":"`+dropbox.AccessToken+`","token_type":"bearer","refresh_token":"`+dropbox.Addition.RefreshToken+`","expiry":"`+currentDate+`T`+currentTime.Add(time.Hour*3).Format("15:04:05")+`.780385354Z"}`)
// e = data.Save()
// if e != nil {
// return ctx.String(200, `<p>保存配置失败:`+e.Error()+`</p>`)
// return
// }
service.MyService.Storage().CreateConfig(dmap, username, "onedrive")
service.MyService.Storage().MountStorage("/mnt/"+username, username+":")
notify["status"] = "success"
notify["message"] = "Success"
notify["driver"] = "Onedrive"
service.MyService.Notify().SendNotify("casaos:file:recover", notify)
} }
return ctx.String(200, `<p>Just close the page</p><script>window.close()</script>`) c.String(200, `<p>Just close the page</p><script>window.close()</script>`)
} }

View File

@@ -20,7 +20,6 @@ import (
"github.com/IceWhaleTech/CasaOS-Common/utils/logger" "github.com/IceWhaleTech/CasaOS-Common/utils/logger"
"github.com/IceWhaleTech/CasaOS-Common/utils/systemctl" "github.com/IceWhaleTech/CasaOS-Common/utils/systemctl"
"github.com/labstack/echo/v4"
"go.uber.org/zap" "go.uber.org/zap"
"github.com/IceWhaleTech/CasaOS/model" "github.com/IceWhaleTech/CasaOS/model"
@@ -29,16 +28,18 @@ import (
"github.com/IceWhaleTech/CasaOS/pkg/utils/file" "github.com/IceWhaleTech/CasaOS/pkg/utils/file"
"github.com/IceWhaleTech/CasaOS/service" "github.com/IceWhaleTech/CasaOS/service"
model2 "github.com/IceWhaleTech/CasaOS/service/model" model2 "github.com/IceWhaleTech/CasaOS/service/model"
"github.com/gin-gonic/gin"
) )
// service // service
func GetSambaStatus(ctx echo.Context) error { func GetSambaStatus(c *gin.Context) {
if status, err := systemctl.IsServiceRunning("smbd"); err != nil || !status { if status, err := systemctl.IsServiceRunning("smbd"); err != nil || !status {
return ctx.JSON(http.StatusInternalServerError, model.Result{ c.JSON(http.StatusInternalServerError, model.Result{
Success: common_err.SERVICE_NOT_RUNNING, Success: common_err.SERVICE_NOT_RUNNING,
Message: common_err.GetMsg(common_err.SERVICE_NOT_RUNNING), Message: common_err.GetMsg(common_err.SERVICE_NOT_RUNNING),
}) })
return
} }
needInit := true needInit := true
@@ -50,10 +51,10 @@ func GetSambaStatus(ctx echo.Context) error {
} }
data := make(map[string]string, 1) data := make(map[string]string, 1)
data["need_init"] = fmt.Sprintf("%v", needInit) data["need_init"] = fmt.Sprintf("%v", needInit)
return ctx.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 GetSambaSharesList(ctx echo.Context) error { func GetSambaSharesList(c *gin.Context) {
shares := service.MyService.Shares().GetSharesList() shares := service.MyService.Shares().GetSharesList()
shareList := []model.Shares{} shareList := []model.Shares{}
for _, v := range shares { for _, v := range shares {
@@ -63,24 +64,28 @@ func GetSambaSharesList(ctx echo.Context) error {
ID: v.ID, ID: v.ID,
}) })
} }
return ctx.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: shareList}) c.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: shareList})
} }
func PostSambaSharesCreate(ctx echo.Context) error { func PostSambaSharesCreate(c *gin.Context) {
shares := []model.Shares{} shares := []model.Shares{}
ctx.Bind(&shares) c.ShouldBindJSON(&shares)
for _, v := range shares { for _, v := range shares {
if v.Path == "" { if v.Path == "" {
return ctx.JSON(common_err.CLIENT_ERROR, model.Result{Success: common_err.INSUFFICIENT_PERMISSIONS, Message: common_err.GetMsg(common_err.INSUFFICIENT_PERMISSIONS)}) c.JSON(common_err.CLIENT_ERROR, model.Result{Success: common_err.INSUFFICIENT_PERMISSIONS, Message: common_err.GetMsg(common_err.INSUFFICIENT_PERMISSIONS)})
return
} }
if !file.Exists(v.Path) { if !file.Exists(v.Path) {
return ctx.JSON(common_err.SERVICE_ERROR, model.Result{Success: common_err.DIR_NOT_EXISTS, Message: common_err.GetMsg(common_err.DIR_NOT_EXISTS)}) c.JSON(common_err.SERVICE_ERROR, model.Result{Success: common_err.DIR_NOT_EXISTS, Message: common_err.GetMsg(common_err.DIR_NOT_EXISTS)})
return
} }
if len(service.MyService.Shares().GetSharesByPath(v.Path)) > 0 { if len(service.MyService.Shares().GetSharesByPath(v.Path)) > 0 {
return ctx.JSON(common_err.CLIENT_ERROR, model.Result{Success: common_err.SHARE_ALREADY_EXISTS, Message: common_err.GetMsg(common_err.SHARE_ALREADY_EXISTS)}) c.JSON(common_err.CLIENT_ERROR, model.Result{Success: common_err.SHARE_ALREADY_EXISTS, Message: common_err.GetMsg(common_err.SHARE_ALREADY_EXISTS)})
return
} }
if len(service.MyService.Shares().GetSharesByPath(filepath.Base(v.Path))) > 0 { if len(service.MyService.Shares().GetSharesByPath(filepath.Base(v.Path))) > 0 {
return ctx.JSON(common_err.CLIENT_ERROR, model.Result{Success: common_err.SHARE_NAME_ALREADY_EXISTS, Message: common_err.GetMsg(common_err.SHARE_NAME_ALREADY_EXISTS)}) c.JSON(common_err.CLIENT_ERROR, model.Result{Success: common_err.SHARE_NAME_ALREADY_EXISTS, Message: common_err.GetMsg(common_err.SHARE_NAME_ALREADY_EXISTS)})
return
} }
} }
for _, v := range shares { for _, v := range shares {
@@ -92,20 +97,21 @@ func PostSambaSharesCreate(ctx echo.Context) error {
service.MyService.Shares().CreateShare(shareDBModel) service.MyService.Shares().CreateShare(shareDBModel)
} }
return ctx.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: shares}) c.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: shares})
} }
func DeleteSambaShares(ctx echo.Context) error { func DeleteSambaShares(c *gin.Context) {
id := ctx.Param("id") id := c.Param("id")
if id == "" { if id == "" {
return ctx.JSON(common_err.CLIENT_ERROR, model.Result{Success: common_err.INSUFFICIENT_PERMISSIONS, Message: common_err.GetMsg(common_err.INSUFFICIENT_PERMISSIONS)}) c.JSON(common_err.CLIENT_ERROR, model.Result{Success: common_err.INSUFFICIENT_PERMISSIONS, Message: common_err.GetMsg(common_err.INSUFFICIENT_PERMISSIONS)})
return
} }
service.MyService.Shares().DeleteShare(id) service.MyService.Shares().DeleteShare(id)
return ctx.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: id}) c.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: id})
} }
// client // client
func GetSambaConnectionsList(ctx echo.Context) error { func GetSambaConnectionsList(c *gin.Context) {
connections := service.MyService.Connections().GetConnectionsList() connections := service.MyService.Connections().GetConnectionsList()
connectionList := []model.Connections{} connectionList := []model.Connections{}
for _, v := range connections { for _, v := range connections {
@@ -117,33 +123,34 @@ func GetSambaConnectionsList(ctx echo.Context) error {
MountPoint: v.MountPoint, MountPoint: v.MountPoint,
}) })
} }
return ctx.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: connectionList}) c.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: connectionList})
} }
func PostSambaConnectionsCreate(ctx echo.Context) error { func PostSambaConnectionsCreate(c *gin.Context) {
connection := model.Connections{} connection := model.Connections{}
ctx.Bind(&connection) c.ShouldBindJSON(&connection)
if connection.Port == "" { if connection.Port == "" {
connection.Port = "445" connection.Port = "445"
} }
if connection.Username == "" || connection.Host == "" { if connection.Username == "" || connection.Host == "" {
return ctx.JSON(common_err.CLIENT_ERROR, model.Result{Success: common_err.CHARACTER_LIMIT, Message: common_err.GetMsg(common_err.CHARACTER_LIMIT)}) c.JSON(common_err.CLIENT_ERROR, model.Result{Success: common_err.CHARACTER_LIMIT, Message: common_err.GetMsg(common_err.CHARACTER_LIMIT)})
return
} }
// if ok, _ := regexp.MatchString(`^[\w@#*.]{4,30}$`, connection.Password); !ok { // if ok, _ := regexp.MatchString(`^[\w@#*.]{4,30}$`, connection.Password); !ok {
// return ctx.JSON(common_err.CLIENT_ERROR, model.Result{Success: common_err.CHARACTER_LIMIT, Message: common_err.GetMsg(common_err.CHARACTER_LIMIT)}) // c.JSON(common_err.CLIENT_ERROR, model.Result{Success: common_err.CHARACTER_LIMIT, Message: common_err.GetMsg(common_err.CHARACTER_LIMIT)})
// return // return
// } // }
// if ok, _ := regexp.MatchString(`^[\w@#*.]{4,30}$`, connection.Username); !ok { // if ok, _ := regexp.MatchString(`^[\w@#*.]{4,30}$`, connection.Username); !ok {
// return ctx.JSON(common_err.CLIENT_ERROR, model.Result{Success: common_err.INVALID_PARAMS, Message: common_err.GetMsg(common_err.INVALID_PARAMS)}) // c.JSON(common_err.CLIENT_ERROR, model.Result{Success: common_err.INVALID_PARAMS, Message: common_err.GetMsg(common_err.INVALID_PARAMS)})
// return // return
// } // }
// if !ip_helper.IsIPv4(connection.Host) && !ip_helper.IsIPv6(connection.Host) { // if !ip_helper.IsIPv4(connection.Host) && !ip_helper.IsIPv6(connection.Host) {
// return ctx.JSON(common_err.CLIENT_ERROR, model.Result{Success: common_err.INVALID_PARAMS, Message: common_err.GetMsg(common_err.INVALID_PARAMS)}) // c.JSON(common_err.CLIENT_ERROR, model.Result{Success: common_err.INVALID_PARAMS, Message: common_err.GetMsg(common_err.INVALID_PARAMS)})
// return // return
// } // }
// if ok, _ := regexp.MatchString("^[0-9]{1,6}$", connection.Port); !ok { // if ok, _ := regexp.MatchString("^[0-9]{1,6}$", connection.Port); !ok {
// return ctx.JSON(common_err.CLIENT_ERROR, model.Result{Success: common_err.INVALID_PARAMS, Message: common_err.GetMsg(common_err.INVALID_PARAMS)}) // c.JSON(common_err.CLIENT_ERROR, model.Result{Success: common_err.INVALID_PARAMS, Message: common_err.GetMsg(common_err.INVALID_PARAMS)})
// return // return
// } // }
@@ -151,12 +158,14 @@ func PostSambaConnectionsCreate(ctx echo.Context) error {
// check is exists // check is exists
connections := service.MyService.Connections().GetConnectionByHost(connection.Host) connections := service.MyService.Connections().GetConnectionByHost(connection.Host)
if len(connections) > 0 { if len(connections) > 0 {
return ctx.JSON(common_err.SERVICE_ERROR, model.Result{Success: common_err.Record_ALREADY_EXIST, Message: common_err.GetMsg(common_err.Record_ALREADY_EXIST), Data: common_err.GetMsg(common_err.Record_ALREADY_EXIST)}) c.JSON(common_err.SERVICE_ERROR, model.Result{Success: common_err.Record_ALREADY_EXIST, Message: common_err.GetMsg(common_err.Record_ALREADY_EXIST), Data: common_err.GetMsg(common_err.Record_ALREADY_EXIST)})
return
} }
// check connect is ok // check connect is ok
directories, err := samba.GetSambaSharesList(connection.Host, connection.Port, connection.Username, connection.Password) directories, err := samba.GetSambaSharesList(connection.Host, connection.Port, connection.Username, connection.Password)
if err != nil { if err != nil {
return ctx.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
} }
connectionDBModel := model2.ConnectionsDBModel{} connectionDBModel := model2.ConnectionsDBModel{}
@@ -178,19 +187,21 @@ func PostSambaConnectionsCreate(ctx echo.Context) error {
service.MyService.Connections().CreateConnection(&connectionDBModel) service.MyService.Connections().CreateConnection(&connectionDBModel)
connection.ID = connectionDBModel.ID connection.ID = connectionDBModel.ID
return ctx.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: connection}) c.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: connection})
} }
func DeleteSambaConnections(ctx echo.Context) error { func DeleteSambaConnections(c *gin.Context) {
id := ctx.Param("id") id := c.Param("id")
connection := service.MyService.Connections().GetConnectionByID(id) connection := service.MyService.Connections().GetConnectionByID(id)
if connection.Username == "" { if connection.Username == "" {
return ctx.JSON(common_err.CLIENT_ERROR, model.Result{Success: common_err.Record_NOT_EXIST, Message: common_err.GetMsg(common_err.Record_NOT_EXIST)}) c.JSON(common_err.CLIENT_ERROR, model.Result{Success: common_err.Record_NOT_EXIST, Message: common_err.GetMsg(common_err.Record_NOT_EXIST)})
return
} }
mountPointList, err := samba.GetSambaSharesList(connection.Host, connection.Port, connection.Username, connection.Password) mountPointList, err := samba.GetSambaSharesList(connection.Host, connection.Port, connection.Username, connection.Password)
// mountPointList, err := service.MyService.System().GetDirPath(connection.MountPoint) //mountPointList, err := service.MyService.System().GetDirPath(connection.MountPoint)
if err != nil { if err != nil {
return ctx.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
} }
baseHostPath := "/mnt/" + connection.Host baseHostPath := "/mnt/" + connection.Host
for _, v := range mountPointList { for _, v := range mountPointList {
@@ -198,14 +209,16 @@ func DeleteSambaConnections(ctx echo.Context) error {
err := service.MyService.Connections().UnmountSmaba(baseHostPath + "/" + v) err := service.MyService.Connections().UnmountSmaba(baseHostPath + "/" + v)
if err != nil { if err != nil {
logger.Error("unmount smaba error", zap.Error(err), zap.Any("path", baseHostPath+"/"+v)) logger.Error("unmount smaba error", zap.Error(err), zap.Any("path", baseHostPath+"/"+v))
return ctx.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
} }
} }
} }
dir, _ := ioutil.ReadDir(connection.MountPoint) dir, _ := ioutil.ReadDir(connection.MountPoint)
if len(dir) == 0 { if len(dir) == 0 {
os.RemoveAll(connection.MountPoint) os.RemoveAll(connection.MountPoint)
} }
service.MyService.Connections().DeleteConnection(id) service.MyService.Connections().DeleteConnection(id)
return ctx.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: id}) c.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: id})
} }

View File

@@ -16,8 +16,8 @@ import (
"testing" "testing"
v1 "github.com/IceWhaleTech/CasaOS/route/v1" v1 "github.com/IceWhaleTech/CasaOS/route/v1"
"github.com/gin-gonic/gin"
"github.com/golang/mock/gomock" "github.com/golang/mock/gomock"
"github.com/labstack/echo/v4"
"gotest.tools/assert" "gotest.tools/assert"
) )
@@ -54,22 +54,17 @@ func performRequest(r http.Handler, method, path string) *httptest.ResponseRecor
func TestGetSambaSharesList(t *testing.T) { func TestGetSambaSharesList(t *testing.T) {
t.Skip("This test is always failing. Skipped to unblock releasing - MUST FIX!") t.Skip("This test is always failing. Skipped to unblock releasing - MUST FIX!")
gin.SetMode(gin.TestMode)
ctrl := gomock.NewController(t) ctrl := gomock.NewController(t)
defer ctrl.Finish() defer ctrl.Finish()
executeWithContext := func() *httptest.ResponseRecorder { executeWithContext := func() *httptest.ResponseRecorder {
response := httptest.NewRecorder() response := httptest.NewRecorder()
// con, ginEngine := gin.CreateTestContext(response) con, ginEngine := gin.CreateTestContext(response)
e := echo.New()
requestUrl := "/v1/samba/shares" requestUrl := "/v1/samba/shares"
httpRequest, _ := http.NewRequest("GET", requestUrl, nil) httpRequest, _ := http.NewRequest("GET", requestUrl, nil)
con := e.NewContext(httpRequest, response)
v1.GetSambaSharesList(con) v1.GetSambaSharesList(con)
e.ServeHTTP(response, httpRequest) ginEngine.ServeHTTP(response, httpRequest)
return response return response
} }

View File

@@ -10,9 +10,8 @@ import (
"github.com/IceWhaleTech/CasaOS-Common/utils/common_err" "github.com/IceWhaleTech/CasaOS-Common/utils/common_err"
"github.com/IceWhaleTech/CasaOS-Common/utils/logger" "github.com/IceWhaleTech/CasaOS-Common/utils/logger"
sshHelper "github.com/IceWhaleTech/CasaOS-Common/utils/ssh" sshHelper "github.com/IceWhaleTech/CasaOS-Common/utils/ssh"
"github.com/IceWhaleTech/CasaOS/pkg/utils"
"github.com/labstack/echo/v4"
"github.com/gin-gonic/gin"
"github.com/gorilla/websocket" "github.com/gorilla/websocket"
"go.uber.org/zap" "go.uber.org/zap"
"golang.org/x/crypto/ssh" "golang.org/x/crypto/ssh"
@@ -27,41 +26,44 @@ var upgrader = websocket.Upgrader{
HandshakeTimeout: time.Duration(time.Second * 5), HandshakeTimeout: time.Duration(time.Second * 5),
} }
func PostSshLogin(ctx echo.Context) error { func PostSshLogin(c *gin.Context) {
j := make(map[string]string) j := make(map[string]string)
ctx.Bind(&j) c.ShouldBind(&j)
userName := j["username"] userName := j["username"]
password := j["password"] password := j["password"]
port := j["port"] port := j["port"]
if userName == "" || password == "" || port == "" { if userName == "" || password == "" || port == "" {
return ctx.JSON(common_err.CLIENT_ERROR, modelCommon.Result{Success: common_err.INVALID_PARAMS, Message: common_err.GetMsg(common_err.INVALID_PARAMS), Data: "Username or password or port is empty"}) c.JSON(common_err.CLIENT_ERROR, modelCommon.Result{Success: common_err.INVALID_PARAMS, Message: common_err.GetMsg(common_err.INVALID_PARAMS), Data: "Username or password or port is empty"})
return
} }
_, err := sshHelper.NewSshClient(userName, password, port) _, err := sshHelper.NewSshClient(userName, password, port)
if err != nil { if err != nil {
c.JSON(common_err.CLIENT_ERROR, modelCommon.Result{Success: common_err.CLIENT_ERROR, Message: common_err.GetMsg(common_err.CLIENT_ERROR), Data: "Please check if the username and port are correct, and make sure that ssh server is installed."})
logger.Error("connect ssh error", zap.Any("error", err)) logger.Error("connect ssh error", zap.Any("error", err))
return ctx.JSON(common_err.CLIENT_ERROR, modelCommon.Result{Success: common_err.CLIENT_ERROR, Message: common_err.GetMsg(common_err.CLIENT_ERROR), Data: "Please check if the username and port are correct, and make sure that ssh server is installed."}) return
} }
return ctx.JSON(common_err.SUCCESS, modelCommon.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS)}) c.JSON(common_err.SUCCESS, modelCommon.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS)})
} }
func WsSsh(ctx echo.Context) error { func WsSsh(c *gin.Context) {
_, e := exec.LookPath("ssh") _, e := exec.LookPath("ssh")
if e != nil { if e != nil {
return ctx.JSON(common_err.SERVICE_ERROR, modelCommon.Result{Success: common_err.SERVICE_ERROR, Message: common_err.GetMsg(common_err.SERVICE_ERROR), Data: "ssh server not found"}) c.JSON(common_err.SERVICE_ERROR, modelCommon.Result{Success: common_err.SERVICE_ERROR, Message: common_err.GetMsg(common_err.SERVICE_ERROR), Data: "ssh server not found"})
return
} }
userName := ctx.QueryParam("username") userName := c.Query("username")
password := ctx.QueryParam("password") password := c.Query("password")
port := ctx.QueryParam("port") port := c.Query("port")
wsConn, _ := upgrader.Upgrade(ctx.Response().Writer, ctx.Request(), nil) wsConn, _ := upgrader.Upgrade(c.Writer, c.Request, nil)
logBuff := new(bytes.Buffer) logBuff := new(bytes.Buffer)
quitChan := make(chan bool, 3) quitChan := make(chan bool, 3)
// user := "" // user := ""
// password := "" // password := ""
var login int = 1 var login int = 1
cols, _ := strconv.Atoi(utils.DefaultQuery(ctx, "cols", "200")) cols, _ := strconv.Atoi(c.DefaultQuery("cols", "200"))
rows, _ := strconv.Atoi(utils.DefaultQuery(ctx, "rows", "32")) rows, _ := strconv.Atoi(c.DefaultQuery("rows", "32"))
var client *ssh.Client var client *ssh.Client
for login != 0 { for login != 0 {
@@ -91,5 +93,4 @@ func WsSsh(ctx echo.Context) error {
go ssConn.SessionWait(quitChan) go ssConn.SessionWait(quitChan)
<-quitChan <-quitChan
return nil
} }

View File

@@ -2,7 +2,6 @@ package v1
import ( import (
"bytes" "bytes"
"encoding/json"
"fmt" "fmt"
"io" "io"
"io/ioutil" "io/ioutil"
@@ -19,14 +18,12 @@ import (
"github.com/IceWhaleTech/CasaOS/common" "github.com/IceWhaleTech/CasaOS/common"
"github.com/IceWhaleTech/CasaOS/model" "github.com/IceWhaleTech/CasaOS/model"
"github.com/IceWhaleTech/CasaOS/pkg/config" "github.com/IceWhaleTech/CasaOS/pkg/config"
"github.com/IceWhaleTech/CasaOS/pkg/utils"
"github.com/IceWhaleTech/CasaOS/pkg/utils/common_err" "github.com/IceWhaleTech/CasaOS/pkg/utils/common_err"
"github.com/IceWhaleTech/CasaOS/pkg/utils/version" "github.com/IceWhaleTech/CasaOS/pkg/utils/version"
"github.com/IceWhaleTech/CasaOS/service" "github.com/IceWhaleTech/CasaOS/service"
model2 "github.com/IceWhaleTech/CasaOS/service/model" model2 "github.com/IceWhaleTech/CasaOS/service/model"
"github.com/IceWhaleTech/CasaOS/types" "github.com/IceWhaleTech/CasaOS/types"
"github.com/labstack/echo/v4" "github.com/gin-gonic/gin"
"github.com/tidwall/gjson"
) )
// @Summary check version // @Summary check version
@@ -36,7 +33,7 @@ import (
// @Security ApiKeyAuth // @Security ApiKeyAuth
// @Success 200 {string} string "ok" // @Success 200 {string} string "ok"
// @Router /sys/version/check [get] // @Router /sys/version/check [get]
func GetSystemCheckVersion(ctx echo.Context) error { func GetSystemCheckVersion(c *gin.Context) {
need, version := version.IsNeedUpdate(service.MyService.Casa().GetCasaosVersion()) need, version := version.IsNeedUpdate(service.MyService.Casa().GetCasaosVersion())
if need { if need {
installLog := model2.AppNotify{} installLog := model2.AppNotify{}
@@ -52,7 +49,7 @@ func GetSystemCheckVersion(ctx echo.Context) error {
data["need_update"] = need data["need_update"] = need
data["version"] = version data["version"] = version
data["current_version"] = common.VERSION data["current_version"] = common.VERSION
return ctx.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})
} }
// @Summary 系统信息 // @Summary 系统信息
@@ -62,12 +59,12 @@ func GetSystemCheckVersion(ctx echo.Context) error {
// @Security ApiKeyAuth // @Security ApiKeyAuth
// @Success 200 {string} string "ok" // @Success 200 {string} string "ok"
// @Router /sys/update [post] // @Router /sys/update [post]
func SystemUpdate(ctx echo.Context) error { func SystemUpdate(c *gin.Context) {
need, version := version.IsNeedUpdate(service.MyService.Casa().GetCasaosVersion()) need, version := version.IsNeedUpdate(service.MyService.Casa().GetCasaosVersion())
if need { if need {
service.MyService.System().UpdateSystemVersion(version.Version) service.MyService.System().UpdateSystemVersion(version.Version)
} }
return ctx.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS)}) c.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS)})
} }
// @Summary get logs // @Summary get logs
@@ -77,13 +74,13 @@ func SystemUpdate(ctx echo.Context) error {
// @Security ApiKeyAuth // @Security ApiKeyAuth
// @Success 200 {string} string "ok" // @Success 200 {string} string "ok"
// @Router /sys/error/logs [get] // @Router /sys/error/logs [get]
func GetCasaOSErrorLogs(ctx echo.Context) error { func GetCasaOSErrorLogs(c *gin.Context) {
line, _ := strconv.Atoi(utils.DefaultQuery(ctx, "line", "100")) line, _ := strconv.Atoi(c.DefaultQuery("line", "100"))
return ctx.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: service.MyService.System().GetCasaOSLogs(line)}) 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(ctx echo.Context) error { func GetSystemConfigDebug(c *gin.Context) {
array := service.MyService.System().GetSystemConfigDebug() array := service.MyService.System().GetSystemConfigDebug()
disk := service.MyService.System().GetDiskInfo() disk := service.MyService.System().GetDiskInfo()
sys := service.MyService.System().GetSysInfo() sys := service.MyService.System().GetSysInfo()
@@ -101,7 +98,7 @@ func GetSystemConfigDebug(ctx echo.Context) error {
// array = append(array, fmt.Sprintf("disk,total:%v,used:%v,UsedPercent:%v", disk.Total>>20, disk.Used>>20, disk.UsedPercent)) // array = append(array, fmt.Sprintf("disk,total:%v,used:%v,UsedPercent:%v", disk.Total>>20, disk.Used>>20, disk.UsedPercent))
return ctx.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: bugContent}) c.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: bugContent})
} }
// @Summary get casaos server port // @Summary get casaos server port
@@ -111,8 +108,8 @@ func GetSystemConfigDebug(ctx echo.Context) error {
// @Security ApiKeyAuth // @Security ApiKeyAuth
// @Success 200 {string} string "ok" // @Success 200 {string} string "ok"
// @Router /sys/port [get] // @Router /sys/port [get]
func GetCasaOSPort(ctx echo.Context) error { func GetCasaOSPort(c *gin.Context) {
return ctx.JSON(common_err.SUCCESS, c.JSON(common_err.SUCCESS,
model.Result{ model.Result{
Success: common_err.SUCCESS, Success: common_err.SUCCESS,
Message: common_err.GetMsg(common_err.SUCCESS), Message: common_err.GetMsg(common_err.SUCCESS),
@@ -128,29 +125,31 @@ func GetCasaOSPort(ctx echo.Context) error {
// @Param port json string true "port" // @Param port json string true "port"
// @Success 200 {string} string "ok" // @Success 200 {string} string "ok"
// @Router /sys/port [put] // @Router /sys/port [put]
func PutCasaOSPort(ctx echo.Context) error { func PutCasaOSPort(c *gin.Context) {
json := make(map[string]string) json := make(map[string]string)
ctx.Bind(&json) c.ShouldBind(&json)
portStr := json["port"] portStr := json["port"]
portNumber, err := strconv.Atoi(portStr) portNumber, err := strconv.Atoi(portStr)
if err != nil { if err != nil {
return ctx.JSON(common_err.SERVICE_ERROR, c.JSON(common_err.SERVICE_ERROR,
model.Result{ model.Result{
Success: common_err.SERVICE_ERROR, Success: common_err.SERVICE_ERROR,
Message: err.Error(), Message: err.Error(),
}) })
return
} }
isAvailable := port.IsPortAvailable(portNumber, "tcp") isAvailable := port.IsPortAvailable(portNumber, "tcp")
if !isAvailable { if !isAvailable {
return ctx.JSON(common_err.SERVICE_ERROR, c.JSON(common_err.SERVICE_ERROR,
model.Result{ model.Result{
Success: common_err.PORT_IS_OCCUPIED, Success: common_err.PORT_IS_OCCUPIED,
Message: common_err.GetMsg(common_err.PORT_IS_OCCUPIED), Message: common_err.GetMsg(common_err.PORT_IS_OCCUPIED),
}) })
return
} }
service.MyService.System().UpSystemPort(strconv.Itoa(portNumber)) service.MyService.System().UpSystemPort(strconv.Itoa(portNumber))
return ctx.JSON(common_err.SUCCESS, c.JSON(common_err.SUCCESS,
model.Result{ model.Result{
Success: common_err.SUCCESS, Success: common_err.SUCCESS,
Message: common_err.GetMsg(common_err.SUCCESS), Message: common_err.GetMsg(common_err.SUCCESS),
@@ -164,9 +163,8 @@ func PutCasaOSPort(ctx echo.Context) error {
// @Security ApiKeyAuth // @Security ApiKeyAuth
// @Success 200 {string} string "ok" // @Success 200 {string} string "ok"
// @Router /sys/restart [post] // @Router /sys/restart [post]
func PostKillCasaOS(ctx echo.Context) error { func PostKillCasaOS(c *gin.Context) {
os.Exit(0) os.Exit(0)
return nil
} }
// @Summary get system hardware info // @Summary get system hardware info
@@ -176,20 +174,20 @@ func PostKillCasaOS(ctx echo.Context) error {
// @Security ApiKeyAuth // @Security ApiKeyAuth
// @Success 200 {string} string "ok" // @Success 200 {string} string "ok"
// @Router /sys/hardware/info [get] // @Router /sys/hardware/info [get]
func GetSystemHardwareInfo(ctx echo.Context) error { 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()
data["arch"] = runtime.GOARCH data["arch"] = runtime.GOARCH
if cpu := service.MyService.System().GetCpuInfo(); len(cpu) > 0 { if cpu := service.MyService.System().GetCpuInfo(); len(cpu) > 0 {
return ctx.JSON(common_err.SUCCESS,
c.JSON(common_err.SUCCESS,
model.Result{ model.Result{
Success: common_err.SUCCESS, Success: common_err.SUCCESS,
Message: common_err.GetMsg(common_err.SUCCESS), Message: common_err.GetMsg(common_err.SUCCESS),
Data: data, Data: data,
}) })
} }
return nil
} }
// @Summary system utilization // @Summary system utilization
@@ -199,7 +197,7 @@ func GetSystemHardwareInfo(ctx echo.Context) error {
// @Security ApiKeyAuth // @Security ApiKeyAuth
// @Success 200 {string} string "ok" // @Success 200 {string} string "ok"
// @Router /sys/utilization [get] // @Router /sys/utilization [get]
func GetSystemUtilization(ctx echo.Context) error { func GetSystemUtilization(c *gin.Context) {
data := make(map[string]interface{}) 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()
@@ -243,7 +241,7 @@ func GetSystemUtilization(ctx echo.Context) error {
data[key.(string)] = value data[key.(string)] = value
return true return true
}) })
return ctx.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})
} }
// @Summary get cpu info // @Summary get cpu info
@@ -253,13 +251,13 @@ func GetSystemUtilization(ctx echo.Context) error {
// @Security ApiKeyAuth // @Security ApiKeyAuth
// @Success 200 {string} string "ok" // @Success 200 {string} string "ok"
// @Router /sys/cpu [get] // @Router /sys/cpu [get]
func GetSystemCupInfo(ctx echo.Context) error { func GetSystemCupInfo(c *gin.Context) {
cpu := service.MyService.System().GetCpuPercent() cpu := service.MyService.System().GetCpuPercent()
num := service.MyService.System().GetCpuCoreNum() num := service.MyService.System().GetCpuCoreNum()
data := make(map[string]interface{}) data := make(map[string]interface{})
data["percent"] = cpu data["percent"] = cpu
data["num"] = num data["num"] = num
return ctx.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
@@ -269,9 +267,9 @@ func GetSystemCupInfo(ctx echo.Context) error {
// @Security ApiKeyAuth // @Security ApiKeyAuth
// @Success 200 {string} string "ok" // @Success 200 {string} string "ok"
// @Router /sys/mem [get] // @Router /sys/mem [get]
func GetSystemMemInfo(ctx echo.Context) error { func GetSystemMemInfo(c *gin.Context) {
mem := service.MyService.System().GetMemInfo() mem := service.MyService.System().GetMemInfo()
return ctx.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
@@ -281,9 +279,9 @@ func GetSystemMemInfo(ctx echo.Context) error {
// @Security ApiKeyAuth // @Security ApiKeyAuth
// @Success 200 {string} string "ok" // @Success 200 {string} string "ok"
// @Router /sys/disk [get] // @Router /sys/disk [get]
func GetSystemDiskInfo(ctx echo.Context) error { func GetSystemDiskInfo(c *gin.Context) {
disk := service.MyService.System().GetDiskInfo() disk := service.MyService.System().GetDiskInfo()
return ctx.JSON(http.StatusOK, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: disk}) c.JSON(http.StatusOK, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: disk})
} }
// @Summary get Net info // @Summary get Net info
@@ -293,7 +291,7 @@ func GetSystemDiskInfo(ctx echo.Context) error {
// @Security ApiKeyAuth // @Security ApiKeyAuth
// @Success 200 {string} string "ok" // @Success 200 {string} string "ok"
// @Router /sys/net [get] // @Router /sys/net [get]
func GetSystemNetInfo(ctx echo.Context) error { func GetSystemNetInfo(c *gin.Context) {
netList := service.MyService.System().GetNetInfo() netList := service.MyService.System().GetNetInfo()
newNet := []model.IOCountersStat{} newNet := []model.IOCountersStat{}
for _, n := range netList { for _, n := range netList {
@@ -308,36 +306,35 @@ func GetSystemNetInfo(ctx echo.Context) error {
} }
} }
return ctx.JSON(http.StatusOK, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: newNet}) c.JSON(http.StatusOK, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: newNet})
} }
func GetSystemProxy(ctx echo.Context) error { func GetSystemProxy(c *gin.Context) {
url := ctx.QueryParam("url") url := c.Query("url")
resp, err := http2.Get(url, 30*time.Second) resp, err := http2.Get(url, 30*time.Second)
if err != nil { if err != nil {
return ctx.JSON(http.StatusInternalServerError, model.Result{Success: common_err.SERVICE_ERROR, Message: err.Error()}) return
} }
defer resp.Body.Close() defer resp.Body.Close()
for k, v := range ctx.Request().Header { for k, v := range c.Request.Header {
ctx.Request().Header.Add(k, v[0]) c.Header(k, v[0])
} }
rda, _ := ioutil.ReadAll(resp.Body) rda, _ := ioutil.ReadAll(resp.Body)
// json.NewEncoder(c.Writer).Encode(json.RawMessage(string(rda))) // json.NewEncoder(c.Writer).Encode(json.RawMessage(string(rda)))
// 响应状态码 // 响应状态码
ctx.Response().Writer.WriteHeader(resp.StatusCode) c.Writer.WriteHeader(resp.StatusCode)
// 复制转发的响应Body到响应Body // 复制转发的响应Body到响应Body
io.Copy(ctx.Response().Writer, ioutil.NopCloser(bytes.NewBuffer(rda))) io.Copy(c.Writer, ioutil.NopCloser(bytes.NewBuffer(rda)))
return nil
} }
func PutSystemState(ctx echo.Context) error { func PutSystemState(c *gin.Context) {
state := ctx.Param("state") state := c.Param("state")
if strings.ToLower(state) == "off" { if strings.ToLower(state) == "off" {
service.MyService.System().SystemShutdown() service.MyService.System().SystemShutdown()
} else if strings.ToLower(state) == "restart" { } else if strings.ToLower(state) == "restart" {
service.MyService.System().SystemReboot() service.MyService.System().SystemReboot()
} }
return ctx.JSON(http.StatusOK, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: "The operation will be completed shortly."}) c.JSON(http.StatusOK, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: "The operation will be completed shortly."})
} }
// @Summary 获取一个可用端口 // @Summary 获取一个可用端口
@@ -348,8 +345,8 @@ func PutSystemState(ctx echo.Context) error {
// @Security ApiKeyAuth // @Security ApiKeyAuth
// @Success 200 {string} string "ok" // @Success 200 {string} string "ok"
// @Router /app/getport [get] // @Router /app/getport [get]
func GetPort(ctx echo.Context) error { func GetPort(c *gin.Context) {
t := utils.DefaultQuery(ctx, "type", "tcp") t := c.DefaultQuery("type", "tcp")
var p int var p int
ok := true ok := true
for ok { for ok {
@@ -357,7 +354,7 @@ func GetPort(ctx echo.Context) error {
ok = !port.IsPortAvailable(p, t) ok = !port.IsPortAvailable(p, t)
} }
// @tiger 这里最好封装成 {'port': ...} 的形式,来体现出参的上下文 // @tiger 这里最好封装成 {'port': ...} 的形式,来体现出参的上下文
return ctx.JSON(common_err.SUCCESS, &model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: p}) c.JSON(common_err.SUCCESS, &model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: p})
} }
// @Summary 检查端口是否可用 // @Summary 检查端口是否可用
@@ -369,17 +366,8 @@ func GetPort(ctx echo.Context) error {
// @Security ApiKeyAuth // @Security ApiKeyAuth
// @Success 200 {string} string "ok" // @Success 200 {string} string "ok"
// @Router /app/check/{port} [get] // @Router /app/check/{port} [get]
func PortCheck(ctx echo.Context) error { func PortCheck(c *gin.Context) {
p, _ := strconv.Atoi(ctx.Param("port")) p, _ := strconv.Atoi(c.Param("port"))
t := utils.DefaultQuery(ctx, "type", "tcp") t := c.DefaultQuery("type", "tcp")
return ctx.JSON(common_err.SUCCESS, &model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: port.IsPortAvailable(p, t)}) c.JSON(common_err.SUCCESS, &model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: port.IsPortAvailable(p, t)})
}
func GetSystemEntry(ctx echo.Context) error {
entry := service.MyService.System().GetSystemEntry()
str := json.RawMessage(entry)
if !gjson.ValidBytes(str) {
return ctx.JSON(http.StatusInternalServerError, model.Result{Success: common_err.SERVICE_ERROR, Message: entry, Data: json.RawMessage("[]")})
}
return ctx.JSON(http.StatusOK, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: str})
} }

View File

@@ -1,313 +0,0 @@
package v1
import (
"fmt"
"io/ioutil"
"math/rand"
"net"
"net/http"
"strings"
"time"
"github.com/IceWhaleTech/CasaOS-Common/utils/logger"
"github.com/IceWhaleTech/CasaOS/common"
"github.com/IceWhaleTech/CasaOS/pkg/utils/httper"
"github.com/labstack/echo/v4"
"github.com/tidwall/gjson"
"go.uber.org/zap"
)
func ZerotierProxy(ctx echo.Context) error {
// Read the port number from the file
w := ctx.Response().Writer
r := ctx.Request()
port, err := ioutil.ReadFile("/var/lib/zerotier-one/zerotier-one.port")
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
}
// Get the request path and remove "/zt"
path := strings.TrimPrefix(r.URL.Path, "/v1/zt")
fmt.Println(path)
// Build the target URL
targetURL := fmt.Sprintf("http://localhost:%s%s", strings.TrimSpace(string(port)), path)
// Create a new request
req, err := http.NewRequest(r.Method, targetURL, r.Body)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
}
// Add the X-ZT1-AUTH header
authToken, err := ioutil.ReadFile("/var/lib/zerotier-one/authtoken.secret")
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
}
req.Header.Set("X-ZT1-AUTH", strings.TrimSpace(string(authToken)))
copyHeaders(req.Header, r.Header)
client := http.Client{}
resp, err := client.Do(req)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
}
defer resp.Body.Close()
copyHeaders(w.Header(), resp.Header)
respBody, err := ioutil.ReadAll(resp.Body)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
}
// Return the response to the client
w.WriteHeader(resp.StatusCode)
w.Write(respBody)
// TODO
return nil
}
func copyHeaders(destination, source http.Header) {
for key, values := range source {
for _, value := range values {
destination.Add(key, value)
}
}
}
func CheckNetwork() {
logger.Info("start check network")
respBody, err := httper.ZTGet("/controller/network")
if err != nil {
logger.Error("get network error", zap.Error(err))
return
}
networkId := ""
address := ""
networkNames := gjson.ParseBytes(respBody).Array()
routers := ""
for _, v := range networkNames {
res, err := httper.ZTGet("/controller/network/" + v.Str)
if err != nil {
logger.Error("get network error", zap.Error(err))
return
}
name := gjson.GetBytes(res, "name").Str
if name == common.RANW_NAME {
networkId = gjson.GetBytes(res, "id").Str
routers = gjson.GetBytes(res, "routes.0.target").Str
break
}
}
ip, s, e, c := getZTIP(routers)
logger.Info("ip", zap.Any("ip", ip))
if len(networkId) == 0 {
if len(address) == 0 {
address = GetAddress()
}
networkId = CreateNet(address, s, e, c)
}
res, err := httper.ZTGet("/network")
if err != nil {
logger.Error("get network error", zap.Error(err))
return
}
joined := false
networks := gjson.GetBytes(res, "#.id").Array()
for _, v := range networks {
if v.Str == networkId {
joined = true
break
}
}
logger.Info("joined", zap.Any("joined", joined))
if !joined {
JoinAndUpdateNet(address, networkId, ip)
}
}
func GetAddress() string {
nodeRes, err := httper.ZTGet("/status")
if err != nil {
logger.Error("get status error", zap.Error(err))
return ""
}
return gjson.GetBytes(nodeRes, "address").String()
}
func JoinAndUpdateNet(address, networkId, ip string) {
logger.Info("start join network", zap.Any("ip", ip))
_, err := httper.ZTPost("/network/"+networkId, "")
if err != nil {
logger.Error(" get network error", zap.Error(err))
return
}
if len(address) == 0 {
address = GetAddress()
}
b := `{
"authorized": true,
"activeBridge": true,
"ipAssignments": [
"` + ip + `"
]
}`
_, err = httper.ZTPost("/controller/network/"+networkId+"/member/"+address, b)
if err != nil {
logger.Error("join network error", zap.Error(err))
return
}
}
func CreateNet(address, s, e, c string) string {
body := `{
"name": "` + common.RANW_NAME + `",
"private": false,
"v4AssignMode": {
"zt": true
},
"ipAssignmentPools": [
{
"ipRangeStart": "` + s + `",
"ipRangeEnd": "` + e + `"
}
],
"routes": [
{
"target": "` + c + `"
}
],
"rules": [
{
"etherType": 2048,
"not": true,
"or": false,
"type": "MATCH_ETHERTYPE"
},
{
"etherType": 2054,
"not": true,
"or": false,
"type": "MATCH_ETHERTYPE"
},
{
"etherType": 34525,
"not": true,
"or": false,
"type": "MATCH_ETHERTYPE"
},
{
"type": "ACTION_DROP"
},
{
"type": "ACTION_ACCEPT"
}
],
"v6AssignMode": {
"rfc4193": true
}
}`
createRes, err := httper.ZTPost("/controller/network/"+address+"______", body)
if err != nil {
logger.Error("post network error", zap.Error(err))
return ""
}
return gjson.GetBytes(createRes, "id").Str
}
func GetZTIPs() []gjson.Result {
res, err := httper.ZTGet("/network")
if err != nil {
logger.Error("get network error", zap.Error(err))
return []gjson.Result{}
}
a := gjson.GetBytes(res, "#.routes.0.target")
return a.Array()
}
func getZTIP(routes string) (ip, start, end, cidr string) {
excluded := GetZTIPs()
cidrs := []string{
"10.147.11.0/24",
"10.147.12.0/24",
"10.147.13.0/24",
"10.147.14.0/24",
"10.147.15.0/24",
"10.147.16.0/24",
"10.147.17.0/24",
"10.147.18.0/24",
"10.147.19.0/24",
"10.147.20.0/24",
"10.240.0.0/16",
"10.241.0.0/16",
"10.242.0.0/16",
"10.243.0.0/16",
"10.244.0.0/16",
"10.245.0.0/16",
"10.246.0.0/16",
"10.247.0.0/16",
"10.248.0.0/16",
"10.249.0.0/16",
"172.21.0.0/16",
"172.22.0.0/16",
"172.23.0.0/16",
"172.24.0.0/16",
"172.25.0.0/16",
"172.26.0.0/16",
"172.27.0.0/16",
"172.28.0.0/16",
"172.29.0.0/16",
"172.30.0.0/16",
}
filteredCidrs := make([]string, 0)
if len(routes) > 0 {
filteredCidrs = append(filteredCidrs, routes)
} else {
for _, cidr := range cidrs {
isExcluded := false
for _, excludedIP := range excluded {
if cidr == excludedIP.Str {
isExcluded = true
break
}
}
if !isExcluded {
filteredCidrs = append(filteredCidrs, cidr)
}
}
}
rnd := rand.New(rand.NewSource(time.Now().UnixNano()))
ip = ""
if len(filteredCidrs) > 0 {
randomIndex := rnd.Intn(len(filteredCidrs))
selectedCIDR := filteredCidrs[randomIndex]
_, ipNet, err := net.ParseCIDR(selectedCIDR)
if err != nil {
logger.Error("ParseCIDR error", zap.Error(err))
return
}
cidr = selectedCIDR
startIP := ipNet.IP
endIP := make(net.IP, len(startIP))
copy(endIP, startIP)
for i := range startIP {
endIP[i] |= ^ipNet.Mask[i]
}
startIP[3] = 1
start = startIP.String()
endIP[3] = 254
end = endIP.String()
ipt := ipNet
ipt.IP[3] = 1
ip = ipt.IP.String()
return
} else {
logger.Error("No available CIDR found")
}
return
}

View File

@@ -30,6 +30,7 @@ var (
V2APIPath string V2APIPath string
V2DocPath string V2DocPath string
V3FilePath string V3FilePath string
V4DirPath string
) )
func init() { func init() {
@@ -48,6 +49,7 @@ func init() {
V2APIPath = strings.TrimRight(u.Path, "/") V2APIPath = strings.TrimRight(u.Path, "/")
V2DocPath = "/doc" + V2APIPath V2DocPath = "/doc" + V2APIPath
V3FilePath = "/v3/file" V3FilePath = "/v3/file"
V4DirPath = "/v4/dir"
} }
func InitV2Router() http.Handler { func InitV2Router() http.Handler {
@@ -74,6 +76,10 @@ func InitV2Router() http.Handler {
// return true // return true
}, },
ParseTokenFunc: func(token string, c echo.Context) (interface{}, error) { ParseTokenFunc: func(token string, c echo.Context) (interface{}, error) {
// claims, code := jwt.Validate(token) // TODO - needs JWT validation
// if code != common_err.SUCCESS {
// return nil, echo.ErrUnauthorized
// }
valid, claims, err := jwt.Validate(token, func() (*ecdsa.PublicKey, error) { return external.GetPublicKey(config.CommonInfo.RuntimePath) }) valid, claims, err := jwt.Validate(token, func() (*ecdsa.PublicKey, error) { return external.GetPublicKey(config.CommonInfo.RuntimePath) })
if err != nil || !valid { if err != nil || !valid {
return nil, echo.ErrUnauthorized return nil, echo.ErrUnauthorized
@@ -83,11 +89,11 @@ func InitV2Router() http.Handler {
return claims, nil return claims, nil
}, },
TokenLookupFuncs: []echo_middleware.ValuesExtractor{ TokenLookupFuncs: []echo_middleware.ValuesExtractor{
func(ctx echo.Context) ([]string, error) { func(c echo.Context) ([]string, error) {
if len(ctx.Request().Header.Get(echo.HeaderAuthorization)) > 0 { if len(c.Request().Header.Get(echo.HeaderAuthorization)) > 0 {
return []string{ctx.Request().Header.Get(echo.HeaderAuthorization)}, nil return []string{c.Request().Header.Get(echo.HeaderAuthorization)}, nil
} }
return []string{ctx.QueryParam("token")}, nil return []string{c.QueryParam("token")}, nil
}, },
}, },
})) }))
@@ -115,12 +121,6 @@ func InitV2Router() http.Handler {
// }) // })
e.Use(middleware.OapiRequestValidatorWithOptions(_swagger, &middleware.Options{ e.Use(middleware.OapiRequestValidatorWithOptions(_swagger, &middleware.Options{
Skipper: func(c echo.Context) bool {
// jump validate when upload file
// because file upload can't pass validate
// issue: https://github.com/deepmap/oapi-codegen/issues/514
return strings.Contains(c.Request().Header[echo.HeaderContentType][0], "multipart/form-data")
},
Options: openapi3filter.Options{AuthenticationFunc: openapi3filter.NoopAuthenticationFunc}, Options: openapi3filter.Options{AuthenticationFunc: openapi3filter.NoopAuthenticationFunc},
})) }))
@@ -148,46 +148,16 @@ func InitV2DocRouter(docHTML string, docYAML string) http.Handler {
func InitFile() http.Handler { func InitFile() http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
token := r.URL.Query().Get("token")
if len(token) == 0 {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusUnauthorized)
w.Write([]byte(`{"message": "token not found"}`))
return
}
valid, _, errs := jwt.Validate(token, func() (*ecdsa.PublicKey, error) { return external.GetPublicKey(config.CommonInfo.RuntimePath) })
if errs != nil || !valid {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusUnauthorized)
w.Write([]byte(`{"message": "validation failure"}`))
return
}
filePath := r.URL.Query().Get("path") filePath := r.URL.Query().Get("path")
fileName := path.Base(filePath) fileName := path.Base(filePath)
w.Header().Add("Content-Disposition", "attachment; filename*=utf-8''"+url.PathEscape(fileName)) w.Header().Add("Content-Disposition", "attachment; filename*=utf-8''"+url.PathEscape(fileName))
http.ServeFile(w, r, filePath) http.ServeFile(w, r, filePath)
// http.ServeFile(w, r, filePath) //http.ServeFile(w, r, filePath)
}) })
} }
func InitDir() http.Handler { func InitDir() http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
token := r.URL.Query().Get("token")
if len(token) == 0 {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusUnauthorized)
w.Write([]byte(`{"message": "token not found"}`))
return
}
valid, _, errs := jwt.Validate(token, func() (*ecdsa.PublicKey, error) { return external.GetPublicKey(config.CommonInfo.RuntimePath) })
if errs != nil || !valid {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusUnauthorized)
w.Write([]byte(`{"message": "validation failure"}`))
return
}
t := r.URL.Query().Get("format") t := r.URL.Query().Get("format")
files := r.URL.Query().Get("files") files := r.URL.Query().Get("files")
@@ -201,7 +171,7 @@ func InitDir() http.Handler {
list := strings.Split(files, ",") list := strings.Split(files, ",")
for _, v := range list { for _, v := range list {
if !file.Exists(v) { if !file.Exists(v) {
// return ctx.JSON(common_err.SERVICE_ERROR, model.Result{ // c.JSON(common_err.SERVICE_ERROR, model.Result{
// Success: common_err.FILE_DOES_NOT_EXIST, // Success: common_err.FILE_DOES_NOT_EXIST,
// Message: common_err.GetMsg(common_err.FILE_DOES_NOT_EXIST), // Message: common_err.GetMsg(common_err.FILE_DOES_NOT_EXIST),
// }) // })
@@ -237,7 +207,7 @@ func InitDir() http.Handler {
err = ar.Create(w) err = ar.Create(w)
if err != nil { if err != nil {
// return ctx.JSON(common_err.SERVICE_ERROR, model.Result{ // c.JSON(common_err.SERVICE_ERROR, model.Result{
// Success: common_err.SERVICE_ERROR, // Success: common_err.SERVICE_ERROR,
// Message: common_err.GetMsg(common_err.SERVICE_ERROR), // Message: common_err.GetMsg(common_err.SERVICE_ERROR),
// Data: err.Error(), // Data: err.Error(),

View File

@@ -2,9 +2,7 @@ package v2
import ( import (
"net/http" "net/http"
"strconv"
"github.com/IceWhaleTech/CasaOS/codegen"
"github.com/labstack/echo/v4" "github.com/labstack/echo/v4"
) )
@@ -17,70 +15,3 @@ func (s *CasaOS) GetFileTest(ctx echo.Context) error {
return ctx.String(200, "pong") return ctx.String(200, "pong")
} }
func (c *CasaOS) CheckUploadChunk(ctx echo.Context, params codegen.CheckUploadChunkParams) error {
identifier := ctx.QueryParam("identifier")
chunkNumber, err := strconv.ParseInt(ctx.QueryParam("chunkNumber"), 10, 64)
if err != nil {
return ctx.NoContent(http.StatusBadRequest)
}
err = c.fileUploadService.TestChunk(ctx, identifier, chunkNumber)
if err != nil {
return ctx.NoContent(http.StatusNoContent)
}
return ctx.NoContent(http.StatusOK)
}
func (c *CasaOS) PostUploadFile(ctx echo.Context) error {
path := ctx.FormValue("path")
// handle the request
chunkNumber, err := strconv.ParseInt(ctx.FormValue("chunkNumber"), 10, 64)
if err != nil {
return ctx.JSON(http.StatusBadRequest, err)
}
chunkSize, err := strconv.ParseInt(ctx.FormValue("chunkSize"), 10, 64)
if err != nil {
return ctx.JSON(http.StatusBadRequest, err)
}
currentChunkSize, err := strconv.ParseInt(ctx.FormValue("currentChunkSize"), 10, 64)
if err != nil {
return ctx.JSON(http.StatusBadRequest, err)
}
totalChunks, err := strconv.ParseInt(ctx.FormValue("totalChunks"), 10, 64)
if err != nil {
return ctx.JSON(http.StatusBadRequest, err)
}
totalSize, err := strconv.ParseInt(ctx.FormValue("totalSize"), 10, 64)
if err != nil {
return ctx.JSON(http.StatusBadRequest, err)
}
identifier := ctx.FormValue("identifier")
fileName := ctx.FormValue("filename")
relativePath := ctx.FormValue("relativePath")
bin, err := ctx.FormFile("file")
if err != nil {
return ctx.JSON(http.StatusBadRequest, err)
}
err = c.fileUploadService.UploadFile(
ctx,
path,
chunkNumber,
chunkSize,
currentChunkSize,
totalChunks,
totalSize,
identifier,
relativePath,
fileName,
bin,
)
if err != nil {
return ctx.JSON(http.StatusInternalServerError, err)
}
return ctx.NoContent(http.StatusOK)
}

View File

@@ -2,15 +2,10 @@ package v2
import ( import (
"github.com/IceWhaleTech/CasaOS/codegen" "github.com/IceWhaleTech/CasaOS/codegen"
"github.com/IceWhaleTech/CasaOS/service"
) )
type CasaOS struct { type CasaOS struct{}
fileUploadService *service.FileUploadService
}
func NewCasaOS() codegen.ServerInterface { func NewCasaOS() codegen.ServerInterface {
return &CasaOS{ return &CasaOS{}
fileUploadService: service.NewFileUploadService(),
}
} }

View File

@@ -1,47 +0,0 @@
package v2
import (
"fmt"
"net/http"
"github.com/IceWhaleTech/CasaOS-Common/utils"
"github.com/IceWhaleTech/CasaOS/codegen"
"github.com/IceWhaleTech/CasaOS/common"
"github.com/IceWhaleTech/CasaOS/pkg/utils/httper"
"github.com/labstack/echo/v4"
"github.com/tidwall/gjson"
)
func (s *CasaOS) SetZerotierNetworkStatus(ctx echo.Context, networkId string) error {
return ctx.JSON(http.StatusOK, nil)
}
func (s *CasaOS) GetZerotierInfo(ctx echo.Context) error {
info := codegen.GetZTInfoOK{}
respBody, err := httper.ZTGet("/controller/network")
if err != nil {
return ctx.JSON(http.StatusInternalServerError, codegen.BaseResponse{Message: utils.Ptr(err.Error())})
}
networkNames := gjson.ParseBytes(respBody).Array()
for _, v := range networkNames {
res, err := httper.ZTGet("/controller/network/" + v.Str)
if err != nil {
fmt.Println(err)
return ctx.JSON(http.StatusInternalServerError, codegen.BaseResponse{Message: utils.Ptr(err.Error())})
}
name := gjson.GetBytes(res, "name").Str
if name == common.RANW_NAME {
via := gjson.GetBytes(res, "routes.0.via").Str
info.Id = utils.Ptr(gjson.GetBytes(res, "id").Str)
info.Name = &name
if len(via) == 0 {
info.Status = utils.Ptr("online")
} else {
info.Status = utils.Ptr("offline")
}
break
}
}
return ctx.JSON(http.StatusOK, info)
}

View File

@@ -39,25 +39,20 @@ func (s *connectionsStruct) GetConnectionByHost(host string) (connections []mode
s.db.Select("username,host,status,id").Where("host = ?", host).Find(&connections) s.db.Select("username,host,status,id").Where("host = ?", host).Find(&connections)
return return
} }
func (s *connectionsStruct) GetConnectionByID(id string) (connections model2.ConnectionsDBModel) { func (s *connectionsStruct) GetConnectionByID(id string) (connections model2.ConnectionsDBModel) {
s.db.Select("username,password,host,status,id,directories,mount_point,port").Where("id = ?", id).First(&connections) s.db.Select("username,password,host,status,id,directories,mount_point,port").Where("id = ?", id).First(&connections)
return return
} }
func (s *connectionsStruct) GetConnectionsList() (connections []model2.ConnectionsDBModel) { func (s *connectionsStruct) GetConnectionsList() (connections []model2.ConnectionsDBModel) {
s.db.Select("username,host,port,status,id,mount_point").Find(&connections) s.db.Select("username,host,port,status,id,mount_point").Find(&connections)
return return
} }
func (s *connectionsStruct) CreateConnection(connection *model2.ConnectionsDBModel) { func (s *connectionsStruct) CreateConnection(connection *model2.ConnectionsDBModel) {
s.db.Create(connection) s.db.Create(connection)
} }
func (s *connectionsStruct) UpdateConnection(connection *model2.ConnectionsDBModel) { func (s *connectionsStruct) UpdateConnection(connection *model2.ConnectionsDBModel) {
s.db.Save(connection) s.db.Save(connection)
} }
func (s *connectionsStruct) DeleteConnection(id string) { func (s *connectionsStruct) DeleteConnection(id string) {
s.db.Where("id= ?", id).Delete(&model.ConnectionsDBModel{}) s.db.Where("id= ?", id).Delete(&model.ConnectionsDBModel{})
} }
@@ -71,10 +66,9 @@ func (s *connectionsStruct) MountSmaba(username, host, directory, port, mountPoi
fmt.Sprintf("username=%s,password=%s", username, password), fmt.Sprintf("username=%s,password=%s", username, password),
) )
return err return err
// str := command2.ExecResultStr("source " + config.AppInfo.ShellPath + "/helper.sh ;MountCIFS " + username + " " + host + " " + directory + " " + port + " " + mountPoint + " " + password) //str := command2.ExecResultStr("source " + config.AppInfo.ShellPath + "/helper.sh ;MountCIFS " + username + " " + host + " " + directory + " " + port + " " + mountPoint + " " + password)
// return str //return str
} }
func (s *connectionsStruct) UnmountSmaba(mountPoint string) error { func (s *connectionsStruct) UnmountSmaba(mountPoint string) error {
return mount.Unmount(mountPoint) return mount.Unmount(mountPoint)
} }

View File

@@ -102,20 +102,16 @@ func FileOperate(k string) {
os.RemoveAll(temp.To + "/" + lastPath) os.RemoveAll(temp.To + "/" + lastPath)
} }
} }
err := file.CopyDir(v.From, temp.To, temp.Style) err := os.Rename(v.From, temp.To+"/"+lastPath)
if err == nil { if err != nil {
err = os.RemoveAll(v.From) logger.Error("file move error", zap.Any("err", err))
err = file.MoveFile(v.From, temp.To+"/"+lastPath)
if err != nil { if err != nil {
logger.Error("file move error", zap.Any("err", err)) logger.Error("MoveFile error", zap.Any("err", err))
err = file.MoveFile(v.From, temp.To+"/"+lastPath) continue
if err != nil {
logger.Error("MoveFile error", zap.Any("err", err))
continue
}
} }
}
}
} else if temp.Type == "copy" { } else if temp.Type == "copy" {
err := file.CopyDir(v.From, temp.To, temp.Style) err := file.CopyDir(v.From, temp.To, temp.Style)
if err != nil { if err != nil {

View File

@@ -1,167 +0,0 @@
package service
import (
"fmt"
"io"
"mime/multipart"
"os"
"path/filepath"
"sync"
"github.com/IceWhaleTech/CasaOS-Common/utils/logger"
"github.com/labstack/echo/v4"
"go.uber.org/zap"
)
type FileInfo struct {
init bool
uploaded []bool
uploadedChunkNum int64
}
type FileUploadService struct {
uploadStatus sync.Map
lock sync.RWMutex
}
func NewFileUploadService() *FileUploadService {
return &FileUploadService{
uploadStatus: sync.Map{},
lock: sync.RWMutex{},
}
}
func (s *FileUploadService) TestChunk(
c echo.Context,
identifier string,
chunkNumber int64,
) error {
fileInfoTemp, ok := s.uploadStatus.Load(identifier)
if !ok {
return fmt.Errorf("file not found")
}
fileInfo := fileInfoTemp.(*FileInfo)
if !fileInfo.init {
return fmt.Errorf("file not init")
}
// return StatusNoContent instead of 404
// the is require by frontend
if !fileInfo.uploaded[chunkNumber-1] {
return fmt.Errorf("file not found")
}
return nil
}
func (s *FileUploadService) UploadFile(
c echo.Context,
path string,
chunkNumber int64,
chunkSize int64,
currentChunkSize int64,
totalChunks int64,
totalSize int64,
identifier string,
relativePath string,
fileName string,
bin *multipart.FileHeader,
) error {
s.lock.Lock()
fileInfoTemp, ok := s.uploadStatus.Load(identifier)
var fileInfo *FileInfo
if relativePath != fileName {
// uploaded file is folder
folderPath := filepath.Dir(path + "/" + relativePath)
if _, err := os.Stat(folderPath); os.IsNotExist(err) {
err := os.MkdirAll(folderPath, os.ModePerm)
if err != nil {
s.lock.Unlock()
return err
}
}
}
file, err := os.OpenFile(path+"/"+relativePath+".tmp", os.O_WRONLY|os.O_CREATE, 0644)
if err != nil {
s.lock.Unlock()
return err
}
if !ok {
if err != nil {
s.lock.Unlock()
return err
}
// pre allocate file size
fmt.Println("truncate", totalSize)
if err != nil {
s.lock.Unlock()
return err
}
// file info init
fileInfo = &FileInfo{
init: true,
uploaded: make([]bool, totalChunks),
uploadedChunkNum: 0,
}
s.uploadStatus.Store(identifier, fileInfo)
} else {
fileInfo = fileInfoTemp.(*FileInfo)
}
s.lock.Unlock()
_, err = file.Seek((chunkNumber-1)*chunkSize, io.SeekStart)
if err != nil {
return err
}
src, err := bin.Open()
if err != nil {
return err
}
defer src.Close()
_, err = io.Copy(file, src)
if err != nil {
fmt.Println(err)
return err
}
s.lock.Lock()
// handle file after write a chunk
// handle single chunk upload twice
if !fileInfo.uploaded[chunkNumber-1] {
fileInfo.uploadedChunkNum++
fileInfo.uploaded[chunkNumber-1] = true
}
// handle file after write all chunk
if fileInfo.uploadedChunkNum == totalChunks {
err := file.Close()
if err != nil {
s.lock.Unlock()
logger.Error("close file error: ", zap.Error(err))
}
err = os.Rename(path+"/"+relativePath+".tmp", path+"/"+relativePath)
if err != nil {
s.lock.Unlock()
logger.Error("rename file error: ", zap.Error(err))
}
// remove upload status info after upload complete
s.uploadStatus.Delete(identifier)
}
s.lock.Unlock()
return nil
}

View File

@@ -14,8 +14,8 @@ import (
"path/filepath" "path/filepath"
"strings" "strings"
"github.com/IceWhaleTech/CasaOS-Common/utils/command"
"github.com/IceWhaleTech/CasaOS/pkg/config" "github.com/IceWhaleTech/CasaOS/pkg/config"
command2 "github.com/IceWhaleTech/CasaOS/pkg/utils/command"
"github.com/IceWhaleTech/CasaOS/pkg/utils/file" "github.com/IceWhaleTech/CasaOS/pkg/utils/file"
"github.com/IceWhaleTech/CasaOS/service/model" "github.com/IceWhaleTech/CasaOS/service/model"
model2 "github.com/IceWhaleTech/CasaOS/service/model" model2 "github.com/IceWhaleTech/CasaOS/service/model"
@@ -47,23 +47,19 @@ func (s *sharesStruct) GetSharesByName(name string) (shares []model2.SharesDBMod
return return
} }
func (s *sharesStruct) GetSharesByPath(path string) (shares []model2.SharesDBModel) { func (s *sharesStruct) GetSharesByPath(path string) (shares []model2.SharesDBModel) {
s.db.Select("anonymous,path,id").Where("path = ?", path).Find(&shares) s.db.Select("anonymous,path,id").Where("path = ?", path).Find(&shares)
return return
} }
func (s *sharesStruct) GetSharesList() (shares []model2.SharesDBModel) { func (s *sharesStruct) GetSharesList() (shares []model2.SharesDBModel) {
s.db.Select("anonymous,path,id").Find(&shares) s.db.Select("anonymous,path,id").Find(&shares)
return return
} }
func (s *sharesStruct) CreateShare(share model2.SharesDBModel) { func (s *sharesStruct) CreateShare(share model2.SharesDBModel) {
s.db.Create(&share) s.db.Create(&share)
s.InitSambaConfig() s.InitSambaConfig()
s.UpdateConfigFile() s.UpdateConfigFile()
} }
func (s *sharesStruct) DeleteShare(id string) { func (s *sharesStruct) DeleteShare(id string) {
s.db.Where("id= ?", id).Delete(&model.SharesDBModel{}) s.db.Where("id= ?", id).Delete(&model.SharesDBModel{})
s.UpdateConfigFile() s.UpdateConfigFile()
@@ -72,8 +68,8 @@ func (s *sharesStruct) DeleteShare(id string) {
func (s *sharesStruct) UpdateConfigFile() { func (s *sharesStruct) UpdateConfigFile() {
shares := []model2.SharesDBModel{} shares := []model2.SharesDBModel{}
s.db.Select("anonymous,path").Find(&shares) s.db.Select("anonymous,path").Find(&shares)
// generated config file //generated config file
configStr := "" var configStr = ""
for _, share := range shares { for _, share := range shares {
dirName := filepath.Base(share.Path) dirName := filepath.Base(share.Path)
configStr += ` configStr += `
@@ -90,12 +86,12 @@ force user = root
` `
} }
// write config file //write config file
file.WriteToPath([]byte(configStr), "/etc/samba", "smb.casa.conf") file.WriteToPath([]byte(configStr), "/etc/samba", "smb.casa.conf")
// restart samba //restart samba
command.OnlyExec("source " + config.AppInfo.ShellPath + "/helper.sh ;RestartSMBD") command2.ExecResultStrArray("source " + config.AppInfo.ShellPath + "/helper.sh ;RestartSMBD")
}
}
func (s *sharesStruct) InitSambaConfig() { func (s *sharesStruct) InitSambaConfig() {
if file.Exists("/etc/samba/smb.conf") { if file.Exists("/etc/samba/smb.conf") {
str := file.ReadLine(1, "/etc/samba/smb.conf") str := file.ReadLine(1, "/etc/samba/smb.conf")
@@ -103,7 +99,7 @@ func (s *sharesStruct) InitSambaConfig() {
return return
} }
file.MoveFile("/etc/samba/smb.conf", "/etc/samba/smb.conf.bak") file.MoveFile("/etc/samba/smb.conf", "/etc/samba/smb.conf.bak")
smbConf := "" var smbConf = ""
smbConf += `# Copyright (c) 2021-2022 CasaOS Inc. All rights reserved. smbConf += `# Copyright (c) 2021-2022 CasaOS Inc. All rights reserved.
# #
# #
@@ -154,6 +150,7 @@ func (s *sharesStruct) InitSambaConfig() {
include=/etc/samba/smb.casa.conf` include=/etc/samba/smb.casa.conf`
file.WriteToPath([]byte(smbConf), "/etc/samba", "smb.conf") file.WriteToPath([]byte(smbConf), "/etc/samba", "smb.conf")
} }
} }
func NewSharesService(db *gorm.DB) SharesService { func NewSharesService(db *gorm.DB) SharesService {

View File

@@ -1,30 +1,24 @@
package service package service
import ( import (
"encoding/json"
"errors" "errors"
"fmt" "fmt"
"io" "io/ioutil"
net2 "net" net2 "net"
"os" "os"
"os/exec"
"path/filepath" "path/filepath"
"runtime" "runtime"
"strconv" "strconv"
"strings" "strings"
"time" "time"
"github.com/IceWhaleTech/CasaOS-Common/utils/command"
exec2 "github.com/IceWhaleTech/CasaOS-Common/utils/exec"
"github.com/IceWhaleTech/CasaOS-Common/utils/file" "github.com/IceWhaleTech/CasaOS-Common/utils/file"
"github.com/IceWhaleTech/CasaOS-Common/utils/logger" "github.com/IceWhaleTech/CasaOS-Common/utils/logger"
"github.com/IceWhaleTech/CasaOS/common"
"github.com/IceWhaleTech/CasaOS/model" "github.com/IceWhaleTech/CasaOS/model"
"github.com/IceWhaleTech/CasaOS/pkg/config" "github.com/IceWhaleTech/CasaOS/pkg/config"
command2 "github.com/IceWhaleTech/CasaOS/pkg/utils/command"
"github.com/IceWhaleTech/CasaOS/pkg/utils/common_err" "github.com/IceWhaleTech/CasaOS/pkg/utils/common_err"
"github.com/IceWhaleTech/CasaOS/pkg/utils/httper"
"github.com/IceWhaleTech/CasaOS/pkg/utils/ip_helper"
"github.com/tidwall/gjson"
"go.uber.org/zap" "go.uber.org/zap"
"github.com/shirou/gopsutil/v3/cpu" "github.com/shirou/gopsutil/v3/cpu"
@@ -55,7 +49,6 @@ type SystemService interface {
GetDiskInfo() *disk.UsageStat GetDiskInfo() *disk.UsageStat
GetSysInfo() host.InfoStat GetSysInfo() host.InfoStat
GetDeviceTree() string GetDeviceTree() string
GetDeviceInfo() model.DeviceInfo
CreateFile(path string) (int, error) CreateFile(path string) (int, error)
RenameFile(oldF, newF string) (int, error) RenameFile(oldF, newF string) (int, error)
MkdirAll(path string) (int, error) MkdirAll(path string) (int, error)
@@ -64,118 +57,9 @@ type SystemService interface {
GetMacAddress() (string, error) GetMacAddress() (string, error)
SystemReboot() error SystemReboot() error
SystemShutdown() error SystemShutdown() error
GetSystemEntry() string
GenreateSystemEntry()
} }
type systemService struct{} type systemService struct{}
func (c *systemService) GetDeviceInfo() model.DeviceInfo {
m := model.DeviceInfo{}
m.OS_Version = common.VERSION
err, portStr := MyService.Gateway().GetPort()
if err != nil {
m.Port = 80
} else {
port := gjson.Get(portStr, "data")
if len(port.Raw) == 0 {
m.Port = 80
} else {
p, err := strconv.Atoi(port.Raw)
if err != nil {
m.Port = 80
} else {
m.Port = p
}
}
}
allIpv4 := ip_helper.GetDeviceAllIPv4()
ip := []string{}
nets := MyService.System().GetNet(true)
for _, n := range nets {
if v, ok := allIpv4[n]; ok {
{
ip = append(ip, v)
}
}
}
m.LanIpv4 = ip
h, err := host.Info() /* */
if err == nil {
m.DeviceName = h.Hostname
}
mb := model.BaseInfo{}
err = json.Unmarshal(file.ReadFullFile(config.AppInfo.DBPath+"/baseinfo.conf"), &mb)
if err == nil {
m.Hash = mb.Hash
}
osRelease, _ := file.ReadOSRelease()
m.DeviceModel = osRelease["MODEL"]
m.DeviceSN = osRelease["SN"]
res := httper.Get("http://127.0.0.1:"+strconv.Itoa(m.Port)+"/v1/users/status", nil)
init := gjson.Get(res, "data.initialized")
m.Initialized, _ = strconv.ParseBool(init.Raw)
return m
}
func (c *systemService) GenreateSystemEntry() {
modelsPath := "/var/lib/casaos/www/modules"
entryFileName := "entry.json"
entryFilePath := filepath.Join(config.AppInfo.DBPath, "db", entryFileName)
file.IsNotExistCreateFile(entryFilePath)
dir, err := os.ReadDir(modelsPath)
if err != nil {
logger.Error("read dir error", zap.Error(err))
return
}
json := "["
for _, v := range dir {
data, err := os.ReadFile(filepath.Join(modelsPath, v.Name(), entryFileName))
if err != nil {
logger.Error("read entry file error", zap.Error(err))
continue
}
json += string(data) + ","
}
json = strings.TrimRight(json, ",")
json += "]"
err = os.WriteFile(entryFilePath, []byte(json), 0o666)
if err != nil {
logger.Error("write entry file error", zap.Error(err))
return
}
}
func (c *systemService) GetSystemEntry() string {
modelsPath := "/var/lib/casaos/www/modules"
entryFileName := "entry.json"
dir, err := os.ReadDir(modelsPath)
if err != nil {
logger.Error("read dir error", zap.Error(err))
return ""
}
json := "["
for _, v := range dir {
data, err := os.ReadFile(filepath.Join(modelsPath, v.Name(), entryFileName))
if err != nil {
logger.Error("read entry file error", zap.Error(err))
continue
}
json += string(data) + ","
}
json = strings.TrimRight(json, ",")
json += "]"
if err != nil {
logger.Error("write entry file error", zap.Error(err))
return ""
}
return json
}
func (c *systemService) GetMacAddress() (string, error) { func (c *systemService) GetMacAddress() (string, error) {
interfaces, err := net.Interfaces() interfaces, err := net.Interfaces()
if err != nil { if err != nil {
@@ -237,11 +121,7 @@ func (c *systemService) CreateFile(path string) (int, error) {
} }
func (c *systemService) GetDeviceTree() string { func (c *systemService) GetDeviceTree() string {
if output, err := command.OnlyExec("source " + config.AppInfo.ShellPath + "/helper.sh ;GetDeviceTree"); err != nil { return command2.ExecResultStr("source " + config.AppInfo.ShellPath + "/helper.sh ;GetDeviceTree")
return ""
} else {
return output
}
} }
func (c *systemService) GetSysInfo() host.InfoStat { func (c *systemService) GetSysInfo() host.InfoStat {
@@ -261,11 +141,7 @@ func (c *systemService) GetDiskInfo() *disk.UsageStat {
} }
func (c *systemService) GetNetState(name string) string { func (c *systemService) GetNetState(name string) string {
if output, err := command.OnlyExec("source " + config.AppInfo.ShellPath + "/helper.sh ;CatNetCardState " + name); err != nil { return command2.ExecResultStr("source " + config.AppInfo.ShellPath + "/helper.sh ;CatNetCardState " + name)
return ""
} else {
return output
}
} }
func (c *systemService) GetDirPathOne(path string) (m model.Path) { func (c *systemService) GetDirPathOne(path string) (m model.Path) {
@@ -362,12 +238,7 @@ func (c *systemService) GetNet(physics bool) []string {
if physics { if physics {
t = "2" t = "2"
} }
return command2.ExecResultStrArray("source " + config.AppInfo.ShellPath + "/helper.sh ;GetNetCard " + t)
if output, err := command.OnlyExec("source " + config.AppInfo.ShellPath + "/helper.sh ;GetNetCard " + t); err != nil {
return []string{}
} else {
return strings.Split(output, "\n")
}
} }
func (s *systemService) UpdateSystemVersion(version string) { func (s *systemService) UpdateSystemVersion(version string) {
@@ -379,10 +250,10 @@ 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")
if len(config.ServerInfo.UpdateUrl) > 0 { if len(config.ServerInfo.UpdateUrl) > 0 {
go command.OnlyExec("curl -fsSL " + config.ServerInfo.UpdateUrl + " | bash") go command2.OnlyExec("curl -fsSL " + config.ServerInfo.UpdateUrl + " | bash")
} else { } else {
osRelease, _ := file.ReadOSRelease() osRelease, _ := file.ReadOSRelease()
go command.OnlyExec("curl -fsSL https://get.casaos.io/update?t=" + osRelease["MANUFACTURER"] + " | bash") go command2.OnlyExec("curl -fsSL https://get.casaos.io/update?t=" + osRelease["MANUFACTURER"] + " | bash")
} }
// s.log.Error(config.AppInfo.ProjectPath + "/shell/tool.sh -r " + version) // s.log.Error(config.AppInfo.ProjectPath + "/shell/tool.sh -r " + version)
@@ -390,23 +261,15 @@ func (s *systemService) UpdateSystemVersion(version string) {
} }
func (s *systemService) UpdateAssist() { func (s *systemService) UpdateAssist() {
command.ExecResultStrArray("source " + config.AppInfo.ShellPath + "/assist.sh") command2.ExecResultStrArray("source " + config.AppInfo.ShellPath + "/assist.sh")
} }
func (s *systemService) GetTimeZone() string { func (s *systemService) GetTimeZone() string {
if output, err := command.OnlyExec("source " + config.AppInfo.ShellPath + "/helper.sh ;GetTimeZone"); err != nil { return command2.ExecResultStr("source " + config.AppInfo.ShellPath + "/helper.sh ;GetTimeZone")
return ""
} else {
return output
}
} }
func (s *systemService) GetSystemConfigDebug() []string { func (s *systemService) GetSystemConfigDebug() []string {
if output, err := command.OnlyExec("source " + config.AppInfo.ShellPath + "/helper.sh ;GetSysInfo"); err != nil { return command2.ExecResultStrArray("source " + config.AppInfo.ShellPath + "/helper.sh ;GetSysInfo")
return []string{}
} else {
return strings.Split(output, "\n")
}
} }
func (s *systemService) UpAppOrderFile(str, id string) { func (s *systemService) UpAppOrderFile(str, id string) {
@@ -434,7 +297,7 @@ func (s *systemService) GetCasaOSLogs(lineNumber int) string {
return err.Error() return err.Error()
} }
defer file.Close() defer file.Close()
content, err := io.ReadAll(file) content, err := ioutil.ReadAll(file)
if err != nil { if err != nil {
return err.Error() return err.Error()
} }
@@ -496,7 +359,6 @@ func GetCPUThermalZone() string {
break break
} }
} }
Cache.SetDefault(keyName, path) Cache.SetDefault(keyName, path)
return path return path
} }
@@ -507,10 +369,7 @@ func (s *systemService) GetCPUTemperature() int {
if len(path) > 0 { if len(path) > 0 {
outPut = string(file.ReadFullFile(path + "/temp")) outPut = string(file.ReadFullFile(path + "/temp"))
} else { } else {
outPut = string(file.ReadFullFile("/sys/class/hwmon/hwmon0/temp1_input")) outPut = "0"
if len(outPut) == 0 {
outPut = "0"
}
} }
celsius, _ := strconv.Atoi(strings.TrimSpace(outPut)) celsius, _ := strconv.Atoi(strings.TrimSpace(outPut))
@@ -533,8 +392,9 @@ func (s *systemService) GetCPUPower() map[string]string {
} }
func (s *systemService) SystemReboot() error { func (s *systemService) SystemReboot() error {
// cmd := exec.Command("/bin/bash", "-c", "reboot")
arg := []string{"6"} arg := []string{"6"}
cmd := exec2.Command("init", arg...) cmd := exec.Command("init", arg...)
_, err := cmd.CombinedOutput() _, err := cmd.CombinedOutput()
if err != nil { if err != nil {
return err return err
@@ -544,7 +404,7 @@ func (s *systemService) SystemReboot() error {
func (s *systemService) SystemShutdown() error { func (s *systemService) SystemShutdown() error {
arg := []string{"0"} arg := []string{"0"}
cmd := exec2.Command("init", arg...) cmd := exec.Command("init", arg...)
_, err := cmd.CombinedOutput() _, err := cmd.CombinedOutput()
if err != nil { if err != nil {
return err return err

View File

@@ -1,25 +0,0 @@
{
"compilerOptions": {
"declaration": true,
"lib": [
"es2017",
"DOM"
],
"module": "commonjs",
"target": "es6",
"skipLibCheck": true,
"sourceMap": false,
"strict": true,
"useUnknownInCatchVariables": false,
"resolveJsonModule": true,
"esModuleInterop": true,
"outDir": "dist",
"types": [
"node"
],
},
"exclude": [
"node_modules"
],
"main": "generate/index"
}