Compare commits

...

133 Commits

Author SHA1 Message Date
link
0d3b2f444e
Update README.md (#2323)
Some checks failed
Collect Code Coverage / build (push) Has been cancelled
Auto Publish Website / goreleaser (push) Has been cancelled
Signed-off-by: link <a624669980@163.com>
2025-08-06 16:54:02 +08:00
link
030bcd1095
Update README.md (#2322)
Signed-off-by: link <a624669980@163.com>
2025-08-06 16:09:10 +08:00
link
dad2f3f8c2
Update README.md (#2321)
Signed-off-by: link <a624669980@163.com>
2025-08-06 16:06:08 +08:00
link
b09160e76b
Update README.md (#2320)
Signed-off-by: link <a624669980@163.com>
2025-08-06 16:05:13 +08:00
link
12fc102753
Update README.md (#2319)
Signed-off-by: link <a624669980@163.com>
2025-08-06 15:51:40 +08:00
link
6ffe2cc89d
add twitter (#2318)
Signed-off-by: link <a624669980@163.com>
2025-08-06 15:48:06 +08:00
link
b9098101e2
Update system.go
Some checks failed
Collect Code Coverage / build (push) Has been cancelled
Auto Publish Website / goreleaser (push) Has been cancelled
Signed-off-by: link <a624669980@163.com>
2025-07-01 15:05:40 +08:00
U2FsdGVkX1
a6ff39e47d
Add initial RISC-V support (#2206)
Some checks failed
Collect Code Coverage / build (push) Has been cancelled
Auto Publish Website / goreleaser (push) Has been cancelled
It depends upon https://github.com/IceWhaleTech/github/pull/3

resolved https://github.com/IceWhaleTech/CasaOS/issues/1669
2025-04-16 14:16:50 +08:00
CorrectRoad
23eb739f01
Update README.md (#2185)
Some checks failed
Collect Code Coverage / build (push) Has been cancelled
Auto Publish Website / goreleaser (push) Has been cancelled
Signed-off-by: CorrectRoad <a778917369@gmail.com>
2025-03-08 12:38:58 +08:00
Ns2Kracy
ba285cb8bd
fix: update user info retrieval and clean up unused code (#2101)
Some checks failed
Collect Code Coverage / build (push) Has been cancelled
Auto Publish Website / goreleaser (push) Has been cancelled
2024-12-19 11:14:15 +08:00
Ns2Kracy
63f01489a8
update version (#2098)
Some checks failed
Collect Code Coverage / build (push) Has been cancelled
Auto Publish Website / goreleaser (push) Has been cancelled
2024-12-17 15:54:54 +08:00
Ns2Kracy
6bbb0802aa
fix: problem while getting storage type (#2097) 2024-12-17 15:53:04 +08:00
Ns2Kracy
c26cf4dbec
fix: cloud storage (#2096)
Some checks are pending
Collect Code Coverage / build (push) Waiting to run
Auto Publish Website / goreleaser (push) Waiting to run
2024-12-17 15:23:15 +08:00
Ns2Kracy
958a483385
Update constants.go (#2083)
Some checks failed
Collect Code Coverage / build (push) Has been cancelled
Auto Publish Website / goreleaser (push) Has been cancelled
2024-12-10 17:42:46 +08:00
Ns2Kracy
16e97ec66f
fix: too much log (#2078)
Some checks failed
Collect Code Coverage / build (push) Has been cancelled
Auto Publish Website / goreleaser (push) Has been cancelled
2024-12-06 15:43:54 +08:00
David Wood
5ea588b813
chore: fix problematic comments (#2030)
Some checks failed
Collect Code Coverage / build (push) Has been cancelled
Auto Publish Website / goreleaser (push) Has been cancelled
2024-12-04 11:04:17 +08:00
Lauren
7da0f0d49e
Update README.md
Signed-off-by: Lauren <Lauren-ED209@users.noreply.github.com>
2024-10-17 18:59:41 +08:00
Ns2Kracy
2adb795896
Update to 0.4.13 (#2004) 2024-09-18 15:53:41 +08:00
Ns2Kracy
8b251dc407
fix: get file content twice (#2000) 2024-09-14 23:21:03 +08:00
CorrectRoad
e4bf67dad5
chore: bump casaos version (#1999)
Signed-off-by: CorrectRoad <a778917369@gmail.com>
2024-09-14 11:37:28 +08:00
CorrectRoad
e8f9d3aaf5
fix: fix GitHub Action not work (#1996) 2024-09-11 16:04:30 +08:00
CorrectRoad
bb0d9ac25c
feat: add sync OpenAPI workflows (#1995) 2024-09-11 16:00:28 +08:00
link
3a835c00e3
Update constants.go (#1961)
Signed-off-by: link <a624669980@163.com>
2024-08-14 13:35:09 +08:00
link
e4447981cb
Update constants.go (#1950)
Signed-off-by: link <a624669980@163.com>
2024-08-12 14:19:40 +08:00
James Stroud
170b599e86
add instructions to update CasaOS (#1925)
This will help users to updates and determine the version of CasaOS from
a terminal session. I tested all commands multiple times. I hope you
like my suggestions. Take care
2024-07-31 14:26:24 +08:00
Ns2Kracy
18ce1d6342
fix: safe cmd (#1921) 2024-07-24 21:46:08 +08:00
Kian Kasad
1c483a5d9c
Fix typo in README.md: "tutoial" → "tutorial" (#1862)
Just fixing a typo I noticed while reading the README.

Signed-off-by: Kian Kasad <kian@kasad.com>
2024-07-23 10:34:45 +08:00
Ns2Kracy
8f7c99779f
feat: migrate gin to echo (#1854) 2024-06-04 14:14:55 +08:00
Link
0883f5f3aa update version 2024-05-15 09:27:01 +01:00
CorrectRoad
36dda53e9c
chore: bump version to 0.4.8 (#1750) 2024-03-26 11:28:20 +08:00
Link
53c3879907 update version 2024-03-05 06:43:33 +00:00
LinkLeong
ef57d3348d update version 2024-01-23 09:09:15 +00:00
link
7a76aca022
Update constants.go (#1615)
Signed-off-by: link <a624669980@163.com>
2024-01-18 15:45:35 +08:00
CorrectRoadH
fffdc7fd5e
fix: fix upload folder fail (#1614)
Signed-off-by: CorrectRoadH <a778917369@gmail.com>
2024-01-18 12:23:27 +08:00
CorrectRoadH
29d16d13ba
fix: fix upload specify file format is fail (#1613) 2024-01-18 11:39:49 +08:00
CorrectRoadH
54a115ae89
fix: fix upload folder is wrong (#1611) 2024-01-17 17:32:19 +08:00
John Guan
17fa7868a4
Update README.md (#1589)
add youtube link

Signed-off-by: John Guan <Guan.Ningchuan@gmail.com>
2024-01-05 15:05:16 +08:00
Eng Zer Jun
27d6dd86e2
Replace satori/go.uuid with google/uuid (#1573)
`github.com/satori/go.uuid` is no longer being actively maintained (last
commit was 5 years ago [^1]). So we should just use the newer
`github.com/google/uuid`.

[^1]: https://github.com/satori/go.uuid/commits/master/

Signed-off-by: Eng Zer Jun <engzerjun@gmail.com>
2023-12-28 16:40:17 +08:00
CorrectRoadH
ae50a9bb17
feat: add file upload implement to v2 api (#1566)
Signed-off-by: CorrectRoadH <a778917369@gmail.com>
2023-12-27 16:17:33 +08:00
Link
caf3347da9 update common 2023-12-26 09:51:43 +00:00
CorrectRoadH
718a08eab2
fix: fix codecov action run fail (#1567) 2023-12-21 15:14:36 +08:00
John Guan
6f722b3506
Update push_events_to_discord.yml (#1544)
remove alpha webhook

Signed-off-by: John Guan <Guan.Ningchuan@gmail.com>
2023-12-05 15:54:03 +08:00
Link
e722d841a9 update release 2023-11-28 08:08:59 +00:00
Link
3ccf58695b update go sum 2023-11-28 07:53:20 +00:00
Link
c52386cef4 update release 2023-11-28 07:48:38 +00:00
Link
acac2df40f update go.mod 2023-11-20 08:30:14 +00:00
Link
0b507cb7ad update action 2023-11-20 08:22:13 +00:00
Link
ac90509c66 update action 2023-11-20 08:20:03 +00:00
Link
abf7134710 update releaser 2023-11-20 08:13:41 +00:00
Link
f9a26af93f update goreleaser 2023-11-20 08:05:25 +00:00
John Guan
33eacbf4b3
Update demo.yml (#1513)
Update to CasaOS-v0.4.4-3-Demo-1700132299

Signed-off-by: John Guan <Guan.Ningchuan@gmail.com>
2023-11-16 19:05:48 +08:00
John Guan
262e0d49c8
Update demo.yml (#1512)
update CasaOS demo to v0.4.4.3-demo

Signed-off-by: John Guan <Guan.Ningchuan@gmail.com>
2023-11-16 18:14:22 +08:00
LinkLeong
689b0f769a update file 2023-11-10 03:24:24 +00:00
LinkLeong
8f8a082888 update zt 2023-11-09 06:04:45 +00:00
link
9b8c6f4299
Delete __debug_bin782867005
Signed-off-by: link <a624669980@163.com>
2023-10-24 18:57:41 +08:00
LinkLeong
657cbe5c41 delay delete temp file 2023-10-23 09:06:41 +01:00
Liviu
b17bff68dd
Added small description on th casosapi health and file sys (#1417)
🐙  Hi , 

hope the small description is oke ! :)
2023-09-27 18:35:17 +08:00
LinkLeong
7807cfdb01 updat version 2023-09-22 10:03:34 +01:00
LinkLeong
9e5381710f update file task 2023-09-12 09:16:18 +01:00
LinkLeong
fa62c65526 add amd cpu suport 2023-09-11 09:39:50 +01:00
LinkLeong
3aea945277 update readme 2023-09-11 04:22:08 +01:00
LinkLeong
4d8ca182cb Merge branch 'main' of github.com:IceWhaleTech/CasaOS 2023-09-04 04:30:59 +01:00
LinkLeong
b727606a0a update version 2023-09-04 04:30:53 +01:00
Ikko Eltociear Ashimine
428be5f2c2
Update casa.yml (#1375)
enviroment -> environment

Signed-off-by: Ikko Eltociear Ashimine <eltociear@gmail.com>
Co-authored-by: Tiger Wang <tigerwang@outlook.com>
2023-09-04 07:36:38 +08:00
aevum123
995d67543d
Update README.md (#1374)
Couple small grammar fixes

Signed-off-by: aevum123 <87996440+aevum123@users.noreply.github.com>
2023-09-04 07:35:20 +08:00
omahs
590beac43a
Fix minor typos (#1372)
Fix minor typos

Signed-off-by: omahs <73983677+omahs@users.noreply.github.com>
2023-09-03 20:56:48 +08:00
kerta1n
e7bf227232
Update README.md, Debian 12 stable (#1352)
Now that Debian 12 is stable, IWT's team should check to make sure that
CasaOS is stable and then update the wiki

Signed-off-by: kerta1n <36344851+kerta1n@users.noreply.github.com>
Co-authored-by: Tiger Wang <tigerwang@outlook.com>
2023-09-01 15:41:33 +08:00
LinkLeong
eedfdde311 add filter 2023-08-31 07:26:44 +01:00
LinkLeong
38c7b5a569 update name 2023-08-24 11:57:32 +01:00
LinkLeong
8c0b219621 update path 2023-08-24 11:21:44 +01:00
LinkLeong
23fc677f30 Merge branch 'main' of github.com:IceWhaleTech/CasaOS 2023-08-24 09:23:45 +01:00
LinkLeong
a06508783c update path 2023-08-24 09:23:40 +01:00
Tiger Wang
37fee157dd
add message-bus-codegen CLI tool for generating a markdown of all event types (#1346) 2023-08-23 18:21:12 +08:00
LinkLeong
3f1c7098bd add v3 file path 2023-08-23 08:29:41 +01:00
LinkLeong
b11d046c52 add route 2023-08-23 04:35:43 +01:00
LinkLeong
d6a9ba65ed add onedrive icon 2023-08-22 05:01:40 +01:00
link
5f1df76dbf
Community (#1341) 2023-08-18 15:46:29 +08:00
Tiger Wang
0cf353c56e
create default config if it does not already exist (#1304) 2023-07-31 16:53:03 +08:00
LinkLeong
5dc6297047 Merge branch 'main' of github.com:IceWhaleTech/CasaOS 2023-07-25 03:29:00 +01:00
LinkLeong
f26ae2793c Update zerotier 2023-07-25 03:28:52 +01:00
CorrectRoadH
d7641e1b93
chore: fix the readme error (#1270)
Signed-off-by: CorrectRoadH <a778917369@gmail.com>
2023-07-21 20:44:11 +08:00
CorrectRoadH
37c496fd6a
chore:add zhanghenxing to contributor (#1269)
same to the title
2023-07-21 20:43:07 +08:00
CorrectRoadH
cb15c06f7e
chore: add Contributor (#1268)
😆add me to the contributor list🤫
My Code in https://github.com/IceWhaleTech/CasaOS-AppManagement
My Document in https://github.com/IceWhaleTech/CasaOS-AppStore/pull/187
2023-07-21 20:38:04 +08:00
LinkLeong
89a0ea34b0 Add get version function 2023-07-20 04:12:46 +01:00
LinkLeong
d8dd815baa Update ip 2023-07-19 07:46:23 +01:00
LinkLeong
a77b5d1954 Update ip 2023-07-18 08:54:01 +01:00
LinkLeong
d0fb2f06f5 Supplementary log 2023-07-18 08:13:11 +01:00
raller1028
dd8032a8be
Update push_test_server.yml (#1243)
Signed-off-by: raller1028 <57336867+raller1028@users.noreply.github.com>
2023-07-12 15:06:55 +08:00
raller1028
760882e147
Update push_test_server.yml (#1233)
Signed-off-by: raller1028 <57336867+raller1028@users.noreply.github.com>
2023-07-03 17:10:45 +08:00
LinkLeong
dfeed76a66 Update permission issues 2023-07-03 10:08:05 +01:00
Tiger Wang
28d724731a
remove submit application template 2023-06-27 08:18:15 -04:00
Tiger Wang
4549d8778b
remove feedback template 2023-06-27 08:15:52 -04:00
Tiger Wang
05cadaabf3
update bug_report.md (#1216)
Signed-off-by: Tiger Wang <tigerwang@outlook.com>
2023-06-26 17:36:34 -04:00
link
1a0c15208c
Update demo.yml (#1213)
Signed-off-by: link <a624669980@163.com>
2023-06-25 17:09:31 +08:00
link
4f5b4b0887
Update demo.yml (#1212)
Signed-off-by: link <a624669980@163.com>
2023-06-25 17:07:17 +08:00
link
cbfe44be61
Update demo.yml (#1211)
Signed-off-by: link <a624669980@163.com>
2023-06-25 17:05:27 +08:00
link
e1bbb998df
Update demo.yml (#1210)
Signed-off-by: link <a624669980@163.com>
2023-06-25 16:58:29 +08:00
link
f48cddf924
Up json (#1186) 2023-06-14 11:32:04 +08:00
raller1028
23ce3487e1
Update demo.yml (#1174)
Add demo reset error handle

Signed-off-by: raller1028 <57336867+raller1028@users.noreply.github.com>
2023-06-07 16:09:01 +08:00
link
6246421dae
Up json (#1173)
Signed-off-by: link <a624669980@163.com>
2023-06-07 15:23:29 +08:00
link
f867453573
Update entry json output (#1172) 2023-06-07 15:21:22 +08:00
link
78e7a8b411
Add zt dynamic ip (#1168) 2023-06-05 16:49:32 +08:00
link
1aa8fb600b
Remove 9527 (#1162) 2023-06-02 18:51:25 +08:00
link
7ecfea71ab
Update json (#1160) 2023-06-01 17:09:34 +08:00
link
d911d80254
Socket update (#1159) 2023-06-01 10:22:04 +08:00
link
9bfe37305c
Socket update (#1154) 2023-05-31 18:02:46 +08:00
link
94dd2e00c7
Socket update (#1153) 2023-05-31 16:10:14 +08:00
link
c5d2cebe92
Socket update (#1151) 2023-05-30 18:57:15 +08:00
link
955e8dea07
Update socket address (#1147) 2023-05-29 17:17:39 +08:00
link
4c7b3a749b
Zt update (#1146) 2023-05-29 15:38:39 +08:00
link
e86a61596b
Update zt (#1139) 2023-05-26 18:37:16 +08:00
link
c9617e583f
Add zertier (#1137)
Signed-off-by: link <a624669980@163.com>
2023-05-26 17:45:18 +08:00
link
dda15b0821
Add zertier (#1124)
Signed-off-by: link <a624669980@163.com>
2023-05-25 12:14:32 +08:00
link
50816c68b0
Update demo.yml (#1121)
Signed-off-by: link <a624669980@163.com>
2023-05-24 19:12:18 +08:00
李旭海
c5de0319fb
Update publish_npm.yaml (#1120)
Signed-off-by: 李旭海 <lxh_shine@hotmail.com>
Signed-off-by: zhanghengxin <812718649@qq.com>
Co-authored-by: zhanghengxin <812718649@qq.com>
2023-05-24 13:49:03 +08:00
link
78b7c6ce09
Add zertier (#1116) 2023-05-23 16:39:25 +08:00
link
b420a2d930
Add logs function (#1108) 2023-05-22 17:28:30 +08:00
zhanghengxin
c67ee1731c
Introducing new features.Incorporating automatic publishin… (#1107)
Introducing new features.Incorporating automatic publishing for the
openAPI npm package.
2023-05-22 16:45:06 +08:00
raller1028
eaca399ef9
Add zerotier route (#1098) 2023-05-22 16:44:39 +08:00
LinkLeong
e0e9f97764 Update ip address 2023-05-22 04:32:47 +01:00
link
2fefee87fa
Fixed compression error (#1097) 2023-05-19 16:50:48 +08:00
link
280ad4fcf9
Add merge json (#1079) 2023-05-15 11:01:21 +08:00
Tiger Wang
538639b623
fix (*service).Ports() missing ports from IPv6 (#1069) 2023-05-09 17:02:59 -04:00
老竭力
39535d6a38
Update README.md (#1067)
Signed-off-by: 老竭力 <jerrykuku@qq.com>
2023-05-09 18:13:29 +08:00
老竭力
4d977d7a62
Update demo.yml (#1049)
Signed-off-by: 老竭力 <jerrykuku@qq.com>
2023-05-06 11:35:44 +08:00
link
08c500c434
Add local jwt (#1047) 2023-05-05 10:37:23 +08:00
link
705bf1facb
Update jwt (#1025) 2023-04-26 16:00:43 +08:00
Tiger Wang
aae1802191 bump version from 0.4.3 to 0.4.4
Signed-off-by: Tiger Wang <tigerwang@outlook.com>
2023-04-24 16:11:16 -04:00
Tiger Wang
8e1b9b82c1
add /v2/casaos/health/ports to get ports in use (#1023)
Signed-off-by: Tiger Wang <tigerwang@outlook.com>
2023-04-24 16:10:15 -04:00
link
af440eac55
Update samba (#1021) 2023-04-24 11:24:22 +08:00
link
34b4e154a1
fix reboot auto mount (#1007) 2023-04-12 13:53:27 +08:00
Lauren
79db93ec02
Update README.md
Update the project introduction

Signed-off-by: Lauren <Lauren-ED209@users.noreply.github.com>
2023-03-29 17:57:17 +08:00
Tiger Wang
f8ec3b20cd
upgrade dependencies (#978)
Signed-off-by: Tiger Wang <tigerwang@outlook.com>
2023-03-25 23:37:00 -04:00
79 changed files with 2882 additions and 3705 deletions

View File

@ -8,39 +8,57 @@ assignees: ''
---
**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**
Steps to reproduce the behavior:
> Steps to reproduce the behavior:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error
**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**
If applicable, add screenshots to help explain your problem.
> If applicable, add screenshots to help explain your problem.
**Desktop (please complete the following information):**
```
- OS: [e.g. iOS]
- Browser [e.g. chrome, safari]
- Version [e.g. 22]
```
**System Time**
> Run `timedatectl` and share the output
```
(timedatectl output here)
```
**Logs**
run following command to collect corresponding logs:
> Run following command to collect corresponding logs:
```bash
sudo journalctl -xef -u casaos-gateway
sudo journalctl -xef -u casaos-user-service
sudo journalctl -xef -u casaos-local-storage
sudo journalctl -xef -u casaos-app-management
sudo journalctl -xef -u casaos.service
```
**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.

View File

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

View File

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

View File

@ -65,7 +65,7 @@ jobs:
# ls
- name: Set enviroment for github-release
- name: Set environment for github-release
run: |
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

View File

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

View File

@ -33,9 +33,10 @@ jobs:
- name: Get old instance and snapshot name, create new instance name
run: |
echo "OLD_INSTANCE_SNAPSHOT_NAME=$(aws lightsail get-instance-snapshots | grep '"name": "updateto_to_0.4.1-1676285322' | sed 's/ //g' | sed 's/"//g' | sed 's/,//g' | sed 's/name://g')" >> $GITHUB_ENV
echo "OLD_INSTANCE_NAME=$(aws lightsail get-instances | grep '"name": "CasaOS-Demo-[0-9]' | 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_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]' | tail -1 | sed 's/ //g' | sed 's/"//g' | sed 's/,//g' | sed 's/name://g')" >> $GITHUB_ENV
# echo "OLD_INSTANCE_NAME=CasaOS-Demo-1687680295" >> $GITHUB_ENV
echo "NEW_INSTANCE_NAME= CasaOS-Demo-$(date +%s)" >> $GITHUB_ENV
- name: Create instances from snapshot
run: |
@ -75,5 +76,9 @@ jobs:
run: |
aws lightsail delete-instance \
--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
View 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}}

View File

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

View File

@ -3,6 +3,8 @@ on:
push:
branches:
- main
workflow_dispatch:
permissions:
contents: write
jobs:
@ -19,7 +21,7 @@ jobs:
- name: git global
run: sudo git config --global --add safe.directory '*'
- name: set version
run: sudo git tag v99.99.99-alpha
run: sudo git tag v00.00.00-alpha
- name: Fetch all tags
run: sudo git fetch --force --tags
@ -44,10 +46,16 @@ jobs:
with:
# either 'goreleaser' (default) or 'goreleaser-pro'
distribution: goreleaser
version: latest
version: 1.14.1
args: release --rm-dist --snapshot
env:
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
# GORELEASER_KEY: ${{ secrets.GORELEASER_KEY }}

View File

@ -7,57 +7,19 @@ on:
permissions:
contents: write
jobs:
goreleaser:
runs-on: ubuntu-22.04
steps:
- name: Install dependencies for cross-compiling
run: |
sudo apt update
sudo apt-get --no-install-recommends --yes install \
upx libc6-dev-amd64-cross \
gcc-aarch64-linux-gnu libc6-dev-arm64-cross \
gcc-arm-linux-gnueabihf libc6-dev-armhf-cross
- name: Checkout
uses: actions/checkout@v3
with:
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@v4
with:
go-version: "1.20"
- name: Run GoReleaser
uses: goreleaser/goreleaser-action@v4
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
call-workflow-passing-data:
uses: IceWhaleTech/github/.github/workflows/go_release.yml@main
with:
project-name: CasaOS
file-name: casaos
secrets:
GoogleID: ${{ secrets.GoogleID }}
GoogleSecret: ${{ secrets.GoogleSecret }}
DropboxKey: ${{ secrets.DropboxKey }}
DropboxSecret: ${{ secrets.DropboxSecret }}
OneDriveID: ${{ secrets.OneDriveID }}
OneDriveSecret: ${{ secrets.OneDriveSecret }}
OneDrivePublic: ${{ secrets.OneDrivePublic }}
OSS_KEY_ID: ${{ secrets.OSS_KEY_ID }}
OSS_KEY_SECRET: ${{ secrets.OSS_KEY_SECRET }}

19
.github/workflows/sync_openapi.yml vendored Normal file
View 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
View File

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

View File

@ -59,6 +59,22 @@ builds:
- arm
goarm:
- "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
binary: build/sysroot/usr/bin/casaos-migration-tool
main: ./cmd/migration-tool
@ -112,25 +128,42 @@ builds:
- arm
goarm:
- "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:
- name_template: "{{ .Os }}-{{ .Arch }}-{{ .ProjectName }}-v{{ .Version }}"
- name_template: >-
{{ .Os }}-{{- if eq .Arch "arm" }}arm-7{{- else }}{{ .Arch }}{{- end }}-{{ .ProjectName }}-v{{ .Version }}
id: casaos
builds:
- casaos-amd64
- casaos-arm64
- casaos-arm-7
replacements:
arm: arm-7
- casaos-riscv64
files:
- 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
builds:
- casaos-migration-tool-amd64
- casaos-migration-tool-arm64
- casaos-migration-tool-arm-7
replacements:
arm: arm-7
- casaos-migration-tool-riscv64
files:
- build/sysroot/etc/**/*
checksum:

View File

@ -19,6 +19,12 @@ builds:
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"
@ -32,14 +38,20 @@ builds:
- amd64
- id: casaos-arm64
binary: build/sysroot/usr/bin/casaos
hooks:
post:
- upx --best --lzma -v --no-progress "{{ .Path }}"
# hooks:
# post:
# - upx --best --lzma -v --no-progress "{{ .Path }}"
env:
- CC=aarch64-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"
@ -61,6 +73,12 @@ builds:
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"
@ -74,6 +92,30 @@ builds:
- arm
goarm:
- "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
binary: build/sysroot/usr/bin/casaos-migration-tool
hooks:
@ -98,9 +140,9 @@ builds:
- amd64
- id: casaos-migration-tool-arm64
binary: build/sysroot/usr/bin/casaos-migration-tool
hooks:
post:
- upx --best --lzma -v --no-progress "{{ .Path }}"
# hooks:
# post:
# - upx --best --lzma -v --no-progress "{{ .Path }}"
main: ./cmd/migration-tool
env:
- CC=aarch64-linux-gnu-gcc
@ -142,25 +184,44 @@ builds:
- arm
goarm:
- "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:
- name_template: "{{ .Os }}-{{ .Arch }}-{{ .ProjectName }}-v{{ .Version }}"
- name_template: >-
{{ .Os }}-{{- if eq .Arch "arm" }}arm-7{{- else }}{{ .Arch }}{{- end }}-{{ .ProjectName }}-v{{ .Version }}
id: casaos
builds:
- casaos-amd64
- casaos-arm64
- casaos-arm-7
replacements:
arm: arm-7
- casaos-riscv64
files:
- 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
builds:
- casaos-migration-tool-amd64
- casaos-migration-tool-arm64
- casaos-migration-tool-arm-7
replacements:
arm: arm-7
- casaos-migration-tool-riscv64
files:
- build/sysroot/etc/**/*
checksum:

View File

@ -1,6 +1,4 @@
# CasaOS - Your Home Cloud OS
# CasaOS - Your Personal Cloud
<!-- Readme i18n links -->
<!-- > 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">
</picture>
<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/>
<!-- 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" />
</a>
<!-- 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>
<!-- ALL-CONTRIBUTORS-BADGE:END -->
<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>
<!-- 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/>
<!-- CasaOS Links -->
<a href="https://www.casaos.io" target="_blank">Website</a> |
@ -65,18 +75,16 @@
</kbd>
</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?
- 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?
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.
It sounds ridiculous, doesn't it? We are losing control of our own data!
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.
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.
> 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
- ZimaBoard, NUC, RPi, old computers, whatever is available.
- 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
- Over 100,000 apps from the Docker ecosystem can be easily installed
- Elegant drive and file management
@ -108,7 +116,7 @@ CasaOS fully supports ZimaBoard, Intel NUC, and Raspberry Pi. Also, more compute
### System Compatibility
Official Support
- Debian 11 (✅ Tested, Recommended)
- Debian 12 (✅ Tested, Recommended)
- Ubuntu Server 20.04 (✅ Tested)
- Raspberry Pi OS (✅ Tested)
@ -133,6 +141,30 @@ or
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
@ -150,13 +182,13 @@ curl -fsSL https://get.icewhale.io/casaos-uninstall.sh | sudo bash
## 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.
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)!**
@ -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!
- See <https://wiki.casaos.io/en/contribute> for ways of contribution to CasaOS
- See <https://wiki.casaos.io/en/contribute/development> if you want to be involved in code contribution specificially
- 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 specifically
## Credits
@ -182,7 +215,7 @@ Everyone's contribution is greatly appreciated. ([Emoji Key](https://allcontribu
<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/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://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>
@ -199,6 +232,8 @@ Everyone's contribution is greatly appreciated. ([Emoji Key](https://allcontribu
</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/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>
</table>
@ -207,7 +242,7 @@ Everyone's contribution is greatly appreciated. ([Emoji Key](https://allcontribu
<!-- 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

View File

@ -20,10 +20,11 @@ servers:
tags:
- name: Health methods
description: |-
(TODO)
- name: File methods
These methods are used to check the health and status of the CasaOS API and associated services.
- name: File methods
description: |-
(TODO)
The File methods allow you to interact with files and directories on the CasaOS system.
x-tagGroups:
- name: Methods
@ -47,6 +48,35 @@ paths:
$ref: "#/components/responses/GetHealthServicesOK"
"500":
$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:
get:
tags:
@ -60,6 +90,153 @@ paths:
$ref: "#/components/responses/ResponseOK"
"500":
$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:
securitySchemes:
access_token:
@ -75,6 +252,20 @@ components:
schema:
$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:
description: Internal Server Error
content:
@ -93,6 +284,24 @@ components:
data:
$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:
BaseResponse:
properties:
@ -101,6 +310,14 @@ components:
description: message returned by server side if there is any
type: string
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:
properties:
@ -114,3 +331,29 @@ components:
items:
type: string
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"

View File

@ -111,6 +111,9 @@ aarch64)
armv7l)
ARCH="arm-7"
;;
riscv64)
ARCH="riscv64"
;;
*)
__error "Unsupported architecture"
;;

View File

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

View 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)
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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 {
return nil
}
func (d *Dropbox) GetInfo(ctx context.Context) (string, string, string, error) {
return "", "", "", nil
}
var _ driver.Driver = (*Dropbox)(nil)

View File

@ -2,12 +2,9 @@ package dropbox
import (
"github.com/IceWhaleTech/CasaOS/internal/driver"
"github.com/IceWhaleTech/CasaOS/internal/op"
)
const ICONURL = "./img/driver/Dropbox.svg"
const APPKEY = "tciqajyazzdygt9"
const APPSECRET = "e7gtmv441cwdf0n"
type Addition struct {
driver.RootID
@ -15,7 +12,7 @@ type Addition struct {
AppKey string `json:"app_key" type:"string" default:"tciqajyazzdygt9" 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"`
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"`
Code string `json:"code" type:"string" help:"code from auth_url" omit:"true"`
}
@ -25,9 +22,3 @@ var config = driver.Config{
OnlyProxy: true,
DefaultRoot: "root",
}
func init() {
op.RegisterDriver(func() driver.Driver {
return &Dropbox{}
})
}

View File

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

View File

@ -80,6 +80,9 @@ func (d *GoogleDrive) GetUserInfo(ctx context.Context) (string, error) {
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 {
data := base.Json{
"name": dirName,

View File

@ -2,22 +2,19 @@ package google_drive
import (
"github.com/IceWhaleTech/CasaOS/internal/driver"
"github.com/IceWhaleTech/CasaOS/internal/op"
)
const ICONURL = "./img/driver/GoogleDrive.svg"
const CLIENTID = "921743327851-urr4f7jjfp4ts639evqb3i4m4qb4u4cc.apps.googleusercontent.com"
const CLIENTSECRET = "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"
type Addition struct {
driver.RootID
RefreshToken string `json:"refresh_token" required:"true" 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"`
ClientID string `json:"client_id" required:"true" default:"921743327851-urr4f7jjfp4ts639evqb3i4m4qb4u4cc.apps.googleusercontent.com" omit:"true"`
ClientSecret string `json:"client_secret" required:"true" default:"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" omit:"true"`
ClientID string `json:"client_id" required:"true" default:"" 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"`
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"`
Code string `json:"code" type:"string" help:"code from auth_url" omit:"true"`
}
@ -27,9 +24,3 @@ var config = driver.Config{
OnlyProxy: true,
DefaultRoot: "root",
}
func init() {
op.RegisterDriver(func() driver.Driver {
return &GoogleDrive{}
})
}

View File

@ -16,6 +16,11 @@ import (
"go.uber.org/zap"
)
var (
client_id = "private build"
client_secret = "private build"
)
// do others that not defined in Driver interface
func (d *GoogleDrive) getRefreshToken() error {
@ -150,3 +155,13 @@ func (d *GoogleDrive) chunkUpload(ctx context.Context, stream model.FileStreamer
}
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
View 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
View 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
View 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
}

77
go.mod
View File

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

183
go.sum
View File

@ -1,22 +1,16 @@
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/IceWhaleTech/CasaOS-Common v0.4.2-alpha3 h1:WJUYo+hJpLmza7mQngoJVeUJOfnrZevNrX5wzTuOJo0=
github.com/IceWhaleTech/CasaOS-Common v0.4.2-alpha3/go.mod h1:xcemiRsXcs1zrmQxYMyExDjZ7UHYwkJqYE71IDIV0xA=
github.com/IceWhaleTech/CasaOS-Common v0.4.11-alpha4 h1:W+kOJ3NcWCEAnZdjqmnjnhAG+aLbiVNXnOvV+1bHsB0=
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/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/go.mod h1:lvDnEdqiQrp0O42VQGgmlKpxL1AP2+08jFMw88y4klk=
github.com/benbjohnson/clock v1.3.0 h1:ip6w0uFQkncKQ979AypyG0ER7mqUSBdKLOgAle/AT8A=
github.com/benbjohnson/clock v1.3.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
github.com/benbjohnson/clock v1.3.1 h1:Heo0FGXzOxUHquZbraxt+tT7UXVDhesUQH5ISbsOkCQ=
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/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM=
github.com/bytedance/sonic v1.8.5 h1:kjX0/vo5acEQ/sinD/18SkA/lDDUk23F0RcaHvI7omc=
github.com/bytedance/sonic v1.8.5/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U=
github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY=
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 h1:qSGYFH7+jGhDF8vLC+iwCD4WpbV1EBDSzWkJODFLams=
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk=
github.com/coreos/go-systemd v0.0.0-20191104093116-d3cd4ed1dbcf h1:iW4rZ826su+pqaw19uhpSCzhj44qo35pNgKFGqzDKkU=
github.com/coreos/go-systemd v0.0.0-20191104093116-d3cd4ed1dbcf/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs=
@ -39,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-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-20221012082141-d21ac8e2de85 h1:vZkWA0Lduu9QB6qRBtsLy7m5uO/RFNCDH2pzMLTxGts=
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 h1:/IE4iW7gvY7BablV1XY0unqhMv26EYpOquVMwoBo/wc=
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-20200517223158-a10564966e9d/go.mod h1:7I+3Pe2o/YSU88W0hWlm9S22W7XI1JFNJ86U0zPKMf8=
github.com/dsoprea/go-logging v0.0.0-20200710184922-b02d349568dd h1:l+vLbuxptsC6VQyQsfD7NnEC8BZuFpz45PgY+pH8YTg=
@ -53,21 +47,16 @@ github.com/dsoprea/go-utility/v2 v2.0.0-20221003172846-a3e1774ef349 h1:DilThiXje
github.com/dsoprea/go-utility/v2 v2.0.0-20221003172846-a3e1774ef349/go.mod h1:4GC5sXji84i/p+irqghpPFZBF8tRN/Q7+700G0/DLe8=
github.com/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/go.mod h1:jVPKeCbj6MvQZhwLYsGwaGI52oUorHoHKNecGT85ZCc=
github.com/getkin/kin-openapi v0.115.0 h1:c8WHRLVY3G8m9jQTy0/DnIuljgRwTCB5twZytQS4JyU=
github.com/getkin/kin-openapi v0.115.0/go.mod h1:l5e9PaFUo9fyLJCPGQeXI2ML8c3P8BHOEV2VaAVf/pc=
github.com/gin-contrib/gzip v0.0.6 h1:NjcunTcGAj5CO1gn4N8jHOSIeRFHIbn51z6K+xaN4d4=
github.com/gin-contrib/gzip v0.0.6/go.mod h1:QOJlmV2xmayAjkNS2Y8NQsMneuRShOU/kjovCXNuzzk=
github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
github.com/gin-gonic/gin v1.8.1/go.mod h1:ji8BvRH1azfM+SYow9zQ6SZMvR8qOMZHmsCuWR9tTTk=
github.com/gin-gonic/gin v1.9.0 h1:OjyFBKICoexlu99ctXNR2gg+c5pKrKMuyjgARg9qeY8=
github.com/gin-gonic/gin v1.9.0/go.mod h1:W1Me9+hsUSyj3CePGrd1/QrKJMSJ1Tu/0hFEH89961k=
github.com/glebarez/go-sqlite v1.21.0 h1:b8MHPtBagkSD2gntImZPsG3o3QEXgMDxguW/GLUonHQ=
github.com/glebarez/go-sqlite v1.21.0/go.mod h1:GodsA6yGSa3eKbvpr7dS+JaqazzVfMcjIXvx6KHhW/c=
github.com/glebarez/sqlite v1.7.0 h1:A7Xj/KN2Lvie4Z4rrgQHY8MsbebX3NyWsL3n2i82MVI=
github.com/glebarez/sqlite v1.7.0/go.mod h1:PkeevrRlF/1BhQBCnzcMWzgrIk7IOop+qS2jUYLfHhk=
github.com/getkin/kin-openapi v0.117.0 h1:QT2DyGujAL09F4NrKDHJGsUoIprlIcFVHWDVDcUFE8A=
github.com/getkin/kin-openapi v0.117.0/go.mod h1:l5e9PaFUo9fyLJCPGQeXI2ML8c3P8BHOEV2VaAVf/pc=
github.com/glebarez/go-sqlite v1.21.1 h1:7MZyUPh2XTrHS7xNEHQbrhfMZuPSzhkm2A1qgg0y5NY=
github.com/glebarez/go-sqlite v1.21.1/go.mod h1:ISs8MF6yk5cL4n/43rSOmVMGJJjHYr7L2MbZZ5Q4E2E=
github.com/glebarez/sqlite v1.8.0 h1:02X12E2I/4C1n+v90yTqrjRa8yuo7c3KeHI3FRznCvc=
github.com/glebarez/sqlite v1.8.0/go.mod h1:bpET16h1za2KOOMb8+jCp6UBP/iahDpfPQqSaYLTLx8=
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.1.1/go.mod h1:psDX2osz5VnTOnFWbDeWwS7yejl+uV3FEWEp4lssFEs=
@ -83,24 +72,10 @@ github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaL
github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
github.com/go-openapi/swag v0.22.3 h1:yMBqmnQ0gyZvEb/+KzuWZOXgllrXT4SADYbvDaXHv/g=
github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14=
github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
github.com/go-playground/locales v0.14.0/go.mod h1:sawfccIbzZTqEDETgFXqTho0QybSa7l++s0DH+LDiLs=
github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
github.com/go-playground/universal-translator v0.18.0/go.mod h1:UvRDBj+xPUEGrFYl+lu/H90nyDXpg0fqeB/AQUGNTVA=
github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
github.com/go-playground/validator/v10 v10.10.0/go.mod h1:74x4gJWsvQexRdW8Pn3dXSGrTK4nAUsbPlLADvpJkos=
github.com/go-playground/validator/v10 v10.11.2 h1:q3SHpufmypg+erIExEKUmsgmhDTyhcJ38oeKGACXohU=
github.com/go-playground/validator/v10 v10.11.2/go.mod h1:NieE624vt4SCTJtD87arVLvdmjPAeV8BQlHtMnw9D7s=
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-test/deep v1.0.8 h1:TDsG77qcSprGbC6vTN8OuXp5g+J+b5Pcguhf7Zt61VM=
github.com/go-test/deep v1.0.8/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE=
github.com/goccy/go-json v0.9.7/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
github.com/goccy/go-json v0.10.1 h1:lEs5Ob+oOG/Ze199njvzHbhn6p9T+h64F5hRj69iTTo=
github.com/goccy/go-json v0.10.1/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk=
github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
@ -111,6 +86,8 @@ github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keL
github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I=
github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg=
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-20200319012246-673a6f80352d/go.mod h1:QZ0nwyI2jOfgRAoBvP+ab5aRr7c9x7lhGEJrKvBwjWI=
github.com/golang/geo v0.0.0-20210211234256-740aa86cb551 h1:gtexQ/VGyN+VVFRXSFiguSNcXmS6rkKT+X7FdIrTtfo=
@ -131,8 +108,9 @@ github.com/gomodule/redigo v1.8.9/go.mod h1:7ArFNvsTjH8GMMzB4uy1snslv2BwmginuMs0
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.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.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
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/go.mod h1:LFlKC047IOqiglRGNqNb9s/iAPTnnjtlshm+bxp+kwk=
github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
@ -140,8 +118,11 @@ github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD
github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26 h1:Xim43kblpZXfIBQsbuBVKCudVG457BR2GZFIz3uw3hQ=
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26/go.mod h1:dDKJzRmX4S37WGHujM7tX//fmj1uioxKzKxz3lo4HJo=
github.com/google/safetext v0.0.0-20240104143208-7a7d9b3d812f h1:o2yGZLlsOj5H5uvtQNEdi6DeA0GbUP3lm0gWW5RvY0s=
github.com/google/safetext v0.0.0-20240104143208-7a7d9b3d812f/go.mod h1:H3K1Iu/utuCfa10JO+GsmKUYSWi7ug57Rk6GaDRHaaQ=
github.com/google/uuid v1.5.0 h1:1p67kYwdtXjb0gL0BPiP1Av9wiZPo5A8z2cWkTZ+eyU=
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=
@ -169,30 +150,25 @@ github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHm
github.com/juju/gnuflag v0.0.0-20171113085948-2ce1bb71843d/go.mod h1:2PavIy+JPciBPrBUjwbNvtwB6RQlve+hkpll6QSNmOE=
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.16.3 h1:XuJt9zzcnaz6a16/OU53ZjWp/v7/42WcR5t2a0PcNQY=
github.com/klauspost/compress v1.16.3/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE=
github.com/klauspost/compress v1.16.7 h1:2mk3MPGNzKyxErAw8YaohYh69+pa4sIQSC0fPGCFR9I=
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/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
github.com/klauspost/cpuid/v2 v2.2.4 h1:acbojRNwl3o09bUq+yDCtZFc1aiwaAAxtcn8YkZXnvk=
github.com/klauspost/cpuid/v2 v2.2.4/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY=
github.com/klauspost/pgzip v1.2.5 h1:qnWYvvKqedOF2ulHpMG72XQol4ILEJ8k2wwRl/Km8oE=
github.com/klauspost/pgzip v1.2.5/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs=
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.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
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/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/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/labstack/echo/v4 v4.10.2 h1:n1jAhnq/elIFTHr1EYpiYtyKgx4RW9ccVgkqByZaN2M=
github.com/labstack/echo/v4 v4.10.2/go.mod h1:OEyqf2//K1DFdE57vw2DRgWY0M7s65IVQO2FzvI4J5k=
github.com/labstack/gommon v0.4.0 h1:y7cvthEAEbU0yHOf4axH8ZG2NH8knB9iNSoTO8dyIk8=
github.com/labstack/gommon v0.4.0/go.mod h1:uW6kP17uPlLJsD3ijUYn3/M5bAxtlZhMI6m3MFxTMTM=
github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY=
github.com/leodido/go-urn v1.2.2 h1:7z68G0FCGvDk646jz1AelTYNYWrTNm0bEcFAo147wt4=
github.com/leodido/go-urn v1.2.2/go.mod h1:kUaIbLZWttglzwNuG0pgsh5vuV6u2YcGBYz1hIPjtOQ=
github.com/labstack/echo-jwt/v4 v4.2.0 h1:odSISV9JgcSCuhgQSV/6Io3i7nUmfM/QkBeR5GVJj5c=
github.com/labstack/echo-jwt/v4 v4.2.0/go.mod h1:MA2RqdXdEn4/uEglx0HcUOgQSyBaTh5JcaHIan3biwU=
github.com/labstack/echo/v4 v4.12.0 h1:IKpw49IMryVB2p1a4dzwlhP1O2Tf2E0Ir/450lH+kI0=
github.com/labstack/echo/v4 v4.12.0/go.mod h1:UP9Cr2DJXbOK3Kr9ONYzNowSh7HP0aG0ShAyycHSJvM=
github.com/labstack/gommon v0.4.2 h1:F8qTUNXgG1+6WQmqoUWnz8WiEU60mXVVw0P4ht1WRA0=
github.com/labstack/gommon v0.4.2/go.mod h1:QlUFxVM+SNXhDL/Z7YhocGIBYOiwB0mXm1+1bAPHPyU=
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=
@ -202,13 +178,11 @@ github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0
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/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/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng=
github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.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/go.mod h1:e3dqJ7H78uzsRSEACH1joayhuSyhnonssnDhppzS1L4=
github.com/mileusna/useragent v1.2.1 h1:p3RJWhi3LfuI6BHdddojREyK3p6qX67vIfOVMnUIVr0=
@ -229,15 +203,11 @@ github.com/nwaples/rardecode v1.1.3 h1:cWCaZwfM5H7nAD6PyEdcVnczzV8i/JtotnyW/dD9l
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/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ=
github.com/pelletier/go-toml/v2 v2.0.1/go.mod h1:r9LEWfGN8R5k0VXJ+0BkIe7MYkRdwZOjgMj2KwnJFUo=
github.com/pelletier/go-toml/v2 v2.0.7 h1:muncTPStnKRos5dpVKULv2FVd4bMOhNePj9CjgDb8Us=
github.com/pelletier/go-toml/v2 v2.0.7/go.mod h1:eumQOmlWiOPt5WriQQqoM5y18pDHwha2N+QD+EUNTek=
github.com/perimeterx/marshmallow v1.1.4 h1:pZLDH9RjlLGGorbXhcaQLhfuV0pFMNfPO55FuFkxqLw=
github.com/perimeterx/marshmallow v1.1.4/go.mod h1:dsXbUu8CRzfYP5a87xpp0xq9S3u0Vchtcl8we9tYaXw=
github.com/pierrec/lz4/v4 v4.1.2/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
github.com/pierrec/lz4/v4 v4.1.17 h1:kV4Ip+/hUBC+8T6+2EgburRtkE9ef4nbY3f4dFhGjMc=
github.com/pierrec/lz4/v4 v4.1.17/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
@ -250,32 +220,29 @@ github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs=
github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro=
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE=
github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
github.com/rwtodd/Go.Sed v0.0.0-20210816025313-55464686f9ef/go.mod h1:8AEUvGVi2uQ5b24BIhcr0GCcpd/RNAFWaN2CJFrWIIQ=
github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww=
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
github.com/rogpeppe/go-internal v1.10.1-0.20230524175051-ec119421bb97 h1:3RPlVWzZ/PDqmVuf/FKHARG5EMid/tl7cv54Sw/QRVY=
github.com/rogpeppe/go-internal v1.10.1-0.20230524175051-ec119421bb97/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA=
github.com/samber/lo v1.38.1 h1:j2XEAqXKb09Am4ebOg31SpvzUTTs6EN3VfgeLUhPdXM=
github.com/samber/lo v1.38.1/go.mod h1:+m/ZKRl6ClXCE2Lgf3MsQlWfh4bn1bz6CXEOxnEXnEA=
github.com/shirou/gopsutil/v3 v3.23.2 h1:PAWSuiAszn7IhPMBtXsbSCafej7PqUOvY6YywlQUExU=
github.com/shirou/gopsutil/v3 v3.23.2/go.mod h1:gv0aQw33GLo3pG8SiWKiQrbDzbRY1K80RyZJ7V4Th1M=
github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0=
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/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.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
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.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.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.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8=
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/tidwall/gjson v1.14.4 h1:uo0p8EbA09J7RQaflQ1aBRffTR7xedD2bcIVSYxLnkM=
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/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM=
github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
@ -285,8 +252,6 @@ github.com/tklauser/go-sysconf v0.3.11 h1:89WgdJhk5SNwJfu+GKyYveZ4IaJ7xAkecBo+Kd
github.com/tklauser/go-sysconf v0.3.11/go.mod h1:GqXfhXY3kiPa0nAXPDIQIWzJbMCB7AmcWpGR8lSZfqI=
github.com/tklauser/numcpus v0.6.0 h1:kebhY2Qt+3U6RNK7UqpYNA+tJ23IBEGKkB7JQBfDYms=
github.com/tklauser/numcpus v0.6.0/go.mod h1:FEZLMke0lhOUG6w2JadTzp0a+Nl8PF/GFkQ5UVIcaL4=
github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI=
github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08=
github.com/ugorji/go v1.2.7/go.mod h1:nF9osbDWLy6bDVv/Rtoh6QgnvNDpmCalQV5urGCCS6M=
github.com/ugorji/go/codec v1.2.7/go.mod h1:WGN1fab3R1fzQlVQTkfxVtIBhWDRqOviHU95kRgeqEY=
github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU=
@ -297,7 +262,6 @@ 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/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/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ=
github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 h1:nIPpBwaJSVYIxUFsDv3M8ofmx9yWTog9BfvIu0q41lo=
@ -310,20 +274,18 @@ go.uber.org/atomic v1.10.0 h1:9qC72Qh0+3MqyJbAn8YU5xVq1frD8bn3JtD2oXtafVQ=
go.uber.org/atomic v1.10.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0=
go.uber.org/goleak v1.2.1 h1:NBol2c7O1ZokfZ0LEU9K6Whx/KnwvepVetCUhtKja4A=
go.uber.org/goleak v1.2.1/go.mod h1:qlT2yGI9QafXHhZZLxlSuNsMw3FFLxBr+tBRlmO1xH4=
go.uber.org/multierr v1.10.0 h1:S0h4aNzvfcFsC3dRF1jLoaov7oRaKqRGC/pUEJ2yvPQ=
go.uber.org/multierr v1.10.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
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/go.mod h1:2kMP+WWQ8aoFoedH3T2sq6iJ2yDWpHbP0f6MQbS9Gkg=
golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
golang.org/x/arch v0.3.0 h1:02VY4/ZcO/gBOH6PUaoiptASxtXU10jazRCP865E97k=
golang.org/x/arch v0.3.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-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.7.0 h1:AvwMYaRytfdeVt3u6mLaxYtErKYjxA2OXjJ1HHq6t3A=
golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU=
golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI=
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
golang.org/x/exp v0.0.0-20230713183714-613f0c0eb8a1 h1:MGwJjxBy0HJshjDNfLsYO8xppfqWlA5ZT9OhtUUhTNw=
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.6.0 h1:bR8b5okrPI3g/gyZakLZHeWxAR8Dn5CyxXv1hLH5g/4=
golang.org/x/image v0.6.0/go.mod h1:MXLdDR43H7cDJq5GEGXEVeeNhPgi+YYEQ2pC1byI1x0=
@ -344,16 +306,17 @@ golang.org/x/net v0.0.0-20211029224645-99673261e6eb/go.mod h1:9nx3DQGgdP8bBQD5qx
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.0.0-20221002022538-bcab6841153b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ=
golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc=
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.6.0 h1:Lh8GPgSKBfWSwFvtuWOfeI3aAAnbXTSutYxJiOJFgIw=
golang.org/x/oauth2 v0.6.0/go.mod h1:ycmewcwgD4Rpr3eZJLSB4Kyyljb3qDh40vJ8STE5HKw=
golang.org/x/oauth2 v0.7.0 h1:qe6s0zUXlPX80/dITx3440hWZ7GwMwgDDyrSGTPJG/g=
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-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 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o=
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-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@ -365,12 +328,7 @@ 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-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-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211103235746-7861aae1554b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
@ -378,22 +336,25 @@ golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBc
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.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ=
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-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
golang.org/x/term v0.6.0 h1:clScbb1cHjoCkyRbWwBEUZ5H/tIFu5TAXIqaZD0Gcjw=
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.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.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.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68=
golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4=
golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk=
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-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
@ -408,14 +369,12 @@ 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/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.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng=
google.golang.org/protobuf v1.30.0/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 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc=
gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
@ -425,20 +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/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-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.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gorm.io/gorm v1.24.6 h1:wy98aq9oFEetsc4CAbKD2SoBCdMzsbSIvSUUFJuHi5s=
gorm.io/gorm v1.24.6/go.mod h1:L4uxeKpfBml98NYqVqwAdmV1a2nBtAec/cf3fpucW/k=
gorm.io/gorm v1.25.0 h1:+KtYtb2roDz14EQe4bla8CbQlmb9dN3VejSai3lprfU=
gorm.io/gorm v1.25.0/go.mod h1:L4uxeKpfBml98NYqVqwAdmV1a2nBtAec/cf3fpucW/k=
gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo=
gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw=
modernc.org/libc v1.22.3 h1:D/g6O5ftAfavceqlLOFwaZuA5KYafKwmr30A6iSqoyY=
modernc.org/libc v1.22.3/go.mod h1:MQrloYP209xa2zHome2a8HLiLm6k0UT8CoHpV74tOFw=
modernc.org/libc v1.22.4 h1:wymSbZb0AlrjdAVX3cjreCHTPCpPARbQXNz6BHPzdwQ=
modernc.org/libc v1.22.4/go.mod h1:jj+Z7dTNX8fBScMVNRAYZ/jF91K8fdT2hYMThc3YjBY=
modernc.org/mathutil v1.5.0 h1:rV0Ko/6SfM+8G+yKiyI830l3Wuz1zRutdslNoQ0kfiQ=
modernc.org/mathutil v1.5.0/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E=
modernc.org/memory v1.5.0 h1:N+/8c5rE6EqugZwHii4IFsaJ7MUhoWX07J5tC/iI5Ds=
modernc.org/memory v1.5.0/go.mod h1:PkUhL0Mugw21sHPeskwZW4D6VscE/GQJOnIpCnW6pSU=
modernc.org/sqlite v1.21.0 h1:4aP4MdUf15i3R3M2mx6Q90WHKz3nZLoz96zlB6tNdow=
modernc.org/sqlite v1.21.0/go.mod h1:XwQ0wZPIh1iKb5mkvCJ3szzbhk+tykC8ZWqTRTgYRwI=
rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=
modernc.org/sqlite v1.21.2 h1:ixuUG0QS413Vfzyx6FWx6PYTmHaOegTY+hjzhn7L+a0=
modernc.org/sqlite v1.21.2/go.mod h1:cxbLkB5WS32DnQqeH4h4o1B0eMr8W/y8/RGuxQ3JsC0=
mvdan.cc/sh/v3 v3.7.0 h1:lSTjdP/1xsddtaKfGg7Myu7DnlHItd3/M2tomOcNNBg=
mvdan.cc/sh/v3 v3.7.0/go.mod h1:K2gwkaesF/D7av7Kxl0HbF5kGOd2ArupNTX3X44+8l8=

View File

@ -34,14 +34,16 @@ type Reader interface {
// 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 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(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 {
// GetRoot get root directory of user
GetUserInfo(ctx context.Context) (string, error)
GetInfo(ctx context.Context) (string, string, string, error)
}
type Getter interface {
GetRoot(ctx context.Context) (model.Obj, error)
}

30
main.go
View File

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

7
model/drive.go Normal file
View File

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

View File

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

View File

@ -23,3 +23,14 @@ type Path struct {
Write bool `json:"write"`
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
View 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"
}

View File

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

View File

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

View File

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

View File

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

View File

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

View 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
}

View File

@ -77,6 +77,22 @@ func RMDir(src string) error {
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
func Open(name string, flag int, perm os.FileMode) (*os.File, error) {
f, err := os.OpenFile(name, flag, perm)
@ -163,7 +179,7 @@ func CreateFileAndWriteContent(path string, content string) error {
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 {
if notExist := CheckNotExist(src); notExist {
if err := CreateFile(src); err != nil {
@ -431,7 +447,9 @@ func AddFile(ar archiver.Writer, path, commonPath string) error {
defer file.Close()
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{
FileInfo: archiver.FileInfo{
FileInfo: info,

View 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
}

View File

@ -1,6 +1,7 @@
package ip_helper
import (
"fmt"
"net"
"strings"
@ -56,7 +57,30 @@ func GetDeviceAllIP(port string) []string {
}
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 {
if ip.IsLoopback() {
return true

View File

@ -17,6 +17,7 @@ import (
"strings"
"time"
file1 "github.com/IceWhaleTech/CasaOS-Common/utils/file"
"github.com/IceWhaleTech/CasaOS-Common/utils/logger"
"github.com/IceWhaleTech/CasaOS/common"
"github.com/IceWhaleTech/CasaOS/model"
@ -24,6 +25,7 @@ import (
"github.com/IceWhaleTech/CasaOS/pkg/samba"
"github.com/IceWhaleTech/CasaOS/pkg/utils/encryption"
"github.com/IceWhaleTech/CasaOS/pkg/utils/file"
v1 "github.com/IceWhaleTech/CasaOS/route/v1"
"github.com/IceWhaleTech/CasaOS/service"
"go.uber.org/zap"
)
@ -31,6 +33,7 @@ import (
func InitFunction() {
go InitNetworkMount()
go InitInfo()
//go InitZerotier()
}
func InitInfo() {
@ -51,6 +54,12 @@ func InitInfo() {
}
mb.Hash = encryption.GetMD5ByStr(mac)
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")
by, err := json.Marshal(mb)
if err != nil {
@ -92,6 +101,12 @@ func InitNetworkMount() {
}
connection.Directories = strings.Join(directories, ",")
service.MyService.Connections().UpdateConnection(&connection)
service.MyService.Storage().CheckAndMountAll()
}
err := service.MyService.Storage().CheckAndMountAll()
if err != nil {
logger.Error("mount storage err", zap.Any("err", err))
}
}
func InitZerotier() {
v1.CheckNetwork()
}

View File

@ -1,45 +1,69 @@
package route
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"
"github.com/IceWhaleTech/CasaOS/pkg/config"
v1 "github.com/IceWhaleTech/CasaOS/route/v1"
"github.com/gin-contrib/gzip"
"github.com/gin-gonic/gin"
"github.com/labstack/echo/v4"
echo_middleware "github.com/labstack/echo/v4/middleware"
)
func InitV1Router() *gin.Engine {
ginMode := gin.ReleaseMode
if config.ServerInfo.RunMode != "" {
ginMode = config.ServerInfo.RunMode
}
if os.Getenv(gin.EnvGinMode) != "" {
ginMode = os.Getenv(gin.EnvGinMode)
}
gin.SetMode(ginMode)
func InitV1Router() http.Handler {
e := echo.New()
r := gin.New()
r.Use(gin.Recovery())
r.Use(middleware.Cors())
r.Use(gzip.Gzip(gzip.DefaultCompression))
if ginMode != gin.ReleaseMode {
r.Use(middleware.WriteLog())
}
e.Use((echo_middleware.CORSWithConfig(echo_middleware.CORSConfig{
AllowOrigins: []string{"*"},
AllowMethods: []string{echo.POST, echo.GET, echo.OPTIONS, echo.PUT, echo.DELETE},
AllowHeaders: []string{echo.HeaderAuthorization, echo.HeaderContentLength, echo.HeaderXCSRFToken, echo.HeaderContentType, echo.HeaderAccessControlAllowOrigin, echo.HeaderAccessControlAllowHeaders, echo.HeaderAccessControlAllowMethods, echo.HeaderConnection, echo.HeaderOrigin, echo.HeaderXRequestedWith},
ExposeHeaders: []string{echo.HeaderContentLength, echo.HeaderAccessControlAllowOrigin, echo.HeaderAccessControlAllowHeaders},
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)
r.GET("/ping", func(ctx *gin.Context) {
ctx.String(200, "pong")
e.GET("/v1/sys/version/check", v1.GetSystemCheckVersion)
e.GET("/v1/sys/version/current", func(ctx echo.Context) error {
return ctx.String(200, common.VERSION)
})
r.GET("/v1/recover/:type", v1.GetRecoverStorage)
v1Group := r.Group("/v1")
e.GET("/ping", func(ctx echo.Context) error {
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")
@ -73,6 +97,7 @@ func InitV1Router() *gin.Engine {
// v1SysGroup.PUT("/port", v1.PutCasaOSPort)
v1SysGroup.GET("/proxy", v1.GetSystemProxy)
v1SysGroup.PUT("/state/:state", v1.PutSystemState)
v1SysGroup.GET("/entry", v1.GetSystemEntry)
}
v1PortGroup := v1Group.Group("/port")
v1PortGroup.Use()
@ -80,7 +105,6 @@ func InitV1Router() *gin.Engine {
v1PortGroup.GET("/", v1.GetPort) // app/port
v1PortGroup.GET("/state/:port", v1.PortCheck) // app/check/:port
}
v1FileGroup := v1Group.Group("/file")
v1FileGroup.Use()
{
@ -92,7 +116,7 @@ func InitV1Router() *gin.Engine {
v1FileGroup.GET("/content", v1.GetFilerContent) // file/read
// 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("/download", v1.UserFileDownloadCommonService)
@ -165,9 +189,13 @@ func InitV1Router() *gin.Engine {
v1OtherGroup.Use()
{
v1OtherGroup.GET("/search", v1.GetSearchResult)
}
v1ZerotierGroup := v1Group.Group("/zt")
v1ZerotierGroup.Use()
{
v1ZerotierGroup.Any("/*url", v1.ZerotierProxy)
}
}
return r
return e
}

View File

@ -6,37 +6,19 @@ import (
"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/gin-gonic/gin"
"github.com/labstack/echo/v4"
"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,
// }})
func ListStorages(ctx echo.Context) error {
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
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++ {
@ -51,51 +33,47 @@ func ListStorages(c *gin.Context) {
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{
Fs: v.Fs,
Icon: v.Icon,
MountPoint: v.MountPoint,
Name: v.Name,
})
list = append(list, httper.MountPoint(v))
}
c.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: list})
return ctx.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: list})
}
func UmountStorage(c *gin.Context) {
func UmountStorage(ctx echo.Context) error {
json := make(map[string]string)
c.ShouldBind(&json)
ctx.Bind(&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
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 {
c.JSON(common_err.SERVICE_ERROR, model.Result{Success: common_err.SERVICE_ERROR, Message: common_err.GetMsg(common_err.SERVICE_ERROR), Data: err.Error()})
return
return ctx.JSON(common_err.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/", ""))
c.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: "success"})
return ctx.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")
func GetStorage(ctx echo.Context) error {
// idStr := ctx.QueryParam("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 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 {
// c.JSON(common_err.SUCCESS, 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.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})
// return ctx.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: storage})
return nil
}

View File

@ -1,12 +1,34 @@
package v1
import (
"github.com/IceWhaleTech/CasaOS-Common/model"
"github.com/IceWhaleTech/CasaOS-Common/utils/common_err"
"github.com/IceWhaleTech/CasaOS/internal/op"
"github.com/gin-gonic/gin"
"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/labstack/echo/v4"
)
func ListDriverInfo(c *gin.Context) {
c.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: op.GetDriverInfoMap()})
func ListDriverInfo(ctx echo.Context) error {
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})
}

View File

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

View File

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

View File

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

View File

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

View File

@ -1,6 +1,8 @@
package v1
import (
"context"
"net/http"
"strconv"
"strings"
"time"
@ -8,64 +10,54 @@ import (
"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/service"
"github.com/gin-gonic/gin"
"github.com/labstack/echo/v4"
"go.uber.org/zap"
)
func GetRecoverStorage(c *gin.Context) {
c.Header("Content-Type", "text/html; charset=utf-8")
t := c.Param("type")
func GetRecoverStorage(ctx echo.Context) error {
t := strings.TrimSuffix(ctx.Param("type"), "/")
currentTime := time.Now().UTC()
currentDate := time.Now().UTC().Format("2006-01-02")
notify := make(map[string]interface{})
event := "casaos:file:recover"
if t == "GoogleDrive" {
add := google_drive.Addition{}
add.Code = c.Query("code")
if len(add.Code) == 0 {
c.String(200, `<p>Code cannot be empty</p><script>window.close()</script>`)
google_drive := google_drive.GetConfig()
google_drive.Code = ctx.QueryParam("code")
if len(google_drive.Code) == 0 {
notify["status"] = "fail"
notify["message"] = "Code cannot be empty"
logger.Error("Then code is empty: ", zap.String("code", add.Code), zap.Any("name", "google_drive"))
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)
return
return ctx.HTML(http.StatusOK, `<p>Code cannot be empty</p><script>window.close()</script>`)
}
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)
err := google_drive.Init(context.Background())
if err != nil {
c.String(200, `<p>Initialization failure:`+err.Error()+`</p><script>window.close()</script>`)
notify["status"] = "fail"
notify["message"] = "Initialization failure"
logger.Error("Then init error: ", zap.Error(err), zap.Any("name", "google_drive"))
service.MyService.Notify().SendNotify("casaos:file:recover", notify)
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 {
c.String(200, `<p>Failed to get user information:`+err.Error()+`</p><script>window.close()</script>`)
notify["status"] = "fail"
notify["message"] = "Failed to get user information"
logger.Error("Then get user info error: ", zap.Error(err), zap.Any("name", "google_drive"))
service.MyService.Notify().SendNotify("casaos:file:recover", notify)
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["username"] = username
configs, err := service.MyService.Storage().GetConfig()
if err != nil {
c.String(200, `<p>Failed to get rclone config:`+err.Error()+`</p><script>window.close()</script>`)
notify["status"] = "fail"
notify["message"] = "Failed to get rclone config"
logger.Error("Then get config error: ", zap.Error(err), zap.Any("name", "google_drive"))
service.MyService.Notify().SendNotify("casaos:file:recover", notify)
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 {
cf, err := service.MyService.Storage().GetConfigByName(v)
@ -74,15 +66,14 @@ func GetRecoverStorage(c *gin.Context) {
continue
}
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)
if err != nil {
logger.Error("check and mount by name error: ", zap.Error(err), zap.Any("name", cf["username"]))
}
notify["status"] = "warn"
notify["message"] = "The same configuration has been added"
service.MyService.Notify().SendNotify("casaos:file:recover", notify)
return
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 {
@ -90,11 +81,10 @@ func GetRecoverStorage(c *gin.Context) {
username = a[0]
}
//username = fileutil.NameAccumulation(username, "/mnt")
username += "_google_drive_" + strconv.FormatInt(time.Now().Unix(), 10)
dmap["client_id"] = add.ClientID
dmap["client_secret"] = add.ClientSecret
dmap["client_id"] = google_drive.ClientID
dmap["client_secret"] = google_drive.ClientSecret
dmap["scope"] = "drive"
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"}`
@ -104,52 +94,45 @@ func GetRecoverStorage(c *gin.Context) {
notify["status"] = "success"
notify["message"] = "Success"
notify["driver"] = "GoogleDrive"
service.MyService.Notify().SendNotify("casaos:file:recover", notify)
service.MyService.Notify().SendNotify(event, notify)
} else if t == "Dropbox" {
add := dropbox.Addition{}
add.Code = c.Query("code")
if len(add.Code) == 0 {
c.String(200, `<p>Code cannot be empty</p><script>window.close()</script>`)
dropbox := dropbox.GetConfig()
dropbox.Code = ctx.QueryParam("code")
if len(dropbox.Code) == 0 {
notify["status"] = "fail"
notify["message"] = "Code cannot be empty"
logger.Error("Then code is empty error: ", zap.String("code", add.Code), zap.Any("name", "dropbox"))
service.MyService.Notify().SendNotify("casaos:file:recover", notify)
return
logger.Error("Then code is empty error: ", zap.String("code", dropbox.Code), zap.Any("name", "dropbox"))
service.MyService.Notify().SendNotify(event, notify)
return ctx.HTML(http.StatusOK, `<p>Code cannot be empty</p><script>window.close()</script>`)
}
add.RootFolderID = ""
add.AppKey = dropbox.APPKEY
add.AppSecret = dropbox.APPSECRET
var dropbox dropbox.Dropbox
dropbox.Addition = add
err := dropbox.Init(c)
err := dropbox.Init(context.Background())
if err != nil {
c.String(200, `<p>Initialization failure:`+err.Error()+`</p><script>window.close()</script>`)
notify["status"] = "fail"
notify["message"] = "Initialization failure"
logger.Error("Then init error: ", zap.Error(err), zap.Any("name", "dropbox"))
service.MyService.Notify().SendNotify("casaos:file:recover", notify)
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 {
c.String(200, `<p>Failed to get user information:`+err.Error()+`</p><script>window.close()</script>`)
notify["status"] = "fail"
notify["message"] = "Failed to get user information"
logger.Error("Then get user information: ", zap.Error(err), zap.Any("name", "dropbox"))
service.MyService.Notify().SendNotify("casaos:file:recover", notify)
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["username"] = username
configs, err := service.MyService.Storage().GetConfig()
if err != nil {
c.String(200, `<p>Failed to get rclone config:`+err.Error()+`</p><script>window.close()</script>`)
notify["status"] = "fail"
notify["message"] = "Failed to get rclone config"
logger.Error("Then get config error: ", zap.Error(err), zap.Any("name", "dropbox"))
service.MyService.Notify().SendNotify("casaos:file:recover", notify)
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 {
cf, err := service.MyService.Storage().GetConfigByName(v)
@ -158,16 +141,14 @@ func GetRecoverStorage(c *gin.Context) {
continue
}
if cf["type"] == "dropbox" && 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)
if err != nil {
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("casaos:file:recover", notify)
return
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 {
@ -176,30 +157,91 @@ func GetRecoverStorage(c *gin.Context) {
}
username += "_dropbox_" + strconv.FormatInt(time.Now().Unix(), 10)
dmap["client_id"] = add.AppKey
dmap["client_secret"] = add.AppSecret
dmap["client_id"] = dropbox.AppKey
dmap["client_secret"] = dropbox.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["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().MountStorage("/mnt/"+username, username+":")
notify["status"] = "success"
notify["message"] = "Success"
notify["driver"] = "Dropbox"
service.MyService.Notify().SendNotify("casaos:file:recover", notify)
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>`)
}

View File

@ -16,32 +16,29 @@ import (
"net/http"
"os"
"path/filepath"
"regexp"
"strings"
"github.com/IceWhaleTech/CasaOS-Common/utils/logger"
"github.com/IceWhaleTech/CasaOS-Common/utils/systemctl"
"github.com/labstack/echo/v4"
"go.uber.org/zap"
"github.com/IceWhaleTech/CasaOS/model"
"github.com/IceWhaleTech/CasaOS/pkg/samba"
"github.com/IceWhaleTech/CasaOS/pkg/utils/common_err"
"github.com/IceWhaleTech/CasaOS/pkg/utils/file"
"github.com/IceWhaleTech/CasaOS/pkg/utils/ip_helper"
"github.com/IceWhaleTech/CasaOS/service"
model2 "github.com/IceWhaleTech/CasaOS/service/model"
"github.com/gin-gonic/gin"
)
// service
func GetSambaStatus(c *gin.Context) {
func GetSambaStatus(ctx echo.Context) error {
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,
Message: common_err.GetMsg(common_err.SERVICE_NOT_RUNNING),
})
return
}
needInit := true
@ -53,10 +50,10 @@ func GetSambaStatus(c *gin.Context) {
}
data := make(map[string]string, 1)
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()
shareList := []model.Shares{}
for _, v := range shares {
@ -66,28 +63,24 @@ func GetSambaSharesList(c *gin.Context) {
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{}
c.ShouldBindJSON(&shares)
ctx.Bind(&shares)
for _, v := range shares {
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
return ctx.JSON(common_err.CLIENT_ERROR, model.Result{Success: common_err.INSUFFICIENT_PERMISSIONS, Message: common_err.GetMsg(common_err.INSUFFICIENT_PERMISSIONS)})
}
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
return ctx.JSON(common_err.SERVICE_ERROR, model.Result{Success: common_err.DIR_NOT_EXISTS, Message: common_err.GetMsg(common_err.DIR_NOT_EXISTS)})
}
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
return ctx.JSON(common_err.CLIENT_ERROR, model.Result{Success: common_err.SHARE_ALREADY_EXISTS, Message: common_err.GetMsg(common_err.SHARE_ALREADY_EXISTS)})
}
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
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)})
}
}
for _, v := range shares {
@ -99,21 +92,20 @@ func PostSambaSharesCreate(c *gin.Context) {
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) {
id := c.Param("id")
func DeleteSambaShares(ctx echo.Context) error {
id := ctx.Param("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
return ctx.JSON(common_err.CLIENT_ERROR, model.Result{Success: common_err.INSUFFICIENT_PERMISSIONS, Message: common_err.GetMsg(common_err.INSUFFICIENT_PERMISSIONS)})
}
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
func GetSambaConnectionsList(c *gin.Context) {
func GetSambaConnectionsList(ctx echo.Context) error {
connections := service.MyService.Connections().GetConnectionsList()
connectionList := []model.Connections{}
for _, v := range connections {
@ -125,49 +117,46 @@ func GetSambaConnectionsList(c *gin.Context) {
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{}
c.ShouldBindJSON(&connection)
ctx.Bind(&connection)
if connection.Port == "" {
connection.Port = "445"
}
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
return ctx.JSON(common_err.CLIENT_ERROR, model.Result{Success: common_err.CHARACTER_LIMIT, Message: common_err.GetMsg(common_err.CHARACTER_LIMIT)})
}
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
}
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
}
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
}
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
}
// if ok, _ := regexp.MatchString(`^[\w@#*.]{4,30}$`, connection.Password); !ok {
// return ctx.JSON(common_err.CLIENT_ERROR, model.Result{Success: common_err.CHARACTER_LIMIT, Message: common_err.GetMsg(common_err.CHARACTER_LIMIT)})
// return
// }
// if ok, _ := regexp.MatchString(`^[\w@#*.]{4,30}$`, connection.Username); !ok {
// return ctx.JSON(common_err.CLIENT_ERROR, model.Result{Success: common_err.INVALID_PARAMS, Message: common_err.GetMsg(common_err.INVALID_PARAMS)})
// return
// }
// if !ip_helper.IsIPv4(connection.Host) && !ip_helper.IsIPv6(connection.Host) {
// return ctx.JSON(common_err.CLIENT_ERROR, model.Result{Success: common_err.INVALID_PARAMS, Message: common_err.GetMsg(common_err.INVALID_PARAMS)})
// return
// }
// if ok, _ := regexp.MatchString("^[0-9]{1,6}$", connection.Port); !ok {
// return ctx.JSON(common_err.CLIENT_ERROR, model.Result{Success: common_err.INVALID_PARAMS, Message: common_err.GetMsg(common_err.INVALID_PARAMS)})
// return
// }
connection.Host = strings.Split(connection.Host, "/")[0]
// check is exists
connections := service.MyService.Connections().GetConnectionByHost(connection.Host)
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
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)})
}
// check connect is ok
directories, err := samba.GetSambaSharesList(connection.Host, connection.Port, connection.Username, connection.Password)
if err != nil {
c.JSON(common_err.SERVICE_ERROR, model.Result{Success: common_err.SERVICE_ERROR, Message: common_err.GetMsg(common_err.SERVICE_ERROR), Data: err.Error()})
return
return ctx.JSON(common_err.SERVICE_ERROR, model.Result{Success: common_err.SERVICE_ERROR, Message: common_err.GetMsg(common_err.SERVICE_ERROR), Data: err.Error()})
}
connectionDBModel := model2.ConnectionsDBModel{}
@ -189,21 +178,19 @@ func PostSambaConnectionsCreate(c *gin.Context) {
service.MyService.Connections().CreateConnection(&connectionDBModel)
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) {
id := c.Param("id")
func DeleteSambaConnections(ctx echo.Context) error {
id := ctx.Param("id")
connection := service.MyService.Connections().GetConnectionByID(id)
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
return ctx.JSON(common_err.CLIENT_ERROR, model.Result{Success: common_err.Record_NOT_EXIST, Message: common_err.GetMsg(common_err.Record_NOT_EXIST)})
}
mountPointList, err := samba.GetSambaSharesList(connection.Host, connection.Port, connection.Username, connection.Password)
//mountPointList, err := service.MyService.System().GetDirPath(connection.MountPoint)
// mountPointList, err := service.MyService.System().GetDirPath(connection.MountPoint)
if err != nil {
c.JSON(common_err.SERVICE_ERROR, model.Result{Success: common_err.SERVICE_ERROR, Message: common_err.GetMsg(common_err.SERVICE_ERROR), Data: err.Error()})
return
return ctx.JSON(common_err.SERVICE_ERROR, model.Result{Success: common_err.SERVICE_ERROR, Message: common_err.GetMsg(common_err.SERVICE_ERROR), Data: err.Error()})
}
baseHostPath := "/mnt/" + connection.Host
for _, v := range mountPointList {
@ -211,16 +198,14 @@ func DeleteSambaConnections(c *gin.Context) {
err := service.MyService.Connections().UnmountSmaba(baseHostPath + "/" + v)
if err != nil {
logger.Error("unmount smaba error", zap.Error(err), zap.Any("path", baseHostPath+"/"+v))
c.JSON(common_err.SERVICE_ERROR, model.Result{Success: common_err.SERVICE_ERROR, Message: common_err.GetMsg(common_err.SERVICE_ERROR), Data: err.Error()})
return
return ctx.JSON(common_err.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)
if len(dir) == 0 {
os.RemoveAll(connection.MountPoint)
}
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})
}

View File

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

View File

@ -10,8 +10,9 @@ import (
"github.com/IceWhaleTech/CasaOS-Common/utils/common_err"
"github.com/IceWhaleTech/CasaOS-Common/utils/logger"
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"
"go.uber.org/zap"
"golang.org/x/crypto/ssh"
@ -26,44 +27,41 @@ var upgrader = websocket.Upgrader{
HandshakeTimeout: time.Duration(time.Second * 5),
}
func PostSshLogin(c *gin.Context) {
func PostSshLogin(ctx echo.Context) error {
j := make(map[string]string)
c.ShouldBind(&j)
ctx.Bind(&j)
userName := j["username"]
password := j["password"]
port := j["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
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"})
}
_, err := sshHelper.NewSshClient(userName, password, port)
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))
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")
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
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"})
}
userName := c.Query("username")
password := c.Query("password")
port := c.Query("port")
wsConn, _ := upgrader.Upgrade(c.Writer, c.Request, nil)
userName := ctx.QueryParam("username")
password := ctx.QueryParam("password")
port := ctx.QueryParam("port")
wsConn, _ := upgrader.Upgrade(ctx.Response().Writer, ctx.Request(), nil)
logBuff := new(bytes.Buffer)
quitChan := make(chan bool, 3)
// user := ""
// password := ""
var login int = 1
cols, _ := strconv.Atoi(c.DefaultQuery("cols", "200"))
rows, _ := strconv.Atoi(c.DefaultQuery("rows", "32"))
cols, _ := strconv.Atoi(utils.DefaultQuery(ctx, "cols", "200"))
rows, _ := strconv.Atoi(utils.DefaultQuery(ctx, "rows", "32"))
var client *ssh.Client
for login != 0 {
@ -93,4 +91,5 @@ func WsSsh(c *gin.Context) {
go ssConn.SessionWait(quitChan)
<-quitChan
return nil
}

View File

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

View File

@ -1,6 +1,7 @@
package route
import (
"crypto/ecdsa"
"log"
"net/http"
"net/url"
@ -10,9 +11,10 @@ import (
"strings"
"github.com/IceWhaleTech/CasaOS/codegen"
"github.com/IceWhaleTech/CasaOS/pkg/config"
"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"
v2Route "github.com/IceWhaleTech/CasaOS/route/v2"
"github.com/deepmap/oapi-codegen/pkg/middleware"
@ -28,7 +30,6 @@ var (
V2APIPath string
V2DocPath string
V3FilePath string
V4DirPath string
)
func init() {
@ -47,7 +48,6 @@ func init() {
V2APIPath = strings.TrimRight(u.Path, "/")
V2DocPath = "/doc" + V2APIPath
V3FilePath = "/v3/file"
V4DirPath = "/v4/dir"
}
func InitV2Router() http.Handler {
@ -71,21 +71,23 @@ func InitV2Router() http.Handler {
e.Use(echo_middleware.JWTWithConfig(echo_middleware.JWTConfig{
Skipper: func(c echo.Context) bool {
return c.RealIP() == "::1" || c.RealIP() == "127.0.0.1"
//return true
// return true
},
ParseTokenFunc: func(token string, c echo.Context) (interface{}, error) {
claims, code := jwt.Validate(token)
if code != common_err.SUCCESS {
valid, claims, err := jwt.Validate(token, func() (*ecdsa.PublicKey, error) { return external.GetPublicKey(config.CommonInfo.RuntimePath) })
if err != nil || !valid {
return nil, echo.ErrUnauthorized
}
c.Request().Header.Set("user_id", strconv.Itoa(claims.ID))
return claims, nil
},
TokenLookupFuncs: []echo_middleware.ValuesExtractor{
func(c echo.Context) ([]string, error) {
return []string{c.Request().Header.Get(echo.HeaderAuthorization)}, nil
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
},
},
}))
@ -113,6 +115,12 @@ func InitV2Router() http.Handler {
// })
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},
}))
@ -137,17 +145,49 @@ func InitV2DocRouter(docHTML string, docYAML string) http.Handler {
}
})
}
func InitFile() http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
token := r.URL.Query().Get("token")
if len(token) == 0 {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusUnauthorized)
w.Write([]byte(`{"message": "token not found"}`))
return
}
valid, _, errs := jwt.Validate(token, func() (*ecdsa.PublicKey, error) { return external.GetPublicKey(config.CommonInfo.RuntimePath) })
if errs != nil || !valid {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusUnauthorized)
w.Write([]byte(`{"message": "validation failure"}`))
return
}
filePath := r.URL.Query().Get("path")
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 {
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")
files := r.URL.Query().Get("files")
@ -161,7 +201,7 @@ func InitDir() http.Handler {
list := strings.Split(files, ",")
for _, v := range list {
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,
// Message: common_err.GetMsg(common_err.FILE_DOES_NOT_EXIST),
// })
@ -174,7 +214,7 @@ func InitDir() http.Handler {
// handles only single files not folders and multiple files
// if len(list) == 1 {
//filePath := list[0]
// filePath := list[0]
// info, err := os.Stat(filePath)
// if err != nil {
@ -197,7 +237,7 @@ func InitDir() http.Handler {
err = ar.Create(w)
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,
// Message: common_err.GetMsg(common_err.SERVICE_ERROR),
// Data: err.Error(),

View File

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

View File

@ -2,10 +2,15 @@ package v2
import (
"net/http"
"net/url"
"os"
"path/filepath"
"github.com/IceWhaleTech/CasaOS/codegen"
"github.com/IceWhaleTech/CasaOS/pkg/utils/file"
"github.com/IceWhaleTech/CasaOS/service"
"github.com/labstack/echo/v4"
"github.com/mholt/archiver/v3"
)
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
}

View File

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

47
route/v2/zerotier.go Normal file
View 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)
}

View File

@ -11,11 +11,12 @@
package service
import (
"github.com/IceWhaleTech/CasaOS/pkg/config"
command2 "github.com/IceWhaleTech/CasaOS/pkg/utils/command"
"fmt"
"github.com/IceWhaleTech/CasaOS/service/model"
model2 "github.com/IceWhaleTech/CasaOS/service/model"
"github.com/moby/sys/mount"
"golang.org/x/sys/unix"
"gorm.io/gorm"
)
@ -26,7 +27,7 @@ type ConnectionsService interface {
CreateConnection(connection *model2.ConnectionsDBModel)
DeleteConnection(id string)
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
}
@ -38,28 +39,42 @@ func (s *connectionsStruct) GetConnectionByHost(host string) (connections []mode
s.db.Select("username,host,status,id").Where("host = ?", host).Find(&connections)
return
}
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)
return
}
func (s *connectionsStruct) GetConnectionsList() (connections []model2.ConnectionsDBModel) {
s.db.Select("username,host,port,status,id,mount_point").Find(&connections)
return
}
func (s *connectionsStruct) CreateConnection(connection *model2.ConnectionsDBModel) {
s.db.Create(connection)
}
func (s *connectionsStruct) UpdateConnection(connection *model2.ConnectionsDBModel) {
s.db.Save(connection)
}
func (s *connectionsStruct) DeleteConnection(id string) {
s.db.Where("id= ?", id).Delete(&model.ConnectionsDBModel{})
}
func (s *connectionsStruct) MountSmaba(username, host, directory, port, mountPoint, password string) string {
str := command2.ExecResultStr("source " + config.AppInfo.ShellPath + "/helper.sh ;MountCIFS " + username + " " + host + " " + directory + " " + port + " " + mountPoint + " " + password)
return str
func (s *connectionsStruct) MountSmaba(username, host, directory, port, mountPoint, password string) error {
err := unix.Mount(
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 {
return mount.Unmount(mountPoint)
}

View File

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

167
service/file_upload.go Normal file
View 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
}

View File

@ -1,11 +1,13 @@
package service
import (
"github.com/IceWhaleTech/CasaOS-Common/utils/port"
"github.com/IceWhaleTech/CasaOS-Common/utils/systemctl"
)
type HealthService interface {
Services() (map[bool]*[]string, error)
Ports() ([]int, []int, error)
}
type service struct{}
@ -34,6 +36,10 @@ func (s *service) Services() (map[bool]*[]string, error) {
return result, nil
}
func (s *service) Ports() ([]int, []int, error) {
return port.ListPortsInUse()
}
func NewHealthService() HealthService {
return &service{}
}

18
service/health_test.go Normal file
View 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)
}

View File

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

View File

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

25
tsconfig.json Normal file
View File

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