mirror of
https://github.com/IceWhaleTech/CasaOS.git
synced 2025-11-07 07:09:46 +00:00
Compare commits
174 Commits
v0.4.2-alp
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0d3b2f444e | ||
|
|
030bcd1095 | ||
|
|
dad2f3f8c2 | ||
|
|
b09160e76b | ||
|
|
12fc102753 | ||
|
|
6ffe2cc89d | ||
|
|
b9098101e2 | ||
|
|
a6ff39e47d | ||
|
|
23eb739f01 | ||
|
|
ba285cb8bd | ||
|
|
63f01489a8 | ||
|
|
6bbb0802aa | ||
|
|
c26cf4dbec | ||
|
|
958a483385 | ||
|
|
16e97ec66f | ||
|
|
5ea588b813 | ||
|
|
7da0f0d49e | ||
|
|
2adb795896 | ||
|
|
8b251dc407 | ||
|
|
e4bf67dad5 | ||
|
|
e8f9d3aaf5 | ||
|
|
bb0d9ac25c | ||
|
|
3a835c00e3 | ||
|
|
e4447981cb | ||
|
|
170b599e86 | ||
|
|
18ce1d6342 | ||
|
|
1c483a5d9c | ||
|
|
8f7c99779f | ||
|
|
0883f5f3aa | ||
|
|
36dda53e9c | ||
|
|
53c3879907 | ||
|
|
ef57d3348d | ||
|
|
7a76aca022 | ||
|
|
fffdc7fd5e | ||
|
|
29d16d13ba | ||
|
|
54a115ae89 | ||
|
|
17fa7868a4 | ||
|
|
27d6dd86e2 | ||
|
|
ae50a9bb17 | ||
|
|
caf3347da9 | ||
|
|
718a08eab2 | ||
|
|
6f722b3506 | ||
|
|
e722d841a9 | ||
|
|
3ccf58695b | ||
|
|
c52386cef4 | ||
|
|
acac2df40f | ||
|
|
0b507cb7ad | ||
|
|
ac90509c66 | ||
|
|
abf7134710 | ||
|
|
f9a26af93f | ||
|
|
33eacbf4b3 | ||
|
|
262e0d49c8 | ||
|
|
689b0f769a | ||
|
|
8f8a082888 | ||
|
|
9b8c6f4299 | ||
|
|
657cbe5c41 | ||
|
|
b17bff68dd | ||
|
|
7807cfdb01 | ||
|
|
9e5381710f | ||
|
|
fa62c65526 | ||
|
|
3aea945277 | ||
|
|
4d8ca182cb | ||
|
|
b727606a0a | ||
|
|
428be5f2c2 | ||
|
|
995d67543d | ||
|
|
590beac43a | ||
|
|
e7bf227232 | ||
|
|
eedfdde311 | ||
|
|
38c7b5a569 | ||
|
|
8c0b219621 | ||
|
|
23fc677f30 | ||
|
|
a06508783c | ||
|
|
37fee157dd | ||
|
|
3f1c7098bd | ||
|
|
b11d046c52 | ||
|
|
d6a9ba65ed | ||
|
|
5f1df76dbf | ||
|
|
0cf353c56e | ||
|
|
5dc6297047 | ||
|
|
f26ae2793c | ||
|
|
d7641e1b93 | ||
|
|
37c496fd6a | ||
|
|
cb15c06f7e | ||
|
|
89a0ea34b0 | ||
|
|
d8dd815baa | ||
|
|
a77b5d1954 | ||
|
|
d0fb2f06f5 | ||
|
|
dd8032a8be | ||
|
|
760882e147 | ||
|
|
dfeed76a66 | ||
|
|
28d724731a | ||
|
|
4549d8778b | ||
|
|
05cadaabf3 | ||
|
|
1a0c15208c | ||
|
|
4f5b4b0887 | ||
|
|
cbfe44be61 | ||
|
|
e1bbb998df | ||
|
|
f48cddf924 | ||
|
|
23ce3487e1 | ||
|
|
6246421dae | ||
|
|
f867453573 | ||
|
|
78e7a8b411 | ||
|
|
1aa8fb600b | ||
|
|
7ecfea71ab | ||
|
|
d911d80254 | ||
|
|
9bfe37305c | ||
|
|
94dd2e00c7 | ||
|
|
c5d2cebe92 | ||
|
|
955e8dea07 | ||
|
|
4c7b3a749b | ||
|
|
e86a61596b | ||
|
|
c9617e583f | ||
|
|
dda15b0821 | ||
|
|
50816c68b0 | ||
|
|
c5de0319fb | ||
|
|
78b7c6ce09 | ||
|
|
b420a2d930 | ||
|
|
c67ee1731c | ||
|
|
eaca399ef9 | ||
|
|
e0e9f97764 | ||
|
|
2fefee87fa | ||
|
|
280ad4fcf9 | ||
|
|
538639b623 | ||
|
|
39535d6a38 | ||
|
|
4d977d7a62 | ||
|
|
08c500c434 | ||
|
|
705bf1facb | ||
|
|
aae1802191 | ||
|
|
8e1b9b82c1 | ||
|
|
af440eac55 | ||
|
|
34b4e154a1 | ||
|
|
79db93ec02 | ||
|
|
f8ec3b20cd | ||
|
|
8c7c8dc1ec | ||
|
|
60a141fe25 | ||
|
|
02e712f649 | ||
|
|
7022cf5d29 | ||
|
|
6cf46ce50c | ||
|
|
202c1de570 | ||
|
|
858ab5b124 | ||
|
|
e319975a60 | ||
|
|
5c2c3b5e98 | ||
|
|
a0dc58264a | ||
|
|
717b47ca2c | ||
|
|
f530f69ba5 | ||
|
|
87b190a84b | ||
|
|
10191a1be3 | ||
|
|
59f2ccbeb3 | ||
|
|
076b7198b2 | ||
|
|
eb483a4c5d | ||
|
|
60e81bc781 | ||
|
|
dc8ee89c85 | ||
|
|
c995750312 | ||
|
|
de6ed093a2 | ||
|
|
449e1515d9 | ||
|
|
e6ddb0d849 | ||
|
|
c19e32c6e9 | ||
|
|
94755e221a | ||
|
|
86a3692dad | ||
|
|
45a5567978 | ||
|
|
3190421fd9 | ||
|
|
a7126cac63 | ||
|
|
151aa037bb | ||
|
|
08ed9933ee | ||
|
|
8425011e73 | ||
|
|
96ff550d61 | ||
|
|
85a803d352 | ||
|
|
5def3e5856 | ||
|
|
c768260b1b | ||
|
|
46e146e633 | ||
|
|
1a2f917b30 | ||
|
|
86adfbaef8 | ||
|
|
143af78745 | ||
|
|
7b07f22685 |
53
.github/ISSUE_TEMPLATE/app_request.yml
vendored
53
.github/ISSUE_TEMPLATE/app_request.yml
vendored
@ -1,53 +0,0 @@
|
|||||||
name: "App Request"
|
|
||||||
description: "Request to add an app to the app store."
|
|
||||||
title: "[App Request] AppName"
|
|
||||||
labels: ["App Request"]
|
|
||||||
body:
|
|
||||||
- type: markdown
|
|
||||||
attributes:
|
|
||||||
value: |
|
|
||||||
### ❤ Thanks for taking the time to fill out this app request!
|
|
||||||
> Before proceeding, please make sure that this app is not in App Store and no one has [requested](https://github.com/IceWhaleTech/CasaOS/labels/App%20Request) the same app before.
|
|
||||||
> If you have already requested the app, please ask your friends to help add a 👍 to this issue. Then be patient and wait for the developers to work on it.
|
|
||||||
> If you have any questions, please ask them on [Discord](https://discord.gg/knqAbbBbeX) or [Github Discussions](https://github.com/IceWhaleTech/CasaOS/discussions).
|
|
||||||
|
|
||||||
- type: textarea
|
|
||||||
id: app-info
|
|
||||||
attributes:
|
|
||||||
label: "App Information"
|
|
||||||
description: "The formal information of this app, as detailed as possible."
|
|
||||||
value: |
|
|
||||||
- Name: <!-- eg. Nextcloud -->
|
|
||||||
- Short Description: <!-- eg. Personal cloud and file sharing solution -->
|
|
||||||
- Official Website: <!-- If available. eg. https://nextcloud.com -->
|
|
||||||
- GitHub Repository: <!-- If available. eg. https://github.com/nextcloud/server -->
|
|
||||||
- Docker Image: <!-- If available. eg. nextcloud/server:latest, ghcr.io/nextcloud/server:latest -->
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
|
|
||||||
- type: textarea
|
|
||||||
id: why
|
|
||||||
attributes:
|
|
||||||
label: "Why do you want this app?"
|
|
||||||
description: "Detailed notes can help developers and others understand the importance of this app."
|
|
||||||
placeholder: |
|
|
||||||
As a [what role], it helps me solve [what problem], and especially [what function] is great!
|
|
||||||
or
|
|
||||||
It solves [what problem] and especially [what feature] works well, which is hard to do with other app.
|
|
||||||
or
|
|
||||||
This is the app that [some device/service] must use and will not work without it.
|
|
||||||
or
|
|
||||||
others
|
|
||||||
|
|
||||||
- type: textarea
|
|
||||||
id: additional-info
|
|
||||||
attributes:
|
|
||||||
label: "Additional information?"
|
|
||||||
description: "Anything else you want to share with the developers and others?"
|
|
||||||
placeholder: |
|
|
||||||
Example:
|
|
||||||
- Noteworthy matters.
|
|
||||||
- Recommended Docker image.
|
|
||||||
- Validated Docker deployment instructions.
|
|
||||||
- Notable Docker setup details.
|
|
||||||
- Recommended config files, user data, accessible directory settings.
|
|
||||||
34
.github/ISSUE_TEMPLATE/bug_report.md
vendored
34
.github/ISSUE_TEMPLATE/bug_report.md
vendored
@ -8,39 +8,57 @@ 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**
|
**Additional context**
|
||||||
Add any other context about the problem here.
|
|
||||||
|
> Add any other context about the problem here.
|
||||||
|
>
|
||||||
|
> If you are a Zimaboard user, make it explicit with when you got your Zimaboard.
|
||||||
|
|||||||
5
.github/ISSUE_TEMPLATE/config.yml
vendored
5
.github/ISSUE_TEMPLATE/config.yml
vendored
@ -1,5 +1,8 @@
|
|||||||
blank_issues_enabled: false
|
blank_issues_enabled: false
|
||||||
contact_links:
|
contact_links:
|
||||||
|
- name: App Request
|
||||||
|
url: https://github.com/IceWhaleTech/CasaOS-AppStore/issues/new?assignees=&labels=App+Request&template=app_request.yml&title=%5BApp+Request%5D+AppName
|
||||||
|
about: Request to add an app to the app store.
|
||||||
- name: Feature/Enhancement Ideas
|
- name: Feature/Enhancement Ideas
|
||||||
url: https://github.com/IceWhaleTech/CasaOS/discussions/164
|
url: https://github.com/IceWhaleTech/CasaOS/discussions/164
|
||||||
about: Have an idea for a new feature/enhancement?
|
about: Have an idea for a new feature/enhancement?
|
||||||
@ -8,4 +11,4 @@ contact_links:
|
|||||||
about: Ask questions, propose ideas, or discuss anything related to CasaOS
|
about: Ask questions, propose ideas, or discuss anything related to CasaOS
|
||||||
- name: Discord
|
- name: Discord
|
||||||
url: https://discord.gg/knqAbbBbeX
|
url: https://discord.gg/knqAbbBbeX
|
||||||
about: Get help or share great ideas on Discord!
|
about: Get help or share great ideas on Discord!
|
||||||
|
|||||||
23
.github/ISSUE_TEMPLATE/feedback.yml
vendored
23
.github/ISSUE_TEMPLATE/feedback.yml
vendored
@ -1,23 +0,0 @@
|
|||||||
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.
|
|
||||||
|
|
||||||
15
.github/ISSUE_TEMPLATE/submit-application.md
vendored
15
.github/ISSUE_TEMPLATE/submit-application.md
vendored
@ -1,15 +0,0 @@
|
|||||||
---
|
|
||||||
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
|
|
||||||
19
.github/sync_openapi.yml
vendored
Normal file
19
.github/sync_openapi.yml
vendored
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
name: Sync OpenAPI
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_call:
|
||||||
|
inputs:
|
||||||
|
project-name:
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
sync:
|
||||||
|
uses: IceWhaleTech/github/.github/workflows/sync_openapi.yml@main
|
||||||
|
with:
|
||||||
|
project-name: casaos
|
||||||
|
secrets:
|
||||||
|
API_TOKEN_GITHUB: ${{ secrets.API_TOKEN_GITHUB }}
|
||||||
6
.github/workflows/casa.yml
vendored
6
.github/workflows/casa.yml
vendored
@ -40,7 +40,7 @@ jobs:
|
|||||||
# env:
|
# env:
|
||||||
# GITHUB_TOKEN: ${{ github.token }}
|
# GITHUB_TOKEN: ${{ github.token }}
|
||||||
|
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
submodules: true
|
submodules: true
|
||||||
@ -65,7 +65,7 @@ jobs:
|
|||||||
# ls
|
# ls
|
||||||
|
|
||||||
|
|
||||||
- name: Set enviroment for github-release
|
- name: Set environment 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
|
||||||
@ -73,7 +73,7 @@ jobs:
|
|||||||
|
|
||||||
|
|
||||||
- name: Use Node.js
|
- name: Use Node.js
|
||||||
uses: actions/setup-node@v2
|
uses: actions/setup-node@v3
|
||||||
with:
|
with:
|
||||||
node-version: '14'
|
node-version: '14'
|
||||||
|
|
||||||
|
|||||||
10
.github/workflows/codecov.yml
vendored
10
.github/workflows/codecov.yml
vendored
@ -13,10 +13,16 @@ jobs:
|
|||||||
runs-on: ubuntu-22.04
|
runs-on: ubuntu-22.04
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v3
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
|
- name: Set up Go
|
||||||
|
uses: actions/setup-go@v4
|
||||||
|
with:
|
||||||
|
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
|
||||||
uses: codecov/codecov-action@v3
|
uses: codecov/codecov-action@v3
|
||||||
|
|||||||
13
.github/workflows/demo.yml
vendored
13
.github/workflows/demo.yml
vendored
@ -22,7 +22,7 @@ jobs:
|
|||||||
# Steps represent a sequence of tasks that will be executed as part of the job
|
# Steps represent a sequence of tasks that will be executed as part of the job
|
||||||
steps:
|
steps:
|
||||||
# Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
|
# Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
|
|
||||||
- name: Configure AWS credentials from Test account
|
- name: Configure AWS credentials from Test account
|
||||||
uses: aws-actions/configure-aws-credentials@v1
|
uses: aws-actions/configure-aws-credentials@v1
|
||||||
@ -33,9 +33,10 @@ 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=$(aws lightsail get-instance-snapshots | grep '"name": "casaos-0.3.6-1666150291' | sed 's/ //g' | sed 's/"//g' | sed 's/,//g' | sed 's/name://g')" >> $GITHUB_ENV
|
echo "OLD_INSTANCE_SNAPSHOT_NAME=CasaOS-v0.4.4-3-Demo-1700132299" >> $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=$(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 "NEW_INSTANCE_NAME=CasaOS-Demo-$(date +%s)" >> $GITHUB_ENV
|
# echo "OLD_INSTANCE_NAME=CasaOS-Demo-1687680295" >> $GITHUB_ENV
|
||||||
|
echo "NEW_INSTANCE_NAME= CasaOS-Demo-$(date +%s)" >> $GITHUB_ENV
|
||||||
|
|
||||||
- name: Create instances from snapshot
|
- name: Create instances from snapshot
|
||||||
run: |
|
run: |
|
||||||
@ -75,5 +76,9 @@ 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 }}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
46
.github/workflows/publish_npm.yaml
vendored
Normal file
46
.github/workflows/publish_npm.yaml
vendored
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
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}}
|
||||||
6
.github/workflows/push_events_to_discord.yml
vendored
6
.github/workflows/push_events_to_discord.yml
vendored
@ -40,9 +40,3 @@ 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 }}
|
|
||||||
|
|||||||
62
.github/workflows/push_test_server.yml
vendored
62
.github/workflows/push_test_server.yml
vendored
@ -3,6 +3,8 @@ on:
|
|||||||
push:
|
push:
|
||||||
branches:
|
branches:
|
||||||
- main
|
- main
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
permissions:
|
permissions:
|
||||||
contents: write
|
contents: write
|
||||||
jobs:
|
jobs:
|
||||||
@ -11,48 +13,80 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
-
|
-
|
||||||
name: Checkout
|
name: Checkout
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v3
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
- name: isntall git
|
- name: isntall git
|
||||||
run: sudo apt install --yes git
|
run: sudo apt install --yes git
|
||||||
- name: git global
|
- name: git global
|
||||||
run: sudo git config --global --add safe.directory '*'
|
run: sudo git config --global --add safe.directory '*'
|
||||||
-
|
- name: set version
|
||||||
name: Fetch all tags
|
run: sudo git tag v00.00.00-alpha
|
||||||
|
|
||||||
|
- name: Fetch all tags
|
||||||
run: sudo git fetch --force --tags
|
run: sudo git fetch --force --tags
|
||||||
|
|
||||||
- name: Get version
|
- name: Get version
|
||||||
id: get_version
|
id: get_version
|
||||||
# run: echo ::set-output name=VERSION::${GITHUB_REF/refs\/tags\//}
|
# run: echo ::set-output name=VERSION::${GITHUB_REF/refs\/tags\//}
|
||||||
run: echo "VERSION=$(git describe --abbrev=0 --tags | awk -F- '{print $1}')" >> $GITHUB_ENV
|
run: echo "VERSION=$(git describe --abbrev=0 --tags | awk -F- '{print $1}')" >> $GITHUB_ENV
|
||||||
|
|
||||||
- name: show version
|
- name: show version
|
||||||
id: show_version
|
id: show_version
|
||||||
# run: echo ::set-output name=VERSION::${GITHUB_REF/refs\/tags\//}
|
# run: echo ::set-output name=VERSION::${GITHUB_REF/refs\/tags\//}
|
||||||
run: echo ${{env.VERSION}}
|
run: echo ${{env.VERSION}}
|
||||||
-
|
|
||||||
name: Set up Go
|
- name: Set up Go
|
||||||
uses: actions/setup-go@v2
|
uses: actions/setup-go@v4
|
||||||
with:
|
with:
|
||||||
go-version: 1.19
|
go-version: 'stable'
|
||||||
-
|
|
||||||
name: Run GoReleaser
|
- name: Run GoReleaser
|
||||||
uses: goreleaser/goreleaser-action@v2
|
uses: goreleaser/goreleaser-action@v4
|
||||||
with:
|
with:
|
||||||
# either 'goreleaser' (default) or 'goreleaser-pro'
|
# either 'goreleaser' (default) or 'goreleaser-pro'
|
||||||
distribution: goreleaser
|
distribution: goreleaser
|
||||||
version: latest
|
version: 1.14.1
|
||||||
args: release --rm-dist
|
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 }}
|
||||||
|
|
||||||
|
- name: remove migration file
|
||||||
|
run: sudo find . -type f \( -name '*migration*' \) -delete
|
||||||
|
|
||||||
- name: install sshpass
|
- name: install sshpass
|
||||||
run: sudo apt install sshpass --yes
|
run: sudo apt install sshpass --yes
|
||||||
|
|
||||||
|
- name: ZeroTier
|
||||||
|
uses: zerotier/github-action@v1.0.1
|
||||||
|
with:
|
||||||
|
network_id: ${{ secrets.ZEROTIER_NETWORK_ID }}
|
||||||
|
auth_token: ${{ secrets.ZEROTIER_CENTRAL_TOKEN }}
|
||||||
|
|
||||||
|
- name: ping host
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
count=10
|
||||||
|
while ! ping -c 1 10.147.18.11 ; do
|
||||||
|
echo "waiting..." ;
|
||||||
|
sleep 1 ;
|
||||||
|
let count=count-1
|
||||||
|
done
|
||||||
|
echo "ping success"
|
||||||
|
|
||||||
- name: copy tar to target host
|
- name: copy tar to target host
|
||||||
shell: bash
|
shell: bash
|
||||||
run: |
|
run: |
|
||||||
sshpass -p "${{ secrets.ssh_password }}" scp -r -o StrictHostKeyChecking=no -P ${{ secrets.ssh_port }} ./dist/*.gz root@${{ secrets.ssh_ip }}:/var/www/download
|
sshpass -p "${{ secrets.ssh_password }}" scp -r -o StrictHostKeyChecking=no -P 22 ./dist/*.gz root@10.147.18.11:/var/www/download
|
||||||
echo "ping success"
|
echo "ping success"
|
||||||
- name: send message
|
- name: send message
|
||||||
run: |
|
run: |
|
||||||
curl -X POST -H "Content-Type: application/json" -d '{"msg_type":"text","content":{"text":"CasaOS updated"}}' https://open.feishu.cn/open-apis/bot/v2/hook/eb8f45c7-9636-4b64-84f2-a66d9aeb9d30
|
curl -X POST -H "Content-Type: application/json" -d '{"msg_type":"text","content":{"text":"CasaOS updated"}}' ${{ secrets.SSH_ROBOT_URL }}
|
||||||
|
|||||||
76
.github/workflows/release.yml
vendored
76
.github/workflows/release.yml
vendored
@ -7,65 +7,19 @@ on:
|
|||||||
|
|
||||||
permissions:
|
permissions:
|
||||||
contents: write
|
contents: write
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
goreleaser:
|
call-workflow-passing-data:
|
||||||
runs-on: ubuntu-22.04
|
uses: IceWhaleTech/github/.github/workflows/go_release.yml@main
|
||||||
steps:
|
with:
|
||||||
-
|
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 }}
|
||||||
-
|
OneDriveSecret: ${{ secrets.OneDriveSecret }}
|
||||||
name: Checkout
|
OneDrivePublic: ${{ secrets.OneDrivePublic }}
|
||||||
uses: actions/checkout@v2
|
OSS_KEY_ID: ${{ secrets.OSS_KEY_ID }}
|
||||||
with:
|
OSS_KEY_SECRET: ${{ secrets.OSS_KEY_SECRET }}
|
||||||
fetch-depth: 0
|
|
||||||
-
|
|
||||||
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@v2
|
|
||||||
with:
|
|
||||||
go-version: 1.19
|
|
||||||
-
|
|
||||||
name: Run GoReleaser
|
|
||||||
uses: goreleaser/goreleaser-action@v2
|
|
||||||
with:
|
|
||||||
# either 'goreleaser' (default) or 'goreleaser-pro'
|
|
||||||
distribution: goreleaser
|
|
||||||
version: latest
|
|
||||||
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
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
19
.github/workflows/sync_openapi.yml
vendored
Normal file
19
.github/workflows/sync_openapi.yml
vendored
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
name: Sync OpenAPI
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_call:
|
||||||
|
inputs:
|
||||||
|
project-name:
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
sync:
|
||||||
|
uses: IceWhaleTech/github/.github/workflows/sync_openapi.yml@main
|
||||||
|
with:
|
||||||
|
project-name: casaos
|
||||||
|
secrets:
|
||||||
|
API_TOKEN_GITHUB: ${{ secrets.API_TOKEN_GITHUB }}
|
||||||
1
.gitignore
vendored
1
.gitignore
vendored
@ -37,6 +37,7 @@ github.com
|
|||||||
.all-contributorsrc
|
.all-contributorsrc
|
||||||
dist
|
dist
|
||||||
CasaOS
|
CasaOS
|
||||||
|
/codegen
|
||||||
|
|
||||||
# System Files
|
# System Files
|
||||||
.DS_Store
|
.DS_Store
|
||||||
|
|||||||
@ -59,6 +59,22 @@ builds:
|
|||||||
- arm
|
- arm
|
||||||
goarm:
|
goarm:
|
||||||
- "7"
|
- "7"
|
||||||
|
- id: casaos-riscv64
|
||||||
|
binary: build/sysroot/usr/bin/casaos
|
||||||
|
env:
|
||||||
|
- CC=riscv64-linux-gnu-gcc
|
||||||
|
gcflags:
|
||||||
|
- all=-N -l
|
||||||
|
ldflags:
|
||||||
|
- -extldflags "-static"
|
||||||
|
tags:
|
||||||
|
- musl
|
||||||
|
- netgo
|
||||||
|
- osusergo
|
||||||
|
goos:
|
||||||
|
- linux
|
||||||
|
goarch:
|
||||||
|
- riscv64
|
||||||
- id: casaos-migration-tool-amd64
|
- id: casaos-migration-tool-amd64
|
||||||
binary: build/sysroot/usr/bin/casaos-migration-tool
|
binary: build/sysroot/usr/bin/casaos-migration-tool
|
||||||
main: ./cmd/migration-tool
|
main: ./cmd/migration-tool
|
||||||
@ -112,25 +128,42 @@ builds:
|
|||||||
- arm
|
- arm
|
||||||
goarm:
|
goarm:
|
||||||
- "7"
|
- "7"
|
||||||
|
- id: casaos-migration-tool-riscv64
|
||||||
|
binary: build/sysroot/usr/bin/casaos-migration-tool
|
||||||
|
main: ./cmd/migration-tool
|
||||||
|
env:
|
||||||
|
- CC=riscv64-linux-gnu-gcc
|
||||||
|
gcflags:
|
||||||
|
- all=-N -l
|
||||||
|
ldflags:
|
||||||
|
- -extldflags "-static"
|
||||||
|
tags:
|
||||||
|
- musl
|
||||||
|
- netgo
|
||||||
|
- osusergo
|
||||||
|
goos:
|
||||||
|
- linux
|
||||||
|
goarch:
|
||||||
|
- riscv64
|
||||||
archives:
|
archives:
|
||||||
- name_template: "{{ .Os }}-{{ .Arch }}-{{ .ProjectName }}-v{{ .Version }}"
|
- name_template: >-
|
||||||
|
{{ .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:
|
- casaos-riscv64
|
||||||
arm: arm-7
|
|
||||||
files:
|
files:
|
||||||
- build/**/*
|
- build/**/*
|
||||||
- name_template: "{{ .Os }}-{{ .Arch }}-{{ .ProjectName }}-migration-tool-v{{ .Version }}"
|
- name_template: >-
|
||||||
|
{{ .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:
|
- casaos-migration-tool-riscv64
|
||||||
arm: arm-7
|
|
||||||
files:
|
files:
|
||||||
- build/sysroot/etc/**/*
|
- build/sysroot/etc/**/*
|
||||||
checksum:
|
checksum:
|
||||||
|
|||||||
@ -19,6 +19,12 @@ 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"
|
||||||
@ -32,14 +38,20 @@ 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"
|
||||||
@ -61,6 +73,12 @@ 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"
|
||||||
@ -74,6 +92,30 @@ builds:
|
|||||||
- arm
|
- arm
|
||||||
goarm:
|
goarm:
|
||||||
- "7"
|
- "7"
|
||||||
|
- id: casaos-riscv64
|
||||||
|
binary: build/sysroot/usr/bin/casaos
|
||||||
|
env:
|
||||||
|
- CC=riscv64-linux-gnu-gcc
|
||||||
|
ldflags:
|
||||||
|
- -X main.commit={{.Commit}}
|
||||||
|
- -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
|
||||||
|
- -w
|
||||||
|
- -extldflags "-static"
|
||||||
|
tags:
|
||||||
|
- musl
|
||||||
|
- netgo
|
||||||
|
- osusergo
|
||||||
|
goos:
|
||||||
|
- linux
|
||||||
|
goarch:
|
||||||
|
- riscv64
|
||||||
- id: casaos-migration-tool-amd64
|
- id: casaos-migration-tool-amd64
|
||||||
binary: build/sysroot/usr/bin/casaos-migration-tool
|
binary: build/sysroot/usr/bin/casaos-migration-tool
|
||||||
hooks:
|
hooks:
|
||||||
@ -98,9 +140,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
|
||||||
@ -142,25 +184,44 @@ builds:
|
|||||||
- arm
|
- arm
|
||||||
goarm:
|
goarm:
|
||||||
- "7"
|
- "7"
|
||||||
|
- id: casaos-migration-tool-riscv64
|
||||||
|
binary: build/sysroot/usr/bin/casaos-migration-tool
|
||||||
|
main: ./cmd/migration-tool
|
||||||
|
env:
|
||||||
|
- CC=riscv64-linux-gnu-gcc
|
||||||
|
ldflags:
|
||||||
|
- -X main.commit={{.Commit}}
|
||||||
|
- -X main.date={{.Date}}
|
||||||
|
- -s
|
||||||
|
- -w
|
||||||
|
- -extldflags "-static"
|
||||||
|
tags:
|
||||||
|
- musl
|
||||||
|
- netgo
|
||||||
|
- osusergo
|
||||||
|
goos:
|
||||||
|
- linux
|
||||||
|
goarch:
|
||||||
|
- riscv64
|
||||||
archives:
|
archives:
|
||||||
- name_template: "{{ .Os }}-{{ .Arch }}-{{ .ProjectName }}-v{{ .Version }}"
|
- name_template: >-
|
||||||
|
{{ .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:
|
- casaos-riscv64
|
||||||
arm: arm-7
|
|
||||||
files:
|
files:
|
||||||
- build/**/*
|
- build/**/*
|
||||||
- name_template: "{{ .Os }}-{{ .Arch }}-{{ .ProjectName }}-migration-tool-v{{ .Version }}"
|
- name_template: >-
|
||||||
|
{{ .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:
|
- casaos-migration-tool-riscv64
|
||||||
arm: arm-7
|
|
||||||
files:
|
files:
|
||||||
- build/sysroot/etc/**/*
|
- build/sysroot/etc/**/*
|
||||||
checksum:
|
checksum:
|
||||||
|
|||||||
43
CHANGELOG.md
43
CHANGELOG.md
@ -16,6 +16,49 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
|
|
||||||
### Security
|
### Security
|
||||||
|
|
||||||
|
## [0.4.3]
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- [Disk] Now usb also supports merging to
|
||||||
|
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- [File] Solve the installation dependency problem, make the installation more smoothly
|
||||||
|
- [File] Change the default permissions of the sharing folder
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- [System] Fixed not see wlan iface ([#909](https://github.com/IceWhaleTech/CasaOS/issues/909))
|
||||||
|
- [System] Terminal font issue fix ([#929](https://github.com/IceWhaleTech/CasaOS/issues/929))
|
||||||
|
- [File] Fixed the problem of not being able to launch after mounting
|
||||||
|
|
||||||
|
### Removed
|
||||||
|
|
||||||
|
|
||||||
|
## [0.4.2]
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- [App] Increase the display of progress during the installation process
|
||||||
|
- [App] Label whether the current app supports x86 or Pi devices
|
||||||
|
- [App] Support single app version upgrade
|
||||||
|
- [File] Support mounting of Google Drive and Dropbox cloud drives
|
||||||
|
- [System] Support Mint Linux
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- [File] Optimize the download speed of a single file
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- [Share] Fix the samba permission issue
|
||||||
|
- [Disk] Fix the problem of disk mount point plus 1 after upgrade ([#770](https://github.com/IceWhaleTech/CasaOS/issues/770))
|
||||||
|
- [File] Fix the problem of file permission change caused by modifying files in casaos ([#829](https://github.com/IceWhaleTech/CasaOS/issues/829))
|
||||||
|
- [Share] Fix the problem of files being deleted due to samba uninstallation failure ([#843](https://github.com/IceWhaleTech/CasaOS/issues/843))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## [0.4.1] - 2023-1-19
|
## [0.4.1] - 2023-1-19
|
||||||
|
|
||||||
|
|||||||
128
CODE_OF_CONDUCT.md
Normal file
128
CODE_OF_CONDUCT.md
Normal file
@ -0,0 +1,128 @@
|
|||||||
|
# Contributor Covenant Code of Conduct
|
||||||
|
|
||||||
|
## Our Pledge
|
||||||
|
|
||||||
|
We as members, contributors, and leaders pledge to make participation in our
|
||||||
|
community a harassment-free experience for everyone, regardless of age, body
|
||||||
|
size, visible or invisible disability, ethnicity, sex characteristics, gender
|
||||||
|
identity and expression, level of experience, education, socio-economic status,
|
||||||
|
nationality, personal appearance, race, religion, or sexual identity
|
||||||
|
and orientation.
|
||||||
|
|
||||||
|
We pledge to act and interact in ways that contribute to an open, welcoming,
|
||||||
|
diverse, inclusive, and healthy community.
|
||||||
|
|
||||||
|
## Our Standards
|
||||||
|
|
||||||
|
Examples of behavior that contributes to a positive environment for our
|
||||||
|
community include:
|
||||||
|
|
||||||
|
* Demonstrating empathy and kindness toward other people
|
||||||
|
* Being respectful of differing opinions, viewpoints, and experiences
|
||||||
|
* Giving and gracefully accepting constructive feedback
|
||||||
|
* Accepting responsibility and apologizing to those affected by our mistakes,
|
||||||
|
and learning from the experience
|
||||||
|
* Focusing on what is best not just for us as individuals, but for the
|
||||||
|
overall community
|
||||||
|
|
||||||
|
Examples of unacceptable behavior include:
|
||||||
|
|
||||||
|
* The use of sexualized language or imagery, and sexual attention or
|
||||||
|
advances of any kind
|
||||||
|
* Trolling, insulting or derogatory comments, and personal or political attacks
|
||||||
|
* Public or private harassment
|
||||||
|
* Publishing others' private information, such as a physical or email
|
||||||
|
address, without their explicit permission
|
||||||
|
* Other conduct which could reasonably be considered inappropriate in a
|
||||||
|
professional setting
|
||||||
|
|
||||||
|
## Enforcement Responsibilities
|
||||||
|
|
||||||
|
Community leaders are responsible for clarifying and enforcing our standards of
|
||||||
|
acceptable behavior and will take appropriate and fair corrective action in
|
||||||
|
response to any behavior that they deem inappropriate, threatening, offensive,
|
||||||
|
or harmful.
|
||||||
|
|
||||||
|
Community leaders have the right and responsibility to remove, edit, or reject
|
||||||
|
comments, commits, code, wiki edits, issues, and other contributions that are
|
||||||
|
not aligned to this Code of Conduct, and will communicate reasons for moderation
|
||||||
|
decisions when appropriate.
|
||||||
|
|
||||||
|
## Scope
|
||||||
|
|
||||||
|
This Code of Conduct applies within all community spaces, and also applies when
|
||||||
|
an individual is officially representing the community in public spaces.
|
||||||
|
Examples of representing our community include using an official e-mail address,
|
||||||
|
posting via an official social media account, or acting as an appointed
|
||||||
|
representative at an online or offline event.
|
||||||
|
|
||||||
|
## Enforcement
|
||||||
|
|
||||||
|
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
||||||
|
reported to the community leaders responsible for enforcement at
|
||||||
|
wiki@casaos.io.
|
||||||
|
All complaints will be reviewed and investigated promptly and fairly.
|
||||||
|
|
||||||
|
All community leaders are obligated to respect the privacy and security of the
|
||||||
|
reporter of any incident.
|
||||||
|
|
||||||
|
## Enforcement Guidelines
|
||||||
|
|
||||||
|
Community leaders will follow these Community Impact Guidelines in determining
|
||||||
|
the consequences for any action they deem in violation of this Code of Conduct:
|
||||||
|
|
||||||
|
### 1. Correction
|
||||||
|
|
||||||
|
**Community Impact**: Use of inappropriate language or other behavior deemed
|
||||||
|
unprofessional or unwelcome in the community.
|
||||||
|
|
||||||
|
**Consequence**: A private, written warning from community leaders, providing
|
||||||
|
clarity around the nature of the violation and an explanation of why the
|
||||||
|
behavior was inappropriate. A public apology may be requested.
|
||||||
|
|
||||||
|
### 2. Warning
|
||||||
|
|
||||||
|
**Community Impact**: A violation through a single incident or series
|
||||||
|
of actions.
|
||||||
|
|
||||||
|
**Consequence**: A warning with consequences for continued behavior. No
|
||||||
|
interaction with the people involved, including unsolicited interaction with
|
||||||
|
those enforcing the Code of Conduct, for a specified period of time. This
|
||||||
|
includes avoiding interactions in community spaces as well as external channels
|
||||||
|
like social media. Violating these terms may lead to a temporary or
|
||||||
|
permanent ban.
|
||||||
|
|
||||||
|
### 3. Temporary Ban
|
||||||
|
|
||||||
|
**Community Impact**: A serious violation of community standards, including
|
||||||
|
sustained inappropriate behavior.
|
||||||
|
|
||||||
|
**Consequence**: A temporary ban from any sort of interaction or public
|
||||||
|
communication with the community for a specified period of time. No public or
|
||||||
|
private interaction with the people involved, including unsolicited interaction
|
||||||
|
with those enforcing the Code of Conduct, is allowed during this period.
|
||||||
|
Violating these terms may lead to a permanent ban.
|
||||||
|
|
||||||
|
### 4. Permanent Ban
|
||||||
|
|
||||||
|
**Community Impact**: Demonstrating a pattern of violation of community
|
||||||
|
standards, including sustained inappropriate behavior, harassment of an
|
||||||
|
individual, or aggression toward or disparagement of classes of individuals.
|
||||||
|
|
||||||
|
**Consequence**: A permanent ban from any sort of public interaction within
|
||||||
|
the community.
|
||||||
|
|
||||||
|
## Attribution
|
||||||
|
|
||||||
|
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
|
||||||
|
version 2.0, available at
|
||||||
|
https://www.contributor-covenant.org/version/2/0/code_of_conduct.html.
|
||||||
|
|
||||||
|
Community Impact Guidelines were inspired by [Mozilla's code of conduct
|
||||||
|
enforcement ladder](https://github.com/mozilla/diversity).
|
||||||
|
|
||||||
|
[homepage]: https://www.contributor-covenant.org
|
||||||
|
|
||||||
|
For answers to common questions about this code of conduct, see the FAQ at
|
||||||
|
https://www.contributor-covenant.org/faq. Translations are available at
|
||||||
|
https://www.contributor-covenant.org/translations.
|
||||||
83
README.md
83
README.md
@ -1,6 +1,4 @@
|
|||||||
# CasaOS - Your Home Cloud OS
|
# CasaOS - Your Personal Cloud
|
||||||
|
|
||||||
|
|
||||||
<!-- Readme i18n links -->
|
<!-- Readme i18n links -->
|
||||||
<!-- > English | [中文](#) | [Français](#) -->
|
<!-- > English | [中文](#) | [Français](#) -->
|
||||||
|
|
||||||
@ -12,7 +10,7 @@
|
|||||||
<img alt="CasaOS" src="https://raw.githubusercontent.com/IceWhaleTech/logo/main/casaos/casaos_banner_twilight_blue_800x300.png">
|
<img alt="CasaOS" src="https://raw.githubusercontent.com/IceWhaleTech/logo/main/casaos/casaos_banner_twilight_blue_800x300.png">
|
||||||
</picture>
|
</picture>
|
||||||
<br/>
|
<br/>
|
||||||
<i>Connect with the community developing HOME CLOUD, creating self-sovereign, and defining the future of the distributed cloud.</i>
|
<i>Connect with the community, establish autonomy, reduce the cost of SaaS, and MAXIMIZE the potential for a personalized copilot.</i>
|
||||||
<br/>
|
<br/>
|
||||||
<br/>
|
<br/>
|
||||||
<!-- CasaOS Badges -->
|
<!-- CasaOS Badges -->
|
||||||
@ -46,8 +44,20 @@
|
|||||||
<img alt="CasaOS GitHub Discussions" src="https://img.shields.io/github/discussions/IceWhaleTech/CasaOS?color=162453&style=flat-square&label=Discussions&logo=github" />
|
<img alt="CasaOS GitHub Discussions" src="https://img.shields.io/github/discussions/IceWhaleTech/CasaOS?color=162453&style=flat-square&label=Discussions&logo=github" />
|
||||||
</a>
|
</a>
|
||||||
<!-- 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">
|
||||||
<!-- ALL-CONTRIBUTORS-BADGE:END -->
|
<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>
|
||||||
|
<!-- 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=flat-square&logo=youtube&logoColor=red&label=YouTube%20Tutorial%20Views" />
|
||||||
|
</a>
|
||||||
|
<br/>
|
||||||
|
<a href="http://bit.ly/45JQIiL" target="_blank">
|
||||||
|
<img alt="twitter ZimaSpace" src="https://img.shields.io/twitter/follow/ZimaSpace?style=flat-square&logo=X&label=Contact%20Us%20%40%20ZimaSpace&labelColor=555&color=555" />
|
||||||
|
</a>
|
||||||
|
<a href="http://bit.ly/4lgHj7V" target="_blank">
|
||||||
|
<img alt="facebook ZimaSpace" src="https://img.shields.io/badge/ZimaSpace-1877F2?style=flat-square&logo=Facebook&logoColor=fff&label=Contact%20Us&labelColor=555&color=162453" />
|
||||||
|
</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> |
|
||||||
@ -65,18 +75,16 @@
|
|||||||
</kbd>
|
</kbd>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
## Why do we need Home Cloud?
|
## Why do you need Personal Cloud?
|
||||||
|
|
||||||
Think about it seriously. Is control of our data, smart devices and digital assets now only in the hands of some big company?
|
In 2020, the team noticed three important trends:
|
||||||
|
- The cost of computing power and storage was decreasing fast.
|
||||||
|
- A part of cloud computing was moving towards edge computing.
|
||||||
|
- The issue of consumer data asset ownership and attribution had been ignored.
|
||||||
|
|
||||||
- Is your photo album saved in their cloud service?
|
Based on these trends, the team proposed a thought experiment internally: what if personal clouds were available under $100 in next five years? This personal cloud would provide a low-cost data collaboration solution as a personal data center, storing and managing data for creators and small organizations. A distributed collaborative computing network can be formed by personal servers located around the world. It could also control and connect all smart devices, providing cross-ecosystem local intelligent services.
|
||||||
- Do your thermostats, monitors, lamps need to be used through their cloud services?
|
|
||||||
- Do your personal documents, memos, contacts, passwords, etc. reside in their cloud storage services?
|
|
||||||
- Are you just going to have to accept their decisions when they decide to change prices, review content or even discontinue services?
|
|
||||||
|
|
||||||
It sounds ridiculous, doesn't it? We are losing control of our own data!
|
Furthermore, the personal cloud could combine personal data to train personalized AI assistants. The idea is that this technology would be an effective way to solve the issue of consumer data asset ownership and , as well as provide a more affordable and efficient computing solution for individuals and small organizations.
|
||||||
|
|
||||||
Our ideal home cloud is one where you can manage all your data, devices and data assets very easily. In your own home, you have absolute control.
|
|
||||||
|
|
||||||
> If you think what we are doing is valuable. Please **give us a star ⭐** and **fork it 🤞**!
|
> If you think what we are doing is valuable. Please **give us a star ⭐** and **fork it 🤞**!
|
||||||
|
|
||||||
@ -87,7 +95,7 @@ Our ideal home cloud is one where you can manage all your data, devices and data
|
|||||||
- 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, HomeAssiant, AdGuard, Jellyfin, *arr and more!
|
- Nextcloud, HomeAssistant, 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
|
||||||
@ -108,7 +116,7 @@ CasaOS fully supports ZimaBoard, Intel NUC, and Raspberry Pi. Also, more compute
|
|||||||
### System Compatibility
|
### System Compatibility
|
||||||
|
|
||||||
Official Support
|
Official Support
|
||||||
- Debian 11 (✅ Tested, Recommended)
|
- Debian 12 (✅ Tested, Recommended)
|
||||||
- Ubuntu Server 20.04 (✅ Tested)
|
- Ubuntu Server 20.04 (✅ Tested)
|
||||||
- Raspberry Pi OS (✅ Tested)
|
- Raspberry Pi OS (✅ Tested)
|
||||||
|
|
||||||
@ -133,6 +141,30 @@ 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
|
||||||
|
|
||||||
|
|
||||||
@ -150,13 +182,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 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 the 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 believes that through community-driven collaborative innovation and open communication with global developers, we can reshape the digital home experience like never before.
|
We believe 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)!**
|
||||||
|
|
||||||
@ -166,8 +198,9 @@ We believes that through community-driven collaborative innovation and open comm
|
|||||||
|
|
||||||
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 contribution to CasaOS
|
- See <https://wiki.casaos.io/en/contribute> for ways of contributing to CasaOS
|
||||||
- See <https://wiki.casaos.io/en/contribute/development> if you want to be involved in code contribution specificially
|
- See <https://wiki.casaos.io/en/contribute/development> if you want to be involved in code contribution specifically
|
||||||
|
|
||||||
|
|
||||||
## Credits
|
## Credits
|
||||||
|
|
||||||
@ -182,7 +215,7 @@ Everyone's contribution is greatly appreciated. ([Emoji Key](https://allcontribu
|
|||||||
<tr>
|
<tr>
|
||||||
<td align="center"><a href="https://github.com/jerrykuku"><img src="https://avatars.githubusercontent.com/u/9485680?v=4?s=100" width="100px;" alt=""/><br /><sub><b>老竭力</b></sub></a><br /><a href="https://github.com/IceWhaleTech/CasaOS/commits?author=jerrykuku" title="Code">💻</a> <a href="https://github.com/IceWhaleTech/CasaOS/commits?author=jerrykuku" title="Documentation">📖</a> <a href="#ideas-jerrykuku" title="Ideas, Planning, & Feedback">🤔</a> <a href="#infra-jerrykuku" title="Infrastructure (Hosting, Build-Tools, etc)">🚇</a> <a href="#maintenance-jerrykuku" title="Maintenance">🚧</a> <a href="#platform-jerrykuku" title="Packaging/porting to new platform">📦</a> <a href="#question-jerrykuku" title="Answering Questions">💬</a> <a href="https://github.com/IceWhaleTech/CasaOS/pulls?q=is%3Apr+reviewed-by%3Ajerrykuku" title="Reviewed Pull Requests">👀</a></td>
|
<td align="center"><a href="https://github.com/jerrykuku"><img src="https://avatars.githubusercontent.com/u/9485680?v=4?s=100" width="100px;" alt=""/><br /><sub><b>老竭力</b></sub></a><br /><a href="https://github.com/IceWhaleTech/CasaOS/commits?author=jerrykuku" title="Code">💻</a> <a href="https://github.com/IceWhaleTech/CasaOS/commits?author=jerrykuku" title="Documentation">📖</a> <a href="#ideas-jerrykuku" title="Ideas, Planning, & Feedback">🤔</a> <a href="#infra-jerrykuku" title="Infrastructure (Hosting, Build-Tools, etc)">🚇</a> <a href="#maintenance-jerrykuku" title="Maintenance">🚧</a> <a href="#platform-jerrykuku" title="Packaging/porting to new platform">📦</a> <a href="#question-jerrykuku" title="Answering Questions">💬</a> <a href="https://github.com/IceWhaleTech/CasaOS/pulls?q=is%3Apr+reviewed-by%3Ajerrykuku" title="Reviewed Pull Requests">👀</a></td>
|
||||||
<td align="center"><a href="https://github.com/LinkLeong"><img src="https://avatars.githubusercontent.com/u/13556972?v=4?s=100" width="100px;" alt=""/><br /><sub><b>link</b></sub></a><br /><a href="https://github.com/IceWhaleTech/CasaOS/commits?author=LinkLeong" title="Code">💻</a> <a href="https://github.com/IceWhaleTech/CasaOS/commits?author=LinkLeong" title="Documentation">📖</a> <a href="#ideas-LinkLeong" title="Ideas, Planning, & Feedback">🤔</a> <a href="#infra-LinkLeong" title="Infrastructure (Hosting, Build-Tools, etc)">🚇</a> <a href="#maintenance-LinkLeong" title="Maintenance">🚧</a> <a href="#question-LinkLeong" title="Answering Questions">💬</a> <a href="https://github.com/IceWhaleTech/CasaOS/pulls?q=is%3Apr+reviewed-by%3ALinkLeong" title="Reviewed Pull Requests">👀</a></td>
|
<td align="center"><a href="https://github.com/LinkLeong"><img src="https://avatars.githubusercontent.com/u/13556972?v=4?s=100" width="100px;" alt=""/><br /><sub><b>link</b></sub></a><br /><a href="https://github.com/IceWhaleTech/CasaOS/commits?author=LinkLeong" title="Code">💻</a> <a href="https://github.com/IceWhaleTech/CasaOS/commits?author=LinkLeong" title="Documentation">📖</a> <a href="#ideas-LinkLeong" title="Ideas, Planning, & Feedback">🤔</a> <a href="#infra-LinkLeong" title="Infrastructure (Hosting, Build-Tools, etc)">🚇</a> <a href="#maintenance-LinkLeong" title="Maintenance">🚧</a> <a href="#question-LinkLeong" title="Answering Questions">💬</a> <a href="https://github.com/IceWhaleTech/CasaOS/pulls?q=is%3Apr+reviewed-by%3ALinkLeong" title="Reviewed Pull Requests">👀</a></td>
|
||||||
<td align="center"><a href="https://github.com/tigerinus"><img src="https://avatars.githubusercontent.com/u/7172560?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Tiger Wang (王豫)</b></sub></a><br /><a href="https://github.com/IceWhaleTech/CasaOS/commits?author=tigerinus" title="Code">💻</a> <a href="https://github.com/IceWhaleTech/CasaOS/commits?author=tigerinus" title="Documentation">📖</a> <a href="#ideas-tigerinus" title="Ideas, Planning, & Feedback">🤔</a> <a href="#infra-tigerinus" title="Infrastructure (Hosting, Build-Tools, etc)">🚇</a> <a href="#maintenance-tigerinus" title="Maintenance">🚧</a> <a href="#mentoring-tigerinus" title="Mentoring">🧑🏫</a> <a href="#security-tigerinus" title="Security">🛡️</a> <a href="#question-tigerinus" title="Answering Questions">💬</a> <a href="https://github.com/IceWhaleTech/CasaOS/pulls?q=is%3Apr+reviewed-by%3Atigerinus" title="Reviewed Pull Requests">👀</a></td>
|
<td align="center"><a href="https://github.com/tigerinus"><img src="https://avatars.githubusercontent.com/u/7172560?v=4?s=100" width="100px;" alt=""/><br /><sub><b>太戈</b></sub></a><br /><a href="https://github.com/IceWhaleTech/CasaOS/commits?author=tigerinus" title="Code">💻</a> <a href="https://github.com/IceWhaleTech/CasaOS/commits?author=tigerinus" title="Documentation">📖</a> <a href="#ideas-tigerinus" title="Ideas, Planning, & Feedback">🤔</a> <a href="#infra-tigerinus" title="Infrastructure (Hosting, Build-Tools, etc)">🚇</a> <a href="#maintenance-tigerinus" title="Maintenance">🚧</a> <a href="#mentoring-tigerinus" title="Mentoring">🧑🏫</a> <a href="#security-tigerinus" title="Security">🛡️</a> <a href="#question-tigerinus" title="Answering Questions">💬</a> <a href="https://github.com/IceWhaleTech/CasaOS/pulls?q=is%3Apr+reviewed-by%3Atigerinus" title="Reviewed Pull Requests">👀</a></td>
|
||||||
<td align="center"><a href="https://github.com/Lauren-ED209"><img src="https://avatars.githubusercontent.com/u/8243355?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Lauren</b></sub></a><br /><a href="#ideas-Lauren-ED209" title="Ideas, Planning, & Feedback">🤔</a> <a href="#fundingFinding-Lauren-ED209" title="Funding Finding">🔍</a> <a href="#projectManagement-Lauren-ED209" title="Project Management">📆</a> <a href="#question-Lauren-ED209" title="Answering Questions">💬</a> <a href="https://github.com/IceWhaleTech/CasaOS/commits?author=Lauren-ED209" title="Tests">⚠️</a></td>
|
<td align="center"><a href="https://github.com/Lauren-ED209"><img src="https://avatars.githubusercontent.com/u/8243355?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Lauren</b></sub></a><br /><a href="#ideas-Lauren-ED209" title="Ideas, Planning, & Feedback">🤔</a> <a href="#fundingFinding-Lauren-ED209" title="Funding Finding">🔍</a> <a href="#projectManagement-Lauren-ED209" title="Project Management">📆</a> <a href="#question-Lauren-ED209" title="Answering Questions">💬</a> <a href="https://github.com/IceWhaleTech/CasaOS/commits?author=Lauren-ED209" title="Tests">⚠️</a></td>
|
||||||
<td align="center"><a href="https://JohnGuan.Cn"><img src="https://avatars.githubusercontent.com/u/3358477?v=4?s=100" width="100px;" alt=""/><br /><sub><b>John Guan</b></sub></a><br /><a href="#blog-JohnGuan" title="Blogposts">📝</a> <a href="#content-JohnGuan" title="Content">🖋</a> <a href="https://github.com/IceWhaleTech/CasaOS/commits?author=JohnGuan" title="Documentation">📖</a> <a href="#ideas-JohnGuan" title="Ideas, Planning, & Feedback">🤔</a> <a href="#eventOrganizing-JohnGuan" title="Event Organizing">📋</a> <a href="#mentoring-JohnGuan" title="Mentoring">🧑🏫</a> <a href="#question-JohnGuan" title="Answering Questions">💬</a> <a href="https://github.com/IceWhaleTech/CasaOS/pulls?q=is%3Apr+reviewed-by%3AJohnGuan" title="Reviewed Pull Requests">👀</a></td>
|
<td align="center"><a href="https://JohnGuan.Cn"><img src="https://avatars.githubusercontent.com/u/3358477?v=4?s=100" width="100px;" alt=""/><br /><sub><b>John Guan</b></sub></a><br /><a href="#blog-JohnGuan" title="Blogposts">📝</a> <a href="#content-JohnGuan" title="Content">🖋</a> <a href="https://github.com/IceWhaleTech/CasaOS/commits?author=JohnGuan" title="Documentation">📖</a> <a href="#ideas-JohnGuan" title="Ideas, Planning, & Feedback">🤔</a> <a href="#eventOrganizing-JohnGuan" title="Event Organizing">📋</a> <a href="#mentoring-JohnGuan" title="Mentoring">🧑🏫</a> <a href="#question-JohnGuan" title="Answering Questions">💬</a> <a href="https://github.com/IceWhaleTech/CasaOS/pulls?q=is%3Apr+reviewed-by%3AJohnGuan" title="Reviewed Pull Requests">👀</a></td>
|
||||||
<td align="center"><a href="https://blog.tippybits.com"><img src="https://avatars.githubusercontent.com/u/17506770?v=4?s=100" width="100px;" alt=""/><br /><sub><b>David Tippett</b></sub></a><br /><a href="https://github.com/IceWhaleTech/CasaOS/commits?author=dtaivpp" title="Documentation">📖</a> <a href="#ideas-dtaivpp" title="Ideas, Planning, & Feedback">🤔</a> <a href="#question-dtaivpp" title="Answering Questions">💬</a></td>
|
<td align="center"><a href="https://blog.tippybits.com"><img src="https://avatars.githubusercontent.com/u/17506770?v=4?s=100" width="100px;" alt=""/><br /><sub><b>David Tippett</b></sub></a><br /><a href="https://github.com/IceWhaleTech/CasaOS/commits?author=dtaivpp" title="Documentation">📖</a> <a href="#ideas-dtaivpp" title="Ideas, Planning, & Feedback">🤔</a> <a href="#question-dtaivpp" title="Answering Questions">💬</a></td>
|
||||||
@ -199,6 +232,8 @@ 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>
|
||||||
|
|
||||||
@ -207,7 +242,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 welcome!
|
This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind are welcome!
|
||||||
|
|
||||||
## Changelog
|
## Changelog
|
||||||
|
|
||||||
|
|||||||
9
SECURITY.md
Normal file
9
SECURITY.md
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
# Security Policy
|
||||||
|
|
||||||
|
## Supported Versions
|
||||||
|
|
||||||
|
CasaOS is currently under active development. Support is limited before CasaOS reaches v1.0.
|
||||||
|
|
||||||
|
## Reporting a Vulnerability
|
||||||
|
|
||||||
|
If you see any vulnerabiility, email us at wiki@casaos.io
|
||||||
@ -20,10 +20,11 @@ servers:
|
|||||||
tags:
|
tags:
|
||||||
- name: Health methods
|
- name: Health methods
|
||||||
description: |-
|
description: |-
|
||||||
(TODO)
|
These methods are used to check the health and status of the CasaOS API and associated services.
|
||||||
- name: File methods
|
|
||||||
|
- name: File methods
|
||||||
description: |-
|
description: |-
|
||||||
(TODO)
|
The File methods allow you to interact with files and directories on the CasaOS system.
|
||||||
|
|
||||||
x-tagGroups:
|
x-tagGroups:
|
||||||
- name: Methods
|
- name: Methods
|
||||||
@ -47,6 +48,35 @@ paths:
|
|||||||
$ref: "#/components/responses/GetHealthServicesOK"
|
$ref: "#/components/responses/GetHealthServicesOK"
|
||||||
"500":
|
"500":
|
||||||
$ref: "#/components/responses/ResponseInternalServerError"
|
$ref: "#/components/responses/ResponseInternalServerError"
|
||||||
|
|
||||||
|
/health/ports:
|
||||||
|
get:
|
||||||
|
tags:
|
||||||
|
- Health methods
|
||||||
|
summary: Get port in use
|
||||||
|
operationId: getHealthPorts
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
$ref: "#/components/responses/GetHealthPortsOK"
|
||||||
|
"500":
|
||||||
|
$ref: "#/components/responses/ResponseInternalServerError"
|
||||||
|
/health/logs:
|
||||||
|
get:
|
||||||
|
tags:
|
||||||
|
- Health methods
|
||||||
|
summary: Get log
|
||||||
|
operationId: getHealthlogs
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: OK
|
||||||
|
content:
|
||||||
|
application/octet-stream:
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
format: binary
|
||||||
|
"500":
|
||||||
|
$ref: "#/components/responses/ResponseInternalServerError"
|
||||||
|
|
||||||
/file/test:
|
/file/test:
|
||||||
get:
|
get:
|
||||||
tags:
|
tags:
|
||||||
@ -60,6 +90,153 @@ 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:
|
||||||
@ -75,6 +252,20 @@ 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:
|
||||||
@ -93,6 +284,24 @@ components:
|
|||||||
data:
|
data:
|
||||||
$ref: "#/components/schemas/HealthServices"
|
$ref: "#/components/schemas/HealthServices"
|
||||||
|
|
||||||
|
GetHealthPortsOK:
|
||||||
|
description: OK
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
allOf:
|
||||||
|
- $ref: "#/components/schemas/BaseResponse"
|
||||||
|
- properties:
|
||||||
|
data:
|
||||||
|
$ref: "#/components/schemas/HealthPorts"
|
||||||
|
GetZTInfoOK:
|
||||||
|
description: OK
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: "#/components/schemas/ZTInfo"
|
||||||
|
|
||||||
|
|
||||||
schemas:
|
schemas:
|
||||||
BaseResponse:
|
BaseResponse:
|
||||||
properties:
|
properties:
|
||||||
@ -101,6 +310,14 @@ components:
|
|||||||
description: message returned by server side if there is any
|
description: message returned by server side if there is any
|
||||||
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:
|
||||||
@ -114,3 +331,29 @@ components:
|
|||||||
items:
|
items:
|
||||||
type: string
|
type: string
|
||||||
example: "casaos.service"
|
example: "casaos.service"
|
||||||
|
|
||||||
|
HealthPorts:
|
||||||
|
properties:
|
||||||
|
tcp:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
type: integer
|
||||||
|
example: 80
|
||||||
|
x-go-name: TCP
|
||||||
|
udp:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
type: integer
|
||||||
|
example: 53
|
||||||
|
x-go-name: UDP
|
||||||
|
ZTInfo:
|
||||||
|
properties:
|
||||||
|
id:
|
||||||
|
type: string
|
||||||
|
example: "1234567890"
|
||||||
|
name:
|
||||||
|
type: string
|
||||||
|
example: "CasaOS"
|
||||||
|
status:
|
||||||
|
type: string
|
||||||
|
example: "online"
|
||||||
|
|||||||
@ -111,6 +111,9 @@ aarch64)
|
|||||||
armv7l)
|
armv7l)
|
||||||
ARCH="arm-7"
|
ARCH="arm-7"
|
||||||
;;
|
;;
|
||||||
|
riscv64)
|
||||||
|
ARCH="riscv64"
|
||||||
|
;;
|
||||||
*)
|
*)
|
||||||
__error "Unsupported architecture"
|
__error "Unsupported architecture"
|
||||||
;;
|
;;
|
||||||
|
|||||||
@ -1,3 +1,3 @@
|
|||||||
LEGACY_WITHOUT_VERSION ${DOWNLOAD_DOMAIN}IceWhaleTech/CasaOS/releases/download/v0.3.6/linux-${ARCH}-casaos-migration-tool-v0.3.6.tar.gz
|
LEGACY_WITHOUT_VERSION ${DOWNLOAD_DOMAIN}IceWhaleTech/CasaOS/releases/download/v0.3.6/linux-${ARCH}-casaos-migration-tool-v0.3.6.tar.gz
|
||||||
v0.3.5 ${DOWNLOAD_DOMAIN}IceWhaleTech/CasaOS/releases/download/v0.3.6/linux-${ARCH}-casaos-migration-tool-v0.3.6.tar.gz
|
v0.3.5 ${DOWNLOAD_DOMAIN}IceWhaleTech/CasaOS/releases/download/v0.3.6/linux-${ARCH}-casaos-migration-tool-v0.3.6.tar.gz
|
||||||
v0.3.5.1 ${DOWNLOAD_DOMAIN}IceWhaleTech/CasaOS/releases/download/v0.3.6/linux-${ARCH}-casaos-migration-tool-v0.3.6.tar.gz
|
v0.3.5.1 ${DOWNLOAD_DOMAIN}IceWhaleTech/CasaOS/releases/download/v0.3.6/linux-${ARCH}-casaos-migration-tool-v0.3.6.tar.gz
|
||||||
|
|||||||
@ -1,7 +1,6 @@
|
|||||||
[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]
|
||||||
|
|||||||
@ -2,8 +2,9 @@
|
|||||||
Description=rclone
|
Description=rclone
|
||||||
|
|
||||||
[Service]
|
[Service]
|
||||||
ExecStartPre=/usr/bin/rm -f /tmp/rclone.sock
|
ExecStartPre=/usr/bin/mkdir -p /var/run/rclone
|
||||||
ExecStart=/usr/bin/rclone rcd --rc-addr unix:///tmp/rclone.sock --rc-no-auth
|
ExecStartPre=/usr/bin/rm -f /var/run/rclone/rclone.sock
|
||||||
|
ExecStart=/usr/bin/rclone rcd --rc-addr unix:///var/run/rclone/rclone.sock --rc-no-auth --rc-allow-origin "*"
|
||||||
Restart=always
|
Restart=always
|
||||||
RestartSec=10
|
RestartSec=10
|
||||||
|
|
||||||
|
|||||||
@ -25,7 +25,7 @@ GetNetCard() {
|
|||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
if [ -d "/sys/devices/virtual/net" ] && [ -d "/sys/class/net" ]; then
|
if [ -d "/sys/devices/virtual/net" ] && [ -d "/sys/class/net" ]; then
|
||||||
ls /sys/class/net/ | grep -v "$(ls /sys/devices/virtual/net/)"
|
ls /sys/class/net/ | grep -v "$(ls /sys/devices/virtual/net/)" -w
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|||||||
28
cmd/message-bus-docgen/main.go
Normal file
28
cmd/message-bus-docgen/main.go
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
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)
|
||||||
|
}
|
||||||
@ -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"
|
||||||
|
|||||||
@ -1,46 +1,13 @@
|
|||||||
/*
|
|
||||||
* @Author: LinkLeong link@icewhale.org
|
|
||||||
* @Date: 2022-08-24 17:36:00
|
|
||||||
* @LastEditors: LinkLeong
|
|
||||||
* @LastEditTime: 2022-09-05 11:24:27
|
|
||||||
* @FilePath: /CasaOS/cmd/migration-tool/migration-034-035.go
|
|
||||||
* @Description:
|
|
||||||
* @Website: https://www.casaos.io
|
|
||||||
* Copyright (c) 2022 by icewhale, All Rights Reserved.
|
|
||||||
*/
|
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
interfaces "github.com/IceWhaleTech/CasaOS-Common"
|
interfaces "github.com/IceWhaleTech/CasaOS-Common"
|
||||||
"github.com/IceWhaleTech/CasaOS-Common/utils/version"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type migrationTool struct{}
|
type migrationTool struct{}
|
||||||
|
|
||||||
func (u *migrationTool) IsMigrationNeeded() (bool, error) {
|
func (u *migrationTool) IsMigrationNeeded() (bool, error) {
|
||||||
majorVersion, minorVersion, patchVersion, err := version.DetectLegacyVersion()
|
return false, nil
|
||||||
if err != nil {
|
|
||||||
if err == version.ErrLegacyVersionNotFound {
|
|
||||||
return false, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if majorVersion > 0 {
|
|
||||||
return false, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if minorVersion > 3 {
|
|
||||||
return false, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if minorVersion == 3 && patchVersion > 5 {
|
|
||||||
return false, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
_logger.Info("Migration is needed for a CasaOS version 0.3.5 and older...")
|
|
||||||
return true, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *migrationTool) PreMigrate() error {
|
func (u *migrationTool) PreMigrate() error {
|
||||||
|
|||||||
@ -1,210 +0,0 @@
|
|||||||
// 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"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// HealthServices defines model for HealthServices.
|
|
||||||
type HealthServices struct {
|
|
||||||
NotRunning *[]string `json:"not_running,omitempty"`
|
|
||||||
Running *[]string `json:"running,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 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
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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/services", wrapper.GetHealthServices)
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// Base64 encoded, gzipped, json marshaled Swagger object
|
|
||||||
var swaggerSpec = []string{
|
|
||||||
|
|
||||||
"H4sIAAAAAAAC/7xW70/jRhD9V1bTfoDKxBGoUmXpPnC9wiFUpSpIrUSi3GY9sfewd92ZcSBF/t+rXZtL",
|
|
||||||
"SCiC649PiffHe2/e7szsAxhfN96hE4bsAQi58Y4xfpyjfERdSXmFtLIGeXIZho13gk7CX900lTVarHfp",
|
|
||||||
"Z/YujLEpsdZxtqomS8huHuBbwiVk8E26YUv7dZy+14y/DrTQJQ/QkG+QxPYici0R7CWIpyqh67pZ13UJ",
|
|
||||||
"5MiGbBPkQQaTS+gSeKS6cILkdBV2If1E5OlNwb0+pH0lj9yqJ1c9+5a4Nxr9T7QEV7pkAIuOP9mR7Z5H",
|
|
||||||
"jcy6iBNPgYYJRSgtOczVYq24j49tjsoulZRIqCwr7daQAN7ruqkQMoAECHU+cdUaMqEWE5B1E2ZYyLqi",
|
|
||||||
"F75zzHvSnJc5tc6FDdkDWME6jm94jGbtecQ9BOyxfBnQRHodvl+Dd1RowTu9fj1uDIfRtGRlfRWs7yPQ",
|
|
||||||
"xiDzXPwtxiO2wdgSdY4ECThdB4zTVkpP9s94GzZcurGXuO6dsm7p909o2o7HJ6axRlrC+IFTp5RS/QT7",
|
|
||||||
"lgyqGnOr303hoCFcIvGR8ZWno3hBMFO5ptvDKSgmwyjvplCKNJylKem7UWGlbBctIw13d2R8nV4Y/K3U",
|
|
||||||
"FV6jKdPKFz6ttXVpb97wM19o55DmAX7ubFHK/IfxuLkfNa6YwteKrQLQf6hW7mykmC+qFl8WbOtC6SpI",
|
|
||||||
"+FGznlz1ov5/Rb2adOcWTF2vSp3+cqEa8iubI6vassGq0g59y6pGKX3OaulJ5Xa5REInig06TdbzKKCc",
|
|
||||||
"eVKWucWQ47nKLZuW2XrHiWoq1IxqZdlKKAXq5tzKx3ahCBvPVjytZwePbvRO7IffyzxUntRnb5268S2p",
|
|
||||||
"D5aNp3yzO+8HRkWR3ro/TheL9wv8/XA0jeliJebuJmBIYIXEfZKsjkO6+gadbixkcDIaj04ggUZLGXM0",
|
|
||||||
"XdoKU0GOhblA2U+0a2RRYdmjZyOIkBRT9iKHLPTWMxtiYonFb6vtHo/Hf1fUv6xLtzpFl8D3b9nyXOeL",
|
|
||||||
"9aita03r5/QH23TBkN3A2fbwLOxLy1iXU94qzM/aco6ihnqqWLS0rPxSoTal+jRU0u8+qQHmWct2OsDX",
|
|
||||||
"GPfco+bfdzCEOgQyhLplYc+/beJWN4jvpad94GbWzcKCQMZxvqUKMkhXx0P2Q1gwwO+6fnA9+TA53LSP",
|
|
||||||
"Hfbw4np5w5MTD0T3R6KLc/Jt0/MN637euyt7gc66vwIAAP//o5zNVnEKAAA=",
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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
|
|
||||||
}
|
|
||||||
File diff suppressed because it is too large
Load Diff
@ -2,6 +2,7 @@ package common
|
|||||||
|
|
||||||
const (
|
const (
|
||||||
SERVICENAME = "casaos"
|
SERVICENAME = "casaos"
|
||||||
VERSION = "0.4.2"
|
VERSION = "0.4.15"
|
||||||
BODY = " "
|
BODY = " "
|
||||||
|
RANW_NAME = "IceWhale-RemoteAccess"
|
||||||
)
|
)
|
||||||
|
|||||||
@ -1,23 +1,12 @@
|
|||||||
package common
|
package common
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"github.com/IceWhaleTech/CasaOS/codegen/message_bus"
|
"github.com/IceWhaleTech/CasaOS/codegen/message_bus"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
// devtype -> action -> event
|
||||||
// devtype -> action -> event
|
var EventTypes = []message_bus.EventType{
|
||||||
EventTypes map[string]map[string]message_bus.EventType
|
{Name: "casaos:system:utilization", SourceID: SERVICENAME, PropertyTypeList: []message_bus.PropertyType{}},
|
||||||
|
{Name: "casaos:file:recover", SourceID: SERVICENAME, PropertyTypeList: []message_bus.PropertyType{}},
|
||||||
PropertyNameLookupMaps = map[string]map[string]string{
|
{Name: "casaos:file:operate", SourceID: SERVICENAME, PropertyTypeList: []message_bus.PropertyType{}},
|
||||||
"system": {
|
}
|
||||||
fmt.Sprintf("%s:%s", SERVICENAME, "utilization"): "ID_BUS",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
ActionPastTense = map[string]string{
|
|
||||||
"add": "added",
|
|
||||||
"remove": "removed",
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|||||||
@ -3,6 +3,7 @@ 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
|
||||||
|
|||||||
@ -14,7 +14,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type Dropbox struct {
|
type Dropbox struct {
|
||||||
model.Storage
|
model.StorageA
|
||||||
Addition
|
Addition
|
||||||
AccessToken string
|
AccessToken string
|
||||||
}
|
}
|
||||||
@ -96,5 +96,8 @@ 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)
|
||||||
|
|||||||
@ -2,12 +2,9 @@ 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
|
||||||
@ -15,7 +12,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:"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"`
|
AuthUrl string `json:"auth_url" type:"string" default:""`
|
||||||
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"`
|
||||||
}
|
}
|
||||||
@ -25,9 +22,3 @@ var config = driver.Config{
|
|||||||
OnlyProxy: true,
|
OnlyProxy: true,
|
||||||
DefaultRoot: "root",
|
DefaultRoot: "root",
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
|
||||||
op.RegisterDriver(func() driver.Driver {
|
|
||||||
return &Dropbox{}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|||||||
@ -10,6 +10,11 @@ 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
|
||||||
@ -100,3 +105,12 @@ 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
|
||||||
|
}
|
||||||
|
|||||||
@ -17,7 +17,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type GoogleDrive struct {
|
type GoogleDrive struct {
|
||||||
model.Storage
|
model.StorageA
|
||||||
Addition
|
Addition
|
||||||
AccessToken string
|
AccessToken string
|
||||||
}
|
}
|
||||||
@ -80,6 +80,9 @@ 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,
|
||||||
|
|||||||
@ -2,22 +2,19 @@ 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:"921743327851-urr4f7jjfp4ts639evqb3i4m4qb4u4cc.apps.googleusercontent.com" omit:"true"`
|
ClientID string `json:"client_id" required:"true" default:"" omit:"true"`
|
||||||
ClientSecret string `json:"client_secret" required:"true" default:"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" omit:"true"`
|
ClientSecret string `json:"client_secret" required:"true" default:"" 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:"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"`
|
AuthUrl string `json:"auth_url" type:"string" default:""`
|
||||||
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"`
|
||||||
}
|
}
|
||||||
@ -27,9 +24,3 @@ var config = driver.Config{
|
|||||||
OnlyProxy: true,
|
OnlyProxy: true,
|
||||||
DefaultRoot: "root",
|
DefaultRoot: "root",
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
|
||||||
op.RegisterDriver(func() driver.Driver {
|
|
||||||
return &GoogleDrive{}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|||||||
@ -16,6 +16,11 @@ 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 {
|
||||||
@ -150,3 +155,13 @@ 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
|
||||||
|
}
|
||||||
|
|||||||
73
drivers/onedrive/drive.go
Normal file
73
drivers/onedrive/drive.go
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
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{}
|
||||||
|
_, err := d.Request(url, http.MethodGet, nil, &user)
|
||||||
|
if err != nil {
|
||||||
|
return "", "", "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
return user.CreatedBy.User.Email, 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)
|
||||||
62
drivers/onedrive/meta.go
Normal file
62
drivers/onedrive/meta.go
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
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 {
|
||||||
|
CreatedBy struct {
|
||||||
|
User struct {
|
||||||
|
Email string `json:"email"`
|
||||||
|
DisplayName string `json:"displayName"`
|
||||||
|
} `json:"user"`
|
||||||
|
} `json:"createdBy"`
|
||||||
|
ParentReference struct {
|
||||||
|
DriveID string `json:"driveId"`
|
||||||
|
DriveType string `json:"driveType"`
|
||||||
|
} `json:"parentReference"`
|
||||||
|
}
|
||||||
|
|
||||||
|
var config = driver.Config{
|
||||||
|
Name: "Onedrive",
|
||||||
|
LocalSort: true,
|
||||||
|
DefaultRoot: "/",
|
||||||
|
}
|
||||||
160
drivers/onedrive/util.go
Normal file
160
drivers/onedrive/util.go
Normal file
@ -0,0 +1,160 @@
|
|||||||
|
package onedrive
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/IceWhaleTech/CasaOS-Common/utils/logger"
|
||||||
|
"github.com/IceWhaleTech/CasaOS/drivers/base"
|
||||||
|
"github.com/IceWhaleTech/CasaOS/pkg/utils"
|
||||||
|
"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 (d *Onedrive) GetMetaUrl(auth bool, path string) string {
|
||||||
|
host := onedriveHostMap[d.Region]
|
||||||
|
path = utils.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
|
||||||
|
}
|
||||||
132
go.mod
132
go.mod
@ -1,130 +1,126 @@
|
|||||||
module github.com/IceWhaleTech/CasaOS
|
module github.com/IceWhaleTech/CasaOS
|
||||||
|
|
||||||
go 1.19
|
go 1.21
|
||||||
|
|
||||||
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.2-alpha3
|
github.com/IceWhaleTech/CasaOS-Common v0.4.11-alpha4
|
||||||
github.com/Xhofe/go-cache v0.0.0-20220723083548-714439c8af9a
|
|
||||||
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.1.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.0-20221012082141-d21ac8e2de85
|
github.com/dsoprea/go-exif/v3 v3.0.1
|
||||||
github.com/dsoprea/go-logging v0.0.0-20200710184922-b02d349568dd
|
github.com/getkin/kin-openapi v0.117.0
|
||||||
github.com/getkin/kin-openapi v0.113.0
|
github.com/glebarez/sqlite v1.8.0
|
||||||
github.com/gin-contrib/gzip v0.0.6
|
|
||||||
github.com/gin-gonic/gin v1.8.2
|
|
||||||
github.com/glebarez/sqlite v1.6.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/googollee/go-socket.io v1.6.2
|
github.com/google/uuid v1.5.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.10.0
|
github.com/labstack/echo/v4 v4.12.0
|
||||||
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/moby/sys/mount v0.3.3
|
github.com/moby/sys/mount v0.3.3
|
||||||
github.com/moby/sys/mountinfo v0.6.2
|
github.com/moby/sys/mountinfo v0.6.2
|
||||||
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 v1.2.0
|
github.com/robfig/cron/v3 v3.0.1
|
||||||
github.com/satori/go.uuid v1.2.0
|
github.com/samber/lo v1.38.1
|
||||||
github.com/shirou/gopsutil/v3 v3.22.11
|
github.com/shirou/gopsutil/v3 v3.23.2
|
||||||
github.com/sirupsen/logrus v1.9.0
|
github.com/sirupsen/logrus v1.9.3
|
||||||
github.com/stretchr/testify v1.8.1
|
github.com/stretchr/testify v1.9.0
|
||||||
github.com/tidwall/gjson v1.14.4
|
github.com/tidwall/gjson v1.17.0
|
||||||
|
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.5.0
|
golang.org/x/crypto v0.23.0
|
||||||
golang.org/x/oauth2 v0.3.0
|
golang.org/x/oauth2 v0.7.0
|
||||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c
|
golang.org/x/sync v0.3.0
|
||||||
gorm.io/gorm v1.24.3
|
golang.org/x/sys v0.20.0
|
||||||
|
gorm.io/gorm v1.25.0
|
||||||
gotest.tools v2.2.0+incompatible
|
gotest.tools v2.2.0+incompatible
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/andybalholm/brotli v1.0.1 // 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.0 // indirect
|
github.com/benbjohnson/clock v1.3.1 // indirect
|
||||||
github.com/coreos/go-systemd/v22 v22.3.2 // 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
|
||||||
|
github.com/dsoprea/go-logging v0.0.0-20200710184922-b02d349568dd // indirect
|
||||||
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/geoffgarside/ber v1.1.0 // indirect
|
github.com/geoffgarside/ber v1.1.0 // indirect
|
||||||
github.com/gin-contrib/sse v0.1.0 // indirect
|
github.com/glebarez/go-sqlite v1.21.1 // indirect
|
||||||
github.com/glebarez/go-sqlite v1.20.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.5 // indirect
|
github.com/go-openapi/jsonpointer v0.19.6 // indirect
|
||||||
github.com/go-openapi/swag v0.21.1 // indirect
|
github.com/go-openapi/swag v0.22.3 // indirect
|
||||||
github.com/go-playground/locales v0.14.0 // indirect
|
github.com/godbus/dbus/v5 v5.1.0 // indirect
|
||||||
github.com/go-playground/universal-translator v0.18.0 // indirect
|
github.com/gofrs/uuid v4.4.0+incompatible // indirect
|
||||||
github.com/go-playground/validator/v10 v10.11.1 // indirect
|
|
||||||
github.com/goccy/go-json v0.9.11 // indirect
|
|
||||||
github.com/godbus/dbus/v5 v5.0.4 // indirect
|
|
||||||
github.com/gofrs/uuid v4.0.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/v4 v4.4.2 // indirect
|
github.com/golang-jwt/jwt/v4 v4.5.0 // indirect
|
||||||
|
github.com/golang-jwt/jwt/v5 v5.0.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.2 // 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.5.9 // indirect
|
github.com/google/go-cmp v0.6.0 // indirect
|
||||||
github.com/google/go-querystring v1.0.0 // indirect
|
github.com/google/go-querystring v1.1.0 // indirect
|
||||||
github.com/google/uuid v1.3.0 // indirect
|
github.com/google/safetext v0.0.0-20240104143208-7a7d9b3d812f // indirect
|
||||||
github.com/gorilla/mux v1.8.0 // indirect
|
github.com/gorilla/mux v1.8.0 // indirect
|
||||||
github.com/invopop/yaml v0.1.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.15.13 // indirect
|
github.com/klauspost/compress v1.16.7 // indirect
|
||||||
github.com/klauspost/pgzip v1.2.5 // indirect
|
github.com/klauspost/pgzip v1.2.5 // indirect
|
||||||
github.com/labstack/gommon v0.4.0 // indirect
|
github.com/labstack/echo-jwt/v4 v4.2.0 // indirect
|
||||||
github.com/leodido/go-urn v1.2.1 // indirect
|
github.com/labstack/gommon v0.4.2 // indirect
|
||||||
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // 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.16 // indirect
|
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||||
github.com/mattn/go-sqlite3 v1.14.15 // 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.0 // indirect
|
github.com/nwaples/rardecode v1.1.3 // indirect
|
||||||
github.com/pelletier/go-toml/v2 v2.0.6 // indirect
|
|
||||||
github.com/perimeterx/marshmallow v1.1.4 // indirect
|
github.com/perimeterx/marshmallow v1.1.4 // indirect
|
||||||
github.com/pierrec/lz4/v4 v4.1.2 // 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-20210106213030-5aafc221ea8c // indirect
|
github.com/power-devops/perfstat v0.0.0-20221212215047-62379fc7944b // indirect
|
||||||
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 // indirect
|
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
|
||||||
github.com/tidwall/match v1.1.1 // indirect
|
github.com/tidwall/match v1.1.1 // indirect
|
||||||
github.com/tidwall/pretty v1.2.0 // 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/ugorji/go/codec v1.2.7 // indirect
|
github.com/ugorji/go/codec v1.2.11 // indirect
|
||||||
github.com/ulikunitz/xz v0.5.9 // 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
|
||||||
github.com/valyala/fasttemplate v1.2.2 // indirect
|
github.com/valyala/fasttemplate v1.2.2 // indirect
|
||||||
github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 // indirect
|
github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 // indirect
|
||||||
github.com/yusufpapurcu/wmi v1.2.2 // indirect
|
github.com/yusufpapurcu/wmi v1.2.2 // indirect
|
||||||
go.uber.org/atomic v1.7.0 // indirect
|
go.uber.org/atomic v1.10.0 // indirect
|
||||||
go.uber.org/multierr v1.6.0 // indirect
|
go.uber.org/multierr v1.11.0 // indirect
|
||||||
golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8 // indirect
|
golang.org/x/exp v0.0.0-20230713183714-613f0c0eb8a1 // indirect
|
||||||
golang.org/x/net v0.5.0 // indirect
|
golang.org/x/image v0.6.0 // indirect
|
||||||
golang.org/x/sys v0.4.0 // indirect
|
golang.org/x/net v0.25.0 // indirect
|
||||||
golang.org/x/text v0.6.0 // indirect
|
golang.org/x/text v0.15.0 // indirect
|
||||||
golang.org/x/time v0.2.0 // indirect
|
golang.org/x/time v0.5.0 // indirect
|
||||||
google.golang.org/appengine v1.6.7 // indirect
|
google.golang.org/appengine v1.6.7 // indirect
|
||||||
google.golang.org/protobuf v1.28.1 // indirect
|
google.golang.org/protobuf v1.30.0 // indirect
|
||||||
gopkg.in/ini.v1 v1.67.0 // indirect
|
gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect
|
||||||
gopkg.in/natefinch/lumberjack.v2 v2.0.0 // 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.21.5 // indirect
|
modernc.org/libc v1.22.4 // indirect
|
||||||
modernc.org/mathutil v1.5.0 // indirect
|
modernc.org/mathutil v1.5.0 // indirect
|
||||||
modernc.org/memory v1.4.0 // indirect
|
modernc.org/memory v1.5.0 // indirect
|
||||||
modernc.org/sqlite v1.20.0 // indirect
|
modernc.org/sqlite v1.21.2 // indirect
|
||||||
|
mvdan.cc/sh/v3 v3.7.0 // indirect
|
||||||
)
|
)
|
||||||
|
|||||||
338
go.sum
338
go.sum
@ -1,31 +1,26 @@
|
|||||||
github.com/BurntSushi/toml v1.2.0 h1:Rt8g24XnyGTyglgET/PRUNlrUeu9F5L+7FilkXfZgs0=
|
|
||||||
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.2-alpha3 h1:WJUYo+hJpLmza7mQngoJVeUJOfnrZevNrX5wzTuOJo0=
|
github.com/IceWhaleTech/CasaOS-Common v0.4.11-alpha4 h1:W+kOJ3NcWCEAnZdjqmnjnhAG+aLbiVNXnOvV+1bHsB0=
|
||||||
github.com/IceWhaleTech/CasaOS-Common v0.4.2-alpha3/go.mod h1:xcemiRsXcs1zrmQxYMyExDjZ7UHYwkJqYE71IDIV0xA=
|
github.com/IceWhaleTech/CasaOS-Common v0.4.11-alpha4/go.mod h1:513p+6RXPBFr98GQZbY1TCyt6Q0jWiuK6vh+gBTmNwA=
|
||||||
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/Xhofe/go-cache v0.0.0-20220723083548-714439c8af9a h1:RenIAa2q4H8UcS/cqmwdT1WCWIAH5aumP8m8RpbqVsE=
|
|
||||||
github.com/Xhofe/go-cache v0.0.0-20220723083548-714439c8af9a/go.mod h1:sSBbaOg90XwWKtpT56kVujF0bIeVITnPlssLclogS04=
|
|
||||||
github.com/andybalholm/brotli v1.0.1 h1:KqhlKozYbRtJvsPrrEeXcO+N2l6NYT5A2QAFmSULpEc=
|
|
||||||
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/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.0 h1:ip6w0uFQkncKQ979AypyG0ER7mqUSBdKLOgAle/AT8A=
|
github.com/benbjohnson/clock v1.3.1 h1:Heo0FGXzOxUHquZbraxt+tT7UXVDhesUQH5ISbsOkCQ=
|
||||||
github.com/benbjohnson/clock v1.3.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
|
github.com/benbjohnson/clock v1.3.1/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/chzyer/logex v1.2.0/go.mod h1:9+9sk7u7pGNWYMkh0hdiL++6OeibzJccyQU4p4MedaY=
|
|
||||||
github.com/chzyer/readline v1.5.0/go.mod h1:x22KAscuvRqlLoK9CsoYsmxoXZMMFVyOl86cAH8qUic=
|
|
||||||
github.com/chzyer/test v0.0.0-20210722231415-061457976a23/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
|
|
||||||
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.3.2 h1:D9/bQk5vlXQFZ6Kwuu6zaiXJ9oTPe68++AzAJc1DzSI=
|
github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs=
|
||||||
github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
|
github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
|
||||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/deckarep/golang-set/v2 v2.1.0 h1:g47V4Or+DUdzbs8FxCCmgb6VYd+ptPAngjM6dtGktsI=
|
github.com/deckarep/golang-set/v2 v2.3.0 h1:qs18EKUfHm2X9fA50Mr/M5hccg2tNnVqsiBImnyDs0g=
|
||||||
github.com/deckarep/golang-set/v2 v2.1.0/go.mod h1:VAky9rY/yGXJOLEDv3OMci+7wtDpOF4IN+y82NBOac4=
|
github.com/deckarep/golang-set/v2 v2.3.0/go.mod h1:VAky9rY/yGXJOLEDv3OMci+7wtDpOF4IN+y82NBOac4=
|
||||||
github.com/deepmap/oapi-codegen v1.12.4 h1:pPmn6qI9MuOtCz82WY2Xaw46EQjgvxednXXrP7g5Q2s=
|
github.com/deepmap/oapi-codegen v1.12.4 h1:pPmn6qI9MuOtCz82WY2Xaw46EQjgvxednXXrP7g5Q2s=
|
||||||
github.com/deepmap/oapi-codegen v1.12.4/go.mod h1:3lgHGMu6myQ2vqbbTXH2H1o4eXFTGnFiDaOaKKl5yas=
|
github.com/deepmap/oapi-codegen v1.12.4/go.mod h1:3lgHGMu6myQ2vqbbTXH2H1o4eXFTGnFiDaOaKKl5yas=
|
||||||
github.com/disintegration/imaging v1.6.2 h1:w1LecBlG2Lnp8B3jk5zSuNqd7b4DXhcjwek1ei82L+c=
|
github.com/disintegration/imaging v1.6.2 h1:w1LecBlG2Lnp8B3jk5zSuNqd7b4DXhcjwek1ei82L+c=
|
||||||
@ -38,8 +33,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.0-20221012082141-d21ac8e2de85 h1:vZkWA0Lduu9QB6qRBtsLy7m5uO/RFNCDH2pzMLTxGts=
|
github.com/dsoprea/go-exif/v3 v3.0.1 h1:/IE4iW7gvY7BablV1XY0unqhMv26EYpOquVMwoBo/wc=
|
||||||
github.com/dsoprea/go-exif/v3 v3.0.0-20221012082141-d21ac8e2de85/go.mod h1:10HkA1Wz3h398cDP66L+Is9kKDmlqlIJGPv8pk4EWvc=
|
github.com/dsoprea/go-exif/v3 v3.0.1/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=
|
||||||
@ -50,22 +45,18 @@ github.com/dsoprea/go-utility/v2 v2.0.0-20221003142440-7a1927d49d9d/go.mod h1:LV
|
|||||||
github.com/dsoprea/go-utility/v2 v2.0.0-20221003160719-7bc88537c05e/go.mod h1:VZ7cB0pTjm1ADBWhJUOHESu4ZYy9JN+ZPqjfiW09EPU=
|
github.com/dsoprea/go-utility/v2 v2.0.0-20221003160719-7bc88537c05e/go.mod h1:VZ7cB0pTjm1ADBWhJUOHESu4ZYy9JN+ZPqjfiW09EPU=
|
||||||
github.com/dsoprea/go-utility/v2 v2.0.0-20221003172846-a3e1774ef349 h1:DilThiXje0z+3UQ5YjYiSRRzVdtamFpvBQXKwMglWqw=
|
github.com/dsoprea/go-utility/v2 v2.0.0-20221003172846-a3e1774ef349 h1:DilThiXje0z+3UQ5YjYiSRRzVdtamFpvBQXKwMglWqw=
|
||||||
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.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
|
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/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.113.0 h1:t9aNS/q5Agr7a55Jp1AuZ3sR2WzHESv3Dd2ys4UphsM=
|
github.com/getkin/kin-openapi v0.117.0 h1:QT2DyGujAL09F4NrKDHJGsUoIprlIcFVHWDVDcUFE8A=
|
||||||
github.com/getkin/kin-openapi v0.113.0/go.mod h1:l5e9PaFUo9fyLJCPGQeXI2ML8c3P8BHOEV2VaAVf/pc=
|
github.com/getkin/kin-openapi v0.117.0/go.mod h1:l5e9PaFUo9fyLJCPGQeXI2ML8c3P8BHOEV2VaAVf/pc=
|
||||||
github.com/gin-contrib/gzip v0.0.6 h1:NjcunTcGAj5CO1gn4N8jHOSIeRFHIbn51z6K+xaN4d4=
|
github.com/glebarez/go-sqlite v1.21.1 h1:7MZyUPh2XTrHS7xNEHQbrhfMZuPSzhkm2A1qgg0y5NY=
|
||||||
github.com/gin-contrib/gzip v0.0.6/go.mod h1:QOJlmV2xmayAjkNS2Y8NQsMneuRShOU/kjovCXNuzzk=
|
github.com/glebarez/go-sqlite v1.21.1/go.mod h1:ISs8MF6yk5cL4n/43rSOmVMGJJjHYr7L2MbZZ5Q4E2E=
|
||||||
github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
|
github.com/glebarez/sqlite v1.8.0 h1:02X12E2I/4C1n+v90yTqrjRa8yuo7c3KeHI3FRznCvc=
|
||||||
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
|
github.com/glebarez/sqlite v1.8.0/go.mod h1:bpET16h1za2KOOMb8+jCp6UBP/iahDpfPQqSaYLTLx8=
|
||||||
github.com/gin-gonic/gin v1.8.1/go.mod h1:ji8BvRH1azfM+SYow9zQ6SZMvR8qOMZHmsCuWR9tTTk=
|
|
||||||
github.com/gin-gonic/gin v1.8.2 h1:UzKToD9/PoFj/V4rvlKqTRKnQYyz8Sc1MJlv4JHPtvY=
|
|
||||||
github.com/gin-gonic/gin v1.8.2/go.mod h1:qw5AYuDrzRTnhvusDsrov+fDIxp9Dleuu12h8nfB398=
|
|
||||||
github.com/glebarez/go-sqlite v1.20.0 h1:6D9uRXq3Kd+W7At+hOU2eIAeahv6qcYfO8jzmvb4Dr8=
|
|
||||||
github.com/glebarez/go-sqlite v1.20.0/go.mod h1:uTnJoqtwMQjlULmljLT73Cg7HB+2X6evsBHODyyq1ak=
|
|
||||||
github.com/glebarez/sqlite v1.6.0 h1:ZpvDLv4zBi2cuuQPitRiVz/5Uh6sXa5d8eBu0xNTpAo=
|
|
||||||
github.com/glebarez/sqlite v1.6.0/go.mod h1:6D6zPU/HTrFlYmVDKqBJlmQvma90P6r7sRRdkUUZOYk=
|
|
||||||
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=
|
||||||
@ -75,35 +66,28 @@ github.com/go-ini/ini v1.67.0 h1:z6ZrTEZqSWOTyH2FlglNbNgARyHG8oLW9gMELqKr06A=
|
|||||||
github.com/go-ini/ini v1.67.0/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8=
|
github.com/go-ini/ini v1.67.0/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8=
|
||||||
github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY=
|
github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY=
|
||||||
github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
|
github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
|
||||||
github.com/go-openapi/jsonpointer v0.19.5 h1:gZr+CIYByUqjcgeLXnQu2gHYQC9o73G2XUeOFYEICuY=
|
|
||||||
github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
|
github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
|
||||||
|
github.com/go-openapi/jsonpointer v0.19.6 h1:eCs3fxoIi3Wh6vtgmLTOjdhSpiqphQ+DaPn38N2ZdrE=
|
||||||
|
github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs=
|
||||||
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.21.1 h1:wm0rhTb5z7qpJRHBdPOMuY4QjVUMbF6/kwoYeRAOrKU=
|
github.com/go-openapi/swag v0.22.3 h1:yMBqmnQ0gyZvEb/+KzuWZOXgllrXT4SADYbvDaXHv/g=
|
||||||
github.com/go-openapi/swag v0.21.1/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ=
|
github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14=
|
||||||
github.com/go-playground/assert/v2 v2.0.1 h1:MsBgLAaY856+nPRTKrp3/OZK38U/wa0CcBYNjji3q3A=
|
|
||||||
github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
|
|
||||||
github.com/go-playground/locales v0.14.0 h1:u50s323jtVGugKlcYeyzC0etD1HifMjqmJqb8WugfUU=
|
|
||||||
github.com/go-playground/locales v0.14.0/go.mod h1:sawfccIbzZTqEDETgFXqTho0QybSa7l++s0DH+LDiLs=
|
|
||||||
github.com/go-playground/universal-translator v0.18.0 h1:82dyy6p4OuJq4/CByFNOn/jYrnRPArHwAcmLoJZxyho=
|
|
||||||
github.com/go-playground/universal-translator v0.18.0/go.mod h1:UvRDBj+xPUEGrFYl+lu/H90nyDXpg0fqeB/AQUGNTVA=
|
|
||||||
github.com/go-playground/validator/v10 v10.10.0/go.mod h1:74x4gJWsvQexRdW8Pn3dXSGrTK4nAUsbPlLADvpJkos=
|
|
||||||
github.com/go-playground/validator/v10 v10.11.1 h1:prmOlTVv+YjZjmRmNSF3VmspqJIxJWXmqUsHwfTRRkQ=
|
|
||||||
github.com/go-playground/validator/v10 v10.11.1/go.mod h1:i+3WkQ1FvaUjjxh1kSvIA4dMGDBiPU55YFDl0WbKdWU=
|
|
||||||
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.9.11 h1:/pAaQDLHEoCq/5FFmSKBswWmK6H0e8g4159Kc/X/nqk=
|
|
||||||
github.com/goccy/go-json v0.9.11/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
|
|
||||||
github.com/godbus/dbus/v5 v5.0.4 h1:9349emZab16e7zQvpmsbtjc18ykshndd8y2PG3sgJbA=
|
|
||||||
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/gofrs/uuid v4.0.0+incompatible h1:1SD/1F5pU8p29ybwgQSwpQk+mwdRrXCYuPhW6m+TnJw=
|
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/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
|
github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
|
||||||
|
github.com/gofrs/uuid v4.4.0+incompatible h1:3qXRTX8/NbyulANqlc0lchS1gqAVxRgsuW1YrTJupqA=
|
||||||
|
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/v4 v4.4.2 h1:rcc4lwaZgFMCZ5jxF9ABolDcIHdBytAFgqFPbSJQAYs=
|
github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg=
|
||||||
github.com/golang-jwt/jwt/v4 v4.4.2/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
|
github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
|
||||||
|
github.com/golang-jwt/jwt/v5 v5.0.0 h1:1n1XNM9hk7O9mnQoNBGolZvzebBQ7p93ULHRc28XJUE=
|
||||||
|
github.com/golang-jwt/jwt/v5 v5.0.0/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
|
||||||
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=
|
||||||
@ -113,29 +97,34 @@ github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+Licev
|
|||||||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
||||||
github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
|
github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
|
||||||
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
||||||
github.com/golang/snappy v0.0.2/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
github.com/golang/snappy v0.0.2/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||||
github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
|
github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
|
||||||
github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||||
github.com/gomodule/redigo v1.8.4/go.mod h1:P9dn9mFrCBvWhGE1wpxx6fgq7BAeLBk+UUUzlpkBYO0=
|
github.com/gomodule/redigo v1.8.4/go.mod h1:P9dn9mFrCBvWhGE1wpxx6fgq7BAeLBk+UUUzlpkBYO0=
|
||||||
github.com/gomodule/redigo v1.8.9 h1:Sl3u+2BI/kk+VEatbj0scLdrFhjPmbxOc1myhDP41ws=
|
github.com/gomodule/redigo v1.8.9 h1:Sl3u+2BI/kk+VEatbj0scLdrFhjPmbxOc1myhDP41ws=
|
||||||
github.com/gomodule/redigo v1.8.9/go.mod h1:7ArFNvsTjH8GMMzB4uy1snslv2BwmginuMs06a1uzZE=
|
github.com/gomodule/redigo v1.8.9/go.mod h1:7ArFNvsTjH8GMMzB4uy1snslv2BwmginuMs06a1uzZE=
|
||||||
github.com/google/go-cmp v0.5.3/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 h1:Xkwi/a1rcvNg1PPYe5vI8GbeBY/jrVuDX5ASuANWTrk=
|
|
||||||
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=
|
||||||
|
github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8=
|
||||||
|
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/go.mod h1:dDKJzRmX4S37WGHujM7tX//fmj1uioxKzKxz3lo4HJo=
|
github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26/go.mod h1:dDKJzRmX4S37WGHujM7tX//fmj1uioxKzKxz3lo4HJo=
|
||||||
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
|
github.com/google/safetext v0.0.0-20240104143208-7a7d9b3d812f h1:o2yGZLlsOj5H5uvtQNEdi6DeA0GbUP3lm0gWW5RvY0s=
|
||||||
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
github.com/google/safetext v0.0.0-20240104143208-7a7d9b3d812f/go.mod h1:H3K1Iu/utuCfa10JO+GsmKUYSWi7ug57Rk6GaDRHaaQ=
|
||||||
github.com/googollee/go-socket.io v1.6.2 h1:olKLLHJtHz1IkL/OrTyNriZZvVQYEORNkJAqsOwPask=
|
github.com/google/uuid v1.5.0 h1:1p67kYwdtXjb0gL0BPiP1Av9wiZPo5A8z2cWkTZ+eyU=
|
||||||
github.com/googollee/go-socket.io v1.6.2/go.mod h1:0vGP8/dXR9SZUMMD4+xxaGo/lohOw3YWMh2WRiWeKxg=
|
github.com/google/uuid v1.5.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/go.mod h1:0vGP8/dXR9SZUMMD4+xxaGo/lohOw3YWMh2WRiWeKxg=
|
||||||
github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI=
|
github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI=
|
||||||
github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
|
github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
|
||||||
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||||
@ -145,14 +134,13 @@ github.com/h2non/filetype v1.1.3 h1:FKkx9QbD7HR/zjK1Ia5XiBsq9zdLi5Kf3zGyFTAFkGg=
|
|||||||
github.com/h2non/filetype v1.1.3/go.mod h1:319b3zT68BvV+WRj7cwy856M2ehB3HqNOt6sy1HndBY=
|
github.com/h2non/filetype v1.1.3/go.mod h1:319b3zT68BvV+WRj7cwy856M2ehB3HqNOt6sy1HndBY=
|
||||||
github.com/hirochachacha/go-smb2 v1.1.0 h1:b6hs9qKIql9eVXAiN0M2wSFY5xnhbHAQoCwRKbaRTZI=
|
github.com/hirochachacha/go-smb2 v1.1.0 h1:b6hs9qKIql9eVXAiN0M2wSFY5xnhbHAQoCwRKbaRTZI=
|
||||||
github.com/hirochachacha/go-smb2 v1.1.0/go.mod h1:8F1A4d5EZzrGu5R7PU163UcMRDJQl4FtcxjBfsY8TZE=
|
github.com/hirochachacha/go-smb2 v1.1.0/go.mod h1:8F1A4d5EZzrGu5R7PU163UcMRDJQl4FtcxjBfsY8TZE=
|
||||||
github.com/ianlancetaylor/demangle v0.0.0-20220319035150-800ac71e25c2/go.mod h1:aYm2/VgdVmcIU8iMfdMvDMsRAQjcfZSKFby6HOFvi/w=
|
|
||||||
github.com/invopop/yaml v0.1.0 h1:YW3WGUoJEXYfzWBjn00zIlrw7brGVD0fUKRYDPAPhrc=
|
|
||||||
github.com/invopop/yaml v0.1.0/go.mod h1:2XuRLgs/ouIrW3XNzuNj7J3Nvu/Dig5MXvbCEdiBN3Q=
|
github.com/invopop/yaml v0.1.0/go.mod h1:2XuRLgs/ouIrW3XNzuNj7J3Nvu/Dig5MXvbCEdiBN3Q=
|
||||||
|
github.com/invopop/yaml v0.2.0 h1:7zky/qH+O0DwAyoobXUqvVBwgBFRxKoQ/3FjcVpjTMY=
|
||||||
|
github.com/invopop/yaml v0.2.0/go.mod h1:2XuRLgs/ouIrW3XNzuNj7J3Nvu/Dig5MXvbCEdiBN3Q=
|
||||||
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
|
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
|
||||||
github.com/jessevdk/go-flags v1.5.0/go.mod h1:Fw0T6WPc1dYxT4mKEZRfG5kJhaTDP9pj1c2EWnYs/m4=
|
github.com/jessevdk/go-flags v1.5.0/go.mod h1:Fw0T6WPc1dYxT4mKEZRfG5kJhaTDP9pj1c2EWnYs/m4=
|
||||||
github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
|
github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
|
||||||
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
|
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
|
||||||
github.com/jinzhu/now v1.1.4/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
|
|
||||||
github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ=
|
github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ=
|
||||||
github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
|
github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
|
||||||
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
|
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
|
||||||
@ -160,47 +148,45 @@ github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFF
|
|||||||
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
|
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
|
||||||
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
|
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
|
||||||
github.com/juju/gnuflag v0.0.0-20171113085948-2ce1bb71843d/go.mod h1:2PavIy+JPciBPrBUjwbNvtwB6RQlve+hkpll6QSNmOE=
|
github.com/juju/gnuflag v0.0.0-20171113085948-2ce1bb71843d/go.mod h1:2PavIy+JPciBPrBUjwbNvtwB6RQlve+hkpll6QSNmOE=
|
||||||
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8=
|
|
||||||
github.com/klauspost/compress v1.4.1/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
|
github.com/klauspost/compress v1.4.1/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
|
||||||
github.com/klauspost/compress v1.11.4/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
|
github.com/klauspost/compress v1.11.4/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
|
||||||
github.com/klauspost/compress v1.15.13 h1:NFn1Wr8cfnenSJSA46lLq4wHCcBzKTSjnBIexDMMOV0=
|
github.com/klauspost/compress v1.16.7 h1:2mk3MPGNzKyxErAw8YaohYh69+pa4sIQSC0fPGCFR9I=
|
||||||
github.com/klauspost/compress v1.15.13/go.mod h1:QPwzmACJjUTFsnSHH934V6woptycfrDDJnH7hvFVbGM=
|
github.com/klauspost/compress v1.16.7/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/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 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
|
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||||
github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=
|
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/v4 v4.10.0 h1:5CiyngihEO4HXsz3vVsJn7f8xAlWwRr3aY6Ih280ZKA=
|
github.com/labstack/echo-jwt/v4 v4.2.0 h1:odSISV9JgcSCuhgQSV/6Io3i7nUmfM/QkBeR5GVJj5c=
|
||||||
github.com/labstack/echo/v4 v4.10.0/go.mod h1:S/T/5fy/GigaXnHTkh0ZGe4LpkkQysvRjFMSUTkDRNQ=
|
github.com/labstack/echo-jwt/v4 v4.2.0/go.mod h1:MA2RqdXdEn4/uEglx0HcUOgQSyBaTh5JcaHIan3biwU=
|
||||||
github.com/labstack/gommon v0.4.0 h1:y7cvthEAEbU0yHOf4axH8ZG2NH8knB9iNSoTO8dyIk8=
|
github.com/labstack/echo/v4 v4.12.0 h1:IKpw49IMryVB2p1a4dzwlhP1O2Tf2E0Ir/450lH+kI0=
|
||||||
github.com/labstack/gommon v0.4.0/go.mod h1:uW6kP17uPlLJsD3ijUYn3/M5bAxtlZhMI6m3MFxTMTM=
|
github.com/labstack/echo/v4 v4.12.0/go.mod h1:UP9Cr2DJXbOK3Kr9ONYzNowSh7HP0aG0ShAyycHSJvM=
|
||||||
github.com/leodido/go-urn v1.2.1 h1:BqpAaACuzVSgi/VLzGZIobT2z4v53pjosyNd9Yv6n/w=
|
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/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ81pIr0yLvtUWk2if982qA3F3QD6H4=
|
|
||||||
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/go.mod h1:JKx41uQRwqlTZabZc+kILPrO/3jlKnQ2Z8b7YiVw5cE=
|
||||||
github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
||||||
github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
||||||
github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
|
|
||||||
github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
|
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 h1:bq3VjFmv/sOjHtdEhmkEV4x1AJtvUvOJ2PFAZ5+peKQ=
|
|
||||||
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-sqlite3 v1.14.15 h1:vfoHhTN1af61xCRSWzFIWzx2YskyMTwHLrExkBOjvxI=
|
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
||||||
github.com/mattn/go-sqlite3 v1.14.15/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg=
|
github.com/mattn/go-isatty v0.0.20/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/go.mod h1:3d8TOmwL/5I8pJjyVDteHtgDGcefrFUX4ccGOMKNYYc=
|
||||||
github.com/moby/sys/mount v0.3.3 h1:fX1SVkXFJ47XWDoeFW4Sq7PdQJnV2QIDZAqjNqgEjUs=
|
github.com/moby/sys/mount v0.3.3 h1:fX1SVkXFJ47XWDoeFW4Sq7PdQJnV2QIDZAqjNqgEjUs=
|
||||||
github.com/moby/sys/mount v0.3.3/go.mod h1:PBaEorSNTLG5t/+4EgukEQVlAvVEc6ZjTySwKdqp5K0=
|
github.com/moby/sys/mount v0.3.3/go.mod h1:PBaEorSNTLG5t/+4EgukEQVlAvVEc6ZjTySwKdqp5K0=
|
||||||
github.com/moby/sys/mountinfo v0.6.2 h1:BzJjoreD5BMFNmD9Rus6gdd1pLuecOFPt8wC+Vygl78=
|
github.com/moby/sys/mountinfo v0.6.2 h1:BzJjoreD5BMFNmD9Rus6gdd1pLuecOFPt8wC+Vygl78=
|
||||||
@ -212,96 +198,100 @@ github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9G
|
|||||||
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
||||||
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 h1:RWengNIwukTxcDr9M+97sNutRR1RKhG96O6jWumTTnw=
|
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 h1:RWengNIwukTxcDr9M+97sNutRR1RKhG96O6jWumTTnw=
|
||||||
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8=
|
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8=
|
||||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
|
|
||||||
github.com/nwaples/rardecode v1.1.0 h1:vSxaY8vQhOcVr4mm5e8XllHWTiM4JF507A0Katqw7MQ=
|
|
||||||
github.com/nwaples/rardecode v1.1.0/go.mod h1:5DzqNKiOdpKKBH87u8VlvAnPZMXcGRhxWkRpHbbfGS0=
|
github.com/nwaples/rardecode v1.1.0/go.mod h1:5DzqNKiOdpKKBH87u8VlvAnPZMXcGRhxWkRpHbbfGS0=
|
||||||
|
github.com/nwaples/rardecode v1.1.3 h1:cWCaZwfM5H7nAD6PyEdcVnczzV8i/JtotnyW/dD9lEc=
|
||||||
|
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.6 h1:nrzqCb7j9cDFj2coyLNLaZuJTLjWjlaz6nvTvIwycIU=
|
|
||||||
github.com/pelletier/go-toml/v2 v2.0.6/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 h1:qvY3YFXRQE/XB8MlLzJH7mSzBs74eA2gg52YTk6jUPM=
|
|
||||||
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/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
|
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/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=
|
||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c h1:ncq/mPwQF4JjgDlrVEn3C11VoGHZN7m8qihwgMEtzYw=
|
|
||||||
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE=
|
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE=
|
||||||
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 h1:OdAsTTz6OkFY5QxjkYwrChwuRruF69c169dPK26NUlk=
|
github.com/power-devops/perfstat v0.0.0-20221212215047-62379fc7944b h1:0LFwY6Q3gMACTjAbMZBjXAqTOzOwFaj2Ld6cjeQ7Rig=
|
||||||
|
github.com/power-devops/perfstat v0.0.0-20221212215047-62379fc7944b/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE=
|
||||||
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
|
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
|
||||||
github.com/robfig/cron v1.2.0 h1:ZjScXvvxeQ63Dbyxy76Fj3AT3Ut0aKsyd2/tl3DTMuQ=
|
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE=
|
||||||
github.com/robfig/cron v1.2.0/go.mod h1:JGuDeoQd7Z6yL4zQhZ3OPEVHB7fL6Ka6skscFHfmt2k=
|
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
|
||||||
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
|
github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs=
|
||||||
github.com/rogpeppe/go-internal v1.8.0 h1:FCbCCtXNOY3UtUuHUYaghJg4y7Fd14rXifAYUAtL9R8=
|
github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro=
|
||||||
github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE=
|
github.com/rogpeppe/go-internal v1.10.1-0.20230524175051-ec119421bb97 h1:3RPlVWzZ/PDqmVuf/FKHARG5EMid/tl7cv54Sw/QRVY=
|
||||||
github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww=
|
github.com/rogpeppe/go-internal v1.10.1-0.20230524175051-ec119421bb97/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA=
|
||||||
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
|
github.com/samber/lo v1.38.1 h1:j2XEAqXKb09Am4ebOg31SpvzUTTs6EN3VfgeLUhPdXM=
|
||||||
github.com/shirou/gopsutil/v3 v3.22.11 h1:kxsPKS+Eeo+VnEQ2XCaGJepeP6KY53QoRTETx3+1ndM=
|
github.com/samber/lo v1.38.1/go.mod h1:+m/ZKRl6ClXCE2Lgf3MsQlWfh4bn1bz6CXEOxnEXnEA=
|
||||||
github.com/shirou/gopsutil/v3 v3.22.11/go.mod h1:xl0EeL4vXJ+hQMAGN8B9VFpxukEMA0XdevQOe5MZ1oY=
|
github.com/shirou/gopsutil/v3 v3.23.2 h1:PAWSuiAszn7IhPMBtXsbSCafej7PqUOvY6YywlQUExU=
|
||||||
github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0=
|
github.com/shirou/gopsutil/v3 v3.23.2/go.mod h1:gv0aQw33GLo3pG8SiWKiQrbDzbRY1K80RyZJ7V4Th1M=
|
||||||
github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
|
||||||
|
github.com/sirupsen/logrus v1.9.3/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 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
|
|
||||||
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/tidwall/gjson v1.14.4 h1:uo0p8EbA09J7RQaflQ1aBRffTR7xedD2bcIVSYxLnkM=
|
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||||
github.com/tidwall/gjson v1.14.4/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
|
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
|
||||||
|
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||||
|
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 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs=
|
|
||||||
github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
|
github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
|
||||||
|
github.com/tidwall/pretty v1.2.1 h1:qjsOFOWWQl+N3RsoF5/ssm1pHmJJwhjlSbZ51I6wMl4=
|
||||||
|
github.com/tidwall/pretty v1.2.1/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
|
||||||
github.com/tklauser/go-sysconf v0.3.11 h1:89WgdJhk5SNwJfu+GKyYveZ4IaJ7xAkecBo+KdJV0CM=
|
github.com/tklauser/go-sysconf v0.3.11 h1:89WgdJhk5SNwJfu+GKyYveZ4IaJ7xAkecBo+KdJV0CM=
|
||||||
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/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 h1:YPXUKf7fYbp/y8xloBqZOw2qaVggbfwMlI8WM3wZUJ0=
|
|
||||||
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/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
|
||||||
github.com/ulikunitz/xz v0.5.8/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
|
github.com/ulikunitz/xz v0.5.8/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
|
||||||
github.com/ulikunitz/xz v0.5.9 h1:RsKRIA2MO8x56wkkcd3LbtcE/uMszhb6DpRf+3uwa3I=
|
|
||||||
github.com/ulikunitz/xz v0.5.9/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
|
github.com/ulikunitz/xz v0.5.9/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
|
||||||
|
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/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=
|
||||||
github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8/go.mod h1:HUYIGzjTL3rfEspMxjDjgmT5uz5wzYJKVo23qUhYTos=
|
github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8/go.mod h1:HUYIGzjTL3rfEspMxjDjgmT5uz5wzYJKVo23qUhYTos=
|
||||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
|
||||||
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||||
|
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||||
github.com/yusufpapurcu/wmi v1.2.2 h1:KBNDSne4vP5mbSWnJbO+51IMOXJB67QiYCSBrubbPRg=
|
github.com/yusufpapurcu/wmi v1.2.2 h1:KBNDSne4vP5mbSWnJbO+51IMOXJB67QiYCSBrubbPRg=
|
||||||
github.com/yusufpapurcu/wmi v1.2.2/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
|
github.com/yusufpapurcu/wmi v1.2.2/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
|
||||||
go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw=
|
go.uber.org/atomic v1.10.0 h1:9qC72Qh0+3MqyJbAn8YU5xVq1frD8bn3JtD2oXtafVQ=
|
||||||
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
|
go.uber.org/atomic v1.10.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0=
|
||||||
go.uber.org/goleak v1.1.11 h1:wy28qYRKZgnJTxGxvye5/wgWr1EKjmUDGYox5mGlRlI=
|
go.uber.org/goleak v1.2.1 h1:NBol2c7O1ZokfZ0LEU9K6Whx/KnwvepVetCUhtKja4A=
|
||||||
go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4=
|
go.uber.org/goleak v1.2.1/go.mod h1:qlT2yGI9QafXHhZZLxlSuNsMw3FFLxBr+tBRlmO1xH4=
|
||||||
go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
|
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/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/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-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
|
||||||
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-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI=
|
||||||
golang.org/x/crypto v0.5.0 h1:U/0M97KRkSFvyD/3FSmdP5W5swImpNgle/EHFhOsQPE=
|
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
|
||||||
golang.org/x/crypto v0.5.0/go.mod h1:NK/OQwhpMQP3MwtdjgLlYHnH9ebylxKWv3e0fK+mkQU=
|
golang.org/x/exp v0.0.0-20230713183714-613f0c0eb8a1 h1:MGwJjxBy0HJshjDNfLsYO8xppfqWlA5ZT9OhtUUhTNw=
|
||||||
golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8 h1:hVwzHzIUGRjiF7EcUjqNxk3NCfkPxbDKRdnNE1Rpg0U=
|
golang.org/x/exp v0.0.0-20230713183714-613f0c0eb8a1/go.mod h1:FXUEEKJgO7OQYeo8N01OfiKP8RXMtf6e8aTskBGqWdc=
|
||||||
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/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
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/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||||
|
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||||
|
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
|
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
|
||||||
@ -310,26 +300,27 @@ golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLL
|
|||||||
golang.org/x/net v0.0.0-20200320220750-118fecf932d8/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
golang.org/x/net v0.0.0-20200320220750-118fecf932d8/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||||
golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||||
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
|
||||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||||
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
||||||
golang.org/x/net v0.0.0-20211029224645-99673261e6eb/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
golang.org/x/net v0.0.0-20211029224645-99673261e6eb/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
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.5.0 h1:GyT4nK/YDHSqa1c4753ouYCDajOYKTja9Xb/OHtgvSw=
|
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||||
golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws=
|
golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac=
|
||||||
|
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
|
||||||
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.3.0 h1:6l90koy8/LaBLmLu8jpHeHexzMwEita0zFfYlggy2F8=
|
golang.org/x/oauth2 v0.7.0 h1:qe6s0zUXlPX80/dITx3440hWZ7GwMwgDDyrSGTPJG/g=
|
||||||
golang.org/x/oauth2 v0.3.0/go.mod h1:rQrIauxkUhJ6CuwEXwymO2/eh4xz2ZWF1nBkcxS+tGk=
|
golang.org/x/oauth2 v0.7.0/go.mod h1:hPLQkd9LyjfXTiRohC/41GhcFqxisoUQ99sCUOHO9x4=
|
||||||
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-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
|
||||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ=
|
|
||||||
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.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=
|
||||||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
@ -337,35 +328,38 @@ 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-20220310020820-b874c991c1a5/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-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-20220728004956-3c1f35247d10/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-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220928140112-f11e5e49a4ec/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220928140112-f11e5e49a4ec/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
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.4.0 h1:Zr2JFtRQNX3BCZ8YtxRE9hNJYC8J6I1MVbMg6owUp18=
|
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.4.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.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
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.4.0 h1:O7UWfv5+A2qiuulQk30kVinPoMtoIPeVaKLEgLpVkvg=
|
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.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=
|
||||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
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.6.0 h1:3XmdazWV+ubf7QgHSTWeykHOci5oeekaGJBLkrkaw4k=
|
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||||
golang.org/x/text v0.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||||
golang.org/x/time v0.2.0 h1:52I/1L54xyEQAYdtcSuxtiT84KGYTBGXwayxmIpNJhE=
|
golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk=
|
||||||
golang.org/x/time v0.2.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||||
|
golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk=
|
||||||
|
golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
|
||||||
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.0.0-20201124115921-2c860bdd6e78/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
|
||||||
golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||||
|
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||||
|
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
||||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
@ -375,19 +369,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.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w=
|
google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||||
google.golang.org/protobuf v1.28.1/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-20200227125254-8fa46927fb4f/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/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA=
|
gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc=
|
||||||
gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
|
||||||
gopkg.in/natefinch/lumberjack.v2 v2.0.0 h1:1Lc07Kr7qY4U2YPouBjpCLxpiyxIVoxqXgkXLknAOE8=
|
|
||||||
gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k=
|
|
||||||
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=
|
||||||
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
@ -395,45 +384,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-20200615113413-eeeca48fe776/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.24.2/go.mod h1:DVrVomtaYTbqs7gB/x2uVvqnXzv0nqjB396B8cG4dBA=
|
gorm.io/gorm v1.25.0 h1:+KtYtb2roDz14EQe4bla8CbQlmb9dN3VejSai3lprfU=
|
||||||
gorm.io/gorm v1.24.3 h1:WL2ifUmzR/SLp85CSURAfybcHnGZ+yLSGSxgYXlFBHg=
|
gorm.io/gorm v1.25.0/go.mod h1:L4uxeKpfBml98NYqVqwAdmV1a2nBtAec/cf3fpucW/k=
|
||||||
gorm.io/gorm v1.24.3/go.mod h1:DVrVomtaYTbqs7gB/x2uVvqnXzv0nqjB396B8cG4dBA=
|
|
||||||
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=
|
||||||
gotest.tools/v3 v3.3.0 h1:MfDY1b1/0xN1CyMlQDac0ziEy9zJQd9CXBRRDHw2jJo=
|
modernc.org/libc v1.22.4 h1:wymSbZb0AlrjdAVX3cjreCHTPCpPARbQXNz6BHPzdwQ=
|
||||||
lukechampine.com/uint128 v1.1.1/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk=
|
modernc.org/libc v1.22.4/go.mod h1:jj+Z7dTNX8fBScMVNRAYZ/jF91K8fdT2hYMThc3YjBY=
|
||||||
lukechampine.com/uint128 v1.2.0/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk=
|
|
||||||
modernc.org/cc/v3 v3.37.0/go.mod h1:vtL+3mdHx/wcj3iEGz84rQa8vEqR6XM84v5Lcvfph20=
|
|
||||||
modernc.org/cc/v3 v3.38.1/go.mod h1:vtL+3mdHx/wcj3iEGz84rQa8vEqR6XM84v5Lcvfph20=
|
|
||||||
modernc.org/cc/v3 v3.40.0/go.mod h1:/bTg4dnWkSXowUO6ssQKnOV0yMVxDYNIsIrzqTFDGH0=
|
|
||||||
modernc.org/ccgo/v3 v3.0.0-20220904174949-82d86e1b6d56/go.mod h1:YSXjPL62P2AMSxBphRHPn7IkzhVHqkvOnRKAKh+W6ZI=
|
|
||||||
modernc.org/ccgo/v3 v3.0.0-20220910160915-348f15de615a/go.mod h1:8p47QxPkdugex9J4n9P2tLZ9bK01yngIVp00g4nomW0=
|
|
||||||
modernc.org/ccgo/v3 v3.16.13-0.20221017192402-261537637ce8/go.mod h1:fUB3Vn0nVPReA+7IG7yZDfjv1TMWjhQP8gCxrFAtL5g=
|
|
||||||
modernc.org/ccgo/v3 v3.16.13/go.mod h1:2Quk+5YgpImhPjv2Qsob1DnZ/4som1lJTodubIcoUkY=
|
|
||||||
modernc.org/ccorpus v1.11.6/go.mod h1:2gEUTrWqdpH2pXsmTM1ZkjeSrUWDpjMu2T6m29L/ErQ=
|
|
||||||
modernc.org/httpfs v1.0.6/go.mod h1:7dosgurJGp0sPaRanU53W4xZYKh14wfzX420oZADeHM=
|
|
||||||
modernc.org/libc v1.17.4/go.mod h1:WNg2ZH56rDEwdropAJeZPQkXmDwh+JCA1s/htl6r2fA=
|
|
||||||
modernc.org/libc v1.18.0/go.mod h1:vj6zehR5bfc98ipowQOM2nIDUZnVew/wNC/2tOGS+q0=
|
|
||||||
modernc.org/libc v1.19.0/go.mod h1:ZRfIaEkgrYgZDl6pa4W39HgN5G/yDW+NRmNKZBDFrk0=
|
|
||||||
modernc.org/libc v1.20.3/go.mod h1:ZRfIaEkgrYgZDl6pa4W39HgN5G/yDW+NRmNKZBDFrk0=
|
|
||||||
modernc.org/libc v1.21.4/go.mod h1:przBsL5RDOZajTVslkugzLBj1evTue36jEomFQOoYuI=
|
|
||||||
modernc.org/libc v1.21.5 h1:xBkU9fnHV+hvZuPSRszN0AXDG4M7nwPLwTWwkYcvLCI=
|
|
||||||
modernc.org/libc v1.21.5/go.mod h1:przBsL5RDOZajTVslkugzLBj1evTue36jEomFQOoYuI=
|
|
||||||
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.3.0/go.mod h1:PkUhL0Mugw21sHPeskwZW4D6VscE/GQJOnIpCnW6pSU=
|
modernc.org/memory v1.5.0 h1:N+/8c5rE6EqugZwHii4IFsaJ7MUhoWX07J5tC/iI5Ds=
|
||||||
modernc.org/memory v1.4.0 h1:crykUfNSnMAXaOJnnxcSzbUGMqkLWjklJKkBK2nwZwk=
|
modernc.org/memory v1.5.0/go.mod h1:PkUhL0Mugw21sHPeskwZW4D6VscE/GQJOnIpCnW6pSU=
|
||||||
modernc.org/memory v1.4.0/go.mod h1:PkUhL0Mugw21sHPeskwZW4D6VscE/GQJOnIpCnW6pSU=
|
modernc.org/sqlite v1.21.2 h1:ixuUG0QS413Vfzyx6FWx6PYTmHaOegTY+hjzhn7L+a0=
|
||||||
modernc.org/opt v0.1.1/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0=
|
modernc.org/sqlite v1.21.2/go.mod h1:cxbLkB5WS32DnQqeH4h4o1B0eMr8W/y8/RGuxQ3JsC0=
|
||||||
modernc.org/opt v0.1.3/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0=
|
mvdan.cc/sh/v3 v3.7.0 h1:lSTjdP/1xsddtaKfGg7Myu7DnlHItd3/M2tomOcNNBg=
|
||||||
modernc.org/sqlite v1.20.0 h1:80zmD3BGkm8BZ5fUi/4lwJQHiO3GXgIUvZRXpoIfROY=
|
mvdan.cc/sh/v3 v3.7.0/go.mod h1:K2gwkaesF/D7av7Kxl0HbF5kGOd2ArupNTX3X44+8l8=
|
||||||
modernc.org/sqlite v1.20.0/go.mod h1:EsYz8rfOvLCiYTy5ZFsOYzoCcRMu98YYkwAcCw5YIYw=
|
|
||||||
modernc.org/strutil v1.1.3/go.mod h1:MEHNA7PdEnEwLvspRMtWTNnp2nnyvMfkimT1NKNAGbw=
|
|
||||||
modernc.org/tcl v1.15.0/go.mod h1:xRoGotBZ6dU+Zo2tca+2EqVEeMmOUBzHnhIwq4YrVnE=
|
|
||||||
modernc.org/token v1.0.1/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM=
|
|
||||||
modernc.org/z v1.7.0/go.mod h1:hVdgNMh8ggTuRG1rGU8x+xGRFfiQUIAw0ZqlPy8+HyQ=
|
|
||||||
|
|||||||
@ -17,8 +17,8 @@ type Driver interface {
|
|||||||
type Meta interface {
|
type Meta interface {
|
||||||
Config() Config
|
Config() Config
|
||||||
// GetStorage just get raw storage, no need to implement, because model.Storage have implemented
|
// GetStorage just get raw storage, no need to implement, because model.Storage have implemented
|
||||||
GetStorage() *model.Storage
|
GetStorage() *model.StorageA
|
||||||
SetStorage(model.Storage)
|
SetStorage(model.StorageA)
|
||||||
// GetAddition Additional is used for unmarshal of JSON, so need return pointer
|
// GetAddition Additional is used for unmarshal of JSON, so need return pointer
|
||||||
GetAddition() Additional
|
GetAddition() Additional
|
||||||
// Init If already initialized, drop first
|
// Init If already initialized, drop first
|
||||||
@ -34,14 +34,16 @@ 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)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,545 +0,0 @@
|
|||||||
package op
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"os"
|
|
||||||
stdpath "path"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/IceWhaleTech/CasaOS/internal/driver"
|
|
||||||
"github.com/IceWhaleTech/CasaOS/model"
|
|
||||||
"github.com/IceWhaleTech/CasaOS/pkg/generic_sync"
|
|
||||||
"github.com/IceWhaleTech/CasaOS/pkg/singleflight"
|
|
||||||
"github.com/IceWhaleTech/CasaOS/pkg/utils"
|
|
||||||
"github.com/Xhofe/go-cache"
|
|
||||||
"github.com/pkg/errors"
|
|
||||||
pkgerr "github.com/pkg/errors"
|
|
||||||
log "github.com/sirupsen/logrus"
|
|
||||||
)
|
|
||||||
|
|
||||||
// In order to facilitate adding some other things before and after file op
|
|
||||||
|
|
||||||
var listCache = cache.NewMemCache(cache.WithShards[[]model.Obj](64))
|
|
||||||
var listG singleflight.Group[[]model.Obj]
|
|
||||||
|
|
||||||
func updateCacheObj(storage driver.Driver, path string, oldObj model.Obj, newObj model.Obj) {
|
|
||||||
key := Key(storage, path)
|
|
||||||
objs, ok := listCache.Get(key)
|
|
||||||
if ok {
|
|
||||||
for i, obj := range objs {
|
|
||||||
if obj.GetName() == oldObj.GetName() {
|
|
||||||
objs[i] = newObj
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
listCache.Set(key, objs, cache.WithEx[[]model.Obj](time.Minute*time.Duration(storage.GetStorage().CacheExpiration)))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func delCacheObj(storage driver.Driver, path string, obj model.Obj) {
|
|
||||||
key := Key(storage, path)
|
|
||||||
objs, ok := listCache.Get(key)
|
|
||||||
if ok {
|
|
||||||
for i, oldObj := range objs {
|
|
||||||
if oldObj.GetName() == obj.GetName() {
|
|
||||||
objs = append(objs[:i], objs[i+1:]...)
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
listCache.Set(key, objs, cache.WithEx[[]model.Obj](time.Minute*time.Duration(storage.GetStorage().CacheExpiration)))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var addSortDebounceMap generic_sync.MapOf[string, func(func())]
|
|
||||||
|
|
||||||
func addCacheObj(storage driver.Driver, path string, newObj model.Obj) {
|
|
||||||
key := Key(storage, path)
|
|
||||||
objs, ok := listCache.Get(key)
|
|
||||||
if ok {
|
|
||||||
for i, obj := range objs {
|
|
||||||
if obj.GetName() == newObj.GetName() {
|
|
||||||
objs[i] = newObj
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Simple separation of files and folders
|
|
||||||
if len(objs) > 0 && objs[len(objs)-1].IsDir() == newObj.IsDir() {
|
|
||||||
objs = append(objs, newObj)
|
|
||||||
} else {
|
|
||||||
objs = append([]model.Obj{newObj}, objs...)
|
|
||||||
}
|
|
||||||
|
|
||||||
if storage.Config().LocalSort {
|
|
||||||
debounce, _ := addSortDebounceMap.LoadOrStore(key, utils.NewDebounce(time.Minute))
|
|
||||||
log.Debug("addCacheObj: wait start sort")
|
|
||||||
debounce(func() {
|
|
||||||
log.Debug("addCacheObj: start sort")
|
|
||||||
model.SortFiles(objs, storage.GetStorage().OrderBy, storage.GetStorage().OrderDirection)
|
|
||||||
addSortDebounceMap.Delete(key)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
listCache.Set(key, objs, cache.WithEx[[]model.Obj](time.Minute*time.Duration(storage.GetStorage().CacheExpiration)))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func ClearCache(storage driver.Driver, path string) {
|
|
||||||
listCache.Del(Key(storage, path))
|
|
||||||
}
|
|
||||||
|
|
||||||
func Key(storage driver.Driver, path string) string {
|
|
||||||
return stdpath.Join(storage.GetStorage().MountPath, utils.FixAndCleanPath(path))
|
|
||||||
}
|
|
||||||
|
|
||||||
// List files in storage, not contains virtual file
|
|
||||||
func List(ctx context.Context, storage driver.Driver, path string, args model.ListArgs, refresh ...bool) ([]model.Obj, error) {
|
|
||||||
if storage.Config().CheckStatus && storage.GetStorage().Status != WORK {
|
|
||||||
return nil, errors.Errorf("storage not init: %s", storage.GetStorage().Status)
|
|
||||||
}
|
|
||||||
path = utils.FixAndCleanPath(path)
|
|
||||||
log.Debugf("op.List %s", path)
|
|
||||||
key := Key(storage, path)
|
|
||||||
if !utils.IsBool(refresh...) {
|
|
||||||
if files, ok := listCache.Get(key); ok {
|
|
||||||
log.Debugf("use cache when list %s", path)
|
|
||||||
return files, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
dir, err := GetUnwrap(ctx, storage, path)
|
|
||||||
if err != nil {
|
|
||||||
return nil, errors.WithMessage(err, "failed get dir")
|
|
||||||
}
|
|
||||||
log.Debugf("list dir: %+v", dir)
|
|
||||||
if !dir.IsDir() {
|
|
||||||
return nil, errors.WithStack(errors.New("not a folder"))
|
|
||||||
}
|
|
||||||
objs, err, _ := listG.Do(key, func() ([]model.Obj, error) {
|
|
||||||
files, err := storage.List(ctx, dir, args)
|
|
||||||
if err != nil {
|
|
||||||
return nil, errors.Wrapf(err, "failed to list objs")
|
|
||||||
}
|
|
||||||
// set path
|
|
||||||
for _, f := range files {
|
|
||||||
if s, ok := f.(model.SetPath); ok && f.GetPath() == "" && dir.GetPath() != "" {
|
|
||||||
s.SetPath(stdpath.Join(dir.GetPath(), f.GetName()))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// warp obj name
|
|
||||||
model.WrapObjsName(files)
|
|
||||||
// call hooks
|
|
||||||
go func(reqPath string, files []model.Obj) {
|
|
||||||
for _, hook := range ObjsUpdateHooks {
|
|
||||||
hook(args.ReqPath, files)
|
|
||||||
}
|
|
||||||
}(args.ReqPath, files)
|
|
||||||
|
|
||||||
// sort objs
|
|
||||||
if storage.Config().LocalSort {
|
|
||||||
model.SortFiles(files, storage.GetStorage().OrderBy, storage.GetStorage().OrderDirection)
|
|
||||||
}
|
|
||||||
model.ExtractFolder(files, storage.GetStorage().ExtractFolder)
|
|
||||||
|
|
||||||
if !storage.Config().NoCache {
|
|
||||||
if len(files) > 0 {
|
|
||||||
log.Debugf("set cache: %s => %+v", key, files)
|
|
||||||
listCache.Set(key, files, cache.WithEx[[]model.Obj](time.Minute*time.Duration(storage.GetStorage().CacheExpiration)))
|
|
||||||
} else {
|
|
||||||
log.Debugf("del cache: %s", key)
|
|
||||||
listCache.Del(key)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return files, nil
|
|
||||||
})
|
|
||||||
return objs, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get object from list of files
|
|
||||||
func Get(ctx context.Context, storage driver.Driver, path string) (model.Obj, error) {
|
|
||||||
path = utils.FixAndCleanPath(path)
|
|
||||||
log.Debugf("op.Get %s", path)
|
|
||||||
|
|
||||||
// is root folder
|
|
||||||
if utils.PathEqual(path, "/") {
|
|
||||||
var rootObj model.Obj
|
|
||||||
switch r := storage.GetAddition().(type) {
|
|
||||||
case driver.IRootId:
|
|
||||||
rootObj = &model.Object{
|
|
||||||
ID: r.GetRootId(),
|
|
||||||
Name: RootName,
|
|
||||||
Size: 0,
|
|
||||||
Modified: storage.GetStorage().Modified,
|
|
||||||
IsFolder: true,
|
|
||||||
Path: path,
|
|
||||||
}
|
|
||||||
case driver.IRootPath:
|
|
||||||
rootObj = &model.Object{
|
|
||||||
Path: r.GetRootPath(),
|
|
||||||
Name: RootName,
|
|
||||||
Size: 0,
|
|
||||||
Modified: storage.GetStorage().Modified,
|
|
||||||
IsFolder: true,
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
if storage, ok := storage.(driver.Getter); ok {
|
|
||||||
obj, err := storage.GetRoot(ctx)
|
|
||||||
if err != nil {
|
|
||||||
return nil, errors.WithMessage(err, "failed get root obj")
|
|
||||||
}
|
|
||||||
rootObj = obj
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if rootObj == nil {
|
|
||||||
return nil, errors.Errorf("please implement IRootPath or IRootId or Getter method")
|
|
||||||
}
|
|
||||||
return &model.ObjWrapName{
|
|
||||||
Name: RootName,
|
|
||||||
Obj: rootObj,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// not root folder
|
|
||||||
dir, name := stdpath.Split(path)
|
|
||||||
files, err := List(ctx, storage, dir, model.ListArgs{})
|
|
||||||
if err != nil {
|
|
||||||
return nil, errors.WithMessage(err, "failed get parent list")
|
|
||||||
}
|
|
||||||
for _, f := range files {
|
|
||||||
// TODO maybe copy obj here
|
|
||||||
if f.GetName() == name {
|
|
||||||
return f, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
log.Debugf("cant find obj with name: %s", name)
|
|
||||||
return nil, errors.WithStack(errors.New("object not found"))
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetUnwrap(ctx context.Context, storage driver.Driver, path string) (model.Obj, error) {
|
|
||||||
obj, err := Get(ctx, storage, path)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return model.UnwrapObjs(obj), err
|
|
||||||
}
|
|
||||||
|
|
||||||
var linkCache = cache.NewMemCache(cache.WithShards[*model.Link](16))
|
|
||||||
var linkG singleflight.Group[*model.Link]
|
|
||||||
|
|
||||||
// Link get link, if is an url. should have an expiry time
|
|
||||||
func Link(ctx context.Context, storage driver.Driver, path string, args model.LinkArgs) (*model.Link, model.Obj, error) {
|
|
||||||
if storage.Config().CheckStatus && storage.GetStorage().Status != WORK {
|
|
||||||
return nil, nil, errors.Errorf("storage not init: %s", storage.GetStorage().Status)
|
|
||||||
}
|
|
||||||
file, err := GetUnwrap(ctx, storage, path)
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, errors.WithMessage(err, "failed to get file")
|
|
||||||
}
|
|
||||||
if file.IsDir() {
|
|
||||||
return nil, nil, errors.WithStack(errors.New("not a file"))
|
|
||||||
}
|
|
||||||
key := Key(storage, path) + ":" + args.IP
|
|
||||||
if link, ok := linkCache.Get(key); ok {
|
|
||||||
return link, file, nil
|
|
||||||
}
|
|
||||||
fn := func() (*model.Link, error) {
|
|
||||||
link, err := storage.Link(ctx, file, args)
|
|
||||||
if err != nil {
|
|
||||||
return nil, errors.Wrapf(err, "failed get link")
|
|
||||||
}
|
|
||||||
if link.Expiration != nil {
|
|
||||||
linkCache.Set(key, link, cache.WithEx[*model.Link](*link.Expiration))
|
|
||||||
}
|
|
||||||
return link, nil
|
|
||||||
}
|
|
||||||
link, err, _ := linkG.Do(key, fn)
|
|
||||||
return link, file, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Other api
|
|
||||||
func Other(ctx context.Context, storage driver.Driver, args model.FsOtherArgs) (interface{}, error) {
|
|
||||||
obj, err := GetUnwrap(ctx, storage, args.Path)
|
|
||||||
if err != nil {
|
|
||||||
return nil, errors.WithMessagef(err, "failed to get obj")
|
|
||||||
}
|
|
||||||
if o, ok := storage.(driver.Other); ok {
|
|
||||||
return o.Other(ctx, model.OtherArgs{
|
|
||||||
Obj: obj,
|
|
||||||
Method: args.Method,
|
|
||||||
Data: args.Data,
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
return nil, errors.New("not implement")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var mkdirG singleflight.Group[interface{}]
|
|
||||||
|
|
||||||
func MakeDir(ctx context.Context, storage driver.Driver, path string, lazyCache ...bool) error {
|
|
||||||
if storage.Config().CheckStatus && storage.GetStorage().Status != WORK {
|
|
||||||
return errors.Errorf("storage not init: %s", storage.GetStorage().Status)
|
|
||||||
}
|
|
||||||
path = utils.FixAndCleanPath(path)
|
|
||||||
key := Key(storage, path)
|
|
||||||
_, err, _ := mkdirG.Do(key, func() (interface{}, error) {
|
|
||||||
// check if dir exists
|
|
||||||
f, err := GetUnwrap(ctx, storage, path)
|
|
||||||
if err != nil {
|
|
||||||
if errors.Is(pkgerr.Cause(err), errors.New("object not found")) {
|
|
||||||
parentPath, dirName := stdpath.Split(path)
|
|
||||||
err = MakeDir(ctx, storage, parentPath)
|
|
||||||
if err != nil {
|
|
||||||
return nil, errors.WithMessagef(err, "failed to make parent dir [%s]", parentPath)
|
|
||||||
}
|
|
||||||
parentDir, err := GetUnwrap(ctx, storage, parentPath)
|
|
||||||
// this should not happen
|
|
||||||
if err != nil {
|
|
||||||
return nil, errors.WithMessagef(err, "failed to get parent dir [%s]", parentPath)
|
|
||||||
}
|
|
||||||
|
|
||||||
switch s := storage.(type) {
|
|
||||||
case driver.MkdirResult:
|
|
||||||
var newObj model.Obj
|
|
||||||
newObj, err = s.MakeDir(ctx, parentDir, dirName)
|
|
||||||
if err == nil {
|
|
||||||
if newObj != nil {
|
|
||||||
addCacheObj(storage, parentPath, model.WrapObjName(newObj))
|
|
||||||
} else if !utils.IsBool(lazyCache...) {
|
|
||||||
ClearCache(storage, parentPath)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
case driver.Mkdir:
|
|
||||||
err = s.MakeDir(ctx, parentDir, dirName)
|
|
||||||
if err == nil && !utils.IsBool(lazyCache...) {
|
|
||||||
ClearCache(storage, parentPath)
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
return nil, errors.New("not implement")
|
|
||||||
}
|
|
||||||
return nil, errors.WithStack(err)
|
|
||||||
}
|
|
||||||
return nil, errors.WithMessage(err, "failed to check if dir exists")
|
|
||||||
}
|
|
||||||
// dir exists
|
|
||||||
if f.IsDir() {
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
// dir to make is a file
|
|
||||||
return nil, errors.New("file exists")
|
|
||||||
})
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
func Move(ctx context.Context, storage driver.Driver, srcPath, dstDirPath string, lazyCache ...bool) error {
|
|
||||||
if storage.Config().CheckStatus && storage.GetStorage().Status != WORK {
|
|
||||||
return errors.Errorf("storage not init: %s", storage.GetStorage().Status)
|
|
||||||
}
|
|
||||||
srcPath = utils.FixAndCleanPath(srcPath)
|
|
||||||
dstDirPath = utils.FixAndCleanPath(dstDirPath)
|
|
||||||
srcRawObj, err := Get(ctx, storage, srcPath)
|
|
||||||
if err != nil {
|
|
||||||
return errors.WithMessage(err, "failed to get src object")
|
|
||||||
}
|
|
||||||
srcObj := model.UnwrapObjs(srcRawObj)
|
|
||||||
dstDir, err := GetUnwrap(ctx, storage, dstDirPath)
|
|
||||||
if err != nil {
|
|
||||||
return errors.WithMessage(err, "failed to get dst dir")
|
|
||||||
}
|
|
||||||
srcDirPath := stdpath.Dir(srcPath)
|
|
||||||
|
|
||||||
switch s := storage.(type) {
|
|
||||||
case driver.MoveResult:
|
|
||||||
var newObj model.Obj
|
|
||||||
newObj, err = s.Move(ctx, srcObj, dstDir)
|
|
||||||
if err == nil {
|
|
||||||
delCacheObj(storage, srcDirPath, srcRawObj)
|
|
||||||
if newObj != nil {
|
|
||||||
addCacheObj(storage, dstDirPath, model.WrapObjName(newObj))
|
|
||||||
} else if !utils.IsBool(lazyCache...) {
|
|
||||||
ClearCache(storage, dstDirPath)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
case driver.Move:
|
|
||||||
err = s.Move(ctx, srcObj, dstDir)
|
|
||||||
if err == nil {
|
|
||||||
delCacheObj(storage, srcDirPath, srcRawObj)
|
|
||||||
if !utils.IsBool(lazyCache...) {
|
|
||||||
ClearCache(storage, dstDirPath)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
return errors.New("not implement")
|
|
||||||
}
|
|
||||||
return errors.WithStack(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
func Rename(ctx context.Context, storage driver.Driver, srcPath, dstName string, lazyCache ...bool) error {
|
|
||||||
if storage.Config().CheckStatus && storage.GetStorage().Status != WORK {
|
|
||||||
return errors.Errorf("storage not init: %s", storage.GetStorage().Status)
|
|
||||||
}
|
|
||||||
srcPath = utils.FixAndCleanPath(srcPath)
|
|
||||||
srcRawObj, err := Get(ctx, storage, srcPath)
|
|
||||||
if err != nil {
|
|
||||||
return errors.WithMessage(err, "failed to get src object")
|
|
||||||
}
|
|
||||||
srcObj := model.UnwrapObjs(srcRawObj)
|
|
||||||
srcDirPath := stdpath.Dir(srcPath)
|
|
||||||
|
|
||||||
switch s := storage.(type) {
|
|
||||||
case driver.RenameResult:
|
|
||||||
var newObj model.Obj
|
|
||||||
newObj, err = s.Rename(ctx, srcObj, dstName)
|
|
||||||
if err == nil {
|
|
||||||
if newObj != nil {
|
|
||||||
updateCacheObj(storage, srcDirPath, srcRawObj, model.WrapObjName(newObj))
|
|
||||||
} else if !utils.IsBool(lazyCache...) {
|
|
||||||
ClearCache(storage, srcDirPath)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
case driver.Rename:
|
|
||||||
err = s.Rename(ctx, srcObj, dstName)
|
|
||||||
if err == nil && !utils.IsBool(lazyCache...) {
|
|
||||||
ClearCache(storage, srcDirPath)
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
return errors.New("not implement")
|
|
||||||
}
|
|
||||||
return errors.WithStack(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Copy Just copy file[s] in a storage
|
|
||||||
func Copy(ctx context.Context, storage driver.Driver, srcPath, dstDirPath string, lazyCache ...bool) error {
|
|
||||||
if storage.Config().CheckStatus && storage.GetStorage().Status != WORK {
|
|
||||||
return errors.Errorf("storage not init: %s", storage.GetStorage().Status)
|
|
||||||
}
|
|
||||||
srcPath = utils.FixAndCleanPath(srcPath)
|
|
||||||
dstDirPath = utils.FixAndCleanPath(dstDirPath)
|
|
||||||
srcObj, err := GetUnwrap(ctx, storage, srcPath)
|
|
||||||
if err != nil {
|
|
||||||
return errors.WithMessage(err, "failed to get src object")
|
|
||||||
}
|
|
||||||
dstDir, err := GetUnwrap(ctx, storage, dstDirPath)
|
|
||||||
if err != nil {
|
|
||||||
return errors.WithMessage(err, "failed to get dst dir")
|
|
||||||
}
|
|
||||||
|
|
||||||
switch s := storage.(type) {
|
|
||||||
case driver.CopyResult:
|
|
||||||
var newObj model.Obj
|
|
||||||
newObj, err = s.Copy(ctx, srcObj, dstDir)
|
|
||||||
if err == nil {
|
|
||||||
if newObj != nil {
|
|
||||||
addCacheObj(storage, dstDirPath, model.WrapObjName(newObj))
|
|
||||||
} else if !utils.IsBool(lazyCache...) {
|
|
||||||
ClearCache(storage, dstDirPath)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
case driver.Copy:
|
|
||||||
err = s.Copy(ctx, srcObj, dstDir)
|
|
||||||
if err == nil && !utils.IsBool(lazyCache...) {
|
|
||||||
ClearCache(storage, dstDirPath)
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
return errors.New("not implement")
|
|
||||||
}
|
|
||||||
return errors.WithStack(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
func Remove(ctx context.Context, storage driver.Driver, path string) error {
|
|
||||||
if storage.Config().CheckStatus && storage.GetStorage().Status != WORK {
|
|
||||||
return errors.Errorf("storage not init: %s", storage.GetStorage().Status)
|
|
||||||
}
|
|
||||||
path = utils.FixAndCleanPath(path)
|
|
||||||
rawObj, err := Get(ctx, storage, path)
|
|
||||||
if err != nil {
|
|
||||||
// if object not found, it's ok
|
|
||||||
if errors.Is(pkgerr.Cause(err), errors.New("object not found")) {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return errors.WithMessage(err, "failed to get object")
|
|
||||||
}
|
|
||||||
dirPath := stdpath.Dir(path)
|
|
||||||
|
|
||||||
switch s := storage.(type) {
|
|
||||||
case driver.Remove:
|
|
||||||
err = s.Remove(ctx, model.UnwrapObjs(rawObj))
|
|
||||||
if err == nil {
|
|
||||||
delCacheObj(storage, dirPath, rawObj)
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
return errors.New("not implement")
|
|
||||||
}
|
|
||||||
return errors.WithStack(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
func Put(ctx context.Context, storage driver.Driver, dstDirPath string, file *model.FileStream, up driver.UpdateProgress, lazyCache ...bool) error {
|
|
||||||
if storage.Config().CheckStatus && storage.GetStorage().Status != WORK {
|
|
||||||
return errors.Errorf("storage not init: %s", storage.GetStorage().Status)
|
|
||||||
}
|
|
||||||
defer func() {
|
|
||||||
if f, ok := file.GetReadCloser().(*os.File); ok {
|
|
||||||
err := os.RemoveAll(f.Name())
|
|
||||||
if err != nil {
|
|
||||||
log.Errorf("failed to remove file [%s]", f.Name())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
defer func() {
|
|
||||||
if err := file.Close(); err != nil {
|
|
||||||
log.Errorf("failed to close file streamer, %v", err)
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
// if file exist and size = 0, delete it
|
|
||||||
dstDirPath = utils.FixAndCleanPath(dstDirPath)
|
|
||||||
dstPath := stdpath.Join(dstDirPath, file.GetName())
|
|
||||||
fi, err := GetUnwrap(ctx, storage, dstPath)
|
|
||||||
if err == nil {
|
|
||||||
if fi.GetSize() == 0 {
|
|
||||||
err = Remove(ctx, storage, dstPath)
|
|
||||||
if err != nil {
|
|
||||||
return errors.WithMessagef(err, "failed remove file that exist and have size 0")
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
file.Old = fi
|
|
||||||
}
|
|
||||||
}
|
|
||||||
err = MakeDir(ctx, storage, dstDirPath)
|
|
||||||
if err != nil {
|
|
||||||
return errors.WithMessagef(err, "failed to make dir [%s]", dstDirPath)
|
|
||||||
}
|
|
||||||
parentDir, err := GetUnwrap(ctx, storage, dstDirPath)
|
|
||||||
// this should not happen
|
|
||||||
if err != nil {
|
|
||||||
return errors.WithMessagef(err, "failed to get dir [%s]", dstDirPath)
|
|
||||||
}
|
|
||||||
// if up is nil, set a default to prevent panic
|
|
||||||
if up == nil {
|
|
||||||
up = func(p int) {}
|
|
||||||
}
|
|
||||||
|
|
||||||
switch s := storage.(type) {
|
|
||||||
case driver.PutResult:
|
|
||||||
var newObj model.Obj
|
|
||||||
newObj, err = s.Put(ctx, parentDir, file, up)
|
|
||||||
if err == nil {
|
|
||||||
if newObj != nil {
|
|
||||||
addCacheObj(storage, dstDirPath, model.WrapObjName(newObj))
|
|
||||||
} else if !utils.IsBool(lazyCache...) {
|
|
||||||
ClearCache(storage, dstDirPath)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
case driver.Put:
|
|
||||||
err = s.Put(ctx, parentDir, file, up)
|
|
||||||
if err == nil && !utils.IsBool(lazyCache...) {
|
|
||||||
ClearCache(storage, dstDirPath)
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
return errors.New("not implement")
|
|
||||||
}
|
|
||||||
log.Debugf("put file [%s] done", file.GetName())
|
|
||||||
//if err == nil {
|
|
||||||
// //clear cache
|
|
||||||
// key := stdpath.Join(storage.GetStorage().MountPath, dstDirPath)
|
|
||||||
// listCache.Del(key)
|
|
||||||
//}
|
|
||||||
return errors.WithStack(err)
|
|
||||||
}
|
|
||||||
71
main.go
71
main.go
@ -13,25 +13,23 @@ 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"
|
||||||
"github.com/coreos/go-systemd/daemon"
|
"github.com/coreos/go-systemd/daemon"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
|
|
||||||
_ "github.com/IceWhaleTech/CasaOS/drivers"
|
"github.com/robfig/cron/v3"
|
||||||
"github.com/robfig/cron"
|
|
||||||
"gorm.io/gorm"
|
"gorm.io/gorm"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -49,6 +47,9 @@ 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")
|
||||||
@ -64,7 +65,7 @@ func init() {
|
|||||||
println("git commit:", commit)
|
println("git commit:", commit)
|
||||||
println("build date:", date)
|
println("build date:", date)
|
||||||
|
|
||||||
config.InitSetup(*configFlag)
|
config.InitSetup(*configFlag, _confSample)
|
||||||
|
|
||||||
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 {
|
||||||
@ -79,8 +80,13 @@ func init() {
|
|||||||
service.Cache = cache.Init()
|
service.Cache = cache.Init()
|
||||||
|
|
||||||
service.GetCPUThermalZone()
|
service.GetCPUThermalZone()
|
||||||
service.MyService.Storages().InitStorages()
|
|
||||||
route.InitFunction()
|
route.InitFunction()
|
||||||
|
|
||||||
|
//service.MyService.System().GenreateSystemEntry()
|
||||||
|
///
|
||||||
|
//service.MountLists = make(map[string]*mountlib.MountPoint)
|
||||||
|
//configfile.Install()
|
||||||
}
|
}
|
||||||
|
|
||||||
// @title casaOS API
|
// @title casaOS API
|
||||||
@ -98,35 +104,27 @@ 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,
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
cron2 := cron.New()
|
crontab := cron.New(cron.WithSeconds())
|
||||||
// every day execution
|
if _, err := crontab.AddFunc("@every 5s", route.SendAllHardwareStatusBySocket); err != nil {
|
||||||
|
logger.Error("add crontab error", zap.Error(err))
|
||||||
err := cron2.AddFunc("0/5 * * * * *", func() {
|
|
||||||
route.SendAllHardwareStatusBySocket()
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
fmt.Println(err)
|
|
||||||
}
|
}
|
||||||
cron2.Start()
|
|
||||||
|
|
||||||
defer cron2.Stop()
|
crontab.Start()
|
||||||
|
defer crontab.Stop()
|
||||||
|
|
||||||
listener, err := net.Listen("tcp", net.JoinHostPort(LOCALHOST, "0"))
|
listener, err := net.Listen("tcp", net.JoinHostPort(LOCALHOST, "0"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -144,6 +142,9 @@ func main() {
|
|||||||
"/v1/driver",
|
"/v1/driver",
|
||||||
"/v1/cloud",
|
"/v1/cloud",
|
||||||
"/v1/recover",
|
"/v1/recover",
|
||||||
|
"/v1/other",
|
||||||
|
"/v1/zt",
|
||||||
|
"/v1/test",
|
||||||
route.V2APIPath,
|
route.V2APIPath,
|
||||||
route.V2DocPath,
|
route.V2DocPath,
|
||||||
route.V3FilePath,
|
route.V3FilePath,
|
||||||
@ -153,25 +154,25 @@ 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++ {
|
||||||
response, err := service.MyService.MessageBus().RegisterEventTypesWithResponse(context.Background(), events)
|
response, err := service.MyService.MessageBus().RegisterEventTypesWithResponse(context.Background(), common.EventTypes)
|
||||||
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))
|
||||||
}
|
}
|
||||||
|
if response != nil && response.StatusCode() != http.StatusOK {
|
||||||
if response != nil && response.StatusCode() != http.StatusOK {
|
logger.Error("error when trying to register one or more event types - some event type will not be discoverable", zap.String("status", response.Status()), zap.String("body", string(response.Body)))
|
||||||
logger.Error("error when trying to register one or more event types - some event type will not be discoverable", zap.String("status", response.Status()), zap.String("body", string(response.Body)))
|
}
|
||||||
|
if response.StatusCode() == http.StatusOK {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
time.Sleep(time.Second)
|
||||||
}
|
}
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
@ -220,7 +221,7 @@ func main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
logger.Info("CasaOS main service is listening...", zap.Any("address", listener.Addr().String()))
|
logger.Info("CasaOS main service is listening...", zap.Any("address", listener.Addr().String()))
|
||||||
|
// defer service.MyService.Storage().UnmountAllStorage()
|
||||||
err = s.Serve(listener) // not using http.serve() to fix G114: Use of net/http serve function that has no support for setting timeouts (see https://github.com/securego/gosec)
|
err = s.Serve(listener) // not using http.serve() to fix G114: Use of net/http serve function that has no support for setting timeouts (see https://github.com/securego/gosec)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
|
|||||||
7
model/drive.go
Normal file
7
model/drive.go
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
package model
|
||||||
|
|
||||||
|
type Drive struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Icon string `json:"icon"`
|
||||||
|
AuthUrl string `json:"auth_url"`
|
||||||
|
}
|
||||||
@ -1,7 +1,9 @@
|
|||||||
package model
|
package model
|
||||||
|
|
||||||
type SearchFileInfo struct {
|
type SearchEngine struct {
|
||||||
Path string `json:"path"`
|
Name string `json:"name"`
|
||||||
Name string `json:"name"`
|
Icon string `json:"icon"`
|
||||||
Type int `json:"type"`
|
SearchUrl string `json:"search_url"`
|
||||||
|
RecoUrl string `json:"reco_url"`
|
||||||
|
Data []string `json:"data"`
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,7 +2,7 @@ package model
|
|||||||
|
|
||||||
import "time"
|
import "time"
|
||||||
|
|
||||||
type Storage struct {
|
type StorageA struct {
|
||||||
ID uint `json:"id" gorm:"primaryKey"` // unique key
|
ID uint `json:"id" gorm:"primaryKey"` // unique key
|
||||||
MountPath string `json:"mount_path" gorm:"unique" binding:"required"` // must be standardized
|
MountPath string `json:"mount_path" gorm:"unique" binding:"required"` // must be standardized
|
||||||
Order int `json:"order"` // use to sort
|
Order int `json:"order"` // use to sort
|
||||||
@ -29,15 +29,15 @@ type Proxy struct {
|
|||||||
DownProxyUrl string `json:"down_proxy_url"`
|
DownProxyUrl string `json:"down_proxy_url"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Storage) GetStorage() *Storage {
|
func (s *StorageA) GetStorage() *StorageA {
|
||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Storage) SetStorage(storage Storage) {
|
func (s *StorageA) SetStorage(storage StorageA) {
|
||||||
*s = storage
|
*s = storage
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Storage) SetStatus(status string) {
|
func (s *StorageA) SetStatus(status string) {
|
||||||
s.Status = status
|
s.Status = status
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -70,7 +70,8 @@ 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"`
|
||||||
}
|
}
|
||||||
|
|||||||
@ -23,3 +23,14 @@ 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"`
|
||||||
|
}
|
||||||
|
|||||||
39
package.json
Normal file
39
package.json
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
{
|
||||||
|
"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"
|
||||||
|
}
|
||||||
@ -10,6 +10,10 @@
|
|||||||
*/
|
*/
|
||||||
package config
|
package config
|
||||||
|
|
||||||
const (
|
import (
|
||||||
USERCONFIGURL = "/etc/casaos/casaos.conf"
|
"path/filepath"
|
||||||
|
|
||||||
|
"github.com/IceWhaleTech/CasaOS-Common/utils/constants"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var CasaOSConfigFilePath = filepath.Join(constants.DefaultConfigPath, "casaos.conf")
|
||||||
|
|||||||
@ -14,80 +14,72 @@ 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 (
|
||||||
var SysInfo = &model.SysInfoModel{}
|
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
|
||||||
var AppInfo = &model.APPModel{}
|
ConfigFilePath string
|
||||||
|
)
|
||||||
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) {
|
func InitSetup(config string, sample string) {
|
||||||
configDir := USERCONFIGURL
|
ConfigFilePath = CasaOSConfigFilePath
|
||||||
if len(config) > 0 {
|
if len(config) > 0 {
|
||||||
configDir = config
|
ConfigFilePath = config
|
||||||
}
|
}
|
||||||
if runtime.GOOS == "darwin" {
|
|
||||||
configDir = "./conf/conf.conf"
|
// create default config file if not exist
|
||||||
}
|
if _, err := os.Stat(ConfigFilePath); os.IsNotExist(err) {
|
||||||
var err error
|
fmt.Println("config file not exist, create it")
|
||||||
// 读取文件
|
// create config file
|
||||||
Cfg, err = ini.Load(configDir)
|
file, err := os.Create(ConfigFilePath)
|
||||||
if err != nil {
|
|
||||||
Cfg, err = ini.Load("/etc/casaos.conf")
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
Cfg, err = ini.Load("/casaOS/server/conf/conf.ini")
|
panic(err)
|
||||||
if err != nil {
|
}
|
||||||
fmt.Printf("Fail to read file: %v", err)
|
defer file.Close()
|
||||||
os.Exit(1)
|
|
||||||
}
|
// write default config
|
||||||
|
_, err = file.WriteString(sample)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var err error
|
||||||
|
|
||||||
|
// 读取文件
|
||||||
|
Cfg, err = ini.Load(ConfigFilePath)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
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()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 映射
|
// 映射
|
||||||
@ -97,21 +89,3 @@ 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)
|
|
||||||
}
|
|
||||||
|
|||||||
@ -11,14 +11,12 @@
|
|||||||
package sqlite
|
package sqlite
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/IceWhaleTech/CasaOS-Common/utils/logger"
|
|
||||||
"github.com/IceWhaleTech/CasaOS/model"
|
|
||||||
"github.com/IceWhaleTech/CasaOS/pkg/utils/file"
|
"github.com/IceWhaleTech/CasaOS/pkg/utils/file"
|
||||||
model2 "github.com/IceWhaleTech/CasaOS/service/model"
|
model2 "github.com/IceWhaleTech/CasaOS/service/model"
|
||||||
"github.com/glebarez/sqlite"
|
"github.com/glebarez/sqlite"
|
||||||
"go.uber.org/zap"
|
|
||||||
"gorm.io/gorm"
|
"gorm.io/gorm"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -33,23 +31,24 @@ func GetDb(dbPath string) *gorm.DB {
|
|||||||
// db, err := gorm.Open(mysql2.Open(dsn), &gorm.Config{})
|
// db, err := gorm.Open(mysql2.Open(dsn), &gorm.Config{})
|
||||||
file.IsNotExistMkDir(dbPath)
|
file.IsNotExistMkDir(dbPath)
|
||||||
db, err := gorm.Open(sqlite.Open(dbPath+"/casaOS.db"), &gorm.Config{})
|
db, err := gorm.Open(sqlite.Open(dbPath+"/casaOS.db"), &gorm.Config{})
|
||||||
|
if err != nil {
|
||||||
|
panic("sqlite connect error")
|
||||||
|
}
|
||||||
|
|
||||||
c, _ := db.DB()
|
c, _ := db.DB()
|
||||||
c.SetMaxIdleConns(10)
|
c.SetMaxIdleConns(10)
|
||||||
c.SetMaxOpenConns(1)
|
c.SetMaxOpenConns(1)
|
||||||
c.SetConnMaxIdleTime(time.Second * 1000)
|
c.SetConnMaxIdleTime(time.Second * 1000)
|
||||||
if err != nil {
|
|
||||||
logger.Error("sqlite connect error", zap.Any("db connect error", err))
|
|
||||||
panic("sqlite connect error")
|
|
||||||
}
|
|
||||||
gdb = db
|
gdb = db
|
||||||
|
|
||||||
err = db.AutoMigrate(&model2.AppNotify{}, model2.SharesDBModel{}, model2.ConnectionsDBModel{}, model.Storage{})
|
err = db.AutoMigrate(&model2.AppNotify{}, model2.SharesDBModel{}, model2.ConnectionsDBModel{}, model2.PeerDriveDBModel{})
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
}
|
||||||
|
|
||||||
db.Exec("DROP TABLE IF EXISTS o_application")
|
db.Exec("DROP TABLE IF EXISTS o_application")
|
||||||
db.Exec("DROP TABLE IF EXISTS o_friend")
|
db.Exec("DROP TABLE IF EXISTS o_friend")
|
||||||
db.Exec("DROP TABLE IF EXISTS o_person_download")
|
db.Exec("DROP TABLE IF EXISTS o_person_download")
|
||||||
db.Exec("DROP TABLE IF EXISTS o_person_down_record")
|
db.Exec("DROP TABLE IF EXISTS o_person_down_record")
|
||||||
if err != nil {
|
|
||||||
logger.Error("check or create db error", zap.Any("error", err))
|
|
||||||
}
|
|
||||||
return db
|
return db
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,147 +0,0 @@
|
|||||||
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 {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
defer stdout.Close()
|
|
||||||
if err := cmd.Start(); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
cmd.Wait()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
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))
|
|
||||||
}
|
|
||||||
cmd.Wait()
|
|
||||||
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)
|
|
||||||
cmd.Wait()
|
|
||||||
if err != nil {
|
|
||||||
fmt.Println(err)
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
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.")
|
|
||||||
}
|
|
||||||
@ -1,29 +0,0 @@
|
|||||||
package command
|
|
||||||
|
|
||||||
import (
|
|
||||||
"os"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"gotest.tools/assert"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestExecuteScripts(t *testing.T) {
|
|
||||||
// make a temp directory
|
|
||||||
tmpDir, err := os.MkdirTemp("", "casaos-test-*")
|
|
||||||
assert.NilError(t, err)
|
|
||||||
defer os.RemoveAll(tmpDir)
|
|
||||||
|
|
||||||
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)
|
|
||||||
|
|
||||||
ExecuteScripts(tmpDir)
|
|
||||||
}
|
|
||||||
11
pkg/utils/default_post_form.go
Normal file
11
pkg/utils/default_post_form.go
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
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
|
||||||
|
}
|
||||||
11
pkg/utils/default_query.go
Normal file
11
pkg/utils/default_query.go
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
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
|
||||||
|
}
|
||||||
@ -2,6 +2,7 @@ package file
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bufio"
|
"bufio"
|
||||||
|
"bytes"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
@ -76,6 +77,22 @@ 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)
|
||||||
@ -162,7 +179,7 @@ func CreateFileAndWriteContent(path string, content string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsNotExistMkDir create a directory if it does not exist
|
// IsNotExistCreateFile create a file if it does not exist
|
||||||
func IsNotExistCreateFile(src string) error {
|
func IsNotExistCreateFile(src string) error {
|
||||||
if notExist := CheckNotExist(src); notExist {
|
if notExist := CheckNotExist(src); notExist {
|
||||||
if err := CreateFile(src); err != nil {
|
if err := CreateFile(src); err != nil {
|
||||||
@ -430,7 +447,9 @@ func AddFile(ar archiver.Writer, path, commonPath string) error {
|
|||||||
defer file.Close()
|
defer file.Close()
|
||||||
|
|
||||||
if path != commonPath {
|
if path != commonPath {
|
||||||
filename := info.Name()
|
//filename := info.Name()
|
||||||
|
filename := strings.TrimPrefix(path, commonPath)
|
||||||
|
filename = strings.TrimPrefix(filename, string(filepath.Separator))
|
||||||
err = ar.Write(archiver.File{
|
err = ar.Write(archiver.File{
|
||||||
FileInfo: archiver.FileInfo{
|
FileInfo: archiver.FileInfo{
|
||||||
FileInfo: info,
|
FileInfo: info,
|
||||||
@ -596,3 +615,146 @@ func NameAccumulation(name string, dir string) string {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func ParseFileHeader(h []byte, boundary []byte) (map[string]string, bool) {
|
||||||
|
arr := bytes.Split(h, boundary)
|
||||||
|
//var out_header FileHeader
|
||||||
|
//out_header.ContentLength = -1
|
||||||
|
const (
|
||||||
|
CONTENT_DISPOSITION = "Content-Disposition: "
|
||||||
|
NAME = "name=\""
|
||||||
|
FILENAME = "filename=\""
|
||||||
|
CONTENT_TYPE = "Content-Type: "
|
||||||
|
CONTENT_LENGTH = "Content-Length: "
|
||||||
|
)
|
||||||
|
result := make(map[string]string)
|
||||||
|
for _, item := range arr {
|
||||||
|
|
||||||
|
tarr := bytes.Split(item, []byte(";"))
|
||||||
|
if len(tarr) != 2 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
tbyte := tarr[1]
|
||||||
|
fmt.Println(string(tbyte))
|
||||||
|
tbyte = bytes.ReplaceAll(tbyte, []byte("\r\n--"), []byte(""))
|
||||||
|
tbyte = bytes.ReplaceAll(tbyte, []byte("name=\""), []byte(""))
|
||||||
|
tempArr := bytes.Split(tbyte, []byte("\"\r\n\r\n"))
|
||||||
|
if len(tempArr) != 2 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
bytes.HasPrefix(item, []byte("name="))
|
||||||
|
result[strings.TrimSpace(string(tempArr[0]))] = strings.TrimSpace(string(tempArr[1]))
|
||||||
|
}
|
||||||
|
// for _, item := range arr {
|
||||||
|
// if bytes.HasPrefix(item, []byte(CONTENT_DISPOSITION)) {
|
||||||
|
// l := len(CONTENT_DISPOSITION)
|
||||||
|
// arr1 := bytes.Split(item[l:], []byte("; "))
|
||||||
|
// out_header.ContentDisposition = string(arr1[0])
|
||||||
|
// if bytes.HasPrefix(arr1[1], []byte(NAME)) {
|
||||||
|
// out_header.Name = string(arr1[1][len(NAME) : len(arr1[1])-1])
|
||||||
|
// }
|
||||||
|
// l = len(arr1[2])
|
||||||
|
// if bytes.HasPrefix(arr1[2], []byte(FILENAME)) && arr1[2][l-1] == 0x22 {
|
||||||
|
// out_header.FileName = string(arr1[2][len(FILENAME) : l-1])
|
||||||
|
// }
|
||||||
|
// } else if bytes.HasPrefix(item, []byte(CONTENT_TYPE)) {
|
||||||
|
// l := len(CONTENT_TYPE)
|
||||||
|
// out_header.ContentType = string(item[l:])
|
||||||
|
// } else if bytes.HasPrefix(item, []byte(CONTENT_LENGTH)) {
|
||||||
|
// l := len(CONTENT_LENGTH)
|
||||||
|
// s := string(item[l:])
|
||||||
|
// content_length, err := strconv.ParseInt(s, 10, 64)
|
||||||
|
// if err != nil {
|
||||||
|
// log.Printf("content length error:%s", string(item))
|
||||||
|
// return out_header, false
|
||||||
|
// } else {
|
||||||
|
// out_header.ContentLength = content_length
|
||||||
|
// }
|
||||||
|
// } else {
|
||||||
|
// log.Printf("unknown:%s\n", string(item))
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//fmt.Println(result)
|
||||||
|
// if len(out_header.FileName) == 0 {
|
||||||
|
// return out_header, false
|
||||||
|
// }
|
||||||
|
return result, true
|
||||||
|
}
|
||||||
|
|
||||||
|
func ReadToBoundary(boundary []byte, stream io.ReadCloser, target io.WriteCloser) ([]byte, bool, error) {
|
||||||
|
read_data := make([]byte, 1024*8)
|
||||||
|
read_data_len := 0
|
||||||
|
buf := make([]byte, 1024*4)
|
||||||
|
b_len := len(boundary)
|
||||||
|
reach_end := false
|
||||||
|
for !reach_end {
|
||||||
|
read_len, err := stream.Read(buf)
|
||||||
|
if err != nil {
|
||||||
|
if err != io.EOF && read_len <= 0 {
|
||||||
|
return nil, true, err
|
||||||
|
}
|
||||||
|
reach_end = true
|
||||||
|
}
|
||||||
|
|
||||||
|
copy(read_data[read_data_len:], buf[:read_len])
|
||||||
|
read_data_len += read_len
|
||||||
|
if read_data_len < b_len+4 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
loc := bytes.Index(read_data[:read_data_len], boundary)
|
||||||
|
if loc >= 0 {
|
||||||
|
|
||||||
|
target.Write(read_data[:loc-4])
|
||||||
|
return read_data[loc:read_data_len], reach_end, nil
|
||||||
|
}
|
||||||
|
target.Write(read_data[:read_data_len-b_len-4])
|
||||||
|
copy(read_data[0:], read_data[read_data_len-b_len-4:])
|
||||||
|
read_data_len = b_len + 4
|
||||||
|
}
|
||||||
|
target.Write(read_data[:read_data_len])
|
||||||
|
return nil, reach_end, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func ParseFromHead(read_data []byte, read_total int, boundary []byte, stream io.ReadCloser) (map[string]string, []byte, error) {
|
||||||
|
|
||||||
|
buf := make([]byte, 1024*8)
|
||||||
|
found_boundary := false
|
||||||
|
boundary_loc := -1
|
||||||
|
|
||||||
|
for {
|
||||||
|
read_len, err := stream.Read(buf)
|
||||||
|
if err != nil {
|
||||||
|
if err != io.EOF {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if read_total+read_len > cap(read_data) {
|
||||||
|
return nil, nil, fmt.Errorf("not found boundary")
|
||||||
|
}
|
||||||
|
copy(read_data[read_total:], buf[:read_len])
|
||||||
|
read_total += read_len
|
||||||
|
if !found_boundary {
|
||||||
|
boundary_loc = bytes.LastIndex(read_data[:read_total], boundary)
|
||||||
|
if boundary_loc == -1 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
found_boundary = true
|
||||||
|
}
|
||||||
|
start_loc := boundary_loc + len(boundary)
|
||||||
|
fmt.Println(string(read_data))
|
||||||
|
file_head_loc := bytes.Index(read_data[start_loc:read_total], []byte("\r\n\r\n"))
|
||||||
|
if file_head_loc == -1 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
file_head_loc += start_loc
|
||||||
|
ret := false
|
||||||
|
headMap, ret := ParseFileHeader(read_data, boundary)
|
||||||
|
if !ret {
|
||||||
|
return headMap, nil, fmt.Errorf("ParseFileHeader fail:%s", string(read_data[start_loc:file_head_loc]))
|
||||||
|
}
|
||||||
|
return headMap, read_data[file_head_loc+4 : read_total], nil
|
||||||
|
}
|
||||||
|
return nil, nil, fmt.Errorf("reach to sream EOF")
|
||||||
|
}
|
||||||
|
|||||||
@ -3,9 +3,13 @@ package file
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"go.uber.org/goleak"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestNameAccumulation(t *testing.T) {
|
func TestNameAccumulation(t *testing.T) {
|
||||||
|
goleak.VerifyNone(t)
|
||||||
|
|
||||||
fmt.Println("aaa")
|
fmt.Println("aaa")
|
||||||
a := NameAccumulation("/mnt/test_1_1", "/")
|
a := NameAccumulation("/mnt/test_1_1", "/")
|
||||||
fmt.Println(a)
|
fmt.Println(a)
|
||||||
|
|||||||
@ -13,16 +13,19 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type MountList struct {
|
type MountList struct {
|
||||||
MountPoints []struct {
|
MountPoints []MountPoints `json:"mountPoints"`
|
||||||
MountPoint string `json:"MountPoint"`
|
}
|
||||||
Fs string `json:"Fs"`
|
type MountPoints struct {
|
||||||
Icon string `json:"Icon"`
|
MountPoint string `json:"MountPoint"`
|
||||||
} `json:"mountPoints"`
|
Fs string `json:"Fs"`
|
||||||
|
Icon string `json:"Icon"`
|
||||||
|
Name string `json:"Name"`
|
||||||
}
|
}
|
||||||
type MountPoint struct {
|
type MountPoint struct {
|
||||||
MountPoint string `json:"mount_point"`
|
MountPoint string `json:"mount_point"`
|
||||||
Fs string `json:"fs"`
|
Fs string `json:"fs"`
|
||||||
Icon string `json:"icon"`
|
Icon string `json:"icon"`
|
||||||
|
Name string `json:"name"`
|
||||||
}
|
}
|
||||||
type MountResult struct {
|
type MountResult struct {
|
||||||
Error string `json:"error"`
|
Error string `json:"error"`
|
||||||
@ -43,7 +46,7 @@ var DefaultTimeout = time.Second * 30
|
|||||||
|
|
||||||
func NewRestyClient() *resty.Client {
|
func NewRestyClient() *resty.Client {
|
||||||
|
|
||||||
unixSocket := "/tmp/rclone.sock"
|
unixSocket := "/var/run/rclone/rclone.sock"
|
||||||
|
|
||||||
transport := http.Transport{
|
transport := http.Transport{
|
||||||
Dial: func(_, _ string) (net.Conn, error) {
|
Dial: func(_, _ string) (net.Conn, error) {
|
||||||
@ -73,10 +76,13 @@ func GetMountList() (MountList, error) {
|
|||||||
}
|
}
|
||||||
return result, err
|
return result, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func Mount(mountPoint string, fs string) error {
|
func Mount(mountPoint string, fs string) error {
|
||||||
res, err := NewRestyClient().R().SetFormData(map[string]string{
|
res, err := NewRestyClient().R().SetFormData(map[string]string{
|
||||||
"mountPoint": mountPoint,
|
"mountPoint": mountPoint,
|
||||||
"fs": fs,
|
"fs": fs,
|
||||||
|
"mountOpt": `{"AllowOther": true}`,
|
||||||
|
"vfsOpt": `{"CacheMode": 3}`,
|
||||||
}).Post("/mount/mount")
|
}).Post("/mount/mount")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -99,6 +105,7 @@ func Unmount(mountPoint string) error {
|
|||||||
logger.Error("then unmount failed", zap.Any("res", res.Body()))
|
logger.Error("then unmount failed", zap.Any("res", res.Body()))
|
||||||
return fmt.Errorf("unmount failed")
|
return fmt.Errorf("unmount failed")
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.Info("unmount then", zap.Any("res", res.Body()))
|
logger.Info("unmount then", zap.Any("res", res.Body()))
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
78
pkg/utils/httper/zerotier.go
Normal file
78
pkg/utils/httper/zerotier.go
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
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
|
||||||
|
}
|
||||||
@ -1,6 +1,7 @@
|
|||||||
package ip_helper
|
package ip_helper
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
@ -10,21 +11,22 @@ import (
|
|||||||
func IsIPv4(address string) bool {
|
func IsIPv4(address string) bool {
|
||||||
return strings.Count(address, ":") < 2
|
return strings.Count(address, ":") < 2
|
||||||
}
|
}
|
||||||
|
|
||||||
func IsIPv6(address string) bool {
|
func IsIPv6(address string) bool {
|
||||||
return strings.Count(address, ":") >= 2
|
return strings.Count(address, ":") >= 2
|
||||||
}
|
}
|
||||||
|
|
||||||
//获取外网ip
|
// 获取外网ip
|
||||||
func GetExternalIPV4() string {
|
func GetExternalIPV4() string {
|
||||||
return httper2.Get("https://api.ipify.org", nil)
|
return httper2.Get("https://api.ipify.org", nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
//获取外网ip
|
// 获取外网ip
|
||||||
func GetExternalIPV6() string {
|
func GetExternalIPV6() string {
|
||||||
return httper2.Get("https://api6.ipify.org", nil)
|
return httper2.Get("https://api6.ipify.org", nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
//获取本地ip
|
// 获取本地ip
|
||||||
func GetLoclIp() string {
|
func GetLoclIp() string {
|
||||||
addrs, err := net.InterfaceAddrs()
|
addrs, err := net.InterfaceAddrs()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -35,11 +37,11 @@ func GetLoclIp() string {
|
|||||||
if ipnet.IP.To4() != nil {
|
if ipnet.IP.To4() != nil {
|
||||||
return ipnet.IP.String()
|
return ipnet.IP.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return "127.0.0.1"
|
return "127.0.0.1"
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetDeviceAllIP(port string) []string {
|
func GetDeviceAllIP(port string) []string {
|
||||||
var address []string
|
var address []string
|
||||||
addrs, err := net.InterfaceAddrs()
|
addrs, err := net.InterfaceAddrs()
|
||||||
@ -55,12 +57,34 @@ 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
|
||||||
}
|
}
|
||||||
ip.String()
|
|
||||||
|
|
||||||
ip4 := ip.To4()
|
ip4 := ip.To4()
|
||||||
if ip4 == nil {
|
if ip4 == nil {
|
||||||
|
|||||||
@ -4,23 +4,28 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"go.uber.org/goleak"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestGetExternalIPV4(t *testing.T) {
|
func TestGetExternalIPV4(t *testing.T) {
|
||||||
|
goleak.VerifyNone(t)
|
||||||
|
|
||||||
ipv4 := make(chan string)
|
ipv4 := make(chan string)
|
||||||
go func() { ipv4 <- GetExternalIPV4() }()
|
go func() { ipv4 <- GetExternalIPV4() }()
|
||||||
fmt.Println(<-ipv4)
|
fmt.Println(<-ipv4)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGetExternalIPV6(t *testing.T) {
|
func TestGetExternalIPV6(t *testing.T) {
|
||||||
ipv6 := make(chan string)
|
ipv6 := make(chan string)
|
||||||
go func() { ipv6 <- GetExternalIPV6() }()
|
go func() { ipv6 <- GetExternalIPV6() }()
|
||||||
fmt.Println(<-ipv6)
|
fmt.Println(<-ipv6)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGetLoclIp(t *testing.T) {
|
func TestGetLoclIp(t *testing.T) {
|
||||||
fmt.Println(GetLoclIp())
|
fmt.Println(GetLoclIp())
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestHasLocalIP(t *testing.T) {
|
func TestHasLocalIP(t *testing.T) {
|
||||||
fmt.Println("dddd")
|
fmt.Println("dddd")
|
||||||
fmt.Println(HasLocalIP(net.ParseIP("192.168.2.10")))
|
fmt.Println(HasLocalIP(net.ParseIP("192.168.2.10")))
|
||||||
|
|||||||
@ -17,6 +17,7 @@ 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"
|
||||||
@ -24,6 +25,7 @@ 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"
|
||||||
)
|
)
|
||||||
@ -31,6 +33,7 @@ import (
|
|||||||
func InitFunction() {
|
func InitFunction() {
|
||||||
go InitNetworkMount()
|
go InitNetworkMount()
|
||||||
go InitInfo()
|
go InitInfo()
|
||||||
|
//go InitZerotier()
|
||||||
}
|
}
|
||||||
|
|
||||||
func InitInfo() {
|
func InitInfo() {
|
||||||
@ -51,6 +54,12 @@ 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 {
|
||||||
@ -93,9 +102,11 @@ func InitNetworkMount() {
|
|||||||
connection.Directories = strings.Join(directories, ",")
|
connection.Directories = strings.Join(directories, ",")
|
||||||
service.MyService.Connections().UpdateConnection(&connection)
|
service.MyService.Connections().UpdateConnection(&connection)
|
||||||
}
|
}
|
||||||
|
|
||||||
err := service.MyService.Storage().CheckAndMountAll()
|
err := service.MyService.Storage().CheckAndMountAll()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Error("mount storage err", zap.Any("err", err))
|
logger.Error("mount storage err", zap.Any("err", err))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
func InitZerotier() {
|
||||||
|
v1.CheckNetwork()
|
||||||
|
}
|
||||||
|
|||||||
103
route/v1.go
103
route/v1.go
@ -1,45 +1,69 @@
|
|||||||
package route
|
package route
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"os"
|
"crypto/ecdsa"
|
||||||
|
"net/http"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
"github.com/IceWhaleTech/CasaOS-Common/middleware"
|
"github.com/IceWhaleTech/CasaOS-Common/external"
|
||||||
"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"
|
||||||
"github.com/gin-contrib/gzip"
|
echo_middleware "github.com/labstack/echo/v4/middleware"
|
||||||
"github.com/gin-gonic/gin"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func InitV1Router() *gin.Engine {
|
func InitV1Router() http.Handler {
|
||||||
ginMode := gin.ReleaseMode
|
e := echo.New()
|
||||||
if config.ServerInfo.RunMode != "" {
|
|
||||||
ginMode = config.ServerInfo.RunMode
|
|
||||||
}
|
|
||||||
if os.Getenv(gin.EnvGinMode) != "" {
|
|
||||||
ginMode = os.Getenv(gin.EnvGinMode)
|
|
||||||
}
|
|
||||||
gin.SetMode(ginMode)
|
|
||||||
|
|
||||||
r := gin.New()
|
e.Use((echo_middleware.CORSWithConfig(echo_middleware.CORSConfig{
|
||||||
r.Use(gin.Recovery())
|
AllowOrigins: []string{"*"},
|
||||||
r.Use(middleware.Cors())
|
AllowMethods: []string{echo.POST, echo.GET, echo.OPTIONS, echo.PUT, echo.DELETE},
|
||||||
r.Use(gzip.Gzip(gzip.DefaultCompression))
|
AllowHeaders: []string{echo.HeaderAuthorization, echo.HeaderContentLength, echo.HeaderXCSRFToken, echo.HeaderContentType, echo.HeaderAccessControlAllowOrigin, echo.HeaderAccessControlAllowHeaders, echo.HeaderAccessControlAllowMethods, echo.HeaderConnection, echo.HeaderOrigin, echo.HeaderXRequestedWith},
|
||||||
if ginMode != gin.ReleaseMode {
|
ExposeHeaders: []string{echo.HeaderContentLength, echo.HeaderAccessControlAllowOrigin, echo.HeaderAccessControlAllowHeaders},
|
||||||
r.Use(middleware.WriteLog())
|
MaxAge: 172800,
|
||||||
}
|
AllowCredentials: true,
|
||||||
|
})))
|
||||||
|
e.Use(echo_middleware.Gzip())
|
||||||
|
e.Use(echo_middleware.Recover())
|
||||||
|
e.Use(echo_middleware.Logger())
|
||||||
|
|
||||||
r.GET("/v1/sys/debug", v1.GetSystemConfigDebug) // //debug
|
e.GET("/v1/sys/debug", v1.GetSystemConfigDebug) // //debug
|
||||||
|
|
||||||
r.GET("/v1/sys/version/check", v1.GetSystemCheckVersion)
|
e.GET("/v1/sys/version/check", v1.GetSystemCheckVersion)
|
||||||
r.GET("/ping", func(ctx *gin.Context) {
|
e.GET("/v1/sys/version/current", func(ctx echo.Context) error {
|
||||||
ctx.String(200, "pong")
|
return ctx.String(200, common.VERSION)
|
||||||
})
|
})
|
||||||
r.GET("/v1/recover/:type", v1.GetRecoverStorage)
|
e.GET("/ping", func(ctx echo.Context) error {
|
||||||
v1Group := r.Group("/v1")
|
return ctx.String(200, "pong")
|
||||||
|
})
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
v1Group.Use(jwt.ExceptLocalhost())
|
c.Request().Header.Set("user_id", strconv.Itoa(claims.ID))
|
||||||
|
|
||||||
|
return claims, nil
|
||||||
|
},
|
||||||
|
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")
|
||||||
@ -73,6 +97,7 @@ func InitV1Router() *gin.Engine {
|
|||||||
// 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()
|
||||||
@ -80,7 +105,6 @@ func InitV1Router() *gin.Engine {
|
|||||||
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()
|
||||||
{
|
{
|
||||||
@ -92,22 +116,25 @@ func InitV1Router() *gin.Engine {
|
|||||||
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.GET("/upload", v1.GetFileUpload)
|
v1FileGroup.GET("/upload", v1.GetFileUpload)
|
||||||
// v1FileGroup.GET("/download", v1.UserFileDownloadCommonService)
|
// v1FileGroup.GET("/download", v1.UserFileDownloadCommonService)
|
||||||
|
v1FileGroup.GET("/ws", v1.ConnectWebSocket)
|
||||||
|
v1FileGroup.GET("/peers", v1.GetPeers)
|
||||||
}
|
}
|
||||||
v1CloudGroup := v1Group.Group("/cloud")
|
v1CloudGroup := v1Group.Group("/cloud")
|
||||||
v1CloudGroup.Use()
|
v1CloudGroup.Use()
|
||||||
{
|
{
|
||||||
v1CloudGroup.GET("", v1.ListStorages)
|
v1CloudGroup.GET("", v1.ListStorages)
|
||||||
v1CloudGroup.DELETE("", v1.DeleteStorage)
|
v1CloudGroup.DELETE("", v1.UmountStorage)
|
||||||
}
|
}
|
||||||
v1DriverGroup := v1Group.Group("/driver")
|
v1DriverGroup := v1Group.Group("/driver")
|
||||||
v1DriverGroup.Use()
|
v1DriverGroup.Use()
|
||||||
{
|
{
|
||||||
v1DriverGroup.GET("", v1.ListDriverInfo)
|
v1DriverGroup.GET("", v1.ListDriverInfo)
|
||||||
}
|
}
|
||||||
|
|
||||||
v1FolderGroup := v1Group.Group("/folder")
|
v1FolderGroup := v1Group.Group("/folder")
|
||||||
v1FolderGroup.Use()
|
v1FolderGroup.Use()
|
||||||
{
|
{
|
||||||
@ -115,6 +142,7 @@ func InitV1Router() *gin.Engine {
|
|||||||
v1FolderGroup.GET("", v1.DirPath) ///file/dirpath
|
v1FolderGroup.GET("", v1.DirPath) ///file/dirpath
|
||||||
v1FolderGroup.POST("", v1.MkdirAll) ///file/mkdir
|
v1FolderGroup.POST("", v1.MkdirAll) ///file/mkdir
|
||||||
v1FolderGroup.GET("/size", v1.GetSize)
|
v1FolderGroup.GET("/size", v1.GetSize)
|
||||||
|
v1FolderGroup.GET("/count", v1.GetFileCount)
|
||||||
}
|
}
|
||||||
v1BatchGroup := v1Group.Group("/batch")
|
v1BatchGroup := v1Group.Group("/batch")
|
||||||
v1BatchGroup.Use()
|
v1BatchGroup.Use()
|
||||||
@ -156,7 +184,18 @@ func InitV1Router() *gin.Engine {
|
|||||||
// merge to system
|
// merge to system
|
||||||
v1NotifyGroup.POST("/system_status", v1.PostSystemStatusNotify)
|
v1NotifyGroup.POST("/system_status", v1.PostSystemStatusNotify)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
v1OtherGroup := v1Group.Group("/other")
|
||||||
|
v1OtherGroup.Use()
|
||||||
|
{
|
||||||
|
v1OtherGroup.GET("/search", v1.GetSearchResult)
|
||||||
|
}
|
||||||
|
v1ZerotierGroup := v1Group.Group("/zt")
|
||||||
|
v1ZerotierGroup.Use()
|
||||||
|
{
|
||||||
|
v1ZerotierGroup.Any("/*url", v1.ZerotierProxy)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return r
|
return e
|
||||||
}
|
}
|
||||||
|
|||||||
79
route/v1/cloud.go
Normal file
79
route/v1/cloud.go
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
package v1
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/IceWhaleTech/CasaOS-Common/utils/logger"
|
||||||
|
"github.com/IceWhaleTech/CasaOS/drivers/dropbox"
|
||||||
|
"github.com/IceWhaleTech/CasaOS/drivers/google_drive"
|
||||||
|
"github.com/IceWhaleTech/CasaOS/drivers/onedrive"
|
||||||
|
"github.com/IceWhaleTech/CasaOS/model"
|
||||||
|
"github.com/IceWhaleTech/CasaOS/pkg/utils/common_err"
|
||||||
|
"github.com/IceWhaleTech/CasaOS/pkg/utils/httper"
|
||||||
|
"github.com/IceWhaleTech/CasaOS/service"
|
||||||
|
"github.com/labstack/echo/v4"
|
||||||
|
"go.uber.org/zap"
|
||||||
|
)
|
||||||
|
|
||||||
|
func ListStorages(ctx echo.Context) error {
|
||||||
|
r, err := service.MyService.Storage().GetStorages()
|
||||||
|
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()})
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 0; i < len(r.MountPoints); i++ {
|
||||||
|
dataMap, err := service.MyService.Storage().GetConfigByName(r.MountPoints[i].Fs)
|
||||||
|
if err != nil {
|
||||||
|
logger.Error("GetConfigByName", zap.Any("err", err))
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if dataMap["type"] == "drive" {
|
||||||
|
r.MountPoints[i].Icon = google_drive.ICONURL
|
||||||
|
}
|
||||||
|
if dataMap["type"] == "dropbox" {
|
||||||
|
r.MountPoints[i].Icon = dropbox.ICONURL
|
||||||
|
}
|
||||||
|
if dataMap["type"] == "onedrive" {
|
||||||
|
r.MountPoints[i].Icon = onedrive.ICONURL
|
||||||
|
}
|
||||||
|
r.MountPoints[i].Name = dataMap["username"]
|
||||||
|
}
|
||||||
|
list := []httper.MountPoint{}
|
||||||
|
|
||||||
|
for _, v := range r.MountPoints {
|
||||||
|
list = append(list, httper.MountPoint(v))
|
||||||
|
}
|
||||||
|
|
||||||
|
return ctx.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 {
|
||||||
|
json := make(map[string]string)
|
||||||
|
ctx.Bind(&json)
|
||||||
|
mountPoint := json["mount_point"]
|
||||||
|
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"})
|
||||||
|
}
|
||||||
|
err := service.MyService.Storage().UnmountStorage(mountPoint)
|
||||||
|
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()})
|
||||||
|
}
|
||||||
|
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"})
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetStorage(ctx echo.Context) error {
|
||||||
|
// idStr := ctx.QueryParam("id")
|
||||||
|
// id, err := strconv.Atoi(idStr)
|
||||||
|
// 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()})
|
||||||
|
// return
|
||||||
|
// }
|
||||||
|
// storage, err := service.MyService.Storage().GetStorageById(uint(id))
|
||||||
|
// 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()})
|
||||||
|
// return
|
||||||
|
// }
|
||||||
|
// return ctx.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: storage})
|
||||||
|
return nil
|
||||||
|
}
|
||||||
@ -1,12 +1,34 @@
|
|||||||
package v1
|
package v1
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/IceWhaleTech/CasaOS/internal/op"
|
"github.com/IceWhaleTech/CasaOS-Common/utils/common_err"
|
||||||
|
"github.com/IceWhaleTech/CasaOS/drivers/dropbox"
|
||||||
|
"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/labstack/echo/v4"
|
||||||
"github.com/gin-gonic/gin"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func ListDriverInfo(c *gin.Context) {
|
func ListDriverInfo(ctx echo.Context) error {
|
||||||
c.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: op.GetDriverInfoMap()})
|
list := []model.Drive{}
|
||||||
|
|
||||||
|
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})
|
||||||
}
|
}
|
||||||
|
|||||||
840
route/v1/file.go
840
route/v1/file.go
File diff suppressed because it is too large
Load Diff
@ -1,96 +0,0 @@
|
|||||||
package v1
|
|
||||||
|
|
||||||
import (
|
|
||||||
"path/filepath"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/IceWhaleTech/CasaOS/model"
|
|
||||||
"github.com/IceWhaleTech/CasaOS/pkg/utils/common_err"
|
|
||||||
"github.com/IceWhaleTech/CasaOS/service"
|
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
|
||||||
)
|
|
||||||
|
|
||||||
type ListReq struct {
|
|
||||||
model.PageReq
|
|
||||||
Path string `json:"path" form:"path"`
|
|
||||||
//Refresh bool `json:"refresh"`
|
|
||||||
}
|
|
||||||
type ObjResp struct {
|
|
||||||
Name string `json:"name"`
|
|
||||||
Size int64 `json:"size"`
|
|
||||||
IsDir bool `json:"is_dir"`
|
|
||||||
Modified time.Time `json:"modified"`
|
|
||||||
Sign string `json:"sign"`
|
|
||||||
Thumb string `json:"thumb"`
|
|
||||||
Type int `json:"type"`
|
|
||||||
Path string `json:"path"`
|
|
||||||
Extensions map[string]interface{} `json:"extensions"`
|
|
||||||
}
|
|
||||||
type FsListResp struct {
|
|
||||||
Content []ObjResp `json:"content"`
|
|
||||||
Total int64 `json:"total"`
|
|
||||||
Readme string `json:"readme,omitempty"`
|
|
||||||
Write bool `json:"write,omitempty"`
|
|
||||||
Provider string `json:"provider,omitempty"`
|
|
||||||
Index int `json:"index"`
|
|
||||||
Size int `json:"size"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func FsList(c *gin.Context) {
|
|
||||||
var req ListReq
|
|
||||||
if err := c.ShouldBind(&req); err != nil {
|
|
||||||
c.JSON(common_err.SUCCESS, model.Result{Success: common_err.CLIENT_ERROR, Message: common_err.GetMsg(common_err.CLIENT_ERROR), Data: err.Error()})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
req.Validate()
|
|
||||||
objs, err := service.MyService.FsService().FList(c, req.Path, false)
|
|
||||||
if err != nil {
|
|
||||||
c.JSON(common_err.SUCCESS, model.Result{Success: common_err.SERVICE_ERROR, Message: common_err.GetMsg(common_err.SERVICE_ERROR), Data: err.Error()})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
total, objs := pagination(objs, &req.PageReq)
|
|
||||||
provider := "unknown"
|
|
||||||
storage, err := service.MyService.FsService().GetStorage(req.Path)
|
|
||||||
if err == nil {
|
|
||||||
provider = storage.GetStorage().Driver
|
|
||||||
}
|
|
||||||
c.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: FsListResp{
|
|
||||||
Content: toObjsResp(objs, req.Path, false),
|
|
||||||
Total: int64(total),
|
|
||||||
Readme: "",
|
|
||||||
Write: false,
|
|
||||||
Provider: provider,
|
|
||||||
}})
|
|
||||||
}
|
|
||||||
func pagination(objs []model.Obj, req *model.PageReq) (int, []model.Obj) {
|
|
||||||
pageIndex, pageSize := req.Index, req.Size
|
|
||||||
total := len(objs)
|
|
||||||
start := (pageIndex - 1) * pageSize
|
|
||||||
if start > total {
|
|
||||||
return total, []model.Obj{}
|
|
||||||
}
|
|
||||||
end := start + pageSize
|
|
||||||
if end > total {
|
|
||||||
end = total
|
|
||||||
}
|
|
||||||
return total, objs[start:end]
|
|
||||||
}
|
|
||||||
|
|
||||||
func toObjsResp(objs []model.Obj, parent string, encrypt bool) []ObjResp {
|
|
||||||
var resp []ObjResp
|
|
||||||
for _, obj := range objs {
|
|
||||||
thumb, _ := model.GetThumb(obj)
|
|
||||||
resp = append(resp, ObjResp{
|
|
||||||
Name: obj.GetName(),
|
|
||||||
Size: obj.GetSize(),
|
|
||||||
IsDir: obj.IsDir(),
|
|
||||||
Modified: obj.ModTime(),
|
|
||||||
Sign: "",
|
|
||||||
Path: filepath.Join(parent, obj.GetName()),
|
|
||||||
Thumb: thumb,
|
|
||||||
Type: 0,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
return resp
|
|
||||||
}
|
|
||||||
@ -6,28 +6,26 @@ 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/gin-gonic/gin"
|
"github.com/labstack/echo/v4"
|
||||||
)
|
)
|
||||||
|
|
||||||
func PostNotifyMessage(c *gin.Context) {
|
func PostNotifyMessage(ctx echo.Context) error {
|
||||||
name := c.Param("name")
|
name := ctx.Param("name")
|
||||||
message := make(map[string]interface{})
|
message := make(map[string]interface{})
|
||||||
if err := c.ShouldBind(&message); err != nil {
|
if err := ctx.Bind(&message); err != nil {
|
||||||
c.JSON(http.StatusBadRequest, model.Result{Success: common_err.INVALID_PARAMS, Message: err.Error()})
|
return ctx.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)
|
||||||
c.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS)})
|
return ctx.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS)})
|
||||||
}
|
}
|
||||||
|
|
||||||
func PostSystemStatusNotify(c *gin.Context) {
|
func PostSystemStatusNotify(ctx echo.Context) error {
|
||||||
message := make(map[string]interface{})
|
message := make(map[string]interface{})
|
||||||
if err := c.ShouldBind(&message); err != nil {
|
if err := ctx.Bind(&message); err != nil {
|
||||||
c.JSON(http.StatusBadRequest, model.Result{Success: common_err.INVALID_PARAMS, Message: err.Error()})
|
return ctx.JSON(http.StatusBadRequest, model.Result{Success: common_err.INVALID_PARAMS, Message: err.Error()})
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
service.MyService.Notify().SettingSystemTempData(message)
|
service.MyService.Notify().SettingSystemTempData(message)
|
||||||
c.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS)})
|
return ctx.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS)})
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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(c *gin.Context) {
|
func NotifyWS(ctx echo.Context) error {
|
||||||
//升级get请求为webSocket协议
|
// 升级get请求为webSocket协议
|
||||||
ws, err := upGrader.Upgrade(c.Writer, c.Request, nil)
|
ws, err := upGrader.Upgrade(ctx.Response().Writer, ctx.Request(), nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return nil
|
||||||
}
|
}
|
||||||
defer ws.Close()
|
defer ws.Close()
|
||||||
service.WebSocketConns = append(service.WebSocketConns, ws)
|
service.WebSocketConns = append(service.WebSocketConns, ws)
|
||||||
@ -41,7 +41,6 @@ func NotifyWS(c *gin.Context) {
|
|||||||
mt, message, err := ws.ReadMessage()
|
mt, message, err := ws.ReadMessage()
|
||||||
fmt.Println(mt, message, err)
|
fmt.Println(mt, message, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// @Summary 标记notify已读
|
// @Summary 标记notify已读
|
||||||
@ -51,12 +50,13 @@ func NotifyWS(c *gin.Context) {
|
|||||||
// @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(c *gin.Context) {
|
func PutNotifyRead(ctx echo.Context) error {
|
||||||
id := c.Param("id")
|
id := ctx.Param("id")
|
||||||
// if len(id) == 0 {
|
// if len(id) == 0 {
|
||||||
// c.JSON(http.StatusOK, model.Result{Success: oasis_err.INVALID_PARAMS, Message: oasis_err.GetMsg(oasis_err.INVALID_PARAMS)})
|
// return ctx.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
|
||||||
}
|
}
|
||||||
|
|||||||
28
route/v1/other.go
Normal file
28
route/v1/other.go
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
package v1
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/IceWhaleTech/CasaOS/model"
|
||||||
|
"github.com/IceWhaleTech/CasaOS/pkg/utils/common_err"
|
||||||
|
"github.com/IceWhaleTech/CasaOS/service"
|
||||||
|
"github.com/labstack/echo/v4"
|
||||||
|
)
|
||||||
|
|
||||||
|
func GetSearchResult(ctx echo.Context) error {
|
||||||
|
json := make(map[string]string)
|
||||||
|
ctx.Bind(&json)
|
||||||
|
url := json["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"})
|
||||||
|
}
|
||||||
|
// data, err := service.MyService.Other().Search(key)
|
||||||
|
data, err := service.MyService.Other().AgentSearch(url)
|
||||||
|
if err != nil {
|
||||||
|
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()})
|
||||||
|
}
|
||||||
|
|
||||||
|
return ctx.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: data})
|
||||||
|
}
|
||||||
@ -1,67 +1,63 @@
|
|||||||
package v1
|
package v1
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
|
"net/http"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"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"
|
||||||
fileutil "github.com/IceWhaleTech/CasaOS/pkg/utils/file"
|
"github.com/IceWhaleTech/CasaOS/drivers/onedrive"
|
||||||
"github.com/IceWhaleTech/CasaOS/service"
|
"github.com/IceWhaleTech/CasaOS/service"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/labstack/echo/v4"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
)
|
)
|
||||||
|
|
||||||
func GetRecoverStorage(c *gin.Context) {
|
func GetRecoverStorage(ctx echo.Context) error {
|
||||||
c.Header("Content-Type", "text/html; charset=utf-8")
|
t := strings.TrimSuffix(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{})
|
||||||
|
event := "casaos:file:recover"
|
||||||
if t == "GoogleDrive" {
|
if t == "GoogleDrive" {
|
||||||
add := google_drive.Addition{}
|
google_drive := google_drive.GetConfig()
|
||||||
add.Code = c.Query("code")
|
google_drive.Code = ctx.QueryParam("code")
|
||||||
if len(add.Code) == 0 {
|
if len(google_drive.Code) == 0 {
|
||||||
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"))
|
||||||
service.MyService.Notify().SendNotify("casaos:file:recover", notify)
|
service.MyService.Notify().SendNotify("casaos:file:recover", notify)
|
||||||
return
|
return ctx.HTML(http.StatusOK, `<p>Code cannot be empty</p><script>window.close()</script>`)
|
||||||
}
|
}
|
||||||
|
err := google_drive.Init(context.Background())
|
||||||
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 {
|
||||||
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"
|
||||||
service.MyService.Notify().SendNotify("casaos:file:recover", notify)
|
logger.Error("Then init error: ", zap.Error(err), zap.Any("name", "google_drive"))
|
||||||
return
|
service.MyService.Notify().SendNotify(event, notify)
|
||||||
|
return ctx.HTML(http.StatusOK, `<p>Initialization failure:`+err.Error()+`</p><script>window.close()</script>`)
|
||||||
}
|
}
|
||||||
|
|
||||||
username, err := google_drive.GetUserInfo(c)
|
username, err := google_drive.GetUserInfo(context.Background())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
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"
|
||||||
service.MyService.Notify().SendNotify("casaos:file:recover", notify)
|
logger.Error("Then get user info error: ", zap.Error(err), zap.Any("name", "google_drive"))
|
||||||
return
|
service.MyService.Notify().SendNotify(event, notify)
|
||||||
|
return ctx.HTML(http.StatusOK, `<p>Failed to get user information:`+err.Error()+`</p><script>window.close()</script>`)
|
||||||
}
|
}
|
||||||
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 {
|
||||||
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 rclone config"
|
||||||
service.MyService.Notify().SendNotify("casaos:file:recover", notify)
|
logger.Error("Then get config error: ", zap.Error(err), zap.Any("name", "google_drive"))
|
||||||
return
|
service.MyService.Notify().SendNotify(event, notify)
|
||||||
|
return ctx.HTML(http.StatusOK, `<p>Failed to get rclone config:`+err.Error()+`</p><script>window.close()</script>`)
|
||||||
}
|
}
|
||||||
for _, v := range configs.Remotes {
|
for _, v := range configs.Remotes {
|
||||||
cf, err := service.MyService.Storage().GetConfigByName(v)
|
cf, err := service.MyService.Storage().GetConfigByName(v)
|
||||||
@ -70,27 +66,25 @@ func GetRecoverStorage(c *gin.Context) {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if cf["type"] == "drive" && cf["username"] == dmap["username"] {
|
if cf["type"] == "drive" && cf["username"] == dmap["username"] {
|
||||||
c.String(200, `<p>The same configuration has been added</p><script>window.close()</script>`)
|
err := service.MyService.Storage().CheckAndMountByName(v)
|
||||||
service.MyService.Storage().CheckAndMountByName(cf["username"])
|
if err != nil {
|
||||||
|
logger.Error("check and mount by name error: ", zap.Error(err), zap.Any("name", cf["username"]))
|
||||||
|
}
|
||||||
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(event, notify)
|
||||||
return
|
return ctx.HTML(http.StatusOK, `<p>The same configuration has been added</p><script>window.close()</script>`)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if len(username) > 0 {
|
if len(username) > 0 {
|
||||||
a := strings.Split(username, "@")
|
a := strings.Split(username, "@")
|
||||||
username = a[0]
|
username = a[0]
|
||||||
}
|
}
|
||||||
username = fileutil.NameAccumulation(username, "/mnt")
|
|
||||||
|
|
||||||
dataMap, _ := service.MyService.Storage().GetConfigByName(username)
|
username += "_google_drive_" + strconv.FormatInt(time.Now().Unix(), 10)
|
||||||
if len(dataMap) > 0 {
|
|
||||||
service.MyService.Storage().UnmountStorage("/mnt/" + username)
|
dmap["client_id"] = google_drive.ClientID
|
||||||
service.MyService.Storage().DeleteConfigByName(username)
|
dmap["client_secret"] = google_drive.ClientSecret
|
||||||
}
|
|
||||||
dmap["client_id"] = add.ClientID
|
|
||||||
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"}`
|
||||||
@ -99,48 +93,46 @@ func GetRecoverStorage(c *gin.Context) {
|
|||||||
notify := make(map[string]interface{})
|
notify := make(map[string]interface{})
|
||||||
notify["status"] = "success"
|
notify["status"] = "success"
|
||||||
notify["message"] = "Success"
|
notify["message"] = "Success"
|
||||||
service.MyService.Notify().SendNotify("casaos:file:recover", notify)
|
notify["driver"] = "GoogleDrive"
|
||||||
|
service.MyService.Notify().SendNotify(event, notify)
|
||||||
} else if t == "Dropbox" {
|
} else if t == "Dropbox" {
|
||||||
add := dropbox.Addition{}
|
dropbox := dropbox.GetConfig()
|
||||||
add.Code = c.Query("code")
|
|
||||||
if len(add.Code) == 0 {
|
dropbox.Code = ctx.QueryParam("code")
|
||||||
c.String(200, `<p>Code cannot be empty</p><script>window.close()</script>`)
|
if len(dropbox.Code) == 0 {
|
||||||
|
|
||||||
notify["status"] = "fail"
|
notify["status"] = "fail"
|
||||||
notify["message"] = "Code cannot be empty"
|
notify["message"] = "Code cannot be empty"
|
||||||
service.MyService.Notify().SendNotify("casaos:file:recover", notify)
|
logger.Error("Then code is empty error: ", zap.String("code", dropbox.Code), zap.Any("name", "dropbox"))
|
||||||
return
|
service.MyService.Notify().SendNotify(event, notify)
|
||||||
|
return ctx.HTML(http.StatusOK, `<p>Code cannot be empty</p><script>window.close()</script>`)
|
||||||
}
|
}
|
||||||
add.RootFolderID = ""
|
err := dropbox.Init(context.Background())
|
||||||
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 {
|
||||||
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"
|
||||||
service.MyService.Notify().SendNotify("casaos:file:recover", notify)
|
logger.Error("Then init error: ", zap.Error(err), zap.Any("name", "dropbox"))
|
||||||
return
|
service.MyService.Notify().SendNotify(event, notify)
|
||||||
|
return ctx.HTML(http.StatusOK, `<p>Initialization failure:`+err.Error()+`</p><script>window.close()</script>`)
|
||||||
}
|
}
|
||||||
username, err := dropbox.GetUserInfo(c)
|
username, err := dropbox.GetUserInfo(context.Background())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
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"
|
||||||
service.MyService.Notify().SendNotify("casaos:file:recover", notify)
|
logger.Error("Then get user information: ", zap.Error(err), zap.Any("name", "dropbox"))
|
||||||
return
|
service.MyService.Notify().SendNotify(event, notify)
|
||||||
|
return ctx.HTML(http.StatusOK, `<p>Failed to get user information:`+err.Error()+`</p><script>window.close()</script>`)
|
||||||
}
|
}
|
||||||
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 {
|
||||||
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 rclone config"
|
||||||
service.MyService.Notify().SendNotify("casaos:file:recover", notify)
|
logger.Error("Then get config error: ", zap.Error(err), zap.Any("name", "dropbox"))
|
||||||
return
|
service.MyService.Notify().SendNotify(event, notify)
|
||||||
|
return ctx.HTML(http.StatusOK, `<p>Failed to get rclone config:`+err.Error()+`</p><script>window.close()</script>`)
|
||||||
}
|
}
|
||||||
for _, v := range configs.Remotes {
|
for _, v := range configs.Remotes {
|
||||||
cf, err := service.MyService.Storage().GetConfigByName(v)
|
cf, err := service.MyService.Storage().GetConfigByName(v)
|
||||||
@ -149,49 +141,107 @@ func GetRecoverStorage(c *gin.Context) {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if cf["type"] == "dropbox" && cf["username"] == dmap["username"] {
|
if cf["type"] == "dropbox" && cf["username"] == dmap["username"] {
|
||||||
c.String(200, `<p>The same configuration has been added</p><script>window.close()</script>`)
|
if err := service.MyService.Storage().CheckAndMountByName(v); err != nil {
|
||||||
service.MyService.Storage().CheckAndMountByName(cf["username"])
|
logger.Error("check and mount by name error: ", zap.Error(err), zap.Any("name", cf["username"]))
|
||||||
|
}
|
||||||
|
|
||||||
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(event, notify)
|
||||||
return
|
return ctx.HTML(http.StatusOK, `<p>The same configuration has been added</p><script>window.close()</script>`)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if len(username) > 0 {
|
if len(username) > 0 {
|
||||||
a := strings.Split(username, "@")
|
a := strings.Split(username, "@")
|
||||||
username = a[0]
|
username = a[0]
|
||||||
}
|
}
|
||||||
username = fileutil.NameAccumulation(username, "/mnt")
|
username += "_dropbox_" + strconv.FormatInt(time.Now().Unix(), 10)
|
||||||
dataMap, _ := service.MyService.Storage().GetConfigByName(username)
|
|
||||||
if len(dataMap) > 0 {
|
|
||||||
|
|
||||||
service.MyService.Storage().UnmountStorage("/mnt/" + username)
|
dmap["client_id"] = dropbox.AppKey
|
||||||
service.MyService.Storage().DeleteConfigByName(username)
|
dmap["client_secret"] = dropbox.AppSecret
|
||||||
}
|
|
||||||
|
|
||||||
dmap["client_id"] = add.AppKey
|
|
||||||
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, "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 {
|
|
||||||
// c.String(200, `<p>保存配置失败:`+e.Error()+`</p>`)
|
|
||||||
|
|
||||||
// return
|
|
||||||
// }
|
|
||||||
service.MyService.Storage().CreateConfig(dmap, username, "dropbox")
|
service.MyService.Storage().CreateConfig(dmap, username, "dropbox")
|
||||||
service.MyService.Storage().MountStorage("/mnt/"+username, username+":")
|
service.MyService.Storage().MountStorage("/mnt/"+username, username+":")
|
||||||
|
|
||||||
notify["status"] = "success"
|
notify["status"] = "success"
|
||||||
notify["message"] = "Success"
|
notify["message"] = "Success"
|
||||||
service.MyService.Notify().SendNotify("casaos:file:recover", notify)
|
notify["driver"] = "Dropbox"
|
||||||
|
service.MyService.Notify().SendNotify(event, notify)
|
||||||
|
} else if t == "Onedrive" {
|
||||||
|
onedrive := onedrive.GetConfig()
|
||||||
|
onedrive.Code = ctx.QueryParam("code")
|
||||||
|
if len(onedrive.Code) == 0 {
|
||||||
|
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(event, notify)
|
||||||
|
return ctx.HTML(http.StatusOK, `<p>Code cannot be empty</p><script>window.close()</script>`)
|
||||||
|
}
|
||||||
|
err := onedrive.Init(context.Background())
|
||||||
|
if err != nil {
|
||||||
|
notify["status"] = "fail"
|
||||||
|
notify["message"] = "Initialization failure"
|
||||||
|
logger.Error("Then init error: ", zap.Error(err), zap.Any("name", "onedrive"))
|
||||||
|
service.MyService.Notify().SendNotify(event, notify)
|
||||||
|
return ctx.HTML(http.StatusOK, `<p>Initialization failure:`+err.Error()+`</p><script>window.close()</script>`)
|
||||||
|
}
|
||||||
|
username, driveId, driveType, err := onedrive.GetInfo(context.Background())
|
||||||
|
if err != nil {
|
||||||
|
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(event, notify)
|
||||||
|
return ctx.HTML(http.StatusOK, `<p>Failed to get user information:`+err.Error()+`</p><script>window.close()</script>`)
|
||||||
|
}
|
||||||
|
dmap := make(map[string]string)
|
||||||
|
dmap["username"] = username
|
||||||
|
|
||||||
|
configs, err := service.MyService.Storage().GetConfig()
|
||||||
|
if err != nil {
|
||||||
|
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(event, notify)
|
||||||
|
return ctx.HTML(http.StatusOK, `<p>Failed to get rclone config:`+err.Error()+`</p><script>window.close()</script>`)
|
||||||
|
}
|
||||||
|
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"] {
|
||||||
|
if err := service.MyService.Storage().CheckAndMountByName(v); 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(event, notify)
|
||||||
|
return ctx.HTML(http.StatusOK, `<p>The same configuration has been added</p><script>window.close()</script>`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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
|
||||||
|
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(event, notify)
|
||||||
}
|
}
|
||||||
|
|
||||||
c.String(200, `<p>Just close the page</p><script>window.close()</script>`)
|
return ctx.HTML(200, `<p>Just close the page</p><script>window.close()</script>`)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -16,32 +16,29 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"regexp"
|
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"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"
|
||||||
"github.com/IceWhaleTech/CasaOS/pkg/samba"
|
"github.com/IceWhaleTech/CasaOS/pkg/samba"
|
||||||
"github.com/IceWhaleTech/CasaOS/pkg/utils/common_err"
|
"github.com/IceWhaleTech/CasaOS/pkg/utils/common_err"
|
||||||
"github.com/IceWhaleTech/CasaOS/pkg/utils/file"
|
"github.com/IceWhaleTech/CasaOS/pkg/utils/file"
|
||||||
"github.com/IceWhaleTech/CasaOS/pkg/utils/ip_helper"
|
|
||||||
"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(c *gin.Context) {
|
func GetSambaStatus(ctx echo.Context) error {
|
||||||
if status, err := systemctl.IsServiceRunning("smbd"); err != nil || !status {
|
if status, err := systemctl.IsServiceRunning("smbd"); err != nil || !status {
|
||||||
c.JSON(http.StatusInternalServerError, model.Result{
|
return ctx.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
|
||||||
@ -53,10 +50,10 @@ func GetSambaStatus(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
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)
|
||||||
c.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: data})
|
return ctx.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: data})
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetSambaSharesList(c *gin.Context) {
|
func GetSambaSharesList(ctx echo.Context) error {
|
||||||
shares := service.MyService.Shares().GetSharesList()
|
shares := service.MyService.Shares().GetSharesList()
|
||||||
shareList := []model.Shares{}
|
shareList := []model.Shares{}
|
||||||
for _, v := range shares {
|
for _, v := range shares {
|
||||||
@ -66,28 +63,24 @@ func GetSambaSharesList(c *gin.Context) {
|
|||||||
ID: v.ID,
|
ID: v.ID,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
c.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: shareList})
|
return ctx.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: shareList})
|
||||||
}
|
}
|
||||||
|
|
||||||
func PostSambaSharesCreate(c *gin.Context) {
|
func PostSambaSharesCreate(ctx echo.Context) error {
|
||||||
shares := []model.Shares{}
|
shares := []model.Shares{}
|
||||||
c.ShouldBindJSON(&shares)
|
ctx.Bind(&shares)
|
||||||
for _, v := range shares {
|
for _, v := range shares {
|
||||||
if v.Path == "" {
|
if v.Path == "" {
|
||||||
c.JSON(common_err.CLIENT_ERROR, model.Result{Success: common_err.INSUFFICIENT_PERMISSIONS, Message: common_err.GetMsg(common_err.INSUFFICIENT_PERMISSIONS)})
|
return ctx.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) {
|
||||||
c.JSON(common_err.SERVICE_ERROR, model.Result{Success: common_err.DIR_NOT_EXISTS, Message: common_err.GetMsg(common_err.DIR_NOT_EXISTS)})
|
return ctx.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 {
|
||||||
c.JSON(common_err.CLIENT_ERROR, model.Result{Success: common_err.SHARE_ALREADY_EXISTS, Message: common_err.GetMsg(common_err.SHARE_ALREADY_EXISTS)})
|
return ctx.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 {
|
||||||
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 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)})
|
||||||
return
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for _, v := range shares {
|
for _, v := range shares {
|
||||||
@ -99,21 +92,20 @@ func PostSambaSharesCreate(c *gin.Context) {
|
|||||||
service.MyService.Shares().CreateShare(shareDBModel)
|
service.MyService.Shares().CreateShare(shareDBModel)
|
||||||
}
|
}
|
||||||
|
|
||||||
c.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: shares})
|
return ctx.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: shares})
|
||||||
}
|
}
|
||||||
|
|
||||||
func DeleteSambaShares(c *gin.Context) {
|
func DeleteSambaShares(ctx echo.Context) error {
|
||||||
id := c.Param("id")
|
id := ctx.Param("id")
|
||||||
if id == "" {
|
if id == "" {
|
||||||
c.JSON(common_err.CLIENT_ERROR, model.Result{Success: common_err.INSUFFICIENT_PERMISSIONS, Message: common_err.GetMsg(common_err.INSUFFICIENT_PERMISSIONS)})
|
return ctx.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)
|
||||||
c.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: id})
|
return ctx.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: id})
|
||||||
}
|
}
|
||||||
|
|
||||||
// client
|
// client
|
||||||
func GetSambaConnectionsList(c *gin.Context) {
|
func GetSambaConnectionsList(ctx echo.Context) error {
|
||||||
connections := service.MyService.Connections().GetConnectionsList()
|
connections := service.MyService.Connections().GetConnectionsList()
|
||||||
connectionList := []model.Connections{}
|
connectionList := []model.Connections{}
|
||||||
for _, v := range connections {
|
for _, v := range connections {
|
||||||
@ -125,49 +117,46 @@ func GetSambaConnectionsList(c *gin.Context) {
|
|||||||
MountPoint: v.MountPoint,
|
MountPoint: v.MountPoint,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
c.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: connectionList})
|
return ctx.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: connectionList})
|
||||||
}
|
}
|
||||||
|
|
||||||
func PostSambaConnectionsCreate(c *gin.Context) {
|
func PostSambaConnectionsCreate(ctx echo.Context) error {
|
||||||
connection := model.Connections{}
|
connection := model.Connections{}
|
||||||
c.ShouldBindJSON(&connection)
|
ctx.Bind(&connection)
|
||||||
if connection.Port == "" {
|
if connection.Port == "" {
|
||||||
connection.Port = "445"
|
connection.Port = "445"
|
||||||
}
|
}
|
||||||
if connection.Username == "" || connection.Host == "" {
|
if connection.Username == "" || connection.Host == "" {
|
||||||
c.JSON(common_err.CLIENT_ERROR, model.Result{Success: common_err.CHARACTER_LIMIT, Message: common_err.GetMsg(common_err.CHARACTER_LIMIT)})
|
return ctx.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 {
|
||||||
c.JSON(common_err.CLIENT_ERROR, model.Result{Success: common_err.CHARACTER_LIMIT, Message: common_err.GetMsg(common_err.CHARACTER_LIMIT)})
|
// return ctx.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 {
|
||||||
c.JSON(common_err.CLIENT_ERROR, model.Result{Success: common_err.INVALID_PARAMS, Message: common_err.GetMsg(common_err.INVALID_PARAMS)})
|
// return ctx.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) {
|
||||||
c.JSON(common_err.CLIENT_ERROR, model.Result{Success: common_err.INVALID_PARAMS, Message: common_err.GetMsg(common_err.INVALID_PARAMS)})
|
// return ctx.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 {
|
||||||
c.JSON(common_err.CLIENT_ERROR, model.Result{Success: common_err.INVALID_PARAMS, Message: common_err.GetMsg(common_err.INVALID_PARAMS)})
|
// return ctx.JSON(common_err.CLIENT_ERROR, model.Result{Success: common_err.INVALID_PARAMS, Message: common_err.GetMsg(common_err.INVALID_PARAMS)})
|
||||||
return
|
// return
|
||||||
}
|
// }
|
||||||
|
|
||||||
connection.Host = strings.Split(connection.Host, "/")[0]
|
connection.Host = strings.Split(connection.Host, "/")[0]
|
||||||
// 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 {
|
||||||
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 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)})
|
||||||
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 {
|
||||||
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.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{}
|
||||||
@ -189,27 +178,28 @@ func PostSambaConnectionsCreate(c *gin.Context) {
|
|||||||
service.MyService.Connections().CreateConnection(&connectionDBModel)
|
service.MyService.Connections().CreateConnection(&connectionDBModel)
|
||||||
|
|
||||||
connection.ID = connectionDBModel.ID
|
connection.ID = connectionDBModel.ID
|
||||||
c.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: connection})
|
return ctx.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: connection})
|
||||||
}
|
}
|
||||||
|
|
||||||
func DeleteSambaConnections(c *gin.Context) {
|
func DeleteSambaConnections(ctx echo.Context) error {
|
||||||
id := c.Param("id")
|
id := ctx.Param("id")
|
||||||
connection := service.MyService.Connections().GetConnectionByID(id)
|
connection := service.MyService.Connections().GetConnectionByID(id)
|
||||||
if connection.Username == "" {
|
if connection.Username == "" {
|
||||||
c.JSON(common_err.CLIENT_ERROR, model.Result{Success: common_err.Record_NOT_EXIST, Message: common_err.GetMsg(common_err.Record_NOT_EXIST)})
|
return ctx.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 := service.MyService.System().GetDirPath(connection.MountPoint)
|
mountPointList, err := samba.GetSambaSharesList(connection.Host, connection.Port, connection.Username, connection.Password)
|
||||||
|
// mountPointList, err := service.MyService.System().GetDirPath(connection.MountPoint)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.JSON(common_err.SERVICE_ERROR, model.Result{Success: common_err.SERVICE_ERROR, Message: common_err.GetMsg(common_err.SERVICE_ERROR), Data: err.Error()})
|
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()})
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
baseHostPath := "/mnt/" + connection.Host
|
||||||
for _, v := range mountPointList {
|
for _, v := range mountPointList {
|
||||||
err := service.MyService.Connections().UnmountSmaba(v.Path)
|
if service.IsMounted(baseHostPath + "/" + v) {
|
||||||
if err != nil {
|
err := service.MyService.Connections().UnmountSmaba(baseHostPath + "/" + v)
|
||||||
logger.Error("unmount smaba error", zap.Error(err), zap.Any("path", v.Path))
|
if err != nil {
|
||||||
c.JSON(common_err.SERVICE_ERROR, model.Result{Success: common_err.SERVICE_ERROR, Message: common_err.GetMsg(common_err.SERVICE_ERROR), Data: err.Error()})
|
logger.Error("unmount smaba error", zap.Error(err), zap.Any("path", baseHostPath+"/"+v))
|
||||||
return
|
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()})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
dir, _ := ioutil.ReadDir(connection.MountPoint)
|
dir, _ := ioutil.ReadDir(connection.MountPoint)
|
||||||
@ -217,5 +207,5 @@ func DeleteSambaConnections(c *gin.Context) {
|
|||||||
os.RemoveAll(connection.MountPoint)
|
os.RemoveAll(connection.MountPoint)
|
||||||
}
|
}
|
||||||
service.MyService.Connections().DeleteConnection(id)
|
service.MyService.Connections().DeleteConnection(id)
|
||||||
c.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: id})
|
return ctx.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: id})
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,16 +8,17 @@
|
|||||||
* @Website: https://www.casaos.io
|
* @Website: https://www.casaos.io
|
||||||
* Copyright (c) 2022 by icewhale, All Rights Reserved.
|
* Copyright (c) 2022 by icewhale, All Rights Reserved.
|
||||||
*/
|
*/
|
||||||
package v1
|
package v1_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/http/httptest"
|
"net/http/httptest"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
v1 "github.com/IceWhaleTech/CasaOS/route/v1"
|
||||||
"github.com/golang/mock/gomock"
|
"github.com/golang/mock/gomock"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/labstack/echo/v4"
|
||||||
|
"gotest.tools/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
func performRequest(r http.Handler, method, path string) *httptest.ResponseRecorder {
|
func performRequest(r http.Handler, method, path string) *httptest.ResponseRecorder {
|
||||||
@ -53,17 +54,22 @@ 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)
|
||||||
GetSambaSharesList(con)
|
|
||||||
ginEngine.ServeHTTP(response, httpRequest)
|
con := e.NewContext(httpRequest, response)
|
||||||
|
|
||||||
|
v1.GetSambaSharesList(con)
|
||||||
|
e.ServeHTTP(response, httpRequest)
|
||||||
return response
|
return response
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -10,8 +10,9 @@ 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"
|
||||||
@ -26,44 +27,41 @@ var upgrader = websocket.Upgrader{
|
|||||||
HandshakeTimeout: time.Duration(time.Second * 5),
|
HandshakeTimeout: time.Duration(time.Second * 5),
|
||||||
}
|
}
|
||||||
|
|
||||||
func PostSshLogin(c *gin.Context) {
|
func PostSshLogin(ctx echo.Context) error {
|
||||||
j := make(map[string]string)
|
j := make(map[string]string)
|
||||||
c.ShouldBind(&j)
|
ctx.Bind(&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 == "" {
|
||||||
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 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"})
|
||||||
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
|
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."})
|
||||||
}
|
}
|
||||||
c.JSON(common_err.SUCCESS, modelCommon.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS)})
|
return ctx.JSON(common_err.SUCCESS, modelCommon.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS)})
|
||||||
}
|
}
|
||||||
|
|
||||||
func WsSsh(c *gin.Context) {
|
func WsSsh(ctx echo.Context) error {
|
||||||
_, e := exec.LookPath("ssh")
|
_, e := exec.LookPath("ssh")
|
||||||
if e != nil {
|
if e != nil {
|
||||||
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 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"})
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
userName := c.Query("username")
|
userName := ctx.QueryParam("username")
|
||||||
password := c.Query("password")
|
password := ctx.QueryParam("password")
|
||||||
port := c.Query("port")
|
port := ctx.QueryParam("port")
|
||||||
wsConn, _ := upgrader.Upgrade(c.Writer, c.Request, nil)
|
wsConn, _ := upgrader.Upgrade(ctx.Response().Writer, ctx.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(c.DefaultQuery("cols", "200"))
|
cols, _ := strconv.Atoi(utils.DefaultQuery(ctx, "cols", "200"))
|
||||||
rows, _ := strconv.Atoi(c.DefaultQuery("rows", "32"))
|
rows, _ := strconv.Atoi(utils.DefaultQuery(ctx, "rows", "32"))
|
||||||
var client *ssh.Client
|
var client *ssh.Client
|
||||||
for login != 0 {
|
for login != 0 {
|
||||||
|
|
||||||
@ -93,4 +91,5 @@ func WsSsh(c *gin.Context) {
|
|||||||
go ssConn.SessionWait(quitChan)
|
go ssConn.SessionWait(quitChan)
|
||||||
|
|
||||||
<-quitChan
|
<-quitChan
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,141 +0,0 @@
|
|||||||
package v1
|
|
||||||
|
|
||||||
import (
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/IceWhaleTech/CasaOS-Common/utils/logger"
|
|
||||||
"github.com/IceWhaleTech/CasaOS/drivers/dropbox"
|
|
||||||
"github.com/IceWhaleTech/CasaOS/drivers/google_drive"
|
|
||||||
"github.com/IceWhaleTech/CasaOS/model"
|
|
||||||
"github.com/IceWhaleTech/CasaOS/pkg/utils/common_err"
|
|
||||||
"github.com/IceWhaleTech/CasaOS/pkg/utils/httper"
|
|
||||||
"github.com/IceWhaleTech/CasaOS/service"
|
|
||||||
"github.com/gin-gonic/gin"
|
|
||||||
"go.uber.org/zap"
|
|
||||||
)
|
|
||||||
|
|
||||||
func ListStorages(c *gin.Context) {
|
|
||||||
// var req model.PageReq
|
|
||||||
// if err := c.ShouldBind(&req); err != nil {
|
|
||||||
// c.JSON(common_err.SUCCESS, model.Result{Success: common_err.CLIENT_ERROR, Message: common_err.GetMsg(common_err.CLIENT_ERROR), Data: err.Error()})
|
|
||||||
// return
|
|
||||||
// }
|
|
||||||
// req.Validate()
|
|
||||||
|
|
||||||
//logger.Info("ListStorages", zap.Any("req", req))
|
|
||||||
//storages, total, err := service.MyService.Storage().GetStorages(req.Page, req.PerPage)
|
|
||||||
// if err != nil {
|
|
||||||
// c.JSON(common_err.SUCCESS, model.Result{Success: common_err.SERVICE_ERROR, Message: common_err.GetMsg(common_err.SERVICE_ERROR), Data: err.Error()})
|
|
||||||
// return
|
|
||||||
// }
|
|
||||||
// c.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: model.PageResp{
|
|
||||||
// Content: storages,
|
|
||||||
// Total: total,
|
|
||||||
// }})
|
|
||||||
r, err := service.MyService.Storage().GetStorages()
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
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++ {
|
|
||||||
dataMap, err := service.MyService.Storage().GetConfigByName(r.MountPoints[i].Fs)
|
|
||||||
if err != nil {
|
|
||||||
logger.Error("GetConfigByName", zap.Any("err", err))
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if dataMap["type"] == "drive" {
|
|
||||||
r.MountPoints[i].Icon = google_drive.ICONURL
|
|
||||||
}
|
|
||||||
if dataMap["type"] == "dropbox" {
|
|
||||||
r.MountPoints[i].Icon = dropbox.ICONURL
|
|
||||||
}
|
|
||||||
}
|
|
||||||
list := []httper.MountPoint{}
|
|
||||||
|
|
||||||
for _, v := range r.MountPoints {
|
|
||||||
list = append(list, httper.MountPoint{
|
|
||||||
Fs: v.Fs,
|
|
||||||
Icon: v.Icon,
|
|
||||||
MountPoint: v.MountPoint,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
c.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: list})
|
|
||||||
}
|
|
||||||
|
|
||||||
func UpdateStorage(c *gin.Context) {
|
|
||||||
var req model.Storage
|
|
||||||
if err := c.ShouldBind(&req); err != nil {
|
|
||||||
c.JSON(common_err.SUCCESS, model.Result{Success: common_err.CLIENT_ERROR, Message: common_err.GetMsg(common_err.CLIENT_ERROR), Data: err.Error()})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if err := service.MyService.Storages().UpdateStorage(c, req); err != nil {
|
|
||||||
c.JSON(common_err.SUCCESS, model.Result{Success: common_err.SERVICE_ERROR, Message: common_err.GetMsg(common_err.SERVICE_ERROR), Data: err.Error()})
|
|
||||||
} else {
|
|
||||||
c.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: "success"})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func DeleteStorage(c *gin.Context) {
|
|
||||||
json := make(map[string]string)
|
|
||||||
c.ShouldBind(&json)
|
|
||||||
mountPoint := json["mount_point"]
|
|
||||||
if mountPoint == "" {
|
|
||||||
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)
|
|
||||||
if err != nil {
|
|
||||||
c.JSON(common_err.SERVICE_ERROR, model.Result{Success: common_err.SERVICE_ERROR, Message: common_err.GetMsg(common_err.SERVICE_ERROR), Data: err.Error()})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
service.MyService.Storage().DeleteConfigByName(strings.ReplaceAll(mountPoint, "/mnt/", ""))
|
|
||||||
c.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: "success"})
|
|
||||||
}
|
|
||||||
|
|
||||||
func DisableStorage(c *gin.Context) {
|
|
||||||
idStr := c.Query("id")
|
|
||||||
id, err := strconv.Atoi(idStr)
|
|
||||||
if err != nil {
|
|
||||||
c.JSON(common_err.SUCCESS, model.Result{Success: common_err.CLIENT_ERROR, Message: common_err.GetMsg(common_err.CLIENT_ERROR), Data: err.Error()})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if err := service.MyService.Storages().DisableStorage(c, uint(id)); err != nil {
|
|
||||||
c.JSON(common_err.SUCCESS, model.Result{Success: common_err.SERVICE_ERROR, Message: common_err.GetMsg(common_err.SERVICE_ERROR), Data: err.Error()})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
c.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: "success"})
|
|
||||||
}
|
|
||||||
|
|
||||||
func EnableStorage(c *gin.Context) {
|
|
||||||
idStr := c.Query("id")
|
|
||||||
id, err := strconv.Atoi(idStr)
|
|
||||||
if err != nil {
|
|
||||||
c.JSON(common_err.SUCCESS, model.Result{Success: common_err.CLIENT_ERROR, Message: common_err.GetMsg(common_err.CLIENT_ERROR), Data: err.Error()})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if err := service.MyService.Storages().EnableStorage(c, uint(id)); err != nil {
|
|
||||||
c.JSON(common_err.SUCCESS, model.Result{Success: common_err.SERVICE_ERROR, Message: common_err.GetMsg(common_err.SERVICE_ERROR), Data: err.Error()})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
c.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: "success"})
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetStorage(c *gin.Context) {
|
|
||||||
|
|
||||||
// idStr := c.Query("id")
|
|
||||||
// id, err := strconv.Atoi(idStr)
|
|
||||||
// if err != nil {
|
|
||||||
// c.JSON(common_err.SUCCESS, model.Result{Success: common_err.CLIENT_ERROR, Message: common_err.GetMsg(common_err.CLIENT_ERROR), Data: err.Error()})
|
|
||||||
// return
|
|
||||||
// }
|
|
||||||
// storage, err := service.MyService.Storage().GetStorageById(uint(id))
|
|
||||||
// if err != nil {
|
|
||||||
// c.JSON(common_err.SUCCESS, model.Result{Success: common_err.SERVICE_ERROR, Message: common_err.GetMsg(common_err.SERVICE_ERROR), Data: err.Error()})
|
|
||||||
// return
|
|
||||||
// }
|
|
||||||
// c.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: storage})
|
|
||||||
}
|
|
||||||
@ -2,6 +2,7 @@ package v1
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
@ -18,12 +19,14 @@ 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/gin-gonic/gin"
|
"github.com/labstack/echo/v4"
|
||||||
|
"github.com/tidwall/gjson"
|
||||||
)
|
)
|
||||||
|
|
||||||
// @Summary check version
|
// @Summary check version
|
||||||
@ -33,7 +36,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(c *gin.Context) {
|
func GetSystemCheckVersion(ctx echo.Context) error {
|
||||||
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{}
|
||||||
@ -49,7 +52,7 @@ func GetSystemCheckVersion(c *gin.Context) {
|
|||||||
data["need_update"] = need
|
data["need_update"] = need
|
||||||
data["version"] = version
|
data["version"] = version
|
||||||
data["current_version"] = common.VERSION
|
data["current_version"] = common.VERSION
|
||||||
c.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: data})
|
return ctx.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: data})
|
||||||
}
|
}
|
||||||
|
|
||||||
// @Summary 系统信息
|
// @Summary 系统信息
|
||||||
@ -59,12 +62,12 @@ func GetSystemCheckVersion(c *gin.Context) {
|
|||||||
// @Security ApiKeyAuth
|
// @Security ApiKeyAuth
|
||||||
// @Success 200 {string} string "ok"
|
// @Success 200 {string} string "ok"
|
||||||
// @Router /sys/update [post]
|
// @Router /sys/update [post]
|
||||||
func SystemUpdate(c *gin.Context) {
|
func SystemUpdate(ctx echo.Context) error {
|
||||||
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)
|
||||||
}
|
}
|
||||||
c.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS)})
|
return ctx.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS)})
|
||||||
}
|
}
|
||||||
|
|
||||||
// @Summary get logs
|
// @Summary get logs
|
||||||
@ -74,13 +77,13 @@ func SystemUpdate(c *gin.Context) {
|
|||||||
// @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(c *gin.Context) {
|
func GetCasaOSErrorLogs(ctx echo.Context) error {
|
||||||
line, _ := strconv.Atoi(c.DefaultQuery("line", "100"))
|
line, _ := strconv.Atoi(utils.DefaultQuery(ctx, "line", "100"))
|
||||||
c.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: service.MyService.System().GetCasaOSLogs(line)})
|
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)})
|
||||||
}
|
}
|
||||||
|
|
||||||
// 系统配置
|
// 系统配置
|
||||||
func GetSystemConfigDebug(c *gin.Context) {
|
func GetSystemConfigDebug(ctx echo.Context) error {
|
||||||
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()
|
||||||
@ -98,7 +101,7 @@ func GetSystemConfigDebug(c *gin.Context) {
|
|||||||
|
|
||||||
// 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))
|
||||||
|
|
||||||
c.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: bugContent})
|
return ctx.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
|
||||||
@ -108,8 +111,8 @@ func GetSystemConfigDebug(c *gin.Context) {
|
|||||||
// @Security ApiKeyAuth
|
// @Security ApiKeyAuth
|
||||||
// @Success 200 {string} string "ok"
|
// @Success 200 {string} string "ok"
|
||||||
// @Router /sys/port [get]
|
// @Router /sys/port [get]
|
||||||
func GetCasaOSPort(c *gin.Context) {
|
func GetCasaOSPort(ctx echo.Context) error {
|
||||||
c.JSON(common_err.SUCCESS,
|
return ctx.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),
|
||||||
@ -125,31 +128,29 @@ func GetCasaOSPort(c *gin.Context) {
|
|||||||
// @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(c *gin.Context) {
|
func PutCasaOSPort(ctx echo.Context) error {
|
||||||
json := make(map[string]string)
|
json := make(map[string]string)
|
||||||
c.ShouldBind(&json)
|
ctx.Bind(&json)
|
||||||
portStr := json["port"]
|
portStr := json["port"]
|
||||||
portNumber, err := strconv.Atoi(portStr)
|
portNumber, err := strconv.Atoi(portStr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.JSON(common_err.SERVICE_ERROR,
|
return ctx.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 {
|
||||||
c.JSON(common_err.SERVICE_ERROR,
|
return ctx.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))
|
||||||
c.JSON(common_err.SUCCESS,
|
return ctx.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),
|
||||||
@ -163,8 +164,9 @@ func PutCasaOSPort(c *gin.Context) {
|
|||||||
// @Security ApiKeyAuth
|
// @Security ApiKeyAuth
|
||||||
// @Success 200 {string} string "ok"
|
// @Success 200 {string} string "ok"
|
||||||
// @Router /sys/restart [post]
|
// @Router /sys/restart [post]
|
||||||
func PostKillCasaOS(c *gin.Context) {
|
func PostKillCasaOS(ctx echo.Context) error {
|
||||||
os.Exit(0)
|
os.Exit(0)
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// @Summary get system hardware info
|
// @Summary get system hardware info
|
||||||
@ -174,16 +176,20 @@ func PostKillCasaOS(c *gin.Context) {
|
|||||||
// @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(c *gin.Context) {
|
func GetSystemHardwareInfo(ctx echo.Context) error {
|
||||||
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
|
||||||
c.JSON(common_err.SUCCESS,
|
|
||||||
model.Result{
|
if cpu := service.MyService.System().GetCpuInfo(); len(cpu) > 0 {
|
||||||
Success: common_err.SUCCESS,
|
return ctx.JSON(common_err.SUCCESS,
|
||||||
Message: common_err.GetMsg(common_err.SUCCESS),
|
model.Result{
|
||||||
Data: data,
|
Success: common_err.SUCCESS,
|
||||||
})
|
Message: common_err.GetMsg(common_err.SUCCESS),
|
||||||
|
Data: data,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// @Summary system utilization
|
// @Summary system utilization
|
||||||
@ -193,7 +199,7 @@ func GetSystemHardwareInfo(c *gin.Context) {
|
|||||||
// @Security ApiKeyAuth
|
// @Security ApiKeyAuth
|
||||||
// @Success 200 {string} string "ok"
|
// @Success 200 {string} string "ok"
|
||||||
// @Router /sys/utilization [get]
|
// @Router /sys/utilization [get]
|
||||||
func GetSystemUtilization(c *gin.Context) {
|
func GetSystemUtilization(ctx echo.Context) error {
|
||||||
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()
|
||||||
@ -237,7 +243,7 @@ func GetSystemUtilization(c *gin.Context) {
|
|||||||
data[key.(string)] = value
|
data[key.(string)] = value
|
||||||
return true
|
return true
|
||||||
})
|
})
|
||||||
c.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: data})
|
return ctx.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
|
||||||
@ -247,13 +253,13 @@ func GetSystemUtilization(c *gin.Context) {
|
|||||||
// @Security ApiKeyAuth
|
// @Security ApiKeyAuth
|
||||||
// @Success 200 {string} string "ok"
|
// @Success 200 {string} string "ok"
|
||||||
// @Router /sys/cpu [get]
|
// @Router /sys/cpu [get]
|
||||||
func GetSystemCupInfo(c *gin.Context) {
|
func GetSystemCupInfo(ctx echo.Context) error {
|
||||||
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
|
||||||
c.JSON(http.StatusOK, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: data})
|
return ctx.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
|
||||||
@ -263,9 +269,9 @@ func GetSystemCupInfo(c *gin.Context) {
|
|||||||
// @Security ApiKeyAuth
|
// @Security ApiKeyAuth
|
||||||
// @Success 200 {string} string "ok"
|
// @Success 200 {string} string "ok"
|
||||||
// @Router /sys/mem [get]
|
// @Router /sys/mem [get]
|
||||||
func GetSystemMemInfo(c *gin.Context) {
|
func GetSystemMemInfo(ctx echo.Context) error {
|
||||||
mem := service.MyService.System().GetMemInfo()
|
mem := service.MyService.System().GetMemInfo()
|
||||||
c.JSON(http.StatusOK, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: mem})
|
return ctx.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
|
||||||
@ -275,9 +281,9 @@ func GetSystemMemInfo(c *gin.Context) {
|
|||||||
// @Security ApiKeyAuth
|
// @Security ApiKeyAuth
|
||||||
// @Success 200 {string} string "ok"
|
// @Success 200 {string} string "ok"
|
||||||
// @Router /sys/disk [get]
|
// @Router /sys/disk [get]
|
||||||
func GetSystemDiskInfo(c *gin.Context) {
|
func GetSystemDiskInfo(ctx echo.Context) error {
|
||||||
disk := service.MyService.System().GetDiskInfo()
|
disk := service.MyService.System().GetDiskInfo()
|
||||||
c.JSON(http.StatusOK, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: disk})
|
return ctx.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
|
||||||
@ -287,7 +293,7 @@ func GetSystemDiskInfo(c *gin.Context) {
|
|||||||
// @Security ApiKeyAuth
|
// @Security ApiKeyAuth
|
||||||
// @Success 200 {string} string "ok"
|
// @Success 200 {string} string "ok"
|
||||||
// @Router /sys/net [get]
|
// @Router /sys/net [get]
|
||||||
func GetSystemNetInfo(c *gin.Context) {
|
func GetSystemNetInfo(ctx echo.Context) error {
|
||||||
netList := service.MyService.System().GetNetInfo()
|
netList := service.MyService.System().GetNetInfo()
|
||||||
newNet := []model.IOCountersStat{}
|
newNet := []model.IOCountersStat{}
|
||||||
for _, n := range netList {
|
for _, n := range netList {
|
||||||
@ -302,35 +308,36 @@ func GetSystemNetInfo(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
c.JSON(http.StatusOK, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: newNet})
|
return ctx.JSON(http.StatusOK, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: newNet})
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetSystemProxy(c *gin.Context) {
|
func GetSystemProxy(ctx echo.Context) error {
|
||||||
url := c.Query("url")
|
url := ctx.QueryParam("url")
|
||||||
resp, err := http2.Get(url, 30*time.Second)
|
resp, err := http2.Get(url, 30*time.Second)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return ctx.JSON(http.StatusInternalServerError, model.Result{Success: common_err.SERVICE_ERROR, Message: err.Error()})
|
||||||
}
|
}
|
||||||
defer resp.Body.Close()
|
defer resp.Body.Close()
|
||||||
for k, v := range c.Request.Header {
|
for k, v := range ctx.Request().Header {
|
||||||
c.Header(k, v[0])
|
ctx.Request().Header.Add(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)))
|
||||||
// 响应状态码
|
// 响应状态码
|
||||||
c.Writer.WriteHeader(resp.StatusCode)
|
ctx.Response().Writer.WriteHeader(resp.StatusCode)
|
||||||
// 复制转发的响应Body到响应Body
|
// 复制转发的响应Body到响应Body
|
||||||
io.Copy(c.Writer, ioutil.NopCloser(bytes.NewBuffer(rda)))
|
io.Copy(ctx.Response().Writer, ioutil.NopCloser(bytes.NewBuffer(rda)))
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func PutSystemState(c *gin.Context) {
|
func PutSystemState(ctx echo.Context) error {
|
||||||
state := c.Param("state")
|
state := ctx.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()
|
||||||
}
|
}
|
||||||
c.JSON(http.StatusOK, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: "The operation will be completed shortly."})
|
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."})
|
||||||
}
|
}
|
||||||
|
|
||||||
// @Summary 获取一个可用端口
|
// @Summary 获取一个可用端口
|
||||||
@ -341,8 +348,8 @@ func PutSystemState(c *gin.Context) {
|
|||||||
// @Security ApiKeyAuth
|
// @Security ApiKeyAuth
|
||||||
// @Success 200 {string} string "ok"
|
// @Success 200 {string} string "ok"
|
||||||
// @Router /app/getport [get]
|
// @Router /app/getport [get]
|
||||||
func GetPort(c *gin.Context) {
|
func GetPort(ctx echo.Context) error {
|
||||||
t := c.DefaultQuery("type", "tcp")
|
t := utils.DefaultQuery(ctx, "type", "tcp")
|
||||||
var p int
|
var p int
|
||||||
ok := true
|
ok := true
|
||||||
for ok {
|
for ok {
|
||||||
@ -350,7 +357,7 @@ func GetPort(c *gin.Context) {
|
|||||||
ok = !port.IsPortAvailable(p, t)
|
ok = !port.IsPortAvailable(p, t)
|
||||||
}
|
}
|
||||||
// @tiger 这里最好封装成 {'port': ...} 的形式,来体现出参的上下文
|
// @tiger 这里最好封装成 {'port': ...} 的形式,来体现出参的上下文
|
||||||
c.JSON(common_err.SUCCESS, &model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: p})
|
return ctx.JSON(common_err.SUCCESS, &model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: p})
|
||||||
}
|
}
|
||||||
|
|
||||||
// @Summary 检查端口是否可用
|
// @Summary 检查端口是否可用
|
||||||
@ -362,8 +369,17 @@ func GetPort(c *gin.Context) {
|
|||||||
// @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(c *gin.Context) {
|
func PortCheck(ctx echo.Context) error {
|
||||||
p, _ := strconv.Atoi(c.Param("port"))
|
p, _ := strconv.Atoi(ctx.Param("port"))
|
||||||
t := c.DefaultQuery("type", "tcp")
|
t := utils.DefaultQuery(ctx, "type", "tcp")
|
||||||
c.JSON(common_err.SUCCESS, &model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: port.IsPortAvailable(p, t)})
|
return ctx.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})
|
||||||
}
|
}
|
||||||
|
|||||||
313
route/v1/zerotier.go
Normal file
313
route/v1/zerotier.go
Normal file
@ -0,0 +1,313 @@
|
|||||||
|
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
|
||||||
|
}
|
||||||
71
route/v2.go
71
route/v2.go
@ -1,17 +1,20 @@
|
|||||||
package route
|
package route
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"crypto/ecdsa"
|
||||||
"log"
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
"path"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/IceWhaleTech/CasaOS/codegen"
|
"github.com/IceWhaleTech/CasaOS/codegen"
|
||||||
|
"github.com/IceWhaleTech/CasaOS/pkg/config"
|
||||||
"github.com/IceWhaleTech/CasaOS/pkg/utils/file"
|
"github.com/IceWhaleTech/CasaOS/pkg/utils/file"
|
||||||
|
|
||||||
"github.com/IceWhaleTech/CasaOS-Common/utils/common_err"
|
"github.com/IceWhaleTech/CasaOS-Common/external"
|
||||||
"github.com/IceWhaleTech/CasaOS-Common/utils/jwt"
|
"github.com/IceWhaleTech/CasaOS-Common/utils/jwt"
|
||||||
v2Route "github.com/IceWhaleTech/CasaOS/route/v2"
|
v2Route "github.com/IceWhaleTech/CasaOS/route/v2"
|
||||||
"github.com/deepmap/oapi-codegen/pkg/middleware"
|
"github.com/deepmap/oapi-codegen/pkg/middleware"
|
||||||
@ -27,7 +30,6 @@ var (
|
|||||||
V2APIPath string
|
V2APIPath string
|
||||||
V2DocPath string
|
V2DocPath string
|
||||||
V3FilePath string
|
V3FilePath string
|
||||||
V4DirPath string
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
@ -46,7 +48,6 @@ 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 {
|
||||||
@ -70,21 +71,23 @@ func InitV2Router() http.Handler {
|
|||||||
e.Use(echo_middleware.JWTWithConfig(echo_middleware.JWTConfig{
|
e.Use(echo_middleware.JWTWithConfig(echo_middleware.JWTConfig{
|
||||||
Skipper: func(c echo.Context) bool {
|
Skipper: func(c echo.Context) bool {
|
||||||
return c.RealIP() == "::1" || c.RealIP() == "127.0.0.1"
|
return c.RealIP() == "::1" || c.RealIP() == "127.0.0.1"
|
||||||
//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)
|
valid, claims, err := jwt.Validate(token, func() (*ecdsa.PublicKey, error) { return external.GetPublicKey(config.CommonInfo.RuntimePath) })
|
||||||
if code != common_err.SUCCESS {
|
if err != nil || !valid {
|
||||||
return nil, echo.ErrUnauthorized
|
return nil, echo.ErrUnauthorized
|
||||||
}
|
}
|
||||||
|
|
||||||
c.Request().Header.Set("user_id", strconv.Itoa(claims.ID))
|
c.Request().Header.Set("user_id", strconv.Itoa(claims.ID))
|
||||||
|
|
||||||
return claims, nil
|
return claims, nil
|
||||||
},
|
},
|
||||||
TokenLookupFuncs: []echo_middleware.ValuesExtractor{
|
TokenLookupFuncs: []echo_middleware.ValuesExtractor{
|
||||||
func(c echo.Context) ([]string, error) {
|
func(ctx echo.Context) ([]string, error) {
|
||||||
return []string{c.Request().Header.Get(echo.HeaderAuthorization)}, nil
|
if len(ctx.Request().Header.Get(echo.HeaderAuthorization)) > 0 {
|
||||||
|
return []string{ctx.Request().Header.Get(echo.HeaderAuthorization)}, nil
|
||||||
|
}
|
||||||
|
return []string{ctx.QueryParam("token")}, nil
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}))
|
}))
|
||||||
@ -112,6 +115,12 @@ 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},
|
||||||
}))
|
}))
|
||||||
|
|
||||||
@ -136,15 +145,49 @@ 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) {
|
||||||
path := r.URL.Query().Get("path")
|
token := r.URL.Query().Get("token")
|
||||||
http.ServeFile(w, r, path)
|
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")
|
||||||
|
fileName := path.Base(filePath)
|
||||||
|
w.Header().Add("Content-Disposition", "attachment; filename*=utf-8''"+url.PathEscape(fileName))
|
||||||
|
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")
|
||||||
|
|
||||||
@ -158,7 +201,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) {
|
||||||
// c.JSON(common_err.SERVICE_ERROR, model.Result{
|
// return ctx.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),
|
||||||
// })
|
// })
|
||||||
@ -171,7 +214,7 @@ func InitDir() http.Handler {
|
|||||||
// 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 {
|
||||||
|
|
||||||
@ -194,7 +237,7 @@ func InitDir() http.Handler {
|
|||||||
|
|
||||||
err = ar.Create(w)
|
err = ar.Create(w)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// c.JSON(common_err.SERVICE_ERROR, model.Result{
|
// return ctx.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(),
|
||||||
|
|||||||
@ -2,7 +2,9 @@ package v2
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
"github.com/IceWhaleTech/CasaOS/codegen"
|
||||||
"github.com/labstack/echo/v4"
|
"github.com/labstack/echo/v4"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -15,3 +17,70 @@ 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)
|
||||||
|
}
|
||||||
|
|||||||
@ -2,10 +2,15 @@ package v2
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
|
||||||
"github.com/IceWhaleTech/CasaOS/codegen"
|
"github.com/IceWhaleTech/CasaOS/codegen"
|
||||||
|
"github.com/IceWhaleTech/CasaOS/pkg/utils/file"
|
||||||
"github.com/IceWhaleTech/CasaOS/service"
|
"github.com/IceWhaleTech/CasaOS/service"
|
||||||
"github.com/labstack/echo/v4"
|
"github.com/labstack/echo/v4"
|
||||||
|
"github.com/mholt/archiver/v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (s *CasaOS) GetHealthServices(ctx echo.Context) error {
|
func (s *CasaOS) GetHealthServices(ctx echo.Context) error {
|
||||||
@ -24,3 +29,72 @@ func (s *CasaOS) GetHealthServices(ctx echo.Context) error {
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *CasaOS) GetHealthPorts(ctx echo.Context) error {
|
||||||
|
tcpPorts, udpPorts, err := service.MyService.Health().Ports()
|
||||||
|
if err != nil {
|
||||||
|
message := err.Error()
|
||||||
|
return ctx.JSON(http.StatusInternalServerError, codegen.ResponseInternalServerError{
|
||||||
|
Message: &message,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return ctx.JSON(http.StatusOK, codegen.GetHealthPortsOK{
|
||||||
|
Data: &codegen.HealthPorts{
|
||||||
|
TCP: &tcpPorts,
|
||||||
|
UDP: &udpPorts,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
func (c *CasaOS) GetHealthlogs(ctx echo.Context) error {
|
||||||
|
var name, currentPath, commonDir, extension string
|
||||||
|
var err error
|
||||||
|
var ar archiver.Writer
|
||||||
|
fileList, err := os.ReadDir("/var/log/casaos")
|
||||||
|
if err != nil {
|
||||||
|
message := err.Error()
|
||||||
|
return ctx.JSON(http.StatusInternalServerError, codegen.ResponseInternalServerError{
|
||||||
|
Message: &message,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
extension, ar, err = file.GetCompressionAlgorithm("zip")
|
||||||
|
if err != nil {
|
||||||
|
ctx.Response().Header().Set("Content-Type", "application/json")
|
||||||
|
message := err.Error()
|
||||||
|
return ctx.JSON(http.StatusNotFound, codegen.ResponseInternalServerError{
|
||||||
|
Message: &message,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
err = ar.Create(ctx.Response().Writer)
|
||||||
|
if err != nil {
|
||||||
|
ctx.Response().Header().Set("Content-Type", "application/json")
|
||||||
|
message := err.Error()
|
||||||
|
return ctx.JSON(http.StatusNotFound, codegen.ResponseInternalServerError{
|
||||||
|
Message: &message,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
defer ar.Close()
|
||||||
|
|
||||||
|
commonDir = "/var/log/casaos"
|
||||||
|
|
||||||
|
currentPath = filepath.Base(commonDir)
|
||||||
|
|
||||||
|
name = currentPath
|
||||||
|
name += extension
|
||||||
|
ctx.Response().Header().Add("Content-Type", "application/octet-stream")
|
||||||
|
ctx.Response().Header().Add("Content-Transfer-Encoding", "binary")
|
||||||
|
ctx.Response().Header().Add("Cache-Control", "no-cache")
|
||||||
|
ctx.Response().Header().Add("Content-Disposition", "attachment; filename*=utf-8''"+url.PathEscape(name))
|
||||||
|
|
||||||
|
for _, fname := range fileList {
|
||||||
|
err := file.AddFile(ar, filepath.Join("/var/log/casaos", fname.Name()), commonDir)
|
||||||
|
if err != nil {
|
||||||
|
message := err.Error()
|
||||||
|
return ctx.JSON(http.StatusInternalServerError, codegen.ResponseInternalServerError{
|
||||||
|
Message: &message,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|||||||
@ -2,10 +2,15 @@ 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(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
47
route/v2/zerotier.go
Normal file
47
route/v2/zerotier.go
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
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)
|
||||||
|
}
|
||||||
@ -1,9 +0,0 @@
|
|||||||
package service
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestGetCasaOSCount(t *testing.T) {
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -11,11 +11,12 @@
|
|||||||
package service
|
package service
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/IceWhaleTech/CasaOS/pkg/config"
|
"fmt"
|
||||||
command2 "github.com/IceWhaleTech/CasaOS/pkg/utils/command"
|
|
||||||
"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"
|
||||||
"github.com/moby/sys/mount"
|
"github.com/moby/sys/mount"
|
||||||
|
"golang.org/x/sys/unix"
|
||||||
"gorm.io/gorm"
|
"gorm.io/gorm"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -26,7 +27,7 @@ type ConnectionsService interface {
|
|||||||
CreateConnection(connection *model2.ConnectionsDBModel)
|
CreateConnection(connection *model2.ConnectionsDBModel)
|
||||||
DeleteConnection(id string)
|
DeleteConnection(id string)
|
||||||
UpdateConnection(connection *model2.ConnectionsDBModel)
|
UpdateConnection(connection *model2.ConnectionsDBModel)
|
||||||
MountSmaba(username, host, directory, port, mountPoint, password string) string
|
MountSmaba(username, host, directory, port, mountPoint, password string) error
|
||||||
UnmountSmaba(mountPoint string) error
|
UnmountSmaba(mountPoint string) error
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -38,28 +39,42 @@ 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{})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *connectionsStruct) MountSmaba(username, host, directory, port, mountPoint, password string) string {
|
func (s *connectionsStruct) MountSmaba(username, host, directory, port, mountPoint, password string) error {
|
||||||
str := command2.ExecResultStr("source " + config.AppInfo.ShellPath + "/helper.sh ;MountCIFS " + username + " " + host + " " + directory + " " + port + " " + mountPoint + " " + password)
|
err := unix.Mount(
|
||||||
return str
|
fmt.Sprintf("//%s/%s", host, directory),
|
||||||
|
mountPoint,
|
||||||
|
"cifs",
|
||||||
|
unix.MS_NOATIME|unix.MS_NODEV|unix.MS_NOSUID,
|
||||||
|
fmt.Sprintf("username=%s,password=%s", username, password),
|
||||||
|
)
|
||||||
|
return err
|
||||||
|
// str := command2.ExecResultStr("source " + config.AppInfo.ShellPath + "/helper.sh ;MountCIFS " + username + " " + host + " " + directory + " " + port + " " + mountPoint + " " + password)
|
||||||
|
// return str
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *connectionsStruct) UnmountSmaba(mountPoint string) error {
|
func (s *connectionsStruct) UnmountSmaba(mountPoint string) error {
|
||||||
return mount.Unmount(mountPoint)
|
return mount.Unmount(mountPoint)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -102,16 +102,20 @@ func FileOperate(k string) {
|
|||||||
os.RemoveAll(temp.To + "/" + lastPath)
|
os.RemoveAll(temp.To + "/" + lastPath)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
err := os.Rename(v.From, temp.To+"/"+lastPath)
|
err := file.CopyDir(v.From, temp.To, temp.Style)
|
||||||
if err != nil {
|
if err == nil {
|
||||||
logger.Error("file move error", zap.Any("err", err))
|
err = os.RemoveAll(v.From)
|
||||||
err = file.MoveFile(v.From, temp.To+"/"+lastPath)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Error("MoveFile error", zap.Any("err", err))
|
logger.Error("file move error", zap.Any("err", err))
|
||||||
continue
|
err = file.MoveFile(v.From, temp.To+"/"+lastPath)
|
||||||
}
|
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 {
|
||||||
|
|||||||
167
service/file_upload.go
Normal file
167
service/file_upload.go
Normal file
@ -0,0 +1,167 @@
|
|||||||
|
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
|
||||||
|
}
|
||||||
154
service/fs.go
154
service/fs.go
@ -1,154 +0,0 @@
|
|||||||
package service
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
|
|
||||||
"github.com/IceWhaleTech/CasaOS-Common/utils/logger"
|
|
||||||
"github.com/IceWhaleTech/CasaOS/internal/driver"
|
|
||||||
"github.com/IceWhaleTech/CasaOS/model"
|
|
||||||
log "github.com/dsoprea/go-logging"
|
|
||||||
"go.uber.org/zap"
|
|
||||||
)
|
|
||||||
|
|
||||||
type FsService interface {
|
|
||||||
FList(ctx context.Context, path string, refresh ...bool) ([]model.Obj, error)
|
|
||||||
GetStorage(path string) (driver.Driver, error)
|
|
||||||
Link(ctx context.Context, path string, args model.LinkArgs) (*model.Link, model.Obj, error)
|
|
||||||
}
|
|
||||||
|
|
||||||
type fsService struct {
|
|
||||||
}
|
|
||||||
|
|
||||||
// the param named path of functions in this package is a mount path
|
|
||||||
// So, the purpose of this package is to convert mount path to actual path
|
|
||||||
// then pass the actual path to the op package
|
|
||||||
|
|
||||||
func (f *fsService) FList(ctx context.Context, path string, refresh ...bool) ([]model.Obj, error) {
|
|
||||||
res, err := MyService.FsListService().FsList(ctx, path, refresh...)
|
|
||||||
if err != nil {
|
|
||||||
logger.Info("failed list", zap.Any("path", path), zap.Any("err", err))
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return res, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// func (f *fsService) Get(ctx context.Context, path string) (model.Obj, error) {
|
|
||||||
// res, err := get(ctx, path)
|
|
||||||
// if err != nil {
|
|
||||||
// log.Errorf("failed get %s: %+v", path, err)
|
|
||||||
// return nil, err
|
|
||||||
// }
|
|
||||||
// return res, nil
|
|
||||||
// }
|
|
||||||
|
|
||||||
func (f *fsService) Link(ctx context.Context, path string, args model.LinkArgs) (*model.Link, model.Obj, error) {
|
|
||||||
res, file, err := MyService.FsLinkService().Link(ctx, path, args)
|
|
||||||
if err != nil {
|
|
||||||
log.Errorf("failed link %s: %+v", path, err)
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
return res, file, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// func (f *fsService) MakeDir(ctx context.Context, path string, lazyCache ...bool) error {
|
|
||||||
// err := makeDir(ctx, path, lazyCache...)
|
|
||||||
// if err != nil {
|
|
||||||
// log.Errorf("failed make dir %s: %+v", path, err)
|
|
||||||
// }
|
|
||||||
// return err
|
|
||||||
// }
|
|
||||||
|
|
||||||
// func (f *fsService) Move(ctx context.Context, srcPath, dstDirPath string, lazyCache ...bool) error {
|
|
||||||
// err := move(ctx, srcPath, dstDirPath, lazyCache...)
|
|
||||||
// if err != nil {
|
|
||||||
// log.Errorf("failed move %s to %s: %+v", srcPath, dstDirPath, err)
|
|
||||||
// }
|
|
||||||
// return err
|
|
||||||
// }
|
|
||||||
|
|
||||||
// func (f *fsService) Copy(ctx context.Context, srcObjPath, dstDirPath string, lazyCache ...bool) (bool, error) {
|
|
||||||
// res, err := _copy(ctx, srcObjPath, dstDirPath, lazyCache...)
|
|
||||||
// if err != nil {
|
|
||||||
// log.Errorf("failed copy %s to %s: %+v", srcObjPath, dstDirPath, err)
|
|
||||||
// }
|
|
||||||
// return res, err
|
|
||||||
// }
|
|
||||||
|
|
||||||
// func (f *fsService) Rename(ctx context.Context, srcPath, dstName string, lazyCache ...bool) error {
|
|
||||||
// err := rename(ctx, srcPath, dstName, lazyCache...)
|
|
||||||
// if err != nil {
|
|
||||||
// log.Errorf("failed rename %s to %s: %+v", srcPath, dstName, err)
|
|
||||||
// }
|
|
||||||
// return err
|
|
||||||
// }
|
|
||||||
|
|
||||||
// func (f *fsService) Remove(ctx context.Context, path string) error {
|
|
||||||
// err := remove(ctx, path)
|
|
||||||
// if err != nil {
|
|
||||||
// log.Errorf("failed remove %s: %+v", path, err)
|
|
||||||
// }
|
|
||||||
// return err
|
|
||||||
// }
|
|
||||||
|
|
||||||
// func PutDirectly(ctx context.Context, dstDirPath string, file *model.FileStream, lazyCache ...bool) error {
|
|
||||||
// err := putDirectly(ctx, dstDirPath, file, lazyCache...)
|
|
||||||
// if err != nil {
|
|
||||||
// log.Errorf("failed put %s: %+v", dstDirPath, err)
|
|
||||||
// }
|
|
||||||
// return err
|
|
||||||
// }
|
|
||||||
|
|
||||||
// func (f *fsService) PutAsTask(dstDirPath string, file *model.FileStream) error {
|
|
||||||
// err := putAsTask(dstDirPath, file)
|
|
||||||
// if err != nil {
|
|
||||||
// log.Errorf("failed put %s: %+v", dstDirPath, err)
|
|
||||||
// }
|
|
||||||
// return err
|
|
||||||
// }
|
|
||||||
|
|
||||||
func (f *fsService) GetStorage(path string) (driver.Driver, error) {
|
|
||||||
storageDriver, _, err := MyService.StoragePath().GetStorageAndActualPath(path)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return storageDriver, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// func (f *fsService) Other(ctx context.Context, args model.FsOtherArgs) (interface{}, error) {
|
|
||||||
// res, err := other(ctx, args)
|
|
||||||
// if err != nil {
|
|
||||||
// log.Errorf("failed remove %s: %+v", args.Path, err)
|
|
||||||
// }
|
|
||||||
// return res, err
|
|
||||||
// }
|
|
||||||
|
|
||||||
// func get(ctx context.Context, path string) (model.Obj, error) {
|
|
||||||
// path = utils.FixAndCleanPath(path)
|
|
||||||
// // maybe a virtual file
|
|
||||||
// if path != "/" {
|
|
||||||
// virtualFiles := op.GetStorageVirtualFilesByPath(stdpath.Dir(path))
|
|
||||||
// for _, f := range virtualFiles {
|
|
||||||
// if f.GetName() == stdpath.Base(path) {
|
|
||||||
// return f, nil
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// storage, actualPath, err := op.GetStorageAndActualPath(path)
|
|
||||||
// if err != nil {
|
|
||||||
// // if there are no storage prefix with path, maybe root folder
|
|
||||||
// if path == "/" {
|
|
||||||
// return &model.Object{
|
|
||||||
// Name: "root",
|
|
||||||
// Size: 0,
|
|
||||||
// Modified: time.Time{},
|
|
||||||
// IsFolder: true,
|
|
||||||
// }, nil
|
|
||||||
// }
|
|
||||||
// return nil, errors.WithMessage(err, "failed get storage")
|
|
||||||
// }
|
|
||||||
// return op.Get(ctx, storage, actualPath)
|
|
||||||
// }
|
|
||||||
|
|
||||||
func NewFsService() FsService {
|
|
||||||
return &fsService{}
|
|
||||||
}
|
|
||||||
@ -1,27 +0,0 @@
|
|||||||
package service
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
|
|
||||||
"github.com/IceWhaleTech/CasaOS/internal/op"
|
|
||||||
"github.com/IceWhaleTech/CasaOS/model"
|
|
||||||
"github.com/pkg/errors"
|
|
||||||
)
|
|
||||||
|
|
||||||
type FsLinkService interface {
|
|
||||||
Link(ctx context.Context, path string, args model.LinkArgs) (*model.Link, model.Obj, error)
|
|
||||||
}
|
|
||||||
|
|
||||||
type fsLinkService struct {
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *fsLinkService) Link(ctx context.Context, path string, args model.LinkArgs) (*model.Link, model.Obj, error) {
|
|
||||||
storage, actualPath, err := MyService.StoragePath().GetStorageAndActualPath(path)
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, errors.WithMessage(err, "failed get storage")
|
|
||||||
}
|
|
||||||
return op.Link(ctx, storage, actualPath, args)
|
|
||||||
}
|
|
||||||
func NewFsLinkService() FsLinkService {
|
|
||||||
return &fsLinkService{}
|
|
||||||
}
|
|
||||||
@ -1,198 +0,0 @@
|
|||||||
package service
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
stdpath "path"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/IceWhaleTech/CasaOS-Common/utils/logger"
|
|
||||||
"github.com/IceWhaleTech/CasaOS/internal/driver"
|
|
||||||
"github.com/IceWhaleTech/CasaOS/internal/op"
|
|
||||||
"github.com/IceWhaleTech/CasaOS/model"
|
|
||||||
"github.com/IceWhaleTech/CasaOS/pkg/singleflight"
|
|
||||||
"github.com/IceWhaleTech/CasaOS/pkg/utils"
|
|
||||||
"github.com/Xhofe/go-cache"
|
|
||||||
|
|
||||||
log "github.com/dsoprea/go-logging"
|
|
||||||
"github.com/pkg/errors"
|
|
||||||
"go.uber.org/zap"
|
|
||||||
)
|
|
||||||
|
|
||||||
type FsListService interface {
|
|
||||||
FsList(ctx context.Context, path string, refresh ...bool) ([]model.Obj, error)
|
|
||||||
Key(storage driver.Driver, path string) string
|
|
||||||
Get(ctx context.Context, storage driver.Driver, path string) (model.Obj, error)
|
|
||||||
GetUnwrap(ctx context.Context, storage driver.Driver, path string) (model.Obj, error)
|
|
||||||
List(ctx context.Context, storage driver.Driver, path string, args model.ListArgs, refresh ...bool) ([]model.Obj, error)
|
|
||||||
}
|
|
||||||
|
|
||||||
type fsListService struct {
|
|
||||||
}
|
|
||||||
|
|
||||||
var listCache = cache.NewMemCache(cache.WithShards[[]model.Obj](64))
|
|
||||||
var listG singleflight.Group[[]model.Obj]
|
|
||||||
|
|
||||||
// List files
|
|
||||||
func (fl *fsListService) FsList(ctx context.Context, path string, refresh ...bool) ([]model.Obj, error) {
|
|
||||||
|
|
||||||
virtualFiles := MyService.Storages().GetStorageVirtualFilesByPath(path)
|
|
||||||
storage, actualPath, err := MyService.StoragePath().GetStorageAndActualPath(path)
|
|
||||||
if err != nil && len(virtualFiles) == 0 {
|
|
||||||
return nil, errors.WithMessage(err, "failed get storage")
|
|
||||||
}
|
|
||||||
|
|
||||||
var _objs []model.Obj
|
|
||||||
if storage != nil {
|
|
||||||
_objs, err = fl.List(ctx, storage, actualPath, model.ListArgs{
|
|
||||||
ReqPath: path,
|
|
||||||
}, refresh...)
|
|
||||||
if err != nil {
|
|
||||||
log.Errorf("%+v", err)
|
|
||||||
if len(virtualFiles) == 0 {
|
|
||||||
return nil, errors.WithMessage(err, "failed get objs")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
om := model.NewObjMerge()
|
|
||||||
|
|
||||||
objs := om.Merge(virtualFiles, _objs...)
|
|
||||||
return objs, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (fl *fsListService) Key(storage driver.Driver, path string) string {
|
|
||||||
return stdpath.Join(storage.GetStorage().MountPath, utils.FixAndCleanPath(path))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get object from list of files
|
|
||||||
func (fl *fsListService) Get(ctx context.Context, storage driver.Driver, path string) (model.Obj, error) {
|
|
||||||
path = utils.FixAndCleanPath(path)
|
|
||||||
logger.Info("get", zap.String("path", path))
|
|
||||||
|
|
||||||
// is root folder
|
|
||||||
if utils.PathEqual(path, "/") {
|
|
||||||
var rootObj model.Obj
|
|
||||||
switch r := storage.GetAddition().(type) {
|
|
||||||
case driver.IRootId:
|
|
||||||
rootObj = &model.Object{
|
|
||||||
ID: r.GetRootId(),
|
|
||||||
Name: op.RootName,
|
|
||||||
Size: 0,
|
|
||||||
Modified: storage.GetStorage().Modified,
|
|
||||||
IsFolder: true,
|
|
||||||
}
|
|
||||||
case driver.IRootPath:
|
|
||||||
rootObj = &model.Object{
|
|
||||||
Path: r.GetRootPath(),
|
|
||||||
Name: op.RootName,
|
|
||||||
Size: 0,
|
|
||||||
Modified: storage.GetStorage().Modified,
|
|
||||||
IsFolder: true,
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
if storage, ok := storage.(driver.Getter); ok {
|
|
||||||
obj, err := storage.GetRoot(ctx)
|
|
||||||
if err != nil {
|
|
||||||
return nil, errors.WithMessage(err, "failed get root obj")
|
|
||||||
}
|
|
||||||
rootObj = obj
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if rootObj == nil {
|
|
||||||
return nil, errors.Errorf("please implement IRootPath or IRootId or Getter method")
|
|
||||||
}
|
|
||||||
return &model.ObjWrapName{
|
|
||||||
Name: op.RootName,
|
|
||||||
Obj: rootObj,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// not root folder
|
|
||||||
dir, name := stdpath.Split(path)
|
|
||||||
files, err := fl.List(ctx, storage, dir, model.ListArgs{})
|
|
||||||
if err != nil {
|
|
||||||
return nil, errors.WithMessage(err, "failed get parent list")
|
|
||||||
}
|
|
||||||
for _, f := range files {
|
|
||||||
// TODO maybe copy obj here
|
|
||||||
if f.GetName() == name {
|
|
||||||
return f, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
logger.Info("cant find obj with name", zap.Any("name", name))
|
|
||||||
return nil, errors.WithStack(errors.New("object not found"))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (fl *fsListService) GetUnwrap(ctx context.Context, storage driver.Driver, path string) (model.Obj, error) {
|
|
||||||
obj, err := fl.Get(ctx, storage, path)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return model.UnwrapObjs(obj), err
|
|
||||||
}
|
|
||||||
|
|
||||||
// List files in storage, not contains virtual file
|
|
||||||
func (fl *fsListService) List(ctx context.Context, storage driver.Driver, path string, args model.ListArgs, refresh ...bool) ([]model.Obj, error) {
|
|
||||||
if storage.Config().CheckStatus && storage.GetStorage().Status != op.WORK {
|
|
||||||
return nil, errors.Errorf("storage not init: %s", storage.GetStorage().Status)
|
|
||||||
}
|
|
||||||
path = utils.FixAndCleanPath(path)
|
|
||||||
logger.Info("op.List", zap.Any("path", path))
|
|
||||||
key := fl.Key(storage, path)
|
|
||||||
if !utils.IsBool(refresh...) {
|
|
||||||
if files, ok := listCache.Get(key); ok {
|
|
||||||
logger.Info("op.List", zap.Any("use cache", path))
|
|
||||||
return files, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
dir, err := fl.GetUnwrap(ctx, storage, path)
|
|
||||||
if err != nil {
|
|
||||||
return nil, errors.WithMessage(err, "failed get dir")
|
|
||||||
}
|
|
||||||
logger.Info("op.List", zap.Any("dir", dir))
|
|
||||||
if !dir.IsDir() {
|
|
||||||
return nil, errors.WithStack(errors.New("not a folder"))
|
|
||||||
}
|
|
||||||
objs, err, _ := listG.Do(key, func() ([]model.Obj, error) {
|
|
||||||
files, err := storage.List(ctx, dir, args)
|
|
||||||
if err != nil {
|
|
||||||
return nil, errors.Wrapf(err, "failed to list objs")
|
|
||||||
}
|
|
||||||
// set path
|
|
||||||
for _, f := range files {
|
|
||||||
if s, ok := f.(model.SetPath); ok && f.GetPath() == "" && dir.GetPath() != "" {
|
|
||||||
s.SetPath(stdpath.Join(dir.GetPath(), f.GetName()))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// warp obj name
|
|
||||||
model.WrapObjsName(files)
|
|
||||||
// call hooks
|
|
||||||
go func(reqPath string, files []model.Obj) {
|
|
||||||
for _, hook := range op.ObjsUpdateHooks {
|
|
||||||
hook(args.ReqPath, files)
|
|
||||||
}
|
|
||||||
}(args.ReqPath, files)
|
|
||||||
|
|
||||||
// sort objs
|
|
||||||
if storage.Config().LocalSort {
|
|
||||||
model.SortFiles(files, storage.GetStorage().OrderBy, storage.GetStorage().OrderDirection)
|
|
||||||
}
|
|
||||||
model.ExtractFolder(files, storage.GetStorage().ExtractFolder)
|
|
||||||
|
|
||||||
if !storage.Config().NoCache {
|
|
||||||
if len(files) > 0 {
|
|
||||||
logger.Info("set cache", zap.Any("key", key), zap.Any("files", files))
|
|
||||||
listCache.Set(key, files, cache.WithEx[[]model.Obj](time.Minute*time.Duration(storage.GetStorage().CacheExpiration)))
|
|
||||||
} else {
|
|
||||||
logger.Info("del cache", zap.Any("key", key))
|
|
||||||
listCache.Del(key)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return files, nil
|
|
||||||
})
|
|
||||||
return objs, err
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewFsListService() FsListService {
|
|
||||||
return &fsListService{}
|
|
||||||
}
|
|
||||||
@ -1,11 +1,13 @@
|
|||||||
package service
|
package service
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"github.com/IceWhaleTech/CasaOS-Common/utils/port"
|
||||||
"github.com/IceWhaleTech/CasaOS-Common/utils/systemctl"
|
"github.com/IceWhaleTech/CasaOS-Common/utils/systemctl"
|
||||||
)
|
)
|
||||||
|
|
||||||
type HealthService interface {
|
type HealthService interface {
|
||||||
Services() (map[bool]*[]string, error)
|
Services() (map[bool]*[]string, error)
|
||||||
|
Ports() ([]int, []int, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
type service struct{}
|
type service struct{}
|
||||||
@ -34,6 +36,10 @@ func (s *service) Services() (map[bool]*[]string, error) {
|
|||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *service) Ports() ([]int, []int, error) {
|
||||||
|
return port.ListPortsInUse()
|
||||||
|
}
|
||||||
|
|
||||||
func NewHealthService() HealthService {
|
func NewHealthService() HealthService {
|
||||||
return &service{}
|
return &service{}
|
||||||
}
|
}
|
||||||
|
|||||||
18
service/health_test.go
Normal file
18
service/health_test.go
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
package service_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/IceWhaleTech/CasaOS/service"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestPorts(t *testing.T) {
|
||||||
|
service := service.NewHealthService()
|
||||||
|
|
||||||
|
tcpPorts, udpPorts, err := service.Ports()
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
assert.NotEmpty(t, tcpPorts)
|
||||||
|
assert.NotEmpty(t, udpPorts)
|
||||||
|
}
|
||||||
16
service/model/o_drive.go
Normal file
16
service/model/o_drive.go
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
package model
|
||||||
|
|
||||||
|
type PeerDriveDBModel struct {
|
||||||
|
ID string `gorm:"column:id;primary_key" json:"id"`
|
||||||
|
Updated int64 `gorm:"autoUpdateTime"`
|
||||||
|
Created int64 `gorm:"autoCreateTime"`
|
||||||
|
UserAgent string `json:"user_agent"`
|
||||||
|
DisplayName string `json:"display_name"`
|
||||||
|
DeviceName string `json:"device_name"`
|
||||||
|
Model string `json:"model"`
|
||||||
|
|
||||||
|
IP string `json:"ip"`
|
||||||
|
OS string `json:"os"`
|
||||||
|
Browser string `json:"browser"`
|
||||||
|
Online bool `gorm:"-" json:"online"`
|
||||||
|
}
|
||||||
116
service/other.go
Normal file
116
service/other.go
Normal file
@ -0,0 +1,116 @@
|
|||||||
|
package service
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/url"
|
||||||
|
"strings"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/IceWhaleTech/CasaOS-Common/utils/logger"
|
||||||
|
"github.com/IceWhaleTech/CasaOS/model"
|
||||||
|
"github.com/go-resty/resty/v2"
|
||||||
|
"github.com/tidwall/gjson"
|
||||||
|
"go.uber.org/zap"
|
||||||
|
)
|
||||||
|
|
||||||
|
type OtherService interface {
|
||||||
|
Search(key string) ([]model.SearchEngine, error)
|
||||||
|
AgentSearch(url string) ([]byte, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
type otherService struct{}
|
||||||
|
|
||||||
|
func (s *otherService) Search(key string) ([]model.SearchEngine, error) {
|
||||||
|
|
||||||
|
engines := []model.SearchEngine{}
|
||||||
|
engines = append(engines, model.SearchEngine{
|
||||||
|
Name: "bing",
|
||||||
|
Icon: "https://files.codelife.cc/itab/search/bing.svg",
|
||||||
|
SearchUrl: "https://www.bing.com/search?q=",
|
||||||
|
RecoUrl: "https://www.bing.com/osjson.aspx?query=", // + keyword
|
||||||
|
}, model.SearchEngine{
|
||||||
|
Name: "google",
|
||||||
|
Icon: "https://files.codelife.cc/itab/search/google.svg",
|
||||||
|
SearchUrl: "https://www.google.com/search?q=",
|
||||||
|
RecoUrl: "https://www.google.com/complete/search?client=gws-wiz&xssi=t&hl=en-US&authuser=0&dpr=1&q=", // + keyword
|
||||||
|
}, model.SearchEngine{
|
||||||
|
Name: "baidu",
|
||||||
|
Icon: "https://files.codelife.cc/itab/search/baidu.svg",
|
||||||
|
SearchUrl: "https://www.baidu.com/s?wd=",
|
||||||
|
RecoUrl: "https://www.baidu.com/sugrec?json=1&prod=pc&wd=", // + keyword
|
||||||
|
}, model.SearchEngine{
|
||||||
|
Name: "duckduckgo",
|
||||||
|
Icon: "https://files.codelife.cc/itab/search/duckduckgo.svg",
|
||||||
|
SearchUrl: "https://duckduckgo.com/?q=",
|
||||||
|
RecoUrl: "https://duckduckgo.com/ac/?type=list&q=", // + keyword
|
||||||
|
}, model.SearchEngine{
|
||||||
|
Name: "startpage",
|
||||||
|
Icon: "https://www.startpage.com/sp/cdn/favicons/apple-touch-icon-60x60--default.png",
|
||||||
|
SearchUrl: "https://www.startpage.com/do/search?q=",
|
||||||
|
RecoUrl: "https://www.startpage.com/suggestions?segment=startpage.udog&lui=english&q=", // + keyword
|
||||||
|
})
|
||||||
|
|
||||||
|
client := resty.New()
|
||||||
|
client.SetTimeout(3 * time.Second) // 设置全局超时时间
|
||||||
|
var wg sync.WaitGroup
|
||||||
|
for i := 0; i < len(engines); i++ {
|
||||||
|
wg.Add(1)
|
||||||
|
go func(i int, k string) {
|
||||||
|
name := engines[i].Name
|
||||||
|
url := engines[i].RecoUrl + url.QueryEscape(k)
|
||||||
|
defer wg.Done()
|
||||||
|
resp, err := client.R().Get(url)
|
||||||
|
if err != nil {
|
||||||
|
logger.Error("Then get search result error: %v", zap.Error(err), zap.String("name", name), zap.String("url", url))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
res := []string{}
|
||||||
|
if name == "bing" {
|
||||||
|
r := gjson.Get(resp.String(), "1")
|
||||||
|
for _, v := range r.Array() {
|
||||||
|
res = append(res, v.String())
|
||||||
|
}
|
||||||
|
} else if name == "google" {
|
||||||
|
r := gjson.Get(strings.Replace(resp.String(), ")]}'", "", 1), "0.#.0")
|
||||||
|
for _, v := range r.Array() {
|
||||||
|
res = append(res, strings.ReplaceAll(strings.ReplaceAll(v.String(), "<b>", " "), "</b>", ""))
|
||||||
|
}
|
||||||
|
} else if name == "baidu" {
|
||||||
|
r := gjson.Get(resp.String(), "g.#.q")
|
||||||
|
for _, v := range r.Array() {
|
||||||
|
res = append(res, v.String())
|
||||||
|
}
|
||||||
|
} else if name == "duckduckgo" {
|
||||||
|
r := gjson.Get(resp.String(), "1")
|
||||||
|
for _, v := range r.Array() {
|
||||||
|
res = append(res, v.String())
|
||||||
|
}
|
||||||
|
} else if name == "startpage" {
|
||||||
|
r := gjson.Get(resp.String(), "suggestions.#.text")
|
||||||
|
for _, v := range r.Array() {
|
||||||
|
res = append(res, v.String())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
engines[i].Data = res
|
||||||
|
}(i, key)
|
||||||
|
}
|
||||||
|
wg.Wait()
|
||||||
|
|
||||||
|
return engines, nil
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *otherService) AgentSearch(url string) ([]byte, error) {
|
||||||
|
client := resty.New()
|
||||||
|
client.SetTimeout(3 * time.Second) // 设置全局超时时间
|
||||||
|
resp, err := client.R().Get(url)
|
||||||
|
if err != nil {
|
||||||
|
logger.Error("Then get search result error: %v", zap.Error(err), zap.String("url", url))
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return resp.Body(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewOtherService() OtherService {
|
||||||
|
return &otherService{}
|
||||||
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user