mirror of
https://github.com/IceWhaleTech/CasaOS.git
synced 2025-12-23 13:04:42 +00:00
Compare commits
198 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6bd41ad016 | ||
|
|
05425d638f | ||
|
|
bd5a2e35d4 | ||
|
|
123e7e8758 | ||
|
|
1ec3e2e9fb | ||
|
|
0719c3cc0c | ||
|
|
0a4ceb7c4c | ||
|
|
655f59f00a | ||
|
|
5289f471d6 | ||
|
|
59597befb6 | ||
|
|
df2477a12f | ||
|
|
b709abe682 | ||
|
|
d0f3dc806e | ||
|
|
92d085acf9 | ||
|
|
20dbae21c8 | ||
|
|
9258cb4b9e | ||
|
|
d9794851f9 | ||
|
|
1fcb530ff2 | ||
|
|
364d411438 | ||
|
|
0dacc5db12 | ||
|
|
fcbff194d2 | ||
|
|
04e93b0e3c | ||
|
|
2eff7fa8bc | ||
|
|
dd0645ee0f | ||
|
|
c93aa6286e | ||
|
|
bf7b32309f | ||
|
|
cd779448ce | ||
|
|
c3b2c1d599 | ||
|
|
b7949e100f | ||
|
|
80d24570d6 | ||
|
|
539b72a388 | ||
|
|
a7d15a896e | ||
|
|
9796c5aad7 | ||
|
|
892cd99eb3 | ||
|
|
02cb4cd392 | ||
|
|
9213f9e379 | ||
|
|
4473056d5c | ||
|
|
07e96511cd | ||
|
|
ce1dc52bc2 | ||
|
|
d890b16644 | ||
|
|
5737936318 | ||
|
|
33acfababd | ||
|
|
28c1a52171 | ||
|
|
892eef424c | ||
|
|
f3c73ba79b | ||
|
|
c6928c333d | ||
|
|
63c6c2cebb | ||
|
|
6cba025679 | ||
|
|
d25b93c972 | ||
|
|
b14861703c | ||
|
|
32604225ce | ||
|
|
f623b29c38 | ||
|
|
94ae6ee8ec | ||
|
|
5115bf72e1 | ||
|
|
e1a928cd78 | ||
|
|
3977519c43 | ||
|
|
2f87834ac9 | ||
|
|
53335012d8 | ||
|
|
9d6302f7e3 | ||
|
|
20950e2a60 | ||
|
|
0e0e507f8f | ||
|
|
46e14617b6 | ||
|
|
903c73fafb | ||
|
|
42a56df4a5 | ||
|
|
493dc5c032 | ||
|
|
9a73bc2a18 | ||
|
|
55a9acd9f6 | ||
|
|
d060968b7a | ||
|
|
88a7f53130 | ||
|
|
26e5b18a5d | ||
|
|
011ace96f6 | ||
|
|
5c00655d14 | ||
|
|
eb36c262db | ||
|
|
29d1861545 | ||
|
|
3c9b410693 | ||
|
|
4c3b41433b | ||
|
|
1fd13668c0 | ||
|
|
d1ab7261a6 | ||
|
|
0fc65bcb3a | ||
|
|
f1ce8bfd99 | ||
|
|
3f472f1864 | ||
|
|
229d94cae7 | ||
|
|
c28e1bbf93 | ||
|
|
a840029000 | ||
|
|
aad2646cf2 | ||
|
|
ca1f8ad73e | ||
|
|
dea02763a2 | ||
|
|
ea67385a64 | ||
|
|
fa2daa2767 | ||
|
|
fcb906aa85 | ||
|
|
489a617126 | ||
|
|
601e7ce10b | ||
|
|
4a6fc9a945 | ||
|
|
b377af1d24 | ||
|
|
3fc00f8da7 | ||
|
|
6e39fe5f8c | ||
|
|
20c240a123 | ||
|
|
3ea9fc0de0 | ||
|
|
b80b08ef07 | ||
|
|
505af8d101 | ||
|
|
ae35a6d291 | ||
|
|
2b95c07a47 | ||
|
|
27a011e715 | ||
|
|
476831a12f | ||
|
|
9675eff69e | ||
|
|
85a044246e | ||
|
|
5c41fbcf3d | ||
|
|
6baab7a525 | ||
|
|
ab3b5a9077 | ||
|
|
5811c271b2 | ||
|
|
cf5387346d | ||
|
|
8df63c6c5c | ||
|
|
1d17d27c96 | ||
|
|
bdcbae69a5 | ||
|
|
cdbc3437be | ||
|
|
8940b520e0 | ||
|
|
1d62fbd670 | ||
|
|
a0b56d809e | ||
|
|
f1f6d33e26 | ||
|
|
f292edd2ba | ||
|
|
caa9b50b65 | ||
|
|
61b824065b | ||
|
|
9a900b2ca0 | ||
|
|
4c1cbc98a4 | ||
|
|
8660b95756 | ||
|
|
e7ebdc040f | ||
|
|
6c235d3f2a | ||
|
|
997d912f4d | ||
|
|
2508a4e07d | ||
|
|
90b997337c | ||
|
|
0bb3c92335 | ||
|
|
7fd539c57e | ||
|
|
52bd22ab2b | ||
|
|
46e9458e82 | ||
|
|
3f5595e794 | ||
|
|
d22cc7d3f6 | ||
|
|
eb03a3e6c7 | ||
|
|
65cc1f4752 | ||
|
|
99db197a39 | ||
|
|
7e2a5d553c | ||
|
|
f02337b83b | ||
|
|
f66b67b0c9 | ||
|
|
91087b5341 | ||
|
|
c67191d8c2 | ||
|
|
0fac461783 | ||
|
|
ec5bc922e7 | ||
|
|
7194792c3f | ||
|
|
76c8bade7f | ||
|
|
126857fab0 | ||
|
|
9ca57e105e | ||
|
|
2651140095 | ||
|
|
14175bc438 | ||
|
|
956328da86 | ||
|
|
cc46a96a75 | ||
|
|
049090444e | ||
|
|
796c25b7a5 | ||
|
|
9057290188 | ||
|
|
fcc57bb734 | ||
|
|
a98f5e087c | ||
|
|
403d563869 | ||
|
|
88c15104b4 | ||
|
|
6176289b88 | ||
|
|
5cfd44da79 | ||
|
|
2437da33a6 | ||
|
|
49ca0af746 | ||
|
|
9440b89fab | ||
|
|
f020c1162d | ||
|
|
120fb2cea2 | ||
|
|
37130966cf | ||
|
|
795b82c42c | ||
|
|
57ad33d53a | ||
|
|
a6ceee7bc0 | ||
|
|
44bb05fad0 | ||
|
|
a5fee0ee97 | ||
|
|
da99b2d01a | ||
|
|
1433e3297b | ||
|
|
cad7af13af | ||
|
|
39cb8904a3 | ||
|
|
2ed372b3cd | ||
|
|
8bca76b78b | ||
|
|
595e0f28af | ||
|
|
4939fe10aa | ||
|
|
d2962a8e70 | ||
|
|
d2ff1b0506 | ||
|
|
21f3fd85d9 | ||
|
|
0d6e7ca339 | ||
|
|
4f06be0e45 | ||
|
|
6ba845eec5 | ||
|
|
4fa72289ed | ||
|
|
cc5504c0a9 | ||
|
|
32e00b17b1 | ||
|
|
16108f03ac | ||
|
|
e7f990b224 | ||
|
|
c5d824c4ba | ||
|
|
e69d2e587b | ||
|
|
8fe0e4aa73 | ||
|
|
30a23a93a2 | ||
|
|
53157fbb1f |
32
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
32
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
@@ -0,0 +1,32 @@
|
||||
---
|
||||
name: Bug report
|
||||
about: Create a report to help us improve
|
||||
title: ''
|
||||
labels: ''
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Describe the bug**
|
||||
A clear and concise description of what the bug is.
|
||||
|
||||
**To Reproduce**
|
||||
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.
|
||||
|
||||
**Screenshots**
|
||||
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]
|
||||
|
||||
**Additional context**
|
||||
Add any other context about the problem here.
|
||||
20
.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
20
.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
---
|
||||
name: Feature request
|
||||
about: Suggest an idea for this project
|
||||
title: ''
|
||||
labels: ''
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Is your feature request related to a problem? Please describe.**
|
||||
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
|
||||
|
||||
**Describe the solution you'd like**
|
||||
A clear and concise description of what you want to happen.
|
||||
|
||||
**Describe alternatives you've considered**
|
||||
A clear and concise description of any alternative solutions or features you've considered.
|
||||
|
||||
**Additional context**
|
||||
Add any other context or screenshots about the feature request here.
|
||||
15
.github/ISSUE_TEMPLATE/submit-application.md
vendored
Normal file
15
.github/ISSUE_TEMPLATE/submit-application.md
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
---
|
||||
name: Submit application
|
||||
about: Add an app to this project
|
||||
title: ''
|
||||
labels: ''
|
||||
assignees: LinkLeong
|
||||
|
||||
---
|
||||
|
||||
Tested platform
|
||||
e.g. linux/amd64,linux/arm-v7,linux-arm64
|
||||
|
||||
|
||||
|
||||
Please export and upload the configuration file of this application
|
||||
2
.github/workflows/casa.yml
vendored
2
.github/workflows/casa.yml
vendored
@@ -90,7 +90,7 @@ jobs:
|
||||
- name: Build with xgo
|
||||
uses: crazy-max/ghaction-xgo@v1
|
||||
with:
|
||||
xgo_version: latest
|
||||
xgo_version: v0.7.5
|
||||
go_version: ${{ matrix.go_version }}
|
||||
dest: build
|
||||
prefix: casa
|
||||
|
||||
79
.github/workflows/demo.yml
vendored
Normal file
79
.github/workflows/demo.yml
vendored
Normal file
@@ -0,0 +1,79 @@
|
||||
name: Demo Reset
|
||||
|
||||
# Controls when the workflow will run
|
||||
on:
|
||||
schedule:
|
||||
- cron: "0 * * * *"
|
||||
|
||||
# Allows you to run this workflow manually from the Actions tab
|
||||
workflow_dispatch:
|
||||
|
||||
# OLD_INSTANCE_SNAPSHOT_NAME=$(aws lightsail get-instance-snapshots | grep '"name": "CasaOS-Demo-Snapshot-[0-9]' | sed 's/ //g' | sed 's/"//g' | sed 's/,//g' | sed 's/name://g')
|
||||
# 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')
|
||||
# NEW_INSTANCE_NAME=CasaOS-Demo-$(date +%s)
|
||||
|
||||
# A workflow run is made up of one or more jobs that can run sequentially or in parallel
|
||||
jobs:
|
||||
# This workflow contains a single job called "build"
|
||||
reset:
|
||||
# The type of runner that the job will run on
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
# Steps represent a sequence of tasks that will be executed as part of the job
|
||||
steps:
|
||||
# Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- name: Configure AWS credentials from Test account
|
||||
uses: aws-actions/configure-aws-credentials@v1
|
||||
with:
|
||||
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
|
||||
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
|
||||
aws-region: us-west-2
|
||||
|
||||
- name: Get old instance and snapshot name, create new instance name
|
||||
run: |
|
||||
echo "OLD_INSTANCE_SNAPSHOT_NAME=$(aws lightsail get-instance-snapshots | grep '"name": "CasaOS-Demo-Snapshot-[0-9]' | sed 's/ //g' | sed 's/"//g' | sed 's/,//g' | sed 's/name://g')" >> $GITHUB_ENV
|
||||
echo "OLD_INSTANCE_NAME=$(aws lightsail get-instances | grep '"name": "CasaOS-Demo-[0-9]' | 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
|
||||
|
||||
- name: Create instances from snapshot
|
||||
run: |
|
||||
aws lightsail create-instances-from-snapshot \
|
||||
--instance-snapshot-name ${{ env.OLD_INSTANCE_SNAPSHOT_NAME }} \
|
||||
--instance-names ${{ env.NEW_INSTANCE_NAME }} \
|
||||
--availability-zone us-west-2a \
|
||||
--bundle-id large_2_0
|
||||
|
||||
- name: Wait for new instance running
|
||||
run: |
|
||||
TIMEOUT=$(($(date +%s)+600))
|
||||
while [ $TIMEOUT -gt $(date +%s) ]
|
||||
do
|
||||
NEW_INSTANCE_STATE=$(aws lightsail get-instance-state --instance-name ${{ env.NEW_INSTANCE_NAME }} | grep '"name":' | sed 's/ //g' | sed 's/"//g' | sed 's/name://g')
|
||||
if [ $NEW_INSTANCE_STATE == running ]
|
||||
then
|
||||
echo "New instance is running now"
|
||||
sleep 10s
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
- name: Put instance public ports
|
||||
run: |
|
||||
aws lightsail put-instance-public-ports \
|
||||
--port-infos fromPort=0,toPort=65535,protocol=all \
|
||||
--instance-name ${{ env.NEW_INSTANCE_NAME }}
|
||||
|
||||
- name: Attach static ip
|
||||
run: |
|
||||
aws lightsail attach-static-ip \
|
||||
--static-ip-name CasaOS-Demo-IP \
|
||||
--instance-name ${{ env.NEW_INSTANCE_NAME }}
|
||||
|
||||
- name: Delete old instance
|
||||
run: |
|
||||
aws lightsail delete-instance \
|
||||
--instance-name ${{ env.OLD_INSTANCE_NAME }}
|
||||
|
||||
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -33,3 +33,4 @@ gen
|
||||
__debug_bin
|
||||
main
|
||||
CasaOS
|
||||
github.com
|
||||
|
||||
363
CHANGELOG.md
Normal file
363
CHANGELOG.md
Normal file
@@ -0,0 +1,363 @@
|
||||
# Changelog
|
||||
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
### Added
|
||||
|
||||
### Changed
|
||||
|
||||
### Removed
|
||||
|
||||
### Security
|
||||
|
||||
### Fixed
|
||||
|
||||
## [0.3.1.1] - 2022-05-17
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fix the data loss problem when importing local applications
|
||||
|
||||
## [0.3.1] - 2022-05-16
|
||||
|
||||
### Added
|
||||
|
||||
- CasaConnect and file add image thumbnail function
|
||||
- Import of docker applications
|
||||
- List support custom sorting function
|
||||
- CasaConnect gives priority to LAN connections
|
||||
- USB auto-mount switch (Raspberry Pi is off by default)
|
||||
- Application custom installation supports Docker Compose configuration import in YAML format
|
||||
- You will see the new version changelog from the next version
|
||||
- Added live preview for icons in custom installed applications
|
||||
|
||||
### Changed
|
||||
|
||||
- Application data is no longer saved to the database
|
||||
- Optimize app store speed issues
|
||||
- Optimize the way WebUI is filled in
|
||||
- Image preview has been completely upgraded and now supports switching between all images in the same folder, as well as dragging, zooming, rotating and resetting.
|
||||
- Added color levels to the CPU and RAM charts
|
||||
- Optimized the display of the Connect friends list right-click menu
|
||||
- Change the initial display directory to /DATA
|
||||
|
||||
### Removed
|
||||
|
||||
- Historical Application Data
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fixed the problem that some Docker CLI commands failed to import
|
||||
- Fix the problem that the application is not easily recognized in /DATA/AppData directory and docker command line after installation, it will be shown as application name
|
||||
- Fix Pi-hole installation failure
|
||||
- Fixed the issue that the app could not be updated using WatchTower
|
||||
- Fixed the problem that the task status was lost after closing Files when there was an upload task
|
||||
|
||||
## [0.3.0] - 2022-04-08
|
||||
|
||||
### Added
|
||||
|
||||
- Add CasaConnect function, now you can share private files peer-to-peer with your friends.
|
||||
- Add a widget for network traffic monitoring.
|
||||
- 12 new popular apps added to App Center
|
||||
|
||||
### Changed
|
||||
|
||||
- Updated the sidebar of Files.
|
||||
- Updated the initial directory of Files to the Root directory.
|
||||
- Armbian 22.02 armhf/arm64/amd64 platform tests passed [@igorpecovnik ](https://github.com/igorpecovnik)
|
||||
- Elementary OS 6.1 Jólnir amd64 platform tests passed [@alvarosamudio ](https://github.com/alvarosamudio)
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fix an issue in Files where the backspace button would trigger a return to the previous level of the directory when creating a folder.
|
||||
- Fix the display problem of application list in CPU widget.
|
||||
- Fix the problem that the ipv6 of the application cannot be opened
|
||||
|
||||
### Removed
|
||||
|
||||
- Interfaces related to "zerotier"
|
||||
|
||||
## [0.2.10] - 2022-03-10
|
||||
|
||||
### Added
|
||||
|
||||
- Added CasaOS own file manager, now you can browse, upload, download files from the system, even edit code online, preview photos and videos through it. It will appear in the first position of Apps.
|
||||
- Added CPU core count display and memory capacity display.
|
||||
|
||||
### Changed
|
||||
|
||||
- Optimized the rendering performance of the home page.
|
||||
- Optimized the internationalization display of the time widget.
|
||||
- Show the icon of the stopped application as gray.
|
||||
- Unify the animation of the drop-down menu.
|
||||
- Optimize the display of the application drop-down menu.
|
||||
- Replaced the default font to optimize the display.
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fix the problem of failed to create storage space
|
||||
|
||||
## [0.2.9] - 2022-02-18
|
||||
|
||||
### Added
|
||||
|
||||
- Add a simple notification function
|
||||
|
||||
### Changed
|
||||
|
||||
- Custom installation of new parameters(Capabilities,Hostname,Privileged)
|
||||
- Update front-end translation [@SemVer](https://github.com/zarevskaya) [@koboldMaki](https://github.com/koboldMaki) [@sgastol](https://github.com/sgastol) [@delki8](https://github.com/delki8)
|
||||
|
||||
- Modify the default location and name of the usb mount
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fix the problem of being indexed by search engines
|
||||
- Fix some style display issues
|
||||
- Solve hard drive can't be formatted, can't finish adding storage
|
||||
|
||||
## [0.2.8] - 2022-01-30
|
||||
|
||||
### Added
|
||||
|
||||
- Add USB disk device display
|
||||
|
||||
### Changed
|
||||
|
||||
- Update translation [@baptiste313](https://github.com/baptiste313) [@thueske](https://github.com/thueske)
|
||||
- Compatible with more types of drives
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fix the language initialization bug
|
||||
- Fix the problem that the login page could not be displayed
|
||||
- Fix missing translated content
|
||||
|
||||
## [0.2.7] - 2022.01.26
|
||||
|
||||
### Changed
|
||||
|
||||
- Apply multilingual support
|
||||
|
||||
### Security
|
||||
|
||||
- Fix an injectable execution bug
|
||||
|
||||
## [0.2.6] - 2022.01.26
|
||||
|
||||
### Added
|
||||
|
||||
- Add a bug report panel.
|
||||
- App Store apps start supporting multiple languages
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fix a disk that cannot be formatted under certain circumstances
|
||||
|
||||
## [0.2.5] - 2022.01.24
|
||||
|
||||
### Added
|
||||
|
||||
- Storage Manager
|
||||
|
||||
### Changed
|
||||
|
||||
- Update Disk widget
|
||||
- Update language files [@ImOstrovskiy](https://github.com/ImOstrovskiy) [@baptiste313](https://github.com/baptiste313)
|
||||
|
||||
### Fixed
|
||||
|
||||
- File synchronization issues
|
||||
- Fix the app store classification problem
|
||||
|
||||
## [0.2.4] - 2021.12.30
|
||||
|
||||
### Changed
|
||||
|
||||
- Brand new App Store
|
||||
- Optimize request method
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fix Sync panel width display error.
|
||||
- Fix App panel width display error.
|
||||
|
||||
## [0.2.3] - 2021.12.11
|
||||
|
||||
### Added
|
||||
|
||||
- Add detailed CPU and memory statistics.
|
||||
- Add the multi-language function and add Chinese translation.
|
||||
- Add the function to modify the search engine.
|
||||
- Add the function of modifying the WebUI port
|
||||
|
||||
### Changed
|
||||
|
||||
- Update update script
|
||||
- Preprocessing usb automounting
|
||||
|
||||
### Fixed
|
||||
|
||||
- Volume path problem when customizing the installation of applications
|
||||
- Fix Cpu and Ram usage display error
|
||||
- Fix translation errors
|
||||
- Fixed an error when importing and exporting appfile.
|
||||
|
||||
## [0.2.2] - 2021.12.02
|
||||
|
||||
### Changed
|
||||
|
||||
- UI adjustment
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fix the problem of data display error when manually installing apps
|
||||
- Fix some spelling problems
|
||||
- Fix the bug of synchronization module
|
||||
|
||||
## [0.2.1] - 2021.11.25
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fix Sync display error
|
||||
- Fix Sync Downoad url error
|
||||
- Fix Smart Block display error
|
||||
- Fix widgets settings dispaly error
|
||||
- Fix application installation path error
|
||||
|
||||
## [0.2.0] - 2021.11.25
|
||||
|
||||
### Added
|
||||
|
||||
- Add sync function
|
||||
|
||||
|
||||
## [0.1.11] - 2021.11.10
|
||||
|
||||
### Changed
|
||||
|
||||
- Adaptation of cell phone terminals
|
||||
- Optimize user experience
|
||||
- Replaced the default background
|
||||
- Optimized the display performance and fixed some bugs
|
||||
|
||||
### Fixed
|
||||
|
||||
- Resolve application installation path errors
|
||||
|
||||
## [0.1.10] - 2021.11.04
|
||||
|
||||
### Added
|
||||
|
||||
- Add application terminal
|
||||
- Add application logs
|
||||
- Add system logs
|
||||
- Add App Store for installation
|
||||
|
||||
## [0.1.9] - 2021.11.01 [YANKED]
|
||||
|
||||
## [0.1.8] - 2021.10.27
|
||||
|
||||
### Added
|
||||
|
||||
- Add system terminal
|
||||
- Add the ability to modify the user name and password
|
||||
|
||||
### Changed
|
||||
|
||||
- Experience optimization
|
||||
- Improve single user management function
|
||||
- Fixed Disk widget display error
|
||||
- Fixed Username display error after change
|
||||
- Adaptation for mobile access
|
||||
|
||||
## [0.1.7] - 2021.10.22
|
||||
|
||||
### Added
|
||||
|
||||
- Add user authentication module, Login page and initialization page.
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fix the problem that the application could not start after the system restarted.
|
||||
- Home storage space data display exception
|
||||
- Script override causes application loss after installation
|
||||
- Fix docker network error
|
||||
|
||||
## [0.1.6] - 2021.10.19
|
||||
|
||||
### Added
|
||||
|
||||
- Add app icon auto-fill via docker image name.
|
||||
- Add a file selector for app install.
|
||||
|
||||
### Changed
|
||||
|
||||
- Modify import reminder.
|
||||
- Optimize the application installation process
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fixed an issue with the app were it would disappear when the app was modified.
|
||||
- Fixed device selector default dir to /dev
|
||||
|
||||
## [0.1.5] - 2021.10.15
|
||||
|
||||
### Added
|
||||
|
||||
- Add CPU RAM Status with widget
|
||||
- Add Disk Info with widget
|
||||
- Realize automatic loading of widgets
|
||||
|
||||
### Changed
|
||||
|
||||
- Enhance the Docker cli import experience and automatically fill in the folders that need to be mounted
|
||||
|
||||
### Removed
|
||||
|
||||
- Remove Weather widget.
|
||||
|
||||
### Fixed
|
||||
|
||||
- AppFile upload does not pass verification
|
||||
- The setting menu of the app is displayed abnormally when the browser window is too narrow
|
||||
- The port is occupied and the program cannot start
|
||||
- Fix display bugs when windows size less than 1024px
|
||||
|
||||
## [0.1.4] - 2021.09.30
|
||||
|
||||
### Added
|
||||
|
||||
- Import and export of application configuration files
|
||||
- Automatic parsing of docker commands
|
||||
|
||||
### Changed
|
||||
|
||||
- Improve the program release process
|
||||
- Application installation process UX/UI optimization
|
||||
|
||||
### Fixed
|
||||
|
||||
- Authentication failure during the operation, resulting in the need to re-login
|
||||
|
||||
## [0.1.3] - 2021.09.29 [YANKED]
|
||||
|
||||
## [0.1.2] - 2021.09.28
|
||||
|
||||
### Fixed
|
||||
|
||||
- Application modification and new creation failure issues
|
||||
|
||||
## [0.1.1] - 2021.09.27
|
||||
|
||||
## [0.1.0] - 2021.09.26
|
||||
|
||||
### Added
|
||||
|
||||
- Application Center
|
||||
201
LICENSE
Normal file
201
LICENSE
Normal file
@@ -0,0 +1,201 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
89
README.md
89
README.md
@@ -1,4 +1,4 @@
|
||||
# CasaOS - A simple, easy-to-use, elegant open-source home server system.
|
||||
# CasaOS - A simple, easy-to-use, elegant open-source Home Cloud system.
|
||||
|
||||

|
||||
|
||||
@@ -6,18 +6,58 @@
|
||||
[](https://github.com/IceWhaleTech/CasaOS/pulls)
|
||||
[](https://github.com/IceWhaleTech/CasaOS/issues)
|
||||
[](https://github.com/IceWhaleTech/CasaOS/stargazers)
|
||||
[](https://discord.gg/Gx4BCEtHjx)
|
||||
[](https://discord.gg/knqAbbBbeX)
|
||||
|
||||
CasaOS is an open-source home server system based on the Docker ecosystem and designed for home scenarios. It is committed to building the world's most simple, easy-to-use, and elegant home server system.
|
||||
CasaOS is an open-source Home Cloud system based on the Docker ecosystem and designed for home scenarios. It is committed to building the world's most simple, easy-to-use, and elegant Home Cloud system.
|
||||
|
||||
IceWhale team believes that through community-driven collaborative innovation and open communication with global developers, we can reshape the digital home experience like never before.
|
||||
|
||||

|
||||

|
||||
|
||||
## Getting Started
|
||||
|
||||
> ⚠️ Note:
|
||||
>
|
||||
> CasaOS is still in the early development stage and may vary significantly with the final release. Feel free to test run and share your feedback in the [Discord server](https://discord.gg/knqAbbBbeX)!
|
||||
|
||||
### Quick Setup CasaOS
|
||||
|
||||
Fresh install a system from the list below and run the this command:
|
||||
|
||||
```sh
|
||||
wget -qO- https://get.icewhale.io/casaos.sh | bash
|
||||
```
|
||||
|
||||
or
|
||||
|
||||
```sh
|
||||
curl -fsSL https://get.icewhale.io/casaos.sh | bash
|
||||
```
|
||||
|
||||
### Uninstall CasaOS
|
||||
|
||||
```sh
|
||||
curl -fsSL https://get.icewhale.io/casaos-uninstall.sh | bash
|
||||
```
|
||||
|
||||
### System Compatibility
|
||||
|
||||
- Ubuntu Server 20.04 amd64 (✅ Recommend, Tested)
|
||||
- Armbian 22.02 armhf/arm64/amd64 (✅ Recommend, Tested)
|
||||
- Elementary OS 6.1 Jólnir amd64 (✅ Recommend, Tested)
|
||||
- Deepin 20.4 amd64 (⚠️ Not Fully Tested Yet)
|
||||
- Raspberry Pi Lite OS aarch64/arm64 (⚠️ Not Fully Tested Yet)
|
||||
- Debian 11 amd64 (⚠️ Not Fully Tested Yet)
|
||||
- OpenWrt 21.02 amd64 (⚠️ Not Fully Tested Yet)
|
||||
- OpenWrt 21.02 aarch64/arm64 (⚠️ Not Fully Tested Yet)
|
||||
|
||||
|
||||
## Key Features
|
||||
|
||||
- UI designed for home scenarios - simple, elegant, and easy-to-use
|
||||
- Quick Docker app installation with only three steps, plus automatic management
|
||||
- App Store for private cloud 🚧
|
||||
- App Store for Home Cloud 🚧
|
||||
- Home data/digital asset management 🚧
|
||||
- Smart home manager 🚧
|
||||
|
||||
@@ -34,48 +74,11 @@ After looking at many systems and software on the market, the team found no serv
|
||||
|
||||
So, we set out to build this open source project to develop CasaOS with our own hands, everyone in the community, and you.
|
||||
|
||||
> A warm welcome for you to share and discuss your great ideas in the [Discord server](https://discord.gg/Gx4BCEtHjx)!
|
||||
> A warm welcome for you to share and discuss your great ideas in the [Discord server](https://discord.gg/knqAbbBbeX)!
|
||||
|
||||
[](https://discord.gg/Gx4BCEtHjx)
|
||||
[](https://discord.gg/knqAbbBbeX)
|
||||
|
||||
|
||||
## Getting Started
|
||||
|
||||
> ⚠️ Note:
|
||||
>
|
||||
> CasaOS is still in the early development stage and may vary significantly with the final release. Feel free to test run and share your feedback in the [Discord server](https://discord.gg/Gx4BCEtHjx)!
|
||||
|
||||
### System Compatibility
|
||||
|
||||
- Ubuntu Server 20.04 amd64 (✅ Recommend, Tested)
|
||||
- Debian 11 amd64 (⚠️ Not Fully Tested Yet)
|
||||
- OpenWrt 21.02 amd64 (⚠️ Not Fully Tested Yet)
|
||||
- Raspberry Pi OS aarch64/arm64 (🚧 Under Planning)
|
||||
- OpenWrt 21.02 aarch64/arm64 (🚧 Under Planning)
|
||||
|
||||
### Quick Setup CasaOS
|
||||
|
||||
Fresh install a system from the above list and run the below command:
|
||||
|
||||
```sh
|
||||
curl -fsSL https://get.icewhale.io/casaos.sh | bash
|
||||
```
|
||||
|
||||
|
||||
## To Do
|
||||
|
||||
**v 0.1.x**
|
||||
|
||||
- [x] An elegant UI for home scenarios
|
||||
- [x] Custom installation of Docker Apps
|
||||
- [x] Update, stop, uninstall, restart, etc. of Docker apps
|
||||
- [x] Docker CLI parser
|
||||
- [x] System Update
|
||||
- [ ] Getting Started tutorial
|
||||
- [ ] Docker Compose parser
|
||||
- [ ] App config file import and export
|
||||
- [ ] macvlan network mode
|
||||
|
||||
|
||||
## Maintainers
|
||||
- Jerry Liu
|
||||
|
||||
2
UI
2
UI
Submodule UI updated: 574be529e2...70d9529d06
@@ -9,34 +9,34 @@ DateTimeFormat = 2006-01-02 15:04:05
|
||||
TimeFormat = 15:04:05
|
||||
DateFormat = 2006-01-02
|
||||
ProjectPath = /casaOS/server
|
||||
RootPath = /casaOS
|
||||
|
||||
|
||||
[server]
|
||||
HttpPort = 8089
|
||||
UDPPort =
|
||||
RunMode = release
|
||||
ServerApi = https://api.casaos.zimaboard.com
|
||||
ServerApi = https://api.casaos.io/casaos-api
|
||||
Handshake = socket.casaos.io
|
||||
Token =
|
||||
USBAutoMount =
|
||||
|
||||
[user]
|
||||
UserName = admin
|
||||
PWD = zimaboard
|
||||
UserName =
|
||||
PWD =
|
||||
Email = user@gmail.com
|
||||
Description = description
|
||||
Initialized = false
|
||||
Token = eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6ImVyZXJlIiwicGFzc3dvcmQiOiJhZHNmZGYiLCJleHAiOjE2MjQwMDU0ODEsImlzcyI6Imdpbi1ibG9nIn0.JNsCccZuFCwlSMLJg62iOIB2xymk_k7xGa11xhZ07bc
|
||||
|
||||
[zerotier]
|
||||
UserName = user
|
||||
PWD = pwd
|
||||
Token = yBKYyavr2RdFAIVN7iTpzlsB1o6CqTgm
|
||||
|
||||
[redis]
|
||||
Host = 127.0.0.1:6379
|
||||
Password =
|
||||
MaxIdle = 30
|
||||
MaxActive = 30
|
||||
IdleTimeout = 200
|
||||
Avatar =
|
||||
NickName =
|
||||
PublicKey =
|
||||
|
||||
[system]
|
||||
ConfigStr =
|
||||
WidgetList =
|
||||
Analyse =
|
||||
|
||||
|
||||
[file]
|
||||
ShareDir =
|
||||
DownloadDir =
|
||||
21
go.mod
21
go.mod
@@ -3,19 +3,22 @@ module github.com/IceWhaleTech/CasaOS
|
||||
go 1.16
|
||||
|
||||
require (
|
||||
github.com/Curtis-Milo/nat-type-identifier-go v0.0.0-20220215191915-18d42168c63d
|
||||
github.com/Microsoft/go-winio v0.5.0 // indirect
|
||||
github.com/Microsoft/hcsshim v0.8.22 // indirect
|
||||
github.com/PuerkitoBio/goquery v1.7.0
|
||||
github.com/StackExchange/wmi v0.0.0-20210224194228-fe8f1750fd46 // indirect
|
||||
github.com/bits-and-blooms/bitset v1.2.1 // indirect
|
||||
github.com/containerd/containerd v1.5.7
|
||||
github.com/containerd/continuity v0.2.0 // indirect
|
||||
github.com/disintegration/imaging v1.6.2
|
||||
github.com/docker/distribution v2.8.0+incompatible // indirect
|
||||
github.com/docker/docker v20.10.7+incompatible
|
||||
github.com/docker/go-connections v0.4.0
|
||||
github.com/dsoprea/go-exif/v3 v3.0.0-20210625224831-a6301f85c82b
|
||||
github.com/dsoprea/go-logging v0.0.0-20200710184922-b02d349568dd // indirect
|
||||
github.com/forease/gotld v0.0.0-20190808124948-c50ff635576b
|
||||
github.com/gin-contrib/gzip v0.0.2 // indirect
|
||||
github.com/gin-contrib/gzip v0.0.2
|
||||
github.com/gin-gonic/gin v1.7.2
|
||||
github.com/gliderlabs/ssh v0.3.3
|
||||
github.com/go-ini/ini v1.62.0
|
||||
github.com/go-ole/go-ole v1.2.5 // indirect
|
||||
github.com/go-openapi/spec v0.20.4 // indirect
|
||||
@@ -32,11 +35,15 @@ require (
|
||||
github.com/json-iterator/go v1.1.11 // indirect
|
||||
github.com/klauspost/compress v1.13.6 // indirect
|
||||
github.com/leodido/go-urn v1.2.1 // indirect
|
||||
github.com/lucas-clemente/quic-go v0.25.0
|
||||
github.com/mailru/easyjson v0.7.7 // indirect
|
||||
github.com/mattn/go-isatty v0.0.14 // indirect
|
||||
github.com/mattn/go-sqlite3 v1.14.11 // indirect
|
||||
github.com/moby/term v0.0.0-20210619224110-3f7ff695adc6 // indirect
|
||||
github.com/morikuni/aec v1.0.0 // indirect
|
||||
github.com/opencontainers/image-spec v1.0.2 // indirect
|
||||
github.com/opencontainers/selinux v1.8.5 // indirect
|
||||
github.com/patrickmn/go-cache v2.1.0+incompatible
|
||||
github.com/pkg/errors v0.9.1
|
||||
github.com/prestonTao/upnp v0.0.0-20150206124352-f4370df5e109
|
||||
github.com/prometheus/procfs v0.7.3 // indirect
|
||||
@@ -46,10 +53,10 @@ require (
|
||||
github.com/sirupsen/logrus v1.8.1
|
||||
github.com/smartystreets/assertions v1.2.0 // indirect
|
||||
github.com/smartystreets/goconvey v1.6.4 // indirect
|
||||
github.com/spf13/afero v1.2.2
|
||||
github.com/swaggo/gin-swagger v1.3.0
|
||||
github.com/swaggo/swag v1.7.3
|
||||
github.com/tidwall/gjson v1.8.0
|
||||
github.com/tidwall/pretty v1.2.0 // indirect
|
||||
github.com/tidwall/gjson v1.10.2
|
||||
github.com/tklauser/go-sysconf v0.3.6 // indirect
|
||||
github.com/ugorji/go v1.2.6 // indirect
|
||||
go.opencensus.io v0.23.0 // indirect
|
||||
@@ -67,6 +74,6 @@ require (
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
|
||||
gopkg.in/ini.v1 v1.62.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect
|
||||
gorm.io/driver/sqlite v1.1.5
|
||||
gorm.io/gorm v1.21.15
|
||||
gorm.io/driver/sqlite v1.2.6
|
||||
gorm.io/gorm v1.22.5
|
||||
)
|
||||
|
||||
200
go.sum
200
go.sum
@@ -1,7 +1,9 @@
|
||||
bazil.org/fuse v0.0.0-20160811212531-371fbbdaa898/go.mod h1:Xbm+BRKSBEpa4q4hTSxohYNQpsxXPbPry4JJWOB3LB8=
|
||||
bazil.org/fuse v0.0.0-20200407214033-5883e5a4b512/go.mod h1:FbcW6z/2VytnFDhZfumh8Ss8zxHE6qpMP5sHTRe0EaM=
|
||||
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
cloud.google.com/go v0.31.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
cloud.google.com/go v0.37.0/go.mod h1:TS1dMSSfndXH133OKGwekG838Om/cQT0BUHV3HcBgoo=
|
||||
cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
|
||||
cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU=
|
||||
cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
|
||||
@@ -32,7 +34,12 @@ cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0Zeo
|
||||
cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk=
|
||||
cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs=
|
||||
cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=
|
||||
dmitri.shuralyov.com/app/changes v0.0.0-20180602232624-0a106ad413e3/go.mod h1:Yl+fi1br7+Rr3LqpNJf1/uxUdtRUV+Tnj0o93V2B9MU=
|
||||
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
|
||||
dmitri.shuralyov.com/html/belt v0.0.0-20180602232347-f7d459c86be0/go.mod h1:JLBrvjyP0v+ecvNYvCpyZgu5/xkfAUhi6wJj28eUfSU=
|
||||
dmitri.shuralyov.com/service/change v0.0.0-20181023043359-a85b471d5412/go.mod h1:a1inKt/atXimZ4Mv927x+r7UpyzRUf4emIoiiSC2TN4=
|
||||
dmitri.shuralyov.com/state v0.0.0-20180228185332-28bcc343414c/go.mod h1:0PRwlb0D6DFvNNtx+9ybjezNCa8XF0xaYcETyp6rHWU=
|
||||
git.apache.org/thrift.git v0.0.0-20180902110319-2566ecd5d999/go.mod h1:fPE2ZNJGynbRyZ4dJvy6G277gSllfV2HJqblrnkyeyg=
|
||||
github.com/Azure/azure-sdk-for-go v16.2.1+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc=
|
||||
github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8=
|
||||
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8=
|
||||
@@ -49,6 +56,8 @@ github.com/Azure/go-autorest/logger v0.2.0/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZ
|
||||
github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
||||
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/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc=
|
||||
github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6XgeJcm8brE=
|
||||
github.com/Microsoft/go-winio v0.4.11/go.mod h1:VhR8bwka0BXejwEJY73c50VrPtXAaKcyvVC4A4RozmA=
|
||||
@@ -75,8 +84,6 @@ github.com/Microsoft/hcsshim/test v0.0.0-20201218223536-d3e5debf77da/go.mod h1:5
|
||||
github.com/Microsoft/hcsshim/test v0.0.0-20210227013316-43a75bb4edd3/go.mod h1:mw7qgWloBUl75W/gVH3cQszUg1+gUITj7D6NY7ywVnY=
|
||||
github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ=
|
||||
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
|
||||
github.com/PuerkitoBio/goquery v1.7.0 h1:O5SP3b9JWqMSVMG69zMfj577zwkSNpxrFf7ybS74eiw=
|
||||
github.com/PuerkitoBio/goquery v1.7.0/go.mod h1:GsLWisAFVj4WgDibEWF4pvYnkVQBpKBKeU+7zCJoLcc=
|
||||
github.com/PuerkitoBio/purell v1.1.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
|
||||
github.com/PuerkitoBio/purell v1.1.1 h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tNFfI=
|
||||
github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
|
||||
@@ -92,10 +99,7 @@ github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuy
|
||||
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||
github.com/alexflint/go-filemutex v0.0.0-20171022225611-72bdc8eae2ae/go.mod h1:CgnQgUtFrFz9mxFNtED3jI5tLDjKlOM+oUF/sTk6ps0=
|
||||
github.com/andybalholm/cascadia v1.1.0 h1:BuuO6sSfQNFRu1LppgbD25Hr2vLYW25JvxHs5zzsLTo=
|
||||
github.com/andybalholm/cascadia v1.1.0/go.mod h1:GsXiBklL0woXo1j/WYWtSYYC4ouU9PqHO0sqidkEA4Y=
|
||||
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be h1:9AeTilPcZAjCFIImctFaOjnTIavg87rW78vTPkQqLI8=
|
||||
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be/go.mod h1:ySMOLuWl6zY27l47sB3qLNK6tF2fkHG55UZxx8oIVo4=
|
||||
github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c=
|
||||
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
|
||||
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
|
||||
github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY=
|
||||
@@ -112,8 +116,10 @@ github.com/bits-and-blooms/bitset v1.2.1/go.mod h1:gIdJ4wp64HaoK2YrL1Q5/N7Y16edY
|
||||
github.com/blang/semver v3.1.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk=
|
||||
github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk=
|
||||
github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4=
|
||||
github.com/bradfitz/go-smtpd v0.0.0-20170404230938-deb6d6237625/go.mod h1:HYsPBTaaSFSlLx/70C2HPIMNZpVV8+vt/A+FMnYP11g=
|
||||
github.com/bshuster-repo/logrus-logstash-hook v0.4.1/go.mod h1:zsTqEiSzDgAa/8GZR7E1qaXrhYNDKBYy5/dWPTIflbk=
|
||||
github.com/buger/jsonparser v0.0.0-20180808090653-f4dd9f5a6b44/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s=
|
||||
github.com/buger/jsonparser v0.0.0-20181115193947-bf1c66bbce23/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s=
|
||||
github.com/bugsnag/bugsnag-go v0.0.0-20141110184014-b1d153021fcd/go.mod h1:2oa8nejYd4cQ/b0hMIopN0lCRxU0bueqREvZLWFrtK8=
|
||||
github.com/bugsnag/osext v0.0.0-20130617224835-0dd3f918b21b/go.mod h1:obH5gd0BsqsP2LwDJ9aOkm/6J86V6lyAXCoQWGw3K50=
|
||||
github.com/bugsnag/panicwrap v0.0.0-20151223152923-e2c28503fcd0/go.mod h1:D/8v3kj0zr8ZAKg1AQ6crr+5VwKN5eIywRkfhyM/+dE=
|
||||
@@ -122,6 +128,8 @@ github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghf
|
||||
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/checkpoint-restore/go-criu/v4 v4.1.0/go.mod h1:xUQBLp4RLc5zJtWY++yjOoMoB5lihDt7fai+75m+rGw=
|
||||
github.com/checkpoint-restore/go-criu/v5 v5.0.0/go.mod h1:cfwC0EG7HMUenopBsUf9d89JlCLQIfgVcNsNN0t6T2M=
|
||||
github.com/cheekybits/genny v1.0.0 h1:uGGa4nei+j20rOSeDeP5Of12XVm7TGUd4dJA9RDitfE=
|
||||
github.com/cheekybits/genny v1.0.0/go.mod h1:+tQajlRqAUrPI7DOSpB0XAqZYtQakVtB7wXkRAgjxjQ=
|
||||
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
|
||||
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
|
||||
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
|
||||
@@ -235,6 +243,7 @@ github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3Ee
|
||||
github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
|
||||
github.com/coreos/go-systemd v0.0.0-20161114122254-48702e0da86b/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
||||
github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
||||
github.com/coreos/go-systemd v0.0.0-20181012123002-c6f51f82210d/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
||||
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
||||
github.com/coreos/go-systemd/v22 v22.0.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+1atmu1JpKERPPk=
|
||||
github.com/coreos/go-systemd/v22 v22.1.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+1atmu1JpKERPPk=
|
||||
@@ -258,11 +267,14 @@ github.com/denverdino/aliyungo v0.0.0-20190125010748-a747050bb1ba/go.mod h1:dV8l
|
||||
github.com/dgrijalva/jwt-go v0.0.0-20170104182250-a601269ab70c/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
|
||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
|
||||
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
|
||||
github.com/disintegration/imaging v1.6.2 h1:w1LecBlG2Lnp8B3jk5zSuNqd7b4DXhcjwek1ei82L+c=
|
||||
github.com/disintegration/imaging v1.6.2/go.mod h1:44/5580QXChDfwIclfc/PCwrr44amcmDAg8hxG0Ewe4=
|
||||
github.com/dnaeon/go-vcr v1.0.1/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E=
|
||||
github.com/docker/distribution v0.0.0-20190905152932-14b96e55d84c/go.mod h1:0+TTO4EOBfRPhZXAeF1Vu+W3hHZ8eLp8PgKVZlcvtFY=
|
||||
github.com/docker/distribution v2.7.1-0.20190205005809-0d3efadf0154+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
|
||||
github.com/docker/distribution v2.7.1+incompatible h1:a5mlkVzth6W5A4fOsS3D2EO5BUmsJpcB+cRlLU7cSug=
|
||||
github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
|
||||
github.com/docker/distribution v2.8.0+incompatible h1:l9EaZDICImO1ngI+uTifW+ZYvvz7fKISBAKpg+MbWbY=
|
||||
github.com/docker/distribution v2.8.0+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
|
||||
github.com/docker/docker v20.10.7+incompatible h1:Z6O9Nhsjv+ayUEeI1IojKbYcsGdgYSNqxe1s2MYzUhQ=
|
||||
github.com/docker/docker v20.10.7+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
||||
github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ=
|
||||
@@ -277,6 +289,18 @@ github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDD
|
||||
github.com/docker/libtrust v0.0.0-20150114040149-fa567046d9b1/go.mod h1:cyGadeNEkKy96OOhEzfZl+yxihPEzKnqJwvfuSUqbZE=
|
||||
github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM=
|
||||
github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE=
|
||||
github.com/dsoprea/go-exif/v2 v2.0.0-20200321225314-640175a69fe4/go.mod h1:Lm2lMM2zx8p4a34ZemkaUV95AnMl4ZvLbCUbwOvLC2E=
|
||||
github.com/dsoprea/go-exif/v3 v3.0.0-20200717053412-08f1b6708903/go.mod h1:0nsO1ce0mh5czxGeLo4+OCZ/C6Eo6ZlMWsz7rH/Gxv8=
|
||||
github.com/dsoprea/go-exif/v3 v3.0.0-20210625224831-a6301f85c82b h1:NgNuLvW/gAFKU30ULWW0gtkCt56JfB7FrZ2zyo0wT8I=
|
||||
github.com/dsoprea/go-exif/v3 v3.0.0-20210625224831-a6301f85c82b/go.mod h1:cg5SNYKHMmzxsr9X6ZeLh/nfBRHHp5PngtEPcujONtk=
|
||||
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=
|
||||
github.com/dsoprea/go-logging v0.0.0-20200710184922-b02d349568dd/go.mod h1:7I+3Pe2o/YSU88W0hWlm9S22W7XI1JFNJ86U0zPKMf8=
|
||||
github.com/dsoprea/go-utility v0.0.0-20200711062821-fab8125e9bdf h1:/w4QxepU4AHh3AuO6/g8y/YIIHH5+aKP3Bj8sg5cqhU=
|
||||
github.com/dsoprea/go-utility v0.0.0-20200711062821-fab8125e9bdf/go.mod h1:95+K3z2L0mqsVYd6yveIv1lmtT3tcQQ3dVakPySffW8=
|
||||
github.com/dsoprea/go-utility/v2 v2.0.0-20200717064901-2fccff4aa15e h1:IxIbA7VbCNrwumIYjDoMOdf4KOSkMC6NJE4s8oRbE7E=
|
||||
github.com/dsoprea/go-utility/v2 v2.0.0-20200717064901-2fccff4aa15e/go.mod h1:uAzdkPTub5Y9yQwXe8W4m2XuP0tK4a9Q/dantD0+uaU=
|
||||
github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
|
||||
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
|
||||
github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc=
|
||||
@@ -291,11 +315,14 @@ github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.
|
||||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||
github.com/evanphx/json-patch v4.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
|
||||
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
|
||||
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc=
|
||||
github.com/forease/gotld v0.0.0-20190808124948-c50ff635576b h1:r13MvtFTtnvxtuKK7z0ZSQ2EfMmTzWDHwfDvGCoqUQE=
|
||||
github.com/forease/gotld v0.0.0-20190808124948-c50ff635576b/go.mod h1:EfR6AU78zUiZ36oVS5YrmTzc2um3zDXWPx4L4st++jo=
|
||||
github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k=
|
||||
github.com/francoispqt/gojay v1.2.13/go.mod h1:ehT5mTG4ua4581f1++1WLG0vPdaA9HaiDsoyrBGkyDY=
|
||||
github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k=
|
||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||
github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
|
||||
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
|
||||
github.com/fullsailor/pkcs7 v0.0.0-20190404230743-d7302db945fa/go.mod h1:KnogPXtdwXqoenmZCw6S+25EAm2MkxbG0deNDu4cbSA=
|
||||
github.com/garyburd/redigo v0.0.0-20150301180006-535138d7bcd7/go.mod h1:NR3MbYisc3/PwhQ00EMzDiPmrwpPxAn5GI05/YaO1SY=
|
||||
@@ -313,8 +340,11 @@ github.com/gin-gonic/gin v1.4.0/go.mod h1:OW2EZn3DO8Ln9oIKOvM++LBO+5UPHJJDH72/q/
|
||||
github.com/gin-gonic/gin v1.6.3/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M=
|
||||
github.com/gin-gonic/gin v1.7.2 h1:Tg03T9yM2xa8j6I3Z3oqLaQRSmKvxPd6g/2HJ6zICFA=
|
||||
github.com/gin-gonic/gin v1.7.2/go.mod h1:jD2toBW3GZUr5UMcdrwQA10I7RuaFOl/SGeDjXkfUtY=
|
||||
github.com/gliderlabs/ssh v0.3.3 h1:mBQ8NiOgDkINJrZtoizkC3nDNYgSaWtxyem6S2XHBtA=
|
||||
github.com/gliderlabs/ssh v0.3.3/go.mod h1:ZSS+CUoKHDrqVakTfTWUlKSr9MtMFkC4UvtQKD7O914=
|
||||
github.com/gliderlabs/ssh v0.1.1/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0=
|
||||
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 h1:ljK/pL5ltg3qoN+OtN6yCv9HWSfMwxSx90GJCZQxYNg=
|
||||
github.com/go-errors/errors v1.1.1/go.mod h1:psDX2osz5VnTOnFWbDeWwS7yejl+uV3FEWEp4lssFEs=
|
||||
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
|
||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
||||
@@ -364,6 +394,8 @@ github.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn
|
||||
github.com/go-playground/validator/v10 v10.6.1 h1:W6TRDXt4WcWp4c4nf/G+6BkGdhiIo0k417gfr+V6u4I=
|
||||
github.com/go-playground/validator/v10 v10.6.1/go.mod h1:xm76BBt941f7yWdGnI2DVPFFg1UK3YY04qifoXU3lOk=
|
||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 h1:p104kn46Q8WdvHunIJ9dAyjPVtrBPhSr3KT2yUst43I=
|
||||
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
|
||||
github.com/godbus/dbus v0.0.0-20151105175453-c7fdd8b5cd55/go.mod h1:/YcGZj5zSblfDWMMoOzV4fas9FZnQYTkDnsGvmh2Grw=
|
||||
github.com/godbus/dbus v0.0.0-20180201030542-885f9cc04c9c/go.mod h1:/YcGZj5zSblfDWMMoOzV4fas9FZnQYTkDnsGvmh2Grw=
|
||||
github.com/godbus/dbus v0.0.0-20190422162347-ade71ed3457e/go.mod h1:bBOAhwG1umN6/6ZUMtDFBMQR8jRg9O75tm9K00oMsK4=
|
||||
@@ -383,6 +415,9 @@ github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
|
||||
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
||||
github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY=
|
||||
github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I=
|
||||
github.com/golang/geo v0.0.0-20190916061304-5b978397cfec/go.mod h1:QZ0nwyI2jOfgRAoBvP+ab5aRr7c9x7lhGEJrKvBwjWI=
|
||||
github.com/golang/geo v0.0.0-20200319012246-673a6f80352d h1:C/hKUcHT483btRbeGkrRjJz+Zbcj8audldIi9tRJDCc=
|
||||
github.com/golang/geo v0.0.0-20200319012246-673a6f80352d/go.mod h1:QZ0nwyI2jOfgRAoBvP+ab5aRr7c9x7lhGEJrKvBwjWI=
|
||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||
github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
@@ -391,6 +426,7 @@ github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4er
|
||||
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE=
|
||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:tluoj9z5200jBnyusfRPU2LqT6J+DAorxEvtC7LHB+E=
|
||||
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
|
||||
@@ -398,6 +434,8 @@ github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt
|
||||
github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
|
||||
github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
|
||||
github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=
|
||||
github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc=
|
||||
github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
@@ -432,6 +470,8 @@ github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
|
||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ=
|
||||
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-github v17.0.0+incompatible h1:N0LgJ1j65A7kfXrZnUDaYCs/Sf4rEjNlfyDHW9dolSY=
|
||||
github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ=
|
||||
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 h1:Xkwi/a1rcvNg1PPYe5vI8GbeBY/jrVuDX5ASuANWTrk=
|
||||
@@ -454,6 +494,8 @@ github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+
|
||||
github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
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/googleapis/gax-go v2.0.0+incompatible/go.mod h1:SFVmujtThgffbyetf+mdk2eWhX2bMyUtNHzFKcPA9HY=
|
||||
github.com/googleapis/gax-go/v2 v2.0.3/go.mod h1:LLvjysVCY1JZeum8Z6l8qUty8fiNwE08qbEPm1M08qg=
|
||||
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
|
||||
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
|
||||
github.com/googleapis/gnostic v0.4.1/go.mod h1:LRhVm6pbyptWbWbuZ38d1eyptfvIytN3ir6b65WBswg=
|
||||
@@ -471,6 +513,7 @@ github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:Fecb
|
||||
github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
|
||||
github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
|
||||
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
|
||||
github.com/grpc-ecosystem/grpc-gateway v1.5.0/go.mod h1:RSKVYQBd5MCa4OVpNdGskqpgL2+G+NZTnrVHpWWfpdw=
|
||||
github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
|
||||
github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
|
||||
github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
|
||||
@@ -490,12 +533,15 @@ github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH
|
||||
github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
|
||||
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
|
||||
github.com/j-keck/arping v0.0.0-20160618110441-2cf9dc699c56/go.mod h1:ymszkNOg6tORTn+6F6j+Jc8TOr5osrynvN6ivFWZ2GA=
|
||||
github.com/jellevandenhooff/dkim v0.0.0-20150330215556-f50fe3d243e1/go.mod h1:E0B/fFc00Y+Rasa88328GlI/XbtyysCtTHZS8h7IrBU=
|
||||
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
|
||||
github.com/jinzhu/copier v0.3.2 h1:QdBOCbaouLDYaIPFfi1bKv5F5tPpeTwXe4sD0jqtz5w=
|
||||
github.com/jinzhu/copier v0.3.2/go.mod h1:24xnZezI2Yqac9J61UC6/dG/k76ttpq0DdJI3QmUvro=
|
||||
github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
|
||||
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
|
||||
github.com/jinzhu/now v1.1.2 h1:eVKgfIdy9b6zbWBMgFpfDPoAMifwSZagU9HmEU6zgiI=
|
||||
github.com/jinzhu/now v1.1.2/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
|
||||
github.com/jinzhu/now v1.1.4 h1:tHnRBy1i5F2Dh8BAFxqFzxKqqvezXrL2OW1TnX+Mlas=
|
||||
github.com/jinzhu/now v1.1.4/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
|
||||
github.com/jmespath/go-jmespath v0.0.0-20160202185014-0b12d6b521d8/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
|
||||
github.com/jmespath/go-jmespath v0.0.0-20160803190731-bd40a432e4c7/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
|
||||
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
|
||||
@@ -530,6 +576,7 @@ github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfn
|
||||
github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI=
|
||||
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/pty v1.1.3/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA=
|
||||
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=
|
||||
@@ -537,8 +584,12 @@ github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII=
|
||||
github.com/leodido/go-urn v1.2.1 h1:BqpAaACuzVSgi/VLzGZIobT2z4v53pjosyNd9Yv6n/w=
|
||||
github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY=
|
||||
github.com/lucas-clemente/quic-go v0.25.0 h1:K+X9Gvd7JXsOHtU0N2icZ2Nw3rx82uBej3mP4CLgibc=
|
||||
github.com/lucas-clemente/quic-go v0.25.0/go.mod h1:YtzP8bxRVCBlO77yRanE264+fY/T2U9ZlW1AaHOsMOg=
|
||||
github.com/lunixbochs/vtclean v1.0.0/go.mod h1:pHhQNgMf3btfWnGBVipUOjRYhoOsdGqdm/+2c2E2WMI=
|
||||
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
||||
github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
||||
github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
||||
github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
||||
github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
||||
github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs=
|
||||
@@ -546,6 +597,14 @@ github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJ
|
||||
github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
|
||||
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
|
||||
github.com/marstr/guid v1.1.0/go.mod h1:74gB1z2wpxxInTG6yaqA7KrtM0NZ+RbrcqDvYHefzho=
|
||||
github.com/marten-seemann/qpack v0.2.1/go.mod h1:F7Gl5L1jIgN1D11ucXefiuJS9UMVP2opoCp2jDKb7wc=
|
||||
github.com/marten-seemann/qtls-go1-15 v0.1.4/go.mod h1:GyFwywLKkRt+6mfU99csTEY1joMZz5vmB1WNZH3P81I=
|
||||
github.com/marten-seemann/qtls-go1-16 v0.1.4 h1:xbHbOGGhrenVtII6Co8akhLEdrawwB2iHl5yhJRpnco=
|
||||
github.com/marten-seemann/qtls-go1-16 v0.1.4/go.mod h1:gNpI2Ol+lRS3WwSOtIUUtRwZEQMXjYK+dQSBFbethAk=
|
||||
github.com/marten-seemann/qtls-go1-17 v0.1.0 h1:P9ggrs5xtwiqXv/FHNwntmuLMNq3KaSIG93AtAZ48xk=
|
||||
github.com/marten-seemann/qtls-go1-17 v0.1.0/go.mod h1:fz4HIxByo+LlWcreM4CZOYNuz3taBQ8rN2X6FqvaWo8=
|
||||
github.com/marten-seemann/qtls-go1-18 v0.1.0-beta.1 h1:EnzzN9fPUkUck/1CuY1FlzBaIYMoiBsdwTNmNGkwUUM=
|
||||
github.com/marten-seemann/qtls-go1-18 v0.1.0-beta.1/go.mod h1:PUhIQk19LoFt2174H4+an8TYvWOGjb/hHwphBeaDHwI=
|
||||
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
|
||||
github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
|
||||
github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||
@@ -555,10 +614,12 @@ github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9
|
||||
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
|
||||
github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
|
||||
github.com/mattn/go-shellwords v1.0.3/go.mod h1:3xCvwCdWdlDJUrvuMn7Wuy9eWs4pE8vqg+NOMyg4B2o=
|
||||
github.com/mattn/go-sqlite3 v1.14.8 h1:gDp86IdQsN/xWjIEmr9MF6o9mpksUgh0fu+9ByFxzIU=
|
||||
github.com/mattn/go-sqlite3 v1.14.8/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
|
||||
github.com/mattn/go-sqlite3 v1.14.9/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
|
||||
github.com/mattn/go-sqlite3 v1.14.11 h1:gt+cp9c0XGqe9S/wAHTL3n/7MqY+siPWgWJgqdsFrzQ=
|
||||
github.com/mattn/go-sqlite3 v1.14.11/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4=
|
||||
github.com/microcosm-cc/bluemonday v1.0.1/go.mod h1:hsXNsILzKxV+sX77C5b8FSuKF00vh2OMYv+xgHpAMF4=
|
||||
github.com/miekg/pkcs11 v1.0.3/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs=
|
||||
github.com/mistifyio/go-zfs v2.1.2-0.20190413222219-f784269be439+incompatible/go.mod h1:8AuVvqP/mXw1px98n46wfvcGfQ4ci2FwoAjKYxuo3Z4=
|
||||
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||
@@ -587,8 +648,12 @@ github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8m
|
||||
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
||||
github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw=
|
||||
github.com/ncw/swift v1.0.47/go.mod h1:23YIA4yWVnGwv2dQlN4bB7egfYX6YLn0Yo/S6zZO/ZM=
|
||||
github.com/neelance/astrewrite v0.0.0-20160511093645-99348263ae86/go.mod h1:kHJEU3ofeGjhHklVoIGuVj85JJwZ6kWPaJwCIxgnFmo=
|
||||
github.com/neelance/sourcemap v0.0.0-20151028013722-8c68805598ab/go.mod h1:Qr6/a/Q4r9LP1IltGz7tA7iOK1WonHEYhu1HRBA7ZiM=
|
||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
|
||||
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
|
||||
github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
|
||||
github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
|
||||
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
|
||||
github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo=
|
||||
github.com/onsi/ginkgo v0.0.0-20151202141238-7f8ab55aaf3b/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
@@ -598,11 +663,18 @@ github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+
|
||||
github.com/onsi/ginkgo v1.10.3/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
|
||||
github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY=
|
||||
github.com/onsi/ginkgo v1.16.2/go.mod h1:CObGmKUOKaSC0RjmoAK7tKyn4Azo5P2IWuoMnvwxz1E=
|
||||
github.com/onsi/ginkgo v1.16.4 h1:29JGrr5oVBm5ulCWet69zQkzWipVXIol6ygQUe/EzNc=
|
||||
github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0=
|
||||
github.com/onsi/gomega v0.0.0-20151007035656-2152b45fa28a/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
|
||||
github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
|
||||
github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
||||
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
|
||||
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
|
||||
github.com/onsi/gomega v1.10.3/go.mod h1:V9xEwhxec5O8UDM77eCW8vLymOMltsqPVYWrpDsH8xc=
|
||||
github.com/onsi/gomega v1.13.0 h1:7lLHu94wT9Ij0o6EWWclhu0aOh32VxhkwEJvzuWPeak=
|
||||
github.com/onsi/gomega v1.13.0/go.mod h1:lRk9szgn8TxENtWd0Tp4c3wjlRfMTMH27I+3Je41yGY=
|
||||
github.com/opencontainers/go-digest v0.0.0-20170106003457-a6d0ee40d420/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
|
||||
github.com/opencontainers/go-digest v0.0.0-20180430190053-c9281466c8b2/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
|
||||
github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
|
||||
@@ -610,8 +682,9 @@ github.com/opencontainers/go-digest v1.0.0-rc1.0.20180430190053-c9281466c8b2/go.
|
||||
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
|
||||
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
|
||||
github.com/opencontainers/image-spec v1.0.0/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0=
|
||||
github.com/opencontainers/image-spec v1.0.1 h1:JMemWkRwHx4Zj+fVxWoMCFm/8sYGGrUVojFA6h/TRcI=
|
||||
github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0=
|
||||
github.com/opencontainers/image-spec v1.0.2 h1:9yCKha/T5XdGtO0q9Q9a6T5NUCsTn/DrBg0D7ufOcFM=
|
||||
github.com/opencontainers/image-spec v1.0.2/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0=
|
||||
github.com/opencontainers/runc v0.0.0-20190115041553-12f6a991201f/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U=
|
||||
github.com/opencontainers/runc v0.1.1/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U=
|
||||
github.com/opencontainers/runc v1.0.0-rc8.0.20190926000215-3e425f80a8c9/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U=
|
||||
@@ -632,6 +705,9 @@ github.com/opencontainers/selinux v1.8.0/go.mod h1:RScLhm78qiWa2gbVCcGkC7tCGdgk3
|
||||
github.com/opencontainers/selinux v1.8.2/go.mod h1:MUIHuUEvKB1wtJjQdOyYRgOnLD2xAPP8dBsCoU0KuF8=
|
||||
github.com/opencontainers/selinux v1.8.5 h1:OkT6bMHOQ1JQQO4ihjQ49sj0+wciDcjziSVTRn8VeTA=
|
||||
github.com/opencontainers/selinux v1.8.5/go.mod h1:HTvjPFoGMbpQsG886e3lQwnsRWtE4TC1OF3OUvG9FAo=
|
||||
github.com/openzipkin/zipkin-go v0.1.1/go.mod h1:NtoC/o8u3JlF1lSlyPNswIbeQH9bJTmOf0Erfk+hxe8=
|
||||
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 v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
|
||||
github.com/pelletier/go-toml v1.8.1/go.mod h1:T2/BmBdy8dvIRq1a/8aqjN41wvWlN4lrapLU/GW4pbc=
|
||||
github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU=
|
||||
@@ -646,6 +722,7 @@ github.com/pquerna/cachecontrol v0.0.0-20171018203845-0dec1b30a021/go.mod h1:prY
|
||||
github.com/prestonTao/upnp v0.0.0-20150206124352-f4370df5e109 h1:h9WYaTCQJ7hap8C5vQniEum2YZbc+iRad/ROafTjy10=
|
||||
github.com/prestonTao/upnp v0.0.0-20150206124352-f4370df5e109/go.mod h1:U7VCLF6LMHzOFD/6Kww2MTQuwaNeEA1U1dOxFyZBoBE=
|
||||
github.com/prometheus/client_golang v0.0.0-20180209125602-c332b6f63c06/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
|
||||
github.com/prometheus/client_golang v0.8.0/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
|
||||
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
|
||||
github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso=
|
||||
github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
|
||||
@@ -657,12 +734,14 @@ github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:
|
||||
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/prometheus/common v0.0.0-20180110214958-89604d197083/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
|
||||
github.com/prometheus/common v0.0.0-20180801064454-c7de2306084e/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
|
||||
github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
|
||||
github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
|
||||
github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
|
||||
github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+Zk0j9GMYc=
|
||||
github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo=
|
||||
github.com/prometheus/procfs v0.0.0-20180125133057-cb4147076ac7/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||
github.com/prometheus/procfs v0.0.0-20180725123919-05ee40e3a273/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||
github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
|
||||
github.com/prometheus/procfs v0.0.0-20190522114515-bc1a522cf7b1/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
|
||||
@@ -681,15 +760,39 @@ github.com/robfig/cron v1.2.0/go.mod h1:JGuDeoQd7Z6yL4zQhZ3OPEVHB7fL6Ka6skscFHfm
|
||||
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
|
||||
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
|
||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
|
||||
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/safchain/ethtool v0.0.0-20190326074333-42ed695e3de8/go.mod h1:Z0q5wiBQGYcxhMZ6gUqHn6pYNLypFAvaL3UvgZLR0U4=
|
||||
github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww=
|
||||
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
|
||||
github.com/seccomp/libseccomp-golang v0.9.1/go.mod h1:GbW5+tmTXfcxTToHLXlScSlAvWlF4P2Ca7zGrPiEpWo=
|
||||
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
|
||||
github.com/shirou/gopsutil/v3 v3.21.5 h1:YUBf0w/KPLk7w1803AYBnH7BmA+1Z/Q5MEZxpREUaB4=
|
||||
github.com/shirou/gopsutil/v3 v3.21.5/go.mod h1:ghfMypLDrFSWN2c9cDYFLHyynQ+QUht0cv/18ZqVczw=
|
||||
github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
|
||||
github.com/shurcooL/component v0.0.0-20170202220835-f88ec8f54cc4/go.mod h1:XhFIlyj5a1fBNx5aJTbKoIq0mNaPvOagO+HjB3EtxrY=
|
||||
github.com/shurcooL/events v0.0.0-20181021180414-410e4ca65f48/go.mod h1:5u70Mqkb5O5cxEA8nxTsgrgLehJeAw6Oc4Ab1c/P1HM=
|
||||
github.com/shurcooL/github_flavored_markdown v0.0.0-20181002035957-2122de532470/go.mod h1:2dOwnU2uBioM+SGy2aZoq1f/Sd1l9OkAeAUvjSyvgU0=
|
||||
github.com/shurcooL/go v0.0.0-20180423040247-9e1955d9fb6e/go.mod h1:TDJrrUr11Vxrven61rcy3hJMUqaf/CLWYhHNPmT14Lk=
|
||||
github.com/shurcooL/go-goon v0.0.0-20170922171312-37c2f522c041/go.mod h1:N5mDOmsrJOB+vfqUK+7DmDyjhSLIIBnXo9lvZJj3MWQ=
|
||||
github.com/shurcooL/gofontwoff v0.0.0-20180329035133-29b52fc0a18d/go.mod h1:05UtEgK5zq39gLST6uB0cf3NEHjETfB4Fgr3Gx5R9Vw=
|
||||
github.com/shurcooL/gopherjslib v0.0.0-20160914041154-feb6d3990c2c/go.mod h1:8d3azKNyqcHP1GaQE/c6dDgjkgSx2BZ4IoEi4F1reUI=
|
||||
github.com/shurcooL/highlight_diff v0.0.0-20170515013008-09bb4053de1b/go.mod h1:ZpfEhSmds4ytuByIcDnOLkTHGUI6KNqRNPDLHDk+mUU=
|
||||
github.com/shurcooL/highlight_go v0.0.0-20181028180052-98c3abbbae20/go.mod h1:UDKB5a1T23gOMUJrI+uSuH0VRDStOiUVSjBTRDVBVag=
|
||||
github.com/shurcooL/home v0.0.0-20181020052607-80b7ffcb30f9/go.mod h1:+rgNQw2P9ARFAs37qieuu7ohDNQ3gds9msbT2yn85sg=
|
||||
github.com/shurcooL/htmlg v0.0.0-20170918183704-d01228ac9e50/go.mod h1:zPn1wHpTIePGnXSHpsVPWEktKXHr6+SS6x/IKRb7cpw=
|
||||
github.com/shurcooL/httperror v0.0.0-20170206035902-86b7830d14cc/go.mod h1:aYMfkZ6DWSJPJ6c4Wwz3QtW22G7mf/PEgaB9k/ik5+Y=
|
||||
github.com/shurcooL/httpfs v0.0.0-20171119174359-809beceb2371/go.mod h1:ZY1cvUeJuFPAdZ/B6v7RHavJWZn2YPVFQ1OSXhCGOkg=
|
||||
github.com/shurcooL/httpgzip v0.0.0-20180522190206-b1c53ac65af9/go.mod h1:919LwcH0M7/W4fcZ0/jy0qGght1GIhqyS/EgWGH2j5Q=
|
||||
github.com/shurcooL/issues v0.0.0-20181008053335-6292fdc1e191/go.mod h1:e2qWDig5bLteJ4fwvDAc2NHzqFEthkqn7aOZAOpj+PQ=
|
||||
github.com/shurcooL/issuesapp v0.0.0-20180602232740-048589ce2241/go.mod h1:NPpHK2TI7iSaM0buivtFUc9offApnI0Alt/K8hcHy0I=
|
||||
github.com/shurcooL/notifications v0.0.0-20181007000457-627ab5aea122/go.mod h1:b5uSkrEVM1jQUspwbixRBhaIjIzL2xazXp6kntxYle0=
|
||||
github.com/shurcooL/octicon v0.0.0-20181028054416-fa4f57f9efb2/go.mod h1:eWdoE5JD4R5UVWDucdOPg1g2fqQRq78IQa9zlOV1vpQ=
|
||||
github.com/shurcooL/reactions v0.0.0-20181006231557-f2e0b4ca5b82/go.mod h1:TCR1lToEk4d2s07G3XGfz2QrgHXg4RJBvjrOozvoWfk=
|
||||
github.com/shurcooL/sanitized_anchor_name v0.0.0-20170918181015-86672fcb3f95/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
|
||||
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
|
||||
github.com/shurcooL/users v0.0.0-20180125191416-49c67e49c537/go.mod h1:QJTqeLYEDaXHZDBsXlPCDqdhQuJkuw4NOtaxYe3xii4=
|
||||
github.com/shurcooL/webdavfs v0.0.0-20170829043945-18c3829fa133/go.mod h1:hKmq5kWdCj2z2KEozexVbfEZIWiTjhE0+UjmZgPqehw=
|
||||
github.com/sirupsen/logrus v1.0.4-0.20170822132746-89742aefa4b2/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc=
|
||||
github.com/sirupsen/logrus v1.0.6/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc=
|
||||
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
||||
@@ -706,8 +809,11 @@ github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:s
|
||||
github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s=
|
||||
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
|
||||
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
|
||||
github.com/sourcegraph/annotate v0.0.0-20160123013949-f4cad6c6324d/go.mod h1:UdhH50NIW0fCiwBSr0co2m7BnFLdv4fQTgdqdJTHFeE=
|
||||
github.com/sourcegraph/syntaxhighlight v0.0.0-20170531221838-bd320f5d308e/go.mod h1:HuIsMU8RRBOtsCgI77wP899iHVBQpCmg4ErYMZB+2IA=
|
||||
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
|
||||
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
|
||||
github.com/spf13/afero v1.2.2 h1:5jhuqJyZCZf2JRofRvN/nIFgIWNzPa3/Vz8mYylgbWc=
|
||||
github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk=
|
||||
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
||||
github.com/spf13/cobra v0.0.2-0.20171109065643-2da4a54c5cee/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
|
||||
@@ -742,12 +848,12 @@ github.com/swaggo/swag v1.7.3/go.mod h1:zD8h6h4SPv7t3l+4BKdRquqW1ASWjKZgT6Qv9z3k
|
||||
github.com/syndtr/gocapability v0.0.0-20170704070218-db04d3cc01c8/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww=
|
||||
github.com/syndtr/gocapability v0.0.0-20180916011248-d98352740cb2/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww=
|
||||
github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww=
|
||||
github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cbyO7IOYJZWg1U88JhDg3PB6klq9Hg2pA=
|
||||
github.com/tchap/go-patricia v2.2.6+incompatible/go.mod h1:bmLyhP68RS6kStMGxByiQ23RP/odRBOTVjwp2cDyi6I=
|
||||
github.com/tidwall/gjson v1.8.0 h1:Qt+orfosKn0rbNTZqHYDqBrmm3UDA4KRkv70fDzG+PQ=
|
||||
github.com/tidwall/gjson v1.8.0/go.mod h1:5/xDoumyyDNerp2U36lyolv46b3uF/9Bu6OfyQ9GImk=
|
||||
github.com/tidwall/match v1.0.3 h1:FQUVvBImDutD8wJLN6c5eMzWtjgONK9MwIBCOrUJKeE=
|
||||
github.com/tidwall/match v1.0.3/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM=
|
||||
github.com/tidwall/pretty v1.1.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
|
||||
github.com/tidwall/gjson v1.10.2 h1:APbLGOM0rrEkd8WBw9C24nllro4ajFuJu0Sc9hRz8Bo=
|
||||
github.com/tidwall/gjson v1.10.2/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 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs=
|
||||
github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
|
||||
github.com/tklauser/go-sysconf v0.3.4/go.mod h1:Cl2c8ZRWfHD5IrfHo9VN+FX9kCFjIOyVklgXycLB6ek=
|
||||
@@ -774,6 +880,8 @@ github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijb
|
||||
github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
|
||||
github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
|
||||
github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI=
|
||||
github.com/viant/assertly v0.4.8/go.mod h1:aGifi++jvCrUaklKEKT0BU95igDNaqkvz+49uaYMPRU=
|
||||
github.com/viant/toolbox v0.24.0/go.mod h1:OxMCG57V0PXuIP2HNQrtJf2CjqdmbrOx5EkMILuUhzM=
|
||||
github.com/vishvananda/netlink v0.0.0-20181108222139-023a6dafdcdf/go.mod h1:+SR5DhBJrl6ZM7CoCKvpw5BKroDKQ+PJqOg65H/2ktk=
|
||||
github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYppBueQtXaqoE=
|
||||
github.com/vishvananda/netlink v1.1.1-0.20201029203352-d40f9887b852/go.mod h1:twkDnbuQxJYemMlGd4JFIcuhgX83tXhKS2B/PRMpOho=
|
||||
@@ -791,6 +899,7 @@ github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de
|
||||
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||
github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||
github.com/yvasiyarov/go-metrics v0.0.0-20140926110328-57bccd1ccd43/go.mod h1:aX5oPXxHm3bOH+xeAttToC8pqch2ScQN/JoXYupl6xs=
|
||||
github.com/yvasiyarov/gorelic v0.0.0-20141212073537-a9bba5b9ab50/go.mod h1:NUSPSUX/bi6SeDMUh6brw0nXpxHnc96TguQh0+r/ssA=
|
||||
@@ -800,6 +909,7 @@ go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
|
||||
go.etcd.io/bbolt v1.3.5/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ=
|
||||
go.etcd.io/etcd v0.5.0-alpha.5.0.20200910180754-dd1b699fc489/go.mod h1:yVHk9ub3CSBatqGNg7GRmsnfLWtoW60w4eDYfh7vHDg=
|
||||
go.mozilla.org/pkcs7 v0.0.0-20200128120323-432b2356ecb1/go.mod h1:SNgMg+EgDFwmvSmLRTNKC5fegJjB7v23qTQ0XLGUNHk=
|
||||
go.opencensus.io v0.18.0/go.mod h1:vKdFvxhtzZ9onBp9VKHK8z/sRpBMnKAsufL7wlDrCOA=
|
||||
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
|
||||
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
|
||||
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||
@@ -812,20 +922,24 @@ go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
||||
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
||||
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
|
||||
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
|
||||
go4.org v0.0.0-20180809161055-417644f6feb5/go.mod h1:MkTOUMDaeVYJUOUsaDXIhWPZYa1yOyC1qaOBpL57BhE=
|
||||
golang.org/x/build v0.0.0-20190111050920-041ab4dc3f9d/go.mod h1:OWs+y06UdEOHN4y+MfF/py+xQ/tYqIWW03b70/CG9Rw=
|
||||
golang.org/x/crypto v0.0.0-20171113213409-9f005a07e0d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20181009213950-7c1a557ab941/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20181030102418-4d3f4d9ffa16/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190313024323-a1f597ede03a/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20200221231518-2aa609cf4a9d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
|
||||
golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.0.0-20210817164053-32db794688a5 h1:HWj/xjIHfjYU5nVXpTM0s39J9CbLn7Cc5a7IC5rwsMQ=
|
||||
golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
@@ -840,6 +954,9 @@ golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EH
|
||||
golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
|
||||
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
||||
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||
golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8 h1:hVwzHzIUGRjiF7EcUjqNxk3NCfkPxbDKRdnNE1Rpg0U=
|
||||
golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||
golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
||||
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
@@ -861,17 +978,19 @@ golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.5.0 h1:UG21uOlmZabA4fW5i7ZX6bjw1xELEGg/ZLgZq9auk/Q=
|
||||
golang.org/x/mod v0.5.0/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=
|
||||
golang.org/x/net v0.0.0-20180218175443-cbe0f9307d01/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181005035420-146acd28ed58/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181011144130-49bb7cea24b1/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181029044818-c44066c5c816/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181106065722-10aee1819953/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190313220215-9f648a60d977/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
@@ -892,10 +1011,12 @@ golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLL
|
||||
golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200320220750-118fecf932d8/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
@@ -908,16 +1029,20 @@ golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
||||
golang.org/x/net v0.0.0-20210421230115-4e50805a0758/go.mod h1:72T/g9IO56b78aLF+1Kcs5dz7/ng1VjMUvfKvpfy+jM=
|
||||
golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk=
|
||||
golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20211020060615-d418f374d309 h1:A0lJIi+hcTR6aajJH4YqKWwohY4aW9RO7oRMcdv+HKI=
|
||||
golang.org/x/net v0.0.0-20211020060615-d418f374d309/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f h1:Qmd2pbz05z7z6lm0DrgQVVPuBm92jqujBKMHMOlOQEw=
|
||||
golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/perf v0.0.0-20180704124530-6e6d33e29852/go.mod h1:JLpeXjPJfIyPr5TlbXLkXWLhP8nz10XfvxElABhCtcw=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
@@ -933,12 +1058,14 @@ golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJ
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181029174526-d69651ed3497/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181228144115-9a3f9b0469bb/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190316082340-a2f829d7f35f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
@@ -982,6 +1109,7 @@ golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7w
|
||||
golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200622214017-ed371f2e16b4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
@@ -997,6 +1125,7 @@ golang.org/x/sys v0.0.0-20201117170446-d9b008d0a637/go.mod h1:h1NjWce9XRLGQEsW7w
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201202213521-69691e467435/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210217105451-b926d437f341/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
@@ -1034,7 +1163,9 @@ golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e/go.mod h1:tRJNPiyCQ0inRvYxb
|
||||
golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac h1:7zkz7BUtwNFFqcowJ+RIgu2MaV/MapERkDIy+mwPyjs=
|
||||
golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20181030000716-a0a13e073c7b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
||||
@@ -1081,8 +1212,10 @@ golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roY
|
||||
golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
||||
golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
||||
golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
||||
golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
|
||||
golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.1.7 h1:6j8CgantCy3yc8JGBqkDLMKWqZ0RDU2g1HVgacojGWQ=
|
||||
golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
@@ -1091,6 +1224,9 @@ golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8T
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/api v0.0.0-20160322025152-9bf6e6e569ff/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0=
|
||||
google.golang.org/api v0.0.0-20180910000450-7ca32eb868bf/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0=
|
||||
google.golang.org/api v0.0.0-20181030000543-1d582fd0359e/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0=
|
||||
google.golang.org/api v0.1.0/go.mod h1:UGEZY7KEX120AnNLIHFMKIo4obdJhkp2tPbaPlQx13Y=
|
||||
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
|
||||
google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
|
||||
google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
|
||||
@@ -1108,6 +1244,8 @@ google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0M
|
||||
google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM=
|
||||
google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc=
|
||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||
google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/appengine v1.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
|
||||
@@ -1117,6 +1255,10 @@ 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/cloud v0.0.0-20151119220103-975617b05ea8/go.mod h1:0H1ncTHf11KCFhTc/+EFRbzSCOZx+VUbRMk55Yv5MYk=
|
||||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||
google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||
google.golang.org/genproto v0.0.0-20181029155118-b69ba1387ce2/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||
google.golang.org/genproto v0.0.0-20181202183823-bd91e49a0898/go.mod h1:7Ep/1NZk928CDR8SjdVbjWNpdIf6nzjE3BTgJDr2Atg=
|
||||
google.golang.org/genproto v0.0.0-20190306203927-b5d61aea6440/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
@@ -1152,6 +1294,9 @@ google.golang.org/genproto v0.0.0-20201110150050-8816d57aaa9a/go.mod h1:FWY/as6D
|
||||
google.golang.org/genproto v0.0.0-20210924002016-3dee208752a0 h1:5Tbluzus3QxoAJx4IefGt1W0HQZW4nuMrVk684jI74Q=
|
||||
google.golang.org/genproto v0.0.0-20210924002016-3dee208752a0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
|
||||
google.golang.org/grpc v0.0.0-20160317175043-d3ddb4469d5a/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
|
||||
google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
|
||||
google.golang.org/grpc v1.16.0/go.mod h1:0JHn/cJsOMiMfNA9+DeHDlAU7KAAB5GDlYFpa9MZMio=
|
||||
google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
|
||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
|
||||
google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
|
||||
@@ -1210,6 +1355,7 @@ gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
|
||||
gopkg.in/square/go-jose.v2 v2.2.2/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
|
||||
gopkg.in/square/go-jose.v2 v2.3.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
|
||||
gopkg.in/square/go-jose.v2 v2.5.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
|
||||
gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
|
||||
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
@@ -1217,6 +1363,7 @@ gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||
@@ -1225,15 +1372,18 @@ gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C
|
||||
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gorm.io/driver/sqlite v1.1.5 h1:JU8G59VyKu1x1RMQgjefQnkZjDe9wHc1kARDZPu5dZs=
|
||||
gorm.io/driver/sqlite v1.1.5/go.mod h1:NpaYMcVKEh6vLJ47VP6T7Weieu4H1Drs3dGD/K6GrGc=
|
||||
gorm.io/gorm v1.21.15 h1:gAyaDoPw0lCyrSFWhBlahbUA1U4P5RViC1uIqoB+1Rk=
|
||||
gorm.io/gorm v1.21.15/go.mod h1:F+OptMscr0P2F2qU97WT1WimdH9GaQPoDW7AYd5i2Y0=
|
||||
gorm.io/driver/sqlite v1.2.6 h1:SStaH/b+280M7C8vXeZLz/zo9cLQmIGwwj3cSj7p6l4=
|
||||
gorm.io/driver/sqlite v1.2.6/go.mod h1:gyoX0vHiiwi0g49tv+x2E7l8ksauLK0U/gShcdUsjWY=
|
||||
gorm.io/gorm v1.22.3/go.mod h1:F+OptMscr0P2F2qU97WT1WimdH9GaQPoDW7AYd5i2Y0=
|
||||
gorm.io/gorm v1.22.5 h1:lYREBgc02Be/5lSCTuysZZDb6ffL2qrat6fg9CFbvXU=
|
||||
gorm.io/gorm v1.22.5/go.mod h1:l2lP/RyAtc1ynaTjFksBde/O8v9oOGIApu2/xRitmZk=
|
||||
gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo=
|
||||
gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw=
|
||||
gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk=
|
||||
gotest.tools/v3 v3.0.3 h1:4AuOwCGf4lLR9u3YOe2awrHygurzhO/HeQ6laiA6Sx0=
|
||||
gotest.tools/v3 v3.0.3/go.mod h1:Z7Lb0S5l+klDB31fvDQX8ss/FlKDxtlFlw3Oa8Ymbl8=
|
||||
grpc.go4.org v0.0.0-20170609214715-11d0a25b4919/go.mod h1:77eQGdRu53HpSqPFJFmuJdjuHRquDANNeA4x7B8WQ9o=
|
||||
honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
@@ -1275,3 +1425,5 @@ sigs.k8s.io/structured-merge-diff/v4 v4.0.2/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK
|
||||
sigs.k8s.io/structured-merge-diff/v4 v4.0.3/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw=
|
||||
sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o=
|
||||
sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc=
|
||||
sourcegraph.com/sourcegraph/go-diff v0.5.0/go.mod h1:kuch7UrkMzY0X+p9CRK03kfuPQ2zzQcaEFbx8wA8rck=
|
||||
sourcegraph.com/sqs/pbtypes v0.0.0-20180604144634-d3ebe8f20ae4/go.mod h1:ketZ/q3QxT9HOBeFhu6RdvsftgpsbFHBF5Cas6cDKZ0=
|
||||
|
||||
51
main.go
51
main.go
@@ -6,11 +6,15 @@ import (
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/IceWhaleTech/CasaOS/pkg/cache"
|
||||
"github.com/IceWhaleTech/CasaOS/pkg/config"
|
||||
"github.com/IceWhaleTech/CasaOS/pkg/sqlite"
|
||||
loger2 "github.com/IceWhaleTech/CasaOS/pkg/utils/loger"
|
||||
"github.com/IceWhaleTech/CasaOS/route"
|
||||
"github.com/IceWhaleTech/CasaOS/service"
|
||||
model2 "github.com/IceWhaleTech/CasaOS/service/model"
|
||||
"github.com/IceWhaleTech/CasaOS/types"
|
||||
|
||||
"github.com/robfig/cron"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
@@ -18,7 +22,7 @@ import (
|
||||
var sqliteDB *gorm.DB
|
||||
|
||||
var configFlag = flag.String("c", "", "config address")
|
||||
|
||||
var dbFlag = flag.String("db", "", "db path")
|
||||
var showUserInfo = flag.Bool("show-user-info", false, "show user info")
|
||||
|
||||
func init() {
|
||||
@@ -26,9 +30,28 @@ func init() {
|
||||
config.InitSetup(*configFlag)
|
||||
config.UpdateSetup()
|
||||
loger2.LogSetup()
|
||||
sqliteDB = sqlite.GetDb(config.AppInfo.ProjectPath)
|
||||
if len(*dbFlag) == 0 {
|
||||
*dbFlag = config.AppInfo.ProjectPath + "/db"
|
||||
}
|
||||
sqliteDB = sqlite.GetDb(*dbFlag)
|
||||
//gredis.GetRedisConn(config.RedisInfo),
|
||||
service.MyService = service.NewService(sqliteDB, loger2.NewOLoger())
|
||||
service.Cache = cache.Init()
|
||||
|
||||
go service.UDPService()
|
||||
|
||||
fmt.Println("token", service.GetToken())
|
||||
service.UDPAddressMap = make(map[string]string)
|
||||
//go service.SocketConnect()
|
||||
service.CancelList = make(map[string]string)
|
||||
service.InternalInspection = make(map[string][]string)
|
||||
service.NewVersionApp = make(map[string]string)
|
||||
route.InitFunction()
|
||||
|
||||
go service.SendIPToServer()
|
||||
// go service.LoopFriend()
|
||||
// go service.MyService.App().CheckNewImage()
|
||||
|
||||
}
|
||||
|
||||
// @title casaOS API
|
||||
@@ -53,17 +76,32 @@ func main() {
|
||||
//gredis.Setup()
|
||||
r := route.InitRouter()
|
||||
//service.SyncTask(sqliteDB)
|
||||
cron2 := cron.New() //创建一个cron实例
|
||||
//执行定时任务(每5秒执行一次)
|
||||
err := cron2.AddFunc("0 0 0 1/1 * *", func() {
|
||||
cron2 := cron.New()
|
||||
//every day execution
|
||||
err := cron2.AddFunc("0 0/5 * * * *", func() {
|
||||
//service.PushIpInfo(*&config.ServerInfo.Token)
|
||||
//service.UpdataDDNSList(mysqldb)
|
||||
//service.SyncTask(sqliteDB)
|
||||
|
||||
service.SendIPToServer()
|
||||
|
||||
service.LoopFriend()
|
||||
service.MyService.App().CheckNewImage()
|
||||
})
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
err = cron2.AddFunc("0/1 * * * * *", func() {
|
||||
notify := model2.AppNotify{}
|
||||
notify.CustomId = ""
|
||||
notify.Type = types.NOTIFY_TYPE_HEALTH_CHECK
|
||||
|
||||
//启动/关闭
|
||||
go service.MyService.Notify().SendText(notify)
|
||||
|
||||
})
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
cron2.Start()
|
||||
defer cron2.Stop()
|
||||
s := &http.Server{
|
||||
@@ -73,6 +111,7 @@ func main() {
|
||||
WriteTimeout: 60 * time.Second,
|
||||
MaxHeaderBytes: 1 << 20,
|
||||
}
|
||||
|
||||
s.ListenAndServe()
|
||||
|
||||
}
|
||||
|
||||
@@ -2,8 +2,9 @@ package middleware
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/gin-gonic/gin"
|
||||
"net/http"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
func Cors() gin.HandlerFunc {
|
||||
@@ -17,7 +18,7 @@ func Cors() gin.HandlerFunc {
|
||||
//服务器支持的所有跨域请求的方法
|
||||
c.Header("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE,UPDATE")
|
||||
//允许跨域设置可以返回其他子段,可以自定义字段
|
||||
c.Header("Access-Control-Allow-Headers", "Authorization, Content-Length, X-CSRF-Token, Token,session")
|
||||
c.Header("Access-Control-Allow-Headers", "Authorization, Content-Length, X-CSRF-Token, Token,session,Language")
|
||||
// 允许浏览器(客户端)可以解析的头部 (重要)
|
||||
c.Header("Access-Control-Expose-Headers", "Content-Length, Access-Control-Allow-Origin, Access-Control-Allow-Headers")
|
||||
//设置缓存时间
|
||||
|
||||
27
model/app-analyse.go
Normal file
27
model/app-analyse.go
Normal file
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* @Author: LinkLeong link@icewhale.com
|
||||
* @Date: 2022-03-18 11:40:55
|
||||
* @LastEditors: LinkLeong
|
||||
* @LastEditTime: 2022-05-13 14:48:01
|
||||
* @FilePath: /CasaOS/model/app-analyse.go
|
||||
* @Description:
|
||||
* @Website: https://www.casaos.io
|
||||
* Copyright (c) 2022 by icewhale, All Rights Reserved.
|
||||
*/
|
||||
package model
|
||||
|
||||
type AppAnalyse struct {
|
||||
Name string `json:"name"`
|
||||
Type string `json:"type"`
|
||||
UUId string `json:"uuid"`
|
||||
Language string `json:"language"`
|
||||
Version string `json:"version"`
|
||||
}
|
||||
|
||||
type ConnectionStatus struct {
|
||||
From string `json:"from"`
|
||||
To string `json:"to"`
|
||||
Error string `json:"error"`
|
||||
UUId string `json:"uuid"`
|
||||
Event string `json:"event"`
|
||||
}
|
||||
18
model/app.go
18
model/app.go
@@ -15,12 +15,15 @@ type ServerAppList struct {
|
||||
Icon string `json:"icon"`
|
||||
ScreenshotLink Strings `gorm:"type:json" json:"screenshot_link"`
|
||||
Category string `json:"category"`
|
||||
TcpPort uint `json:"tcp_port"`
|
||||
PortMap uint `json:"port_map"`
|
||||
CategoryFont string `json:"category_font"`
|
||||
PortMap string `json:"port_map"`
|
||||
ImageVersion string `json:"image_version"`
|
||||
Tip string `json:"tip"`
|
||||
Configures configures `gorm:"type:json" json:"configures"`
|
||||
NetworkModel string `json:"network_mode"`
|
||||
Envs EnvArray `json:"envs"`
|
||||
Ports PortArray `json:"ports"`
|
||||
Volumes PathArray `json:"volumes"`
|
||||
Devices PathArray `json:"devices"`
|
||||
NetworkModel string `json:"network_model"`
|
||||
Image string `json:"image"`
|
||||
Index string `json:"index"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
@@ -33,6 +36,13 @@ type ServerAppList struct {
|
||||
Thumbnail string `json:"thumbnail"`
|
||||
Healthy string `json:"healthy"`
|
||||
Plugins Strings `json:"plugins"`
|
||||
Origin string `json:"origin"`
|
||||
Type int `json:"type"`
|
||||
Developer string `json:"developer"`
|
||||
HostName string `json:"host_name"`
|
||||
Privileged bool `json:"privileged"`
|
||||
CapAdd Strings `json:"cap_add"`
|
||||
Cmd Strings `json:"cmd"`
|
||||
}
|
||||
|
||||
type Ports struct {
|
||||
|
||||
@@ -5,6 +5,7 @@ type ServerCategoryList struct {
|
||||
//CreatedAt time.Time `json:"created_at"`
|
||||
//
|
||||
//UpdatedAt time.Time `json:"updated_at"`
|
||||
Font string `json:"font"`
|
||||
Name string `json:"name"`
|
||||
Count uint `json:"count"`
|
||||
}
|
||||
|
||||
@@ -20,12 +20,57 @@ type LSBLKModel struct {
|
||||
Format string `json:"format"`
|
||||
Health string `json:"health"`
|
||||
HotPlug bool `json:"hotplug"`
|
||||
UUID string `json:"uuid"`
|
||||
FSUsed string `json:"fsused"`
|
||||
Temperature int `json:"temperature"`
|
||||
Tran string `json:"tran"`
|
||||
MinIO uint64 `json:"min-io"`
|
||||
UsedPercent float64 `json:"used_percent"`
|
||||
Serial string `json:"serial"`
|
||||
Children []LSBLKModel `json:"children"`
|
||||
SubSystems string `json:"subsystems"`
|
||||
//详情特有
|
||||
StartSector uint64 `json:"start_sector,omitempty"`
|
||||
Rota bool `json:"rota"` //true(hhd) false(ssd)
|
||||
DiskType string `json:"disk_type"`
|
||||
EndSector uint64 `json:"end_sector,omitempty"`
|
||||
}
|
||||
|
||||
type Drive struct {
|
||||
Name string `json:"name"`
|
||||
Size uint64 `json:"size"`
|
||||
Model string `json:"model"`
|
||||
Health string `json:"health"`
|
||||
Temperature int `json:"temperature"`
|
||||
DiskType string `json:"disk_type"`
|
||||
NeedFormat bool `json:"need_format"`
|
||||
Serial string `json:"serial"`
|
||||
Path string `json:"path"`
|
||||
}
|
||||
|
||||
type DriveUSB struct {
|
||||
Name string `json:"name"`
|
||||
Size uint64 `json:"size"`
|
||||
Used uint64 `json:"use"`
|
||||
Model string `json:"model"`
|
||||
Mount bool `json:"mount"` //是否完全挂载
|
||||
Avail uint64 `json:"avail"` //可用空间
|
||||
}
|
||||
|
||||
type Storage struct {
|
||||
Name string `json:"name"`
|
||||
MountPoint string `json:"mountpoint"`
|
||||
Size string `json:"size"`
|
||||
Avail string `json:"avail"` //可用空间
|
||||
Type string `json:"type"`
|
||||
CreatedAt int64 `json:"create_at"`
|
||||
Path string `json:"path"`
|
||||
DriveName string `json:"drive_name"`
|
||||
}
|
||||
|
||||
type Summary struct {
|
||||
Size uint64 `json:"size"`
|
||||
Avail uint64 `json:"avail"` //可用空间
|
||||
Health bool `json:"health"`
|
||||
Used uint64 `json:"used"`
|
||||
}
|
||||
|
||||
8
model/docker.go
Normal file
8
model/docker.go
Normal file
@@ -0,0 +1,8 @@
|
||||
package model
|
||||
|
||||
type DockerStatsModel struct {
|
||||
Icon string `json:"icon"`
|
||||
Title string `json:"title"`
|
||||
Data interface{} `json:"data"`
|
||||
Pre interface{} `json:"pre"`
|
||||
}
|
||||
6
model/heart.go
Normal file
6
model/heart.go
Normal file
@@ -0,0 +1,6 @@
|
||||
package model
|
||||
|
||||
type CasaOSHeart struct {
|
||||
UuId string `json:"uuid"`
|
||||
Type string `json:"type"`
|
||||
}
|
||||
@@ -17,20 +17,22 @@ type UdpPorts struct {
|
||||
/*******************使用gorm支持json************************************/
|
||||
|
||||
type PortMap struct {
|
||||
ContainerPort string `json:"container,omitempty"`
|
||||
CommendPort string `json:"host,omitempty"`
|
||||
ContainerPort string `json:"container"`
|
||||
CommendPort string `json:"host"`
|
||||
Protocol string `json:"protocol"`
|
||||
Desc string `json:"desc"`
|
||||
Type int `json:"type"`
|
||||
}
|
||||
|
||||
type PortArrey []PortMap
|
||||
type PortArray []PortMap
|
||||
|
||||
// Value 实现方法
|
||||
func (p PortArrey) Value() (driver.Value, error) {
|
||||
func (p PortArray) Value() (driver.Value, error) {
|
||||
return json.Marshal(p)
|
||||
}
|
||||
|
||||
// Scan 实现方法
|
||||
func (p *PortArrey) Scan(input interface{}) error {
|
||||
func (p *PortArray) Scan(input interface{}) error {
|
||||
return json.Unmarshal(input.([]byte), p)
|
||||
}
|
||||
|
||||
@@ -41,20 +43,22 @@ func (p *PortArrey) Scan(input interface{}) error {
|
||||
type Env struct {
|
||||
Name string `json:"container"`
|
||||
Value string `json:"host"`
|
||||
Desc string `json:"desc"`
|
||||
Type int `json:"type"`
|
||||
}
|
||||
|
||||
type JSON json.RawMessage
|
||||
|
||||
type EnvArrey []Env
|
||||
type EnvArray []Env
|
||||
|
||||
// Value 实现方法
|
||||
func (p EnvArrey) Value() (driver.Value, error) {
|
||||
func (p EnvArray) Value() (driver.Value, error) {
|
||||
return json.Marshal(p)
|
||||
//return .MarshalJSON()
|
||||
}
|
||||
|
||||
// Scan 实现方法
|
||||
func (p *EnvArrey) Scan(input interface{}) error {
|
||||
func (p *EnvArray) Scan(input interface{}) error {
|
||||
return json.Unmarshal(input.([]byte), p)
|
||||
}
|
||||
|
||||
@@ -65,17 +69,19 @@ func (p *EnvArrey) Scan(input interface{}) error {
|
||||
type PathMap struct {
|
||||
ContainerPath string `json:"container"`
|
||||
Path string `json:"host"`
|
||||
Type int `json:"type"`
|
||||
Desc string `json:"desc"`
|
||||
}
|
||||
|
||||
type PathArrey []PathMap
|
||||
type PathArray []PathMap
|
||||
|
||||
// Value 实现方法
|
||||
func (p PathArrey) Value() (driver.Value, error) {
|
||||
func (p PathArray) Value() (driver.Value, error) {
|
||||
return json.Marshal(p)
|
||||
}
|
||||
|
||||
// Scan 实现方法
|
||||
func (p *PathArrey) Scan(input interface{}) error {
|
||||
func (p *PathArray) Scan(input interface{}) error {
|
||||
return json.Unmarshal(input.([]byte), p)
|
||||
}
|
||||
|
||||
@@ -98,15 +104,16 @@ func (p *PathArrey) Scan(input interface{}) error {
|
||||
//}
|
||||
|
||||
type CustomizationPostData struct {
|
||||
CustomId string `json:"custom_id"`
|
||||
Origin string `json:"origin"`
|
||||
NetworkModel string `json:"network_model"`
|
||||
Index string `json:"index"`
|
||||
Icon string `json:"icon"`
|
||||
Image string `json:"image"`
|
||||
Envs EnvArrey `json:"envs"`
|
||||
Ports PortArrey `json:"ports"`
|
||||
Volumes PathArrey `json:"volumes"`
|
||||
Devices PathArrey `json:"devices"`
|
||||
Envs EnvArray `json:"envs"`
|
||||
Ports PortArray `json:"ports"`
|
||||
Volumes PathArray `json:"volumes"`
|
||||
Devices PathArray `json:"devices"`
|
||||
//Port string `json:"port,omitempty"`
|
||||
PortMap string `json:"port_map"`
|
||||
CpuShares int64 `json:"cpu_shares"`
|
||||
@@ -116,4 +123,8 @@ type CustomizationPostData struct {
|
||||
Label string `json:"label"`
|
||||
Description string `json:"description"`
|
||||
Position bool `json:"position"`
|
||||
HostName string `json:"host_name"`
|
||||
Privileged bool `json:"privileged"`
|
||||
CapAdd []string `json:"cap_add"`
|
||||
Cmd []string `json:"cmd"`
|
||||
}
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
package model
|
||||
|
||||
import "time"
|
||||
|
||||
type IOCountersStat struct {
|
||||
Name string `json:"name"` // interface name
|
||||
BytesSent uint64 `json:"bytesSent"` // number of bytes sent
|
||||
@@ -15,5 +13,5 @@ type IOCountersStat struct {
|
||||
Fifoin uint64 `json:"fifoin"` // total number of FIFO buffers errors while receiving
|
||||
Fifoout uint64 `json:"fifoout"` // total number of FIFO buffers errors while sending
|
||||
State string `json:"state"`
|
||||
DateTime time.Time `json:"date_time"`
|
||||
Time int64 `json:"time"`
|
||||
}
|
||||
|
||||
6
model/notify.go
Normal file
6
model/notify.go
Normal file
@@ -0,0 +1,6 @@
|
||||
package model
|
||||
|
||||
type NotifyMssage struct {
|
||||
Type string `json:"type"`
|
||||
Data string `json:"data"`
|
||||
}
|
||||
54
model/person.go
Normal file
54
model/person.go
Normal file
@@ -0,0 +1,54 @@
|
||||
package model
|
||||
|
||||
import "time"
|
||||
|
||||
type PersionModel struct {
|
||||
Token string `json:"token"`
|
||||
Ips []string `json:"ips"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
}
|
||||
|
||||
//记录链接状态
|
||||
type ConnectState struct {
|
||||
From string `json:"from"`
|
||||
To string `json:"to"`
|
||||
Type string `json:"type"` //current state 1:ready 2:ok
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UUId string `json:"uuid"` //对接标识
|
||||
}
|
||||
type MessageModel struct {
|
||||
Type string `json:"type"`
|
||||
Data interface{} `json:"data"`
|
||||
UUId string `json:"uuid"`
|
||||
From string `json:"from"`
|
||||
To string `json:"to"`
|
||||
}
|
||||
|
||||
type TranFileModel struct {
|
||||
Hash string `json:"hash"` //Verify current fragment integrity
|
||||
Length int `json:"length"`
|
||||
Index int `json:"index"`
|
||||
}
|
||||
|
||||
//需要获取文件详情
|
||||
type FileDetailModel struct {
|
||||
Path string `json:"path"`
|
||||
}
|
||||
|
||||
//返回文件详情
|
||||
type FileSummaryModel struct {
|
||||
Hash string `json:"hash"` //Verify file
|
||||
Name string `json:"name"`
|
||||
BlockSize int `json:"block_size"`
|
||||
Length int `json:"length"`
|
||||
Size int64 `json:"size"`
|
||||
Message string `json:"message"`
|
||||
}
|
||||
|
||||
type FriendsModel struct {
|
||||
Id uint `gorm:"column:id;primary_key" json:"id"`
|
||||
NickName string `json:"nick_name"`
|
||||
Desc string `json:"desc"`
|
||||
ShareId string `json:"share_id"`
|
||||
}
|
||||
1
model/receive/app.go
Normal file
1
model/receive/app.go
Normal file
@@ -0,0 +1 @@
|
||||
package receive
|
||||
69
model/smartctl_model.go
Normal file
69
model/smartctl_model.go
Normal file
@@ -0,0 +1,69 @@
|
||||
package model
|
||||
|
||||
//
|
||||
type SmartctlA struct {
|
||||
Smartctl struct {
|
||||
Version []int `json:"version"`
|
||||
SvnRevision string `json:"svn_revision"`
|
||||
PlatformInfo string `json:"platform_info"`
|
||||
BuildInfo string `json:"build_info"`
|
||||
Argv []string `json:"argv"`
|
||||
ExitStatus int `json:"exit_status"`
|
||||
} `json:"smartctl"`
|
||||
Device struct {
|
||||
Name string `json:"name"`
|
||||
InfoName string `json:"info_name"`
|
||||
Type string `json:"type"`
|
||||
Protocol string `json:"protocol"`
|
||||
} `json:"device"`
|
||||
ModelName string `json:"model_name"`
|
||||
SerialNumber string `json:"serial_number"`
|
||||
FirmwareVersion string `json:"firmware_version"`
|
||||
UserCapacity struct {
|
||||
Blocks int `json:"blocks"`
|
||||
Bytes int64 `json:"bytes"`
|
||||
} `json:"user_capacity"`
|
||||
SmartStatus struct {
|
||||
Passed bool `json:"passed"`
|
||||
} `json:"smart_status"`
|
||||
AtaSmartData struct {
|
||||
OfflineDataCollection struct {
|
||||
Status struct {
|
||||
Value int `json:"value"`
|
||||
String string `json:"string"`
|
||||
} `json:"status"`
|
||||
CompletionSeconds int `json:"completion_seconds"`
|
||||
} `json:"offline_data_collection"`
|
||||
SelfTest struct {
|
||||
Status struct {
|
||||
Value int `json:"value"`
|
||||
String string `json:"string"`
|
||||
Passed bool `json:"passed"`
|
||||
} `json:"status"`
|
||||
PollingMinutes struct {
|
||||
Short int `json:"short"`
|
||||
Extended int `json:"extended"`
|
||||
Conveyance int `json:"conveyance"`
|
||||
} `json:"polling_minutes"`
|
||||
} `json:"self_test"`
|
||||
Capabilities struct {
|
||||
Values []int `json:"values"`
|
||||
ExecOfflineImmediateSupported bool `json:"exec_offline_immediate_supported"`
|
||||
OfflineIsAbortedUponNewCmd bool `json:"offline_is_aborted_upon_new_cmd"`
|
||||
OfflineSurfaceScanSupported bool `json:"offline_surface_scan_supported"`
|
||||
SelfTestsSupported bool `json:"self_tests_supported"`
|
||||
ConveyanceSelfTestSupported bool `json:"conveyance_self_test_supported"`
|
||||
SelectiveSelfTestSupported bool `json:"selective_self_test_supported"`
|
||||
AttributeAutosaveEnabled bool `json:"attribute_autosave_enabled"`
|
||||
ErrorLoggingSupported bool `json:"error_logging_supported"`
|
||||
GpLoggingSupported bool `json:"gp_logging_supported"`
|
||||
} `json:"capabilities"`
|
||||
} `json:"ata_smart_data"`
|
||||
PowerOnTime struct {
|
||||
Hours int `json:"hours"`
|
||||
} `json:"power_on_time"`
|
||||
PowerCycleCount int `json:"power_cycle_count"`
|
||||
Temperature struct {
|
||||
Current int `json:"current"`
|
||||
} `json:"temperature"`
|
||||
}
|
||||
@@ -16,6 +16,9 @@ type UserModel struct {
|
||||
Email string
|
||||
Description string
|
||||
Initialized bool
|
||||
Avatar string
|
||||
NickName string
|
||||
Public string
|
||||
}
|
||||
|
||||
//服务配置
|
||||
@@ -23,6 +26,11 @@ type ServerModel struct {
|
||||
HttpPort string
|
||||
RunMode string
|
||||
ServerApi string
|
||||
LockAccount bool
|
||||
Handshake string
|
||||
Token string
|
||||
UDPPort string
|
||||
USBAutoMount string
|
||||
}
|
||||
|
||||
//服务配置
|
||||
@@ -35,6 +43,7 @@ type APPModel struct {
|
||||
TimeFormat string
|
||||
DateFormat string
|
||||
ProjectPath string
|
||||
RootPath string
|
||||
}
|
||||
|
||||
//公共返回模型
|
||||
@@ -44,13 +53,6 @@ type Result struct {
|
||||
Data interface{} `json:"data" example:"返回结果"`
|
||||
}
|
||||
|
||||
//zeritier相关
|
||||
type ZeroTierModel struct {
|
||||
UserName string
|
||||
PWD string
|
||||
Token string
|
||||
}
|
||||
|
||||
//redis配置文件
|
||||
type RedisModel struct {
|
||||
Host string
|
||||
@@ -64,4 +66,16 @@ type SystemConfig struct {
|
||||
ConfigStr string `json:"config_str"`
|
||||
WidgetList string `json:"widget_list"`
|
||||
ConfigPath string `json:"config_path"`
|
||||
SyncPort string `json:"sync_port"`
|
||||
SyncKey string `json:"sync_key"`
|
||||
Analyse string `json:"analyse"`
|
||||
}
|
||||
|
||||
type CasaOSGlobalVariables struct {
|
||||
AppChange bool
|
||||
}
|
||||
|
||||
type FileSetting struct {
|
||||
ShareDir []string `json:"share_dir" delim:"|"`
|
||||
DownloadDir string `json:"download_dir"`
|
||||
}
|
||||
|
||||
@@ -1,3 +1 @@
|
||||
package model
|
||||
|
||||
|
||||
|
||||
8
model/system_app/sync.go
Normal file
8
model/system_app/sync.go
Normal file
@@ -0,0 +1,8 @@
|
||||
package system_app
|
||||
|
||||
import "encoding/xml"
|
||||
|
||||
type SyncConfig struct {
|
||||
XMLName xml.Name `xml:"configuration"`
|
||||
Key string `xml:"gui>apikey"`
|
||||
}
|
||||
9
model/user.go
Normal file
9
model/user.go
Normal file
@@ -0,0 +1,9 @@
|
||||
package model
|
||||
|
||||
type UserInfo struct {
|
||||
NickName string `json:"nick_name"`
|
||||
Desc string `json:"desc"`
|
||||
ShareId string `json:"share_id"`
|
||||
Avatar string `json:"avatar"`
|
||||
Version int `json:"version,omitempty"`
|
||||
}
|
||||
@@ -4,7 +4,7 @@ import "time"
|
||||
|
||||
type Version struct {
|
||||
Id uint `gorm:"column:id;primary_key" json:"id"`
|
||||
ChangLog string `json:"chang_log"`
|
||||
ChangeLog string `json:"change_log"`
|
||||
Version string `json:"version"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
package model
|
||||
|
||||
type ZeroTierUpData struct {
|
||||
Config ZeroTierConfig `json:"config"`
|
||||
}
|
||||
|
||||
type ZeroTierConfig struct {
|
||||
Private bool `json:"private"`
|
||||
}
|
||||
@@ -1,7 +1,14 @@
|
||||
package model
|
||||
|
||||
import "time"
|
||||
|
||||
type Path struct {
|
||||
Name string `json:"name"`
|
||||
Path string `json:"path"`
|
||||
IsDir bool `json:"is_dir"`
|
||||
Name string `json:"name"` //File name or document name
|
||||
Path string `json:"path"` //Full path to file or folder
|
||||
IsDir bool `json:"is_dir"` //Is it a folder
|
||||
Date time.Time `json:"date"`
|
||||
Size int64 `json:"size"` //File Size
|
||||
Type string `json:"type,omitempty"`
|
||||
Label string `json:"label,omitempty"`
|
||||
Write bool `json:"write"`
|
||||
}
|
||||
|
||||
11
pkg/cache/cache.go
vendored
Normal file
11
pkg/cache/cache.go
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
package cache
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/patrickmn/go-cache"
|
||||
)
|
||||
|
||||
func Init() *cache.Cache {
|
||||
return cache.New(5*time.Minute, 60*time.Second)
|
||||
}
|
||||
@@ -22,17 +22,17 @@ var UserInfo = &model.UserModel{}
|
||||
//用户相关
|
||||
var AppInfo = &model.APPModel{}
|
||||
|
||||
//redis相关配置
|
||||
var RedisInfo = &model.RedisModel{}
|
||||
|
||||
//zerotier相关
|
||||
var ZeroTierInfo = &model.ZeroTierModel{}
|
||||
//var RedisInfo = &model.RedisModel{}
|
||||
|
||||
//server相关
|
||||
var ServerInfo = &model.ServerModel{}
|
||||
|
||||
var SystemConfigInfo = &model.SystemConfig{}
|
||||
|
||||
var CasaOSGlobalVariables = &model.CasaOSGlobalVariables{}
|
||||
|
||||
var FileSettingInfo = &model.FileSetting{}
|
||||
|
||||
var Cfg *ini.File
|
||||
|
||||
//初始化设置,获取系统的部分信息。
|
||||
@@ -52,10 +52,10 @@ func InitSetup(config string) {
|
||||
|
||||
mapTo("user", UserInfo)
|
||||
mapTo("app", AppInfo)
|
||||
mapTo("zerotier", ZeroTierInfo)
|
||||
mapTo("redis", RedisInfo)
|
||||
//mapTo("redis", RedisInfo)
|
||||
mapTo("server", ServerInfo)
|
||||
mapTo("system", SystemConfigInfo)
|
||||
mapTo("file", FileSettingInfo)
|
||||
SystemConfigInfo.ConfigPath = configDir
|
||||
// AppInfo.ProjectPath = getCurrentDirectory() //os.Getwd()
|
||||
|
||||
|
||||
@@ -1,13 +1,30 @@
|
||||
package config
|
||||
|
||||
import "github.com/IceWhaleTech/CasaOS/pkg/utils/file"
|
||||
import (
|
||||
"runtime"
|
||||
|
||||
"github.com/IceWhaleTech/CasaOS/pkg/utils/file"
|
||||
)
|
||||
|
||||
//检查目录是否存在
|
||||
func mkdirDATAAll() {
|
||||
dirArray := [7]string{"/DATA/AppData", "/DATA/Documents", "/DATA/Downloads", "/DATA/Gallery", "/DATA/Media/Movies", "/DATA/Media/TV Shows", "/DATA/Media/Music"}
|
||||
sysType := runtime.GOOS
|
||||
var dirArray []string
|
||||
if sysType == "linux" {
|
||||
dirArray = []string{"/DATA/AppData", "/DATA/Documents", "/DATA/Downloads", "/DATA/Gallery", "/DATA/Media/Movies", "/DATA/Media/TV Shows", "/DATA/Media/Music"}
|
||||
}
|
||||
|
||||
if sysType == "windows" {
|
||||
dirArray = []string{"C:\\CasaOS\\DATA\\AppData", "C:\\CasaOS\\DATA\\Documents", "C:\\CasaOS\\DATA\\Downloads", "C:\\CasaOS\\DATA\\Gallery", "C:\\CasaOS\\DATA\\Media/Movies", "C:\\CasaOS\\DATA\\Media\\TV Shows", "C:\\CasaOS\\DATA\\Media\\Music"}
|
||||
}
|
||||
if sysType == "darwin" {
|
||||
dirArray = []string{"./CasaOS/DATA/AppData", "./CasaOS/DATA/Documents", "./CasaOS/DATA/Downloads", "./CasaOS/DATA/Gallery", "./CasaOS/DATA/Media/Movies", "./CasaOS/DATA/Media/TV Shows", "./CasaOS/DATA/Media/Music"}
|
||||
}
|
||||
|
||||
for _, v := range dirArray {
|
||||
file.IsNotExistMkDir(v)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func UpdateSetup() {
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
package docker
|
||||
|
||||
import "strings"
|
||||
|
||||
func GetDir(id, envName string) string {
|
||||
var path string
|
||||
switch envName {
|
||||
case "/config":
|
||||
path = "/oasis/app_data/" + id + "/"
|
||||
default:
|
||||
//path = "/media"
|
||||
|
||||
if strings.Contains(envName, "$AppID") && len(id) > 0 {
|
||||
return strings.ReplaceAll(envName, "$AppID", id)
|
||||
}
|
||||
return path
|
||||
return envName
|
||||
}
|
||||
|
||||
10
pkg/docker/volumes_test.go
Normal file
10
pkg/docker/volumes_test.go
Normal file
@@ -0,0 +1,10 @@
|
||||
package docker
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestGetDir(t *testing.T) {
|
||||
fmt.Println(GetDir("", "config"))
|
||||
}
|
||||
@@ -6,11 +6,10 @@ import (
|
||||
"golang.org/x/oauth2"
|
||||
)
|
||||
|
||||
|
||||
func GetGithubClient() *github.Client {
|
||||
ctx := context.Background()
|
||||
ts := oauth2.StaticTokenSource(
|
||||
&oauth2.Token{AccessToken: "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"},
|
||||
&oauth2.Token{AccessToken: ""},
|
||||
)
|
||||
tc := oauth2.NewClient(ctx, ts)
|
||||
client := github.NewClient(tc)
|
||||
|
||||
51
pkg/quic_helper/config.go
Normal file
51
pkg/quic_helper/config.go
Normal file
@@ -0,0 +1,51 @@
|
||||
package quic_helper
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"crypto/rsa"
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"encoding/pem"
|
||||
"math/big"
|
||||
|
||||
"github.com/lucas-clemente/quic-go"
|
||||
)
|
||||
|
||||
// Setup a bare-bones TLS config for the server
|
||||
func GetGenerateTLSConfig(token string) *tls.Config {
|
||||
key, err := rsa.GenerateKey(rand.Reader, 1024)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
template := x509.Certificate{SerialNumber: big.NewInt(1)}
|
||||
certDER, err := x509.CreateCertificate(rand.Reader, &template, &template, &key.PublicKey, key)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
keyPEM := pem.EncodeToMemory(&pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(key)})
|
||||
certPEM := pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: certDER})
|
||||
|
||||
tlsCert, err := tls.X509KeyPair(certPEM, keyPEM)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return &tls.Config{
|
||||
Certificates: []tls.Certificate{tlsCert},
|
||||
NextProtos: []string{token},
|
||||
SessionTicketsDisabled: true,
|
||||
}
|
||||
}
|
||||
func GetClientTlsConfig(otherToken string) *tls.Config {
|
||||
return &tls.Config{
|
||||
InsecureSkipVerify: true,
|
||||
NextProtos: []string{otherToken},
|
||||
SessionTicketsDisabled: true,
|
||||
}
|
||||
}
|
||||
|
||||
func GetQUICConfig() *quic.Config {
|
||||
return &quic.Config{
|
||||
ConnectionIDLength: 4,
|
||||
KeepAlive: true,
|
||||
}
|
||||
}
|
||||
@@ -2,24 +2,25 @@ package sqlite
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/IceWhaleTech/CasaOS/pkg/utils/file"
|
||||
model2 "github.com/IceWhaleTech/CasaOS/service/model"
|
||||
"gorm.io/driver/sqlite"
|
||||
"gorm.io/gorm"
|
||||
"time"
|
||||
)
|
||||
|
||||
var gdb *gorm.DB
|
||||
|
||||
func GetDb(projectPath string) *gorm.DB {
|
||||
func GetDb(dbPath string) *gorm.DB {
|
||||
if gdb != nil {
|
||||
return gdb
|
||||
}
|
||||
// 参考 https://github.com/go-sql-driver/mysql#dsn-data-source-name 获取详情
|
||||
//dsn := fmt.Sprintf("%v:%v@tcp(%v:%v)/%v?charset=utf8mb4&parseTime=True&loc=Local", m.User, m.PWD, m.IP, m.Port, m.DBName)
|
||||
//db, err := gorm.Open(mysql2.Open(dsn), &gorm.Config{})
|
||||
file.IsNotExistMkDir(projectPath + "/db/")
|
||||
db, err := gorm.Open(sqlite.Open(projectPath+"/db/casaOS.db"), &gorm.Config{})
|
||||
file.IsNotExistMkDir(dbPath)
|
||||
db, err := gorm.Open(sqlite.Open(dbPath+"/casaOS.db"), &gorm.Config{})
|
||||
c, _ := db.DB()
|
||||
c.SetMaxIdleConns(10)
|
||||
c.SetMaxOpenConns(100)
|
||||
@@ -30,7 +31,7 @@ func GetDb(projectPath string) *gorm.DB {
|
||||
return nil
|
||||
}
|
||||
gdb = db
|
||||
err = db.AutoMigrate(&model2.TaskDBModel{}, &model2.AppNotify{}, &model2.AppListDBModel{})
|
||||
err = db.AutoMigrate(&model2.TaskDBModel{}, &model2.AppNotify{}, &model2.AppListDBModel{}, &model2.SerialDisk{}, model2.PersonDownloadDBModel{}, model2.FriendModel{}, model2.PersonDownRecordDBModel{}, model2.ApplicationModel{})
|
||||
if err != nil {
|
||||
fmt.Println("检查和创建数据库出错", err)
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
func GetCtrlUrl(host,device string) string {
|
||||
func GetCtrlUrl(host, device string) string {
|
||||
request := ctrlUrlRequest(host, device)
|
||||
response, _ := http.DefaultClient.Do(request)
|
||||
resultBody, _ := ioutil.ReadAll(response.Body)
|
||||
|
||||
@@ -22,21 +22,21 @@ func send() (string, error) {
|
||||
"ST: urn:schemas-upnp-org:service:WANIPConnection:1\r\n" +
|
||||
"MAN: \"ssdp:discover\"\r\n" + "MX: 3\r\n\r\n"
|
||||
var conn *net.UDPConn
|
||||
remotAddr, err := net.ResolveUDPAddr("udp", "239.255.255.250:1900")
|
||||
remoteAddr, err := net.ResolveUDPAddr("udp", "239.255.255.250:1900")
|
||||
if err != nil {
|
||||
return "", errors.New("组播地址格式不正确")
|
||||
}
|
||||
locaAddr, err := net.ResolveUDPAddr("udp", ip_helper2.GetLoclIp()+":")
|
||||
localAddr, err := net.ResolveUDPAddr("udp", ip_helper2.GetLoclIp()+":")
|
||||
|
||||
if err != nil {
|
||||
return "", errors.New("本地ip地址格式不正确")
|
||||
}
|
||||
conn, err = net.ListenUDP("udp", locaAddr)
|
||||
conn, err = net.ListenUDP("udp", localAddr)
|
||||
defer conn.Close()
|
||||
if err != nil {
|
||||
return "", errors.New("监听udp出错")
|
||||
}
|
||||
_, err = conn.WriteToUDP([]byte(str), remotAddr)
|
||||
_, err = conn.WriteToUDP([]byte(str), remoteAddr)
|
||||
if err != nil {
|
||||
return "", errors.New("发送msg到组播地址出错")
|
||||
}
|
||||
|
||||
@@ -2,40 +2,37 @@ package upnp
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"github.com/pkg/errors"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
loger2 "github.com/IceWhaleTech/CasaOS/pkg/utils/loger"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
//
|
||||
////添加一个端口映射
|
||||
func (n *Upnp)AddPortMapping(localPort, remotePort int, protocol string) (err error) {
|
||||
defer func(err error) {
|
||||
func (n *Upnp) AddPortMapping(localPort, remotePort int, protocol string) (err error) {
|
||||
defer func() {
|
||||
if errTemp := recover(); errTemp != nil {
|
||||
//log.Println("upnp模块报错了", errTemp)
|
||||
err = errTemp.(error)
|
||||
loger2.NewOLoger().Error("upnp模块报错了", errTemp)
|
||||
}
|
||||
}(err)
|
||||
if issuccess := addSend(localPort, remotePort, protocol,n.GatewayHost, n.CtrlUrl,n.LocalHost); issuccess {
|
||||
}()
|
||||
|
||||
if isSuccess := addSend(localPort, remotePort, protocol, n.GatewayHost, n.CtrlUrl, n.LocalHost); isSuccess {
|
||||
return nil
|
||||
} else {
|
||||
return errors.New("添加一个端口映射失败")
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func addSend(localPort, remotePort int, protocol, host, ctrUrl,localHost string) bool {
|
||||
request := addRequest(localPort, remotePort, protocol, host, ctrUrl,localHost)
|
||||
func addSend(localPort, remotePort int, protocol, host, ctrUrl, localHost string) bool {
|
||||
request := addRequest(localPort, remotePort, protocol, host, ctrUrl, localHost)
|
||||
response, _ := http.DefaultClient.Do(request)
|
||||
defer response.Body.Close()
|
||||
//resultBody, _ := ioutil.ReadAll(response.Body)
|
||||
//fmt.Println(string(resultBody))
|
||||
if response.StatusCode == 200 {
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
return response.StatusCode == 200
|
||||
}
|
||||
|
||||
type Node struct {
|
||||
@@ -45,7 +42,7 @@ type Node struct {
|
||||
Child []Node
|
||||
}
|
||||
|
||||
func addRequest(localPort, remotePort int, protocol string, gatewayHost, ctlUrl,localHost string) *http.Request {
|
||||
func addRequest(localPort, remotePort int, protocol string, gatewayHost, ctlUrl, localHost string) *http.Request {
|
||||
//请求头
|
||||
header := http.Header{}
|
||||
header.Set("Accept", "text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2")
|
||||
@@ -109,27 +106,25 @@ func (n *Node) BuildXML() string {
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
func (n *Upnp)DelPortMapping(remotePort int, protocol string) bool {
|
||||
issuccess := delSendSend(remotePort, protocol,n.GatewayHost,n.CtrlUrl)
|
||||
if issuccess {
|
||||
func (n *Upnp) DelPortMapping(remotePort int, protocol string) bool {
|
||||
isSuccess := delSendSend(remotePort, protocol, n.GatewayHost, n.CtrlUrl)
|
||||
if isSuccess {
|
||||
//this.MappingPort.delMapping(remotePort, protocol)
|
||||
//fmt.Println("删除了一个端口映射: remote:", remotePort)
|
||||
}
|
||||
return issuccess
|
||||
return isSuccess
|
||||
}
|
||||
|
||||
func delSendSend(remotePort int, protocol,host,ctlUrl string) bool {
|
||||
delrequest := delbuildRequest(remotePort, protocol,host,ctlUrl)
|
||||
func delSendSend(remotePort int, protocol, host, ctlUrl string) bool {
|
||||
delrequest := delbuildRequest(remotePort, protocol, host, ctlUrl)
|
||||
response, _ := http.DefaultClient.Do(delrequest)
|
||||
//resultBody, _ := ioutil.ReadAll(response.Body)
|
||||
defer response.Body.Close()
|
||||
if response.StatusCode == 200 {
|
||||
// log.Println(string(resultBody))
|
||||
return true
|
||||
}
|
||||
return false
|
||||
|
||||
return response.StatusCode == 200
|
||||
}
|
||||
func delbuildRequest(remotePort int, protocol,host,ctlUrl string) *http.Request {
|
||||
|
||||
func delbuildRequest(remotePort int, protocol, host, ctlUrl string) *http.Request {
|
||||
//请求头
|
||||
header := http.Header{}
|
||||
header.Set("Accept", "text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2")
|
||||
|
||||
@@ -23,4 +23,3 @@ func Testaaa() {
|
||||
fmt.Println("gateway ip address: ", upnpMan.Gateway.Host)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,9 +2,11 @@ package command
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"context"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os/exec"
|
||||
"time"
|
||||
)
|
||||
|
||||
func OnlyExec(cmdStr string) {
|
||||
@@ -75,6 +77,7 @@ func ExecResultStr(cmdStr string) string {
|
||||
func ExecLSBLK() []byte {
|
||||
output, err := exec.Command("lsblk", "-O", "-J", "-b").Output()
|
||||
if err != nil {
|
||||
fmt.Println("lsblk", err)
|
||||
return nil
|
||||
}
|
||||
return output
|
||||
@@ -84,7 +87,26 @@ func ExecLSBLK() []byte {
|
||||
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
|
||||
}
|
||||
|
||||
//exec smart
|
||||
func ExecSmartCTLByPath(path string) []byte {
|
||||
timeout := 3
|
||||
ctx, cancel := context.WithTimeout(context.Background(), time.Duration(timeout)*time.Second)
|
||||
defer cancel()
|
||||
output, err := exec.CommandContext(ctx, "smartctl", "-a", path, "-j").Output()
|
||||
if err != nil {
|
||||
fmt.Println("smartctl", err)
|
||||
return nil
|
||||
}
|
||||
return output
|
||||
}
|
||||
|
||||
func ExecEnabledSMART(path string) {
|
||||
|
||||
exec.Command("smartctl", "-s on", path).Output()
|
||||
}
|
||||
|
||||
26
pkg/utils/env_helper/env.go
Normal file
26
pkg/utils/env_helper/env.go
Normal file
@@ -0,0 +1,26 @@
|
||||
package env_helper
|
||||
|
||||
import "strings"
|
||||
|
||||
func ReplaceDefaultENV(key, tz string) string {
|
||||
temp := ""
|
||||
switch key {
|
||||
case "$DefaultPassword":
|
||||
temp = "casaos"
|
||||
case "$DefaultUserName":
|
||||
temp = "admin"
|
||||
|
||||
case "$PUID":
|
||||
temp = "1000"
|
||||
case "$PGID":
|
||||
temp = "1000"
|
||||
case "$TZ":
|
||||
temp = tz
|
||||
}
|
||||
return temp
|
||||
}
|
||||
|
||||
//replace env default setting
|
||||
func ReplaceStringDefaultENV(str string) string {
|
||||
return strings.ReplaceAll(strings.ReplaceAll(str, "$DefaultPassword", ReplaceDefaultENV("$DefaultPassword", "")), "$DefaultUserName", ReplaceDefaultENV("$DefaultUserName", ""))
|
||||
}
|
||||
81
pkg/utils/file/block.go
Normal file
81
pkg/utils/file/block.go
Normal file
@@ -0,0 +1,81 @@
|
||||
package file
|
||||
|
||||
import (
|
||||
"crypto/md5"
|
||||
"encoding/hex"
|
||||
"io"
|
||||
"math"
|
||||
"os"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
// Get info of block
|
||||
func GetBlockInfo(fileSize int64) (blockSize int, length int) {
|
||||
switch {
|
||||
case fileSize <= 1<<28: //256M
|
||||
blockSize = 1 << 17 //128kb
|
||||
case fileSize <= 1<<29: //512M
|
||||
blockSize = 1 << 18 //256kb
|
||||
case fileSize <= 1<<30: //1G
|
||||
blockSize = 1 << 19 //512kb
|
||||
case fileSize <= 1<<31: //2G
|
||||
blockSize = 1 << 20 //(mb)
|
||||
case fileSize <= 1<<32: //4G
|
||||
blockSize = 1 << 21 //2mb
|
||||
case fileSize <= 1<<33: //8G
|
||||
blockSize = 1 << 22 //4mb
|
||||
case fileSize <= 1<<34: //16g
|
||||
blockSize = 1 << 23 //8mb
|
||||
default:
|
||||
blockSize = 1 << 24 //16mb
|
||||
}
|
||||
temp := float64(fileSize) / float64(blockSize)
|
||||
length = int(math.Ceil(temp))
|
||||
return
|
||||
}
|
||||
|
||||
//get the hash of the data
|
||||
func GetHashByContent(data []byte) string {
|
||||
sum := md5.Sum(data)
|
||||
return hex.EncodeToString(sum[:])
|
||||
}
|
||||
|
||||
//get the hash of the data
|
||||
func GetHashByPath(path string) string {
|
||||
pFile, err := os.Open(path)
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
defer pFile.Close()
|
||||
md5h := md5.New()
|
||||
io.Copy(md5h, pFile)
|
||||
return hex.EncodeToString(md5h.Sum(nil))
|
||||
}
|
||||
|
||||
//Comparison data hash
|
||||
func ComparisonHash(data []byte, hash string) bool {
|
||||
sum := md5.Sum(data)
|
||||
return hex.EncodeToString(sum[:]) == hash
|
||||
}
|
||||
|
||||
//get prefix byte length
|
||||
func PrefixLength(byteLength int) []byte {
|
||||
lengthByte := []byte{'0', '0', '0', '0', '0', '0'}
|
||||
bSize := strconv.Itoa(byteLength)
|
||||
cha := 6 - len(bSize)
|
||||
for i := len(bSize); i > 0; i-- {
|
||||
lengthByte[cha+i-1] = bSize[i-1]
|
||||
}
|
||||
return lengthByte
|
||||
}
|
||||
|
||||
//get data byte length
|
||||
func DataLength(length int) []byte {
|
||||
lengthByte := []byte{'0', '0', '0', '0', '0', '0', '0', '0'}
|
||||
bSize := strconv.Itoa(length)
|
||||
cha := 8 - len(bSize)
|
||||
for i := len(bSize); i > 0; i-- {
|
||||
lengthByte[cha+i-1] = bSize[i-1]
|
||||
}
|
||||
return lengthByte
|
||||
}
|
||||
@@ -1,11 +1,17 @@
|
||||
package file
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"mime/multipart"
|
||||
"os"
|
||||
"path"
|
||||
path2 "path"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// GetSize get the file size
|
||||
@@ -35,7 +41,7 @@ func CheckPermission(src string) bool {
|
||||
|
||||
// IsNotExistMkDir create a directory if it does not exist
|
||||
func IsNotExistMkDir(src string) error {
|
||||
if notExist := CheckNotExist(src); notExist == true {
|
||||
if notExist := CheckNotExist(src); notExist {
|
||||
if err := MkDir(src); err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -50,6 +56,7 @@ func MkDir(src string) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
os.Chmod(src, 0777)
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -135,6 +142,21 @@ func CreateFile(path string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func CreateFileAndWriteContent(path string, content string) error {
|
||||
file, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE, 0666)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
defer file.Close()
|
||||
write := bufio.NewWriter(file)
|
||||
|
||||
write.WriteString(content)
|
||||
|
||||
write.Flush()
|
||||
return nil
|
||||
}
|
||||
|
||||
// IsNotExistMkDir create a directory if it does not exist
|
||||
func IsNotExistCreateFile(src string) error {
|
||||
if notExist := CheckNotExist(src); notExist == true {
|
||||
@@ -145,3 +167,168 @@ func IsNotExistCreateFile(src string) error {
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func ReadFullFile(path string) []byte {
|
||||
file, err := os.Open(path)
|
||||
if err != nil {
|
||||
return []byte("")
|
||||
}
|
||||
defer file.Close()
|
||||
content, err := ioutil.ReadAll(file)
|
||||
if err != nil {
|
||||
return []byte("")
|
||||
}
|
||||
return content
|
||||
}
|
||||
|
||||
// File copies a single file from src to dst
|
||||
func CopyFile(src, dst string) error {
|
||||
var err error
|
||||
var srcfd *os.File
|
||||
var dstfd *os.File
|
||||
var srcinfo os.FileInfo
|
||||
|
||||
lastPath := src[strings.LastIndex(src, "/")+1:]
|
||||
|
||||
if !strings.HasSuffix(dst, "/") {
|
||||
dst += "/"
|
||||
}
|
||||
dstPath := dst
|
||||
dst += lastPath
|
||||
for i := 0; Exists(dst); i++ {
|
||||
name := strings.Split(lastPath, ".")
|
||||
nameIndex := 0
|
||||
if len(name) > 2 {
|
||||
nameIndex = len(name) - 2
|
||||
}
|
||||
name[nameIndex] = name[nameIndex] + "(Copy)"
|
||||
dst = dstPath
|
||||
for _, v := range name {
|
||||
dst += v + "."
|
||||
}
|
||||
dst = strings.TrimSuffix(dst, ".")
|
||||
}
|
||||
|
||||
if srcfd, err = os.Open(src); err != nil {
|
||||
return err
|
||||
}
|
||||
defer srcfd.Close()
|
||||
|
||||
if dstfd, err = os.Create(dst); err != nil {
|
||||
return err
|
||||
}
|
||||
defer dstfd.Close()
|
||||
|
||||
if _, err = io.Copy(dstfd, srcfd); err != nil {
|
||||
return err
|
||||
}
|
||||
if srcinfo, err = os.Stat(src); err != nil {
|
||||
return err
|
||||
}
|
||||
return os.Chmod(dst, srcinfo.Mode())
|
||||
}
|
||||
|
||||
//Check for duplicate file names
|
||||
func GetNoDuplicateFileName(fullPath string) string {
|
||||
path, fileName := filepath.Split(fullPath)
|
||||
fileSuffix := path2.Ext(fileName)
|
||||
filenameOnly := strings.TrimSuffix(fileName, fileSuffix)
|
||||
for i := 0; Exists(fullPath); i++ {
|
||||
fullPath = path2.Join(path, filenameOnly+"("+strconv.Itoa(i+1)+")"+fileSuffix)
|
||||
}
|
||||
return fullPath
|
||||
}
|
||||
|
||||
// Dir copies a whole directory recursively
|
||||
func CopyDir(src string, dst string) error {
|
||||
var err error
|
||||
var fds []os.FileInfo
|
||||
var srcinfo os.FileInfo
|
||||
|
||||
if srcinfo, err = os.Stat(src); err != nil {
|
||||
return err
|
||||
}
|
||||
if !srcinfo.IsDir() {
|
||||
if err = CopyFile(src, dst); err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
dstPath := dst
|
||||
lastPath := src[strings.LastIndex(src, "/")+1:]
|
||||
dst += "/" + lastPath
|
||||
for i := 0; Exists(dst); i++ {
|
||||
dst = dstPath + "/" + lastPath + strconv.Itoa(i+1)
|
||||
}
|
||||
if err = os.MkdirAll(dst, srcinfo.Mode()); err != nil {
|
||||
return err
|
||||
}
|
||||
if fds, err = ioutil.ReadDir(src); err != nil {
|
||||
return err
|
||||
}
|
||||
for _, fd := range fds {
|
||||
srcfp := path.Join(src, fd.Name())
|
||||
dstfp := dst //path.Join(dst, fd.Name())
|
||||
|
||||
if fd.IsDir() {
|
||||
if err = CopyDir(srcfp, dstfp); err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
} else {
|
||||
if err = CopyFile(srcfp, dstfp); err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func WriteToPath(data []byte, path, name string) error {
|
||||
fullPath := path
|
||||
if strings.HasSuffix(path, "/") {
|
||||
fullPath += name
|
||||
} else {
|
||||
fullPath += "/" + name
|
||||
}
|
||||
IsNotExistCreateFile(fullPath)
|
||||
file, err := os.OpenFile(fullPath,
|
||||
os.O_WRONLY|os.O_TRUNC|os.O_CREATE,
|
||||
0666,
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer file.Close()
|
||||
_, err = file.Write(data)
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
//最终拼接
|
||||
func SpliceFiles(dir, path string, length int, startPoint int) error {
|
||||
|
||||
fullPath := path
|
||||
|
||||
IsNotExistCreateFile(fullPath)
|
||||
|
||||
file, _ := os.OpenFile(fullPath,
|
||||
os.O_WRONLY|os.O_TRUNC|os.O_CREATE,
|
||||
0666,
|
||||
)
|
||||
defer file.Close()
|
||||
bufferedWriter := bufio.NewWriter(file)
|
||||
for i := 0; i < length+startPoint; i++ {
|
||||
data, err := ioutil.ReadFile(dir + "/" + strconv.Itoa(i+startPoint))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = bufferedWriter.Write(data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
bufferedWriter.Flush()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
84
pkg/utils/file/image.go
Normal file
84
pkg/utils/file/image.go
Normal file
@@ -0,0 +1,84 @@
|
||||
package file
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
|
||||
"github.com/disintegration/imaging"
|
||||
"github.com/dsoprea/go-exif/v3"
|
||||
exifcommon "github.com/dsoprea/go-exif/v3/common"
|
||||
)
|
||||
|
||||
func GetImage(path string, width, height int) ([]byte, error) {
|
||||
if thumbnail, err := GetThumbnailByOwnerPhotos(path); err == nil {
|
||||
return thumbnail, nil
|
||||
} else {
|
||||
return GetThumbnailByWebPhoto(path, width, height)
|
||||
}
|
||||
}
|
||||
func GetThumbnailByOwnerPhotos(path string) ([]byte, error) {
|
||||
file, err := os.Open(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
buff := &bytes.Buffer{}
|
||||
|
||||
defer file.Close()
|
||||
offset := 0
|
||||
offsets := []int{12, 30}
|
||||
|
||||
head := make([]byte, 0xffff)
|
||||
|
||||
r := io.TeeReader(file, buff)
|
||||
_, err = r.Read(head)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, offset = range offsets {
|
||||
if _, err = exif.ParseExifHeader(head[offset:]); err == nil {
|
||||
break
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
im, err := exifcommon.NewIfdMappingWithStandard()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
_, index, err := exif.Collect(im, exif.NewTagIndex(), head[offset:])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ifd := index.RootIfd.NextIfd()
|
||||
if ifd == nil {
|
||||
return nil, exif.ErrNoThumbnail
|
||||
}
|
||||
thumbnail, err := ifd.Thumbnail()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return thumbnail, nil
|
||||
}
|
||||
func GetThumbnailByWebPhoto(path string, width, height int) ([]byte, error) {
|
||||
src, err := imaging.Open(path)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
img := imaging.Resize(src, width, 0, imaging.Lanczos)
|
||||
|
||||
f, err := imaging.FormatFromFilename(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
buf := bytes.Buffer{}
|
||||
imaging.Encode(&buf, img, f)
|
||||
return buf.Bytes(), nil
|
||||
}
|
||||
@@ -2,25 +2,62 @@ package httper
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"github.com/IceWhaleTech/CasaOS/pkg/config"
|
||||
"github.com/tidwall/gjson"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/IceWhaleTech/CasaOS/pkg/config"
|
||||
"github.com/tidwall/gjson"
|
||||
)
|
||||
|
||||
//发送GET请求
|
||||
//url:请求地址
|
||||
//response:请求返回的内容
|
||||
func Get(url string, head map[string]string) (response string) {
|
||||
client := http.Client{Timeout: 30 * time.Second}
|
||||
client := &http.Client{Timeout: 30 * time.Second}
|
||||
req, err := http.NewRequest("GET", url, nil)
|
||||
req.BasicAuth()
|
||||
|
||||
for k, v := range head {
|
||||
req.Header.Add(k, v)
|
||||
}
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
//需要错误日志的处理
|
||||
//loger.Error(error)
|
||||
return ""
|
||||
//panic(error)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
var buffer [512]byte
|
||||
result := bytes.NewBuffer(nil)
|
||||
for {
|
||||
n, err := resp.Body.Read(buffer[0:])
|
||||
result.Write(buffer[0:n])
|
||||
if err != nil && err == io.EOF {
|
||||
break
|
||||
} else if err != nil {
|
||||
//loger.Error(err)
|
||||
return ""
|
||||
// panic(err)
|
||||
}
|
||||
}
|
||||
response = result.String()
|
||||
return
|
||||
}
|
||||
|
||||
//发送GET请求
|
||||
//url:请求地址
|
||||
//response:请求返回的内容
|
||||
func PersonGet(url string) (response string) {
|
||||
client := &http.Client{Timeout: 5 * time.Second}
|
||||
req, err := http.NewRequest("GET", url, nil)
|
||||
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
@@ -52,10 +89,13 @@ func Get(url string, head map[string]string) (response string) {
|
||||
//发送POST请求
|
||||
//url:请求地址,data:POST请求提交的数据,contentType:请求体格式,如:application/json
|
||||
//content:请求放回的内容
|
||||
func Post(url string, data interface{}, contentType string) (content string) {
|
||||
jsonStr, _ := json.Marshal(data)
|
||||
req, err := http.NewRequest("POST", url, bytes.NewBuffer(jsonStr))
|
||||
func Post(url string, data []byte, contentType string, head map[string]string) (content string) {
|
||||
|
||||
req, err := http.NewRequest("POST", url, bytes.NewBuffer(data))
|
||||
req.Header.Add("content-type", contentType)
|
||||
for k, v := range head {
|
||||
req.Header.Add(k, v)
|
||||
}
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
@@ -63,97 +103,16 @@ func Post(url string, data interface{}, contentType string) (content string) {
|
||||
client := &http.Client{Timeout: 5 * time.Second}
|
||||
resp, error := client.Do(req)
|
||||
if error != nil {
|
||||
panic(error)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
result, _ := ioutil.ReadAll(resp.Body)
|
||||
content = string(result)
|
||||
fmt.Println(error)
|
||||
return
|
||||
}
|
||||
|
||||
//发送POST请求
|
||||
//url:请求地址,data:POST请求提交的数据,contentType:请求体格式,如:application/json
|
||||
//content:请求放回的内容
|
||||
func ZeroTierPost(url string, data map[string]string, head map[string]string, cookies []*http.Cookie) (content string, code int) {
|
||||
b, _ := json.Marshal(data)
|
||||
req, err := http.NewRequest("POST", url, bytes.NewReader(b))
|
||||
for _, cookie := range cookies {
|
||||
req.AddCookie(cookie)
|
||||
}
|
||||
for k, v := range head {
|
||||
req.Header.Add(k, v)
|
||||
}
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
client := &http.Client{Timeout: 20 * time.Second}
|
||||
resp, error := client.Do(req)
|
||||
|
||||
if error != nil {
|
||||
panic(error)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
code = resp.StatusCode
|
||||
|
||||
result, _ := ioutil.ReadAll(resp.Body)
|
||||
content = string(result)
|
||||
return
|
||||
}
|
||||
|
||||
//发送POST请求
|
||||
//url:请求地址,data:POST请求提交的数据,contentType:请求体格式,如:application/json
|
||||
//content:请求放回的内容
|
||||
func ZeroTierPostJson(url string, data string, head map[string]string) (content string, code int) {
|
||||
var postData *bytes.Buffer
|
||||
|
||||
jsonStr := []byte(data)
|
||||
postData = bytes.NewBuffer(jsonStr)
|
||||
|
||||
req, err := http.NewRequest("POST", url, postData)
|
||||
for k, v := range head {
|
||||
req.Header.Add(k, v)
|
||||
}
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
client := &http.Client{Timeout: 20 * time.Second}
|
||||
resp, error := client.Do(req)
|
||||
|
||||
if error != nil {
|
||||
panic(error)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
result, _ := ioutil.ReadAll(resp.Body)
|
||||
content = string(result)
|
||||
code = resp.StatusCode
|
||||
return
|
||||
}
|
||||
|
||||
func ZeroTierDelete(url string, head map[string]string) (content string, code int) {
|
||||
|
||||
req, err := http.NewRequest("DELETE", url, nil)
|
||||
for k, v := range head {
|
||||
req.Header.Add(k, v)
|
||||
}
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
client := &http.Client{Timeout: 20 * time.Second}
|
||||
resp, error := client.Do(req)
|
||||
|
||||
if error != nil {
|
||||
panic(error)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
result, _ := ioutil.ReadAll(resp.Body)
|
||||
content = string(result)
|
||||
code = resp.StatusCode
|
||||
return
|
||||
}
|
||||
|
||||
//发送POST请求
|
||||
//url:请求地址,data:POST请求提交的数据,contentType:请求体格式,如:application/json
|
||||
//content:请求放回的内容
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
package utils
|
||||
@@ -1,9 +1,10 @@
|
||||
package ip_helper
|
||||
|
||||
import (
|
||||
httper2 "github.com/IceWhaleTech/CasaOS/pkg/utils/httper"
|
||||
"net"
|
||||
"strings"
|
||||
|
||||
httper2 "github.com/IceWhaleTech/CasaOS/pkg/utils/httper"
|
||||
)
|
||||
|
||||
func IsIPv4(address string) bool {
|
||||
@@ -39,3 +40,35 @@ func GetLoclIp() string {
|
||||
}
|
||||
return "127.0.0.1"
|
||||
}
|
||||
func GetDeviceAllIP(port string) []string {
|
||||
var address []string
|
||||
addrs, err := net.InterfaceAddrs()
|
||||
if err != nil {
|
||||
return address
|
||||
}
|
||||
for _, a := range addrs {
|
||||
if ipNet, ok := a.(*net.IPNet); ok && !ipNet.IP.IsLoopback() {
|
||||
if ipNet.IP.To16() != nil {
|
||||
address = append(address, ipNet.IP.String()+":"+port)
|
||||
}
|
||||
}
|
||||
}
|
||||
return address
|
||||
}
|
||||
|
||||
func HasLocalIP(ip net.IP) bool {
|
||||
if ip.IsLoopback() {
|
||||
return true
|
||||
}
|
||||
ip.String()
|
||||
|
||||
ip4 := ip.To4()
|
||||
if ip4 == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
return ip4[0] == 10 || // 10.0.0.0/8
|
||||
(ip4[0] == 172 && ip4[1] >= 16 && ip4[1] <= 31) || // 172.16.0.0/12
|
||||
(ip4[0] == 169 && ip4[1] == 254) || // 169.254.0.0/16
|
||||
(ip4[0] == 192 && ip4[1] == 168) // 192.168.0.0/16
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package ip_helper
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"testing"
|
||||
)
|
||||
|
||||
@@ -20,3 +21,7 @@ func TestGetExternalIPV6(t *testing.T) {
|
||||
func TestGetLoclIp(t *testing.T) {
|
||||
fmt.Println(GetLoclIp())
|
||||
}
|
||||
func TestHasLocalIP(t *testing.T) {
|
||||
fmt.Println("dddd")
|
||||
fmt.Println(HasLocalIP(net.ParseIP("192.168.2.10")))
|
||||
}
|
||||
|
||||
30
pkg/utils/network_detection.go
Normal file
30
pkg/utils/network_detection.go
Normal file
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* @Author: LinkLeong a624669980@163.com
|
||||
* @Date: 2022-05-08 14:58:46
|
||||
* @LastEditors: LinkLeong a624669980@163.com
|
||||
* @LastEditTime: 2022-05-09 13:42:26
|
||||
* @FilePath: /CasaOS/pkg/utils/network_detection.go
|
||||
* @Description:
|
||||
*
|
||||
* Copyright (c) 2022 by LinkLeong a624669980@163.com, All Rights Reserved.
|
||||
*/
|
||||
package utils
|
||||
|
||||
import natType "github.com/Curtis-Milo/nat-type-identifier-go"
|
||||
|
||||
/**
|
||||
* @description:
|
||||
* @param {chanstring} data
|
||||
* @param {string} url
|
||||
* @return {*}
|
||||
*/
|
||||
func GetNetWorkTypeDetection(data chan string, url string) {
|
||||
// fmt.Println("url:", url)
|
||||
// httper.Get(url, nil)
|
||||
// aaa <- url
|
||||
result, err := natType.GetDeterminedNatType(true, 5, url)
|
||||
if err == nil {
|
||||
data <- result
|
||||
}
|
||||
|
||||
}
|
||||
29
pkg/utils/network_detection_test.go
Normal file
29
pkg/utils/network_detection_test.go
Normal file
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* @Author: LinkLeong a624669980@163.com
|
||||
* @Date: 2022-05-08 15:07:31
|
||||
* @LastEditors: LinkLeong a624669980@163.com
|
||||
* @LastEditTime: 2022-05-09 11:43:30
|
||||
* @FilePath: /CasaOS/pkg/utils/network_detection_test.go
|
||||
* @Description:
|
||||
*
|
||||
* Copyright (c) 2022 by LinkLeong a624669980@163.com, All Rights Reserved.
|
||||
*/
|
||||
|
||||
package utils
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestGetResultTest(t *testing.T) {
|
||||
list := []string{"https://www.google.com", "https://www.bing.com", "https://www.baidu.com"}
|
||||
data := make(chan string)
|
||||
//data <- "init"
|
||||
for _, v := range list {
|
||||
go GetNetWorkTypeDetection(data, v)
|
||||
}
|
||||
result := <-data
|
||||
close(data)
|
||||
fmt.Println(result)
|
||||
}
|
||||
@@ -11,56 +11,98 @@ const (
|
||||
PWD_IS_EMPTY = 10002
|
||||
|
||||
PWD_INVALID_OLD = 10003
|
||||
ACCOUNT_LOCK = 10004
|
||||
//system
|
||||
DIR_ALREADY_EXISTS = 20001
|
||||
FILE_ALREADY_EXISTS = 20002
|
||||
FILE_OR_DIR_EXISTS = 20003
|
||||
PORT_IS_OCCUPIED = 20004
|
||||
COMMAND_ERROR_INVALID_OPERATION = 20005
|
||||
|
||||
//zerotier
|
||||
GET_TOKEN_ERROR = 30001
|
||||
|
||||
//disk
|
||||
NAME_NOT_AVAILABLE = 40001
|
||||
DISK_NEEDS_FORMAT = 40002
|
||||
DISK_BUSYING = 40003
|
||||
REMOVE_MOUNT_POINT_ERROR = 40004
|
||||
FORMAT_ERROR = 40005
|
||||
|
||||
//app
|
||||
UNINSTALL_APP_ERROR = 50001
|
||||
PULL_IMAGE_ERROR = 50002
|
||||
DEVICE_NOT_EXIST = 50003
|
||||
ERROR_APP_NAME_EXIST = 50004
|
||||
|
||||
//file
|
||||
FILE_DOES_NOT_EXIST = 60001
|
||||
FILE_READ_ERROR = 60002
|
||||
FILE_DELETE_ERROR = 60003
|
||||
DIR_NOT_EXISTS = 60004
|
||||
|
||||
//shortcuts
|
||||
SHORTCUTS_URL_ERROR = 70001
|
||||
|
||||
//person
|
||||
PERSON_REMOTE_ERROR = 80001
|
||||
PERSON_DOWN_NOT_EXIST = 80002
|
||||
PERSON_EXIST_DOWNLOAD = 80003
|
||||
PERSON_NOT_EXIST_USER = 80004
|
||||
PERSON_EXIST_FRIEND = 80005
|
||||
PERSON_MYSELF = 80006
|
||||
)
|
||||
|
||||
var MsgFlags = map[int]string{
|
||||
SUCCESS: "ok",
|
||||
ERROR: "fail",
|
||||
INVALID_PARAMS: "Invalid params",
|
||||
ERROR_AUTH_TOKEN: "error auth token",
|
||||
INVALID_PARAMS: "Parameters Error",
|
||||
ERROR_AUTH_TOKEN: "Error auth token",
|
||||
|
||||
//user
|
||||
PWD_INVALID: "Password invalid",
|
||||
PWD_INVALID: "Invalid password",
|
||||
PWD_IS_EMPTY: "Password is empty",
|
||||
PWD_INVALID_OLD: "Old Password invalid",
|
||||
PWD_INVALID_OLD: "Invalid old password",
|
||||
ACCOUNT_LOCK: "Account is locked",
|
||||
|
||||
//system
|
||||
DIR_ALREADY_EXISTS: "Directory already exists",
|
||||
DIR_ALREADY_EXISTS: "Folder already exists",
|
||||
FILE_ALREADY_EXISTS: "File already exists",
|
||||
FILE_OR_DIR_EXISTS: "File or directory already exists",
|
||||
FILE_OR_DIR_EXISTS: "File or folder already exists",
|
||||
PORT_IS_OCCUPIED: "Port is occupied",
|
||||
|
||||
//zerotier
|
||||
GET_TOKEN_ERROR: "Get token error,Please log in to zerotier's official website to confirm whether the account is available",
|
||||
|
||||
//app
|
||||
UNINSTALL_APP_ERROR: "uninstall app error",
|
||||
PULL_IMAGE_ERROR: "pull image error",
|
||||
DEVICE_NOT_EXIST: "device not exist",
|
||||
UNINSTALL_APP_ERROR: "Error uninstalling app",
|
||||
PULL_IMAGE_ERROR: "Error pulling image",
|
||||
DEVICE_NOT_EXIST: "Device does not exist",
|
||||
ERROR_APP_NAME_EXIST: "App name already exists",
|
||||
|
||||
//disk
|
||||
NAME_NOT_AVAILABLE: "Name not available",
|
||||
DISK_NEEDS_FORMAT: "Drive needs to be formatted",
|
||||
REMOVE_MOUNT_POINT_ERROR: "Failed to remove mount point",
|
||||
DISK_BUSYING: "Drive is busy",
|
||||
FORMAT_ERROR: "Formatting failed, please check if the directory is occupied",
|
||||
|
||||
//
|
||||
FILE_DOES_NOT_EXIST: "file does not exist",
|
||||
FILE_DOES_NOT_EXIST: "File does not exist",
|
||||
|
||||
FILE_READ_ERROR: "file read error",
|
||||
SHORTCUTS_URL_ERROR: "url error",
|
||||
DIR_NOT_EXISTS: "Directory does not exist",
|
||||
|
||||
FILE_READ_ERROR: "File read error",
|
||||
FILE_DELETE_ERROR: "Delete error",
|
||||
SHORTCUTS_URL_ERROR: "URL error",
|
||||
|
||||
PERSON_REMOTE_ERROR: "Remote connection error",
|
||||
PERSON_DOWN_NOT_EXIST: "Download record does not exist",
|
||||
PERSON_EXIST_DOWNLOAD: "The same download task exists",
|
||||
PERSON_EXIST_FRIEND: "Friend already exist",
|
||||
PERSON_NOT_EXIST_USER: "User does not exist",
|
||||
PERSON_MYSELF: "You can not add yourself",
|
||||
COMMAND_ERROR_INVALID_OPERATION: "invalid operation",
|
||||
}
|
||||
|
||||
//获取错误信息
|
||||
|
||||
@@ -47,6 +47,7 @@ func IsPortAvailable(port int, t string) bool {
|
||||
uc, err := net.ListenUDP("udp", sadd)
|
||||
|
||||
if err != nil {
|
||||
fmt.Println(err.Error())
|
||||
return false
|
||||
} else {
|
||||
defer uc.Close()
|
||||
|
||||
@@ -6,5 +6,5 @@ import (
|
||||
)
|
||||
|
||||
func TestRandomString(t *testing.T) {
|
||||
fmt.Println(RandomString(6,true))
|
||||
fmt.Println(RandomString(6, true))
|
||||
}
|
||||
@@ -1,73 +0,0 @@
|
||||
package sort
|
||||
|
||||
import (
|
||||
"github.com/IceWhaleTech/CasaOS/model"
|
||||
"sort"
|
||||
)
|
||||
|
||||
// 数据集类型, 与上一篇排序文章(多字段单独排序)比较, less字段的数据类型不再是 func(p1, p2 *Change) bool
|
||||
// 而是 []func(p1, p2 *Change) bool 因为在第一个比较的值相等的情况下, 还要比较第二个值, 所以这里需要多个比较函数
|
||||
type devSorter struct {
|
||||
dev []model.Devices
|
||||
less []lessFuncDev
|
||||
}
|
||||
|
||||
// sort接口方法之一(Less)
|
||||
type lessFuncDev func(p1, p2 *model.Devices) bool
|
||||
|
||||
// Sort 函数有两个作用
|
||||
// 第一, 将参数(实际的数据集)赋值给ms对象
|
||||
// 第二, 调用内置sort函数进行排序操作
|
||||
func (ms *devSorter) Sort(dev []model.Devices) {
|
||||
ms.dev = dev
|
||||
sort.Sort(ms)
|
||||
}
|
||||
|
||||
// OrderedBy 函数的作用是返回一个multiSorter实例, 并将所有的实际排序函数赋值给实例的less字段,
|
||||
// 上面已经为multiSorter结构体定义了Sort方法, 所以该函数的返回值可以直接调用Sort方法进行排序
|
||||
// 该函数中, 为multiSorter结构体中的less字段赋值, Sort方法中又将实际数据集传入, 赋值给multiSorter的ports字段
|
||||
// 一个函数, 一个方法调用过后, multiSorter实例中两个字段就已经全部被正确赋值, 可以调用系统sort函数进行排序
|
||||
// 该函数也可看作是一个工厂方法, 用来生成less字段已经被赋值的multiSorter实例
|
||||
func DevSort(less ...lessFuncDev) *devSorter {
|
||||
return &devSorter{
|
||||
less: less,
|
||||
}
|
||||
}
|
||||
|
||||
// Len 为sort接口方法之一
|
||||
func (ms *devSorter) Len() int {
|
||||
return len(ms.dev)
|
||||
}
|
||||
|
||||
// Swap 为sort接口方法之一
|
||||
func (ms *devSorter) Swap(i, j int) {
|
||||
ms.dev[i], ms.dev[j] = ms.dev[j], ms.dev[i]
|
||||
}
|
||||
|
||||
// Less 为sort接口方法之一
|
||||
func (ms *devSorter) Less(i, j int) bool {
|
||||
temp := ms.dev
|
||||
p, q := &temp[i], &temp[j]
|
||||
// Try all but the last comparison.
|
||||
var k int
|
||||
// 由于可能有多个需要排序的字段, 也就对应了多个less函数, 当第一个字段的值相等时,
|
||||
// 需要依次尝试比对后续其他字段的值得大小, 所以这里需要获取比较函数的长度, 以便遍历比较
|
||||
for k = 0; k < len(ms.less)-1; k++ {
|
||||
// 提取比较函数, 将函数赋值到新的变量中以便调用
|
||||
less := ms.less[k]
|
||||
switch {
|
||||
case less(p, q):
|
||||
// 如果 p < q, 返回值为true, 不存在两个值相等需要比较后续字段的情况, 所以这里直接返回
|
||||
// 如果 p > q, 返回值为false, 则调到下一个case中处理
|
||||
return true
|
||||
case less(q, p):
|
||||
// 如果 p > q, 返回值为false, 不存在两个值相等需要比较后续字段的情况, 所以这里直接返回
|
||||
return false
|
||||
}
|
||||
// 如果代码走到这里, 说明ms.less[k]函数比较后 p == q; 重新开始下一次循环, 更换到下一个比较函数处理
|
||||
continue
|
||||
}
|
||||
// 如果代码走到这里, 说明所有的比较函数执行过后, 所有比较的值都相等
|
||||
// 直接返回最后一次的比较结果数据即可
|
||||
return ms.less[k](p, q)
|
||||
}
|
||||
@@ -1,73 +0,0 @@
|
||||
package sort
|
||||
|
||||
import (
|
||||
"github.com/IceWhaleTech/CasaOS/model"
|
||||
"sort"
|
||||
)
|
||||
|
||||
// 数据集类型, 与上一篇排序文章(多字段单独排序)比较, less字段的数据类型不再是 func(p1, p2 *Change) bool
|
||||
// 而是 []func(p1, p2 *Change) bool 因为在第一个比较的值相等的情况下, 还要比较第二个值, 所以这里需要多个比较函数
|
||||
type evnSorter struct {
|
||||
evn []model.Envs
|
||||
less []lessFuncEnv
|
||||
}
|
||||
|
||||
// sort接口方法之一(Less)
|
||||
type lessFuncEnv func(p1, p2 *model.Envs) bool
|
||||
|
||||
// Sort 函数有两个作用
|
||||
// 第一, 将参数(实际的数据集)赋值给ms对象
|
||||
// 第二, 调用内置sort函数进行排序操作
|
||||
func (ms *evnSorter) Sort(env []model.Envs) {
|
||||
ms.evn = env
|
||||
sort.Sort(ms)
|
||||
}
|
||||
|
||||
// OrderedBy 函数的作用是返回一个multiSorter实例, 并将所有的实际排序函数赋值给实例的less字段,
|
||||
// 上面已经为multiSorter结构体定义了Sort方法, 所以该函数的返回值可以直接调用Sort方法进行排序
|
||||
// 该函数中, 为multiSorter结构体中的less字段赋值, Sort方法中又将实际数据集传入, 赋值给multiSorter的ports字段
|
||||
// 一个函数, 一个方法调用过后, multiSorter实例中两个字段就已经全部被正确赋值, 可以调用系统sort函数进行排序
|
||||
// 该函数也可看作是一个工厂方法, 用来生成less字段已经被赋值的multiSorter实例
|
||||
func EnvSort(less ...lessFuncEnv) *evnSorter {
|
||||
return &evnSorter{
|
||||
less: less,
|
||||
}
|
||||
}
|
||||
|
||||
// Len 为sort接口方法之一
|
||||
func (ms *evnSorter) Len() int {
|
||||
return len(ms.evn)
|
||||
}
|
||||
|
||||
// Swap 为sort接口方法之一
|
||||
func (ms *evnSorter) Swap(i, j int) {
|
||||
ms.evn[i], ms.evn[j] = ms.evn[j], ms.evn[i]
|
||||
}
|
||||
|
||||
// Less 为sort接口方法之一
|
||||
func (ms *evnSorter) Less(i, j int) bool {
|
||||
temp := ms.evn
|
||||
p, q := &temp[i], &temp[j]
|
||||
// Try all but the last comparison.
|
||||
var k int
|
||||
// 由于可能有多个需要排序的字段, 也就对应了多个less函数, 当第一个字段的值相等时,
|
||||
// 需要依次尝试比对后续其他字段的值得大小, 所以这里需要获取比较函数的长度, 以便遍历比较
|
||||
for k = 0; k < len(ms.less)-1; k++ {
|
||||
// 提取比较函数, 将函数赋值到新的变量中以便调用
|
||||
less := ms.less[k]
|
||||
switch {
|
||||
case less(p, q):
|
||||
// 如果 p < q, 返回值为true, 不存在两个值相等需要比较后续字段的情况, 所以这里直接返回
|
||||
// 如果 p > q, 返回值为false, 则调到下一个case中处理
|
||||
return true
|
||||
case less(q, p):
|
||||
// 如果 p > q, 返回值为false, 不存在两个值相等需要比较后续字段的情况, 所以这里直接返回
|
||||
return false
|
||||
}
|
||||
// 如果代码走到这里, 说明ms.less[k]函数比较后 p == q; 重新开始下一次循环, 更换到下一个比较函数处理
|
||||
continue
|
||||
}
|
||||
// 如果代码走到这里, 说明所有的比较函数执行过后, 所有比较的值都相等
|
||||
// 直接返回最后一次的比较结果数据即可
|
||||
return ms.less[k](p, q)
|
||||
}
|
||||
@@ -1,73 +0,0 @@
|
||||
package sort
|
||||
|
||||
import (
|
||||
"github.com/IceWhaleTech/CasaOS/model"
|
||||
"sort"
|
||||
)
|
||||
|
||||
// 数据集类型, 与上一篇排序文章(多字段单独排序)比较, less字段的数据类型不再是 func(p1, p2 *Change) bool
|
||||
// 而是 []func(p1, p2 *Change) bool 因为在第一个比较的值相等的情况下, 还要比较第二个值, 所以这里需要多个比较函数
|
||||
type multiSorter struct {
|
||||
ports []model.Ports
|
||||
less []lessFunc
|
||||
}
|
||||
|
||||
// sort接口方法之一(Less)
|
||||
type lessFunc func(p1, p2 *model.Ports) bool
|
||||
|
||||
// Sort 函数有两个作用
|
||||
// 第一, 将参数(实际的数据集)赋值给ms对象
|
||||
// 第二, 调用内置sort函数进行排序操作
|
||||
func (ms *multiSorter) Sort(ports []model.Ports) {
|
||||
ms.ports = ports
|
||||
sort.Sort(ms)
|
||||
}
|
||||
|
||||
// OrderedBy 函数的作用是返回一个multiSorter实例, 并将所有的实际排序函数赋值给实例的less字段,
|
||||
// 上面已经为multiSorter结构体定义了Sort方法, 所以该函数的返回值可以直接调用Sort方法进行排序
|
||||
// 该函数中, 为multiSorter结构体中的less字段赋值, Sort方法中又将实际数据集传入, 赋值给multiSorter的ports字段
|
||||
// 一个函数, 一个方法调用过后, multiSorter实例中两个字段就已经全部被正确赋值, 可以调用系统sort函数进行排序
|
||||
// 该函数也可看作是一个工厂方法, 用来生成less字段已经被赋值的multiSorter实例
|
||||
func PortsSort(less ...lessFunc) *multiSorter {
|
||||
return &multiSorter{
|
||||
less: less,
|
||||
}
|
||||
}
|
||||
|
||||
// Len 为sort接口方法之一
|
||||
func (ms *multiSorter) Len() int {
|
||||
return len(ms.ports)
|
||||
}
|
||||
|
||||
// Swap 为sort接口方法之一
|
||||
func (ms *multiSorter) Swap(i, j int) {
|
||||
ms.ports[i], ms.ports[j] = ms.ports[j], ms.ports[i]
|
||||
}
|
||||
|
||||
// Less 为sort接口方法之一
|
||||
func (ms *multiSorter) Less(i, j int) bool {
|
||||
port := ms.ports
|
||||
p, q := &port[i], &port[j]
|
||||
// Try all but the last comparison.
|
||||
var k int
|
||||
// 由于可能有多个需要排序的字段, 也就对应了多个less函数, 当第一个字段的值相等时,
|
||||
// 需要依次尝试比对后续其他字段的值得大小, 所以这里需要获取比较函数的长度, 以便遍历比较
|
||||
for k = 0; k < len(ms.less)-1; k++ {
|
||||
// 提取比较函数, 将函数赋值到新的变量中以便调用
|
||||
less := ms.less[k]
|
||||
switch {
|
||||
case less(p, q):
|
||||
// 如果 p < q, 返回值为true, 不存在两个值相等需要比较后续字段的情况, 所以这里直接返回
|
||||
// 如果 p > q, 返回值为false, 则调到下一个case中处理
|
||||
return true
|
||||
case less(q, p):
|
||||
// 如果 p > q, 返回值为false, 不存在两个值相等需要比较后续字段的情况, 所以这里直接返回
|
||||
return false
|
||||
}
|
||||
// 如果代码走到这里, 说明ms.less[k]函数比较后 p == q; 重新开始下一次循环, 更换到下一个比较函数处理
|
||||
continue
|
||||
}
|
||||
// 如果代码走到这里, 说明所有的比较函数执行过后, 所有比较的值都相等
|
||||
// 直接返回最后一次的比较结果数据即可
|
||||
return ms.less[k](p, q)
|
||||
}
|
||||
@@ -1,73 +0,0 @@
|
||||
package sort
|
||||
|
||||
import (
|
||||
"github.com/IceWhaleTech/CasaOS/model"
|
||||
"sort"
|
||||
)
|
||||
|
||||
// 数据集类型, 与上一篇排序文章(多字段单独排序)比较, less字段的数据类型不再是 func(p1, p2 *Change) bool
|
||||
// 而是 []func(p1, p2 *Change) bool 因为在第一个比较的值相等的情况下, 还要比较第二个值, 所以这里需要多个比较函数
|
||||
type volSorter struct {
|
||||
vol []model.Volume
|
||||
less []lessFuncVol
|
||||
}
|
||||
|
||||
// sort接口方法之一(Less)
|
||||
type lessFuncVol func(p1, p2 *model.Volume) bool
|
||||
|
||||
// Sort 函数有两个作用
|
||||
// 第一, 将参数(实际的数据集)赋值给ms对象
|
||||
// 第二, 调用内置sort函数进行排序操作
|
||||
func (ms *volSorter) Sort(vol []model.Volume) {
|
||||
ms.vol = vol
|
||||
sort.Sort(ms)
|
||||
}
|
||||
|
||||
// OrderedBy 函数的作用是返回一个multiSorter实例, 并将所有的实际排序函数赋值给实例的less字段,
|
||||
// 上面已经为multiSorter结构体定义了Sort方法, 所以该函数的返回值可以直接调用Sort方法进行排序
|
||||
// 该函数中, 为multiSorter结构体中的less字段赋值, Sort方法中又将实际数据集传入, 赋值给multiSorter的ports字段
|
||||
// 一个函数, 一个方法调用过后, multiSorter实例中两个字段就已经全部被正确赋值, 可以调用系统sort函数进行排序
|
||||
// 该函数也可看作是一个工厂方法, 用来生成less字段已经被赋值的multiSorter实例
|
||||
func VolSort(less ...lessFuncVol) *volSorter {
|
||||
return &volSorter{
|
||||
less: less,
|
||||
}
|
||||
}
|
||||
|
||||
// Len 为sort接口方法之一
|
||||
func (ms *volSorter) Len() int {
|
||||
return len(ms.vol)
|
||||
}
|
||||
|
||||
// Swap 为sort接口方法之一
|
||||
func (ms *volSorter) Swap(i, j int) {
|
||||
ms.vol[i], ms.vol[j] = ms.vol[j], ms.vol[i]
|
||||
}
|
||||
|
||||
// Less 为sort接口方法之一
|
||||
func (ms *volSorter) Less(i, j int) bool {
|
||||
temp := ms.vol
|
||||
p, q := &temp[i], &temp[j]
|
||||
// Try all but the last comparison.
|
||||
var k int
|
||||
// 由于可能有多个需要排序的字段, 也就对应了多个less函数, 当第一个字段的值相等时,
|
||||
// 需要依次尝试比对后续其他字段的值得大小, 所以这里需要获取比较函数的长度, 以便遍历比较
|
||||
for k = 0; k < len(ms.less)-1; k++ {
|
||||
// 提取比较函数, 将函数赋值到新的变量中以便调用
|
||||
less := ms.less[k]
|
||||
switch {
|
||||
case less(p, q):
|
||||
// 如果 p < q, 返回值为true, 不存在两个值相等需要比较后续字段的情况, 所以这里直接返回
|
||||
// 如果 p > q, 返回值为false, 则调到下一个case中处理
|
||||
return true
|
||||
case less(q, p):
|
||||
// 如果 p > q, 返回值为false, 不存在两个值相等需要比较后续字段的情况, 所以这里直接返回
|
||||
return false
|
||||
}
|
||||
// 如果代码走到这里, 说明ms.less[k]函数比较后 p == q; 重新开始下一次循环, 更换到下一个比较函数处理
|
||||
continue
|
||||
}
|
||||
// 如果代码走到这里, 说明所有的比较函数执行过后, 所有比较的值都相等
|
||||
// 直接返回最后一次的比较结果数据即可
|
||||
return ms.less[k](p, q)
|
||||
}
|
||||
@@ -37,6 +37,31 @@ func IsNeedUpdate() (bool, model.Version) {
|
||||
return false, version
|
||||
}
|
||||
|
||||
func IsClientNeedUpdate() (bool, model.Version) {
|
||||
var version model.Version
|
||||
v := httper.OasisGet(config.ServerInfo.ServerApi + "/v1/sys/client/version")
|
||||
data := gjson.Get(v, "data")
|
||||
json2.Unmarshal([]byte(data.String()), &version)
|
||||
|
||||
v1 := strings.Split(version.Version, ".")
|
||||
v2 := strings.Split(types.CURRENTVERSION, ".")
|
||||
|
||||
for len(v1) < len(v2) {
|
||||
v1 = append(v1, "0")
|
||||
}
|
||||
for len(v2) < len(v1) {
|
||||
v2 = append(v2, "0")
|
||||
}
|
||||
for i := 0; i < len(v1); i++ {
|
||||
a, _ := strconv.Atoi(v1[i])
|
||||
b, _ := strconv.Atoi(v2[i])
|
||||
if a > b {
|
||||
return true, version
|
||||
}
|
||||
}
|
||||
return false, version
|
||||
}
|
||||
|
||||
//a版本大于b版本
|
||||
func VersionCompared(a string, b string) bool {
|
||||
v1 := strings.Split(a, ".")
|
||||
|
||||
@@ -1,47 +0,0 @@
|
||||
package zerotier
|
||||
|
||||
import (
|
||||
httper2 "github.com/IceWhaleTech/CasaOS/pkg/utils/httper"
|
||||
"github.com/tidwall/gjson"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
func PostData(url, token string, data string) interface{} {
|
||||
|
||||
body, code := httper2.ZeroTierPostJson(url, data, GetHead(token))
|
||||
|
||||
if code != http.StatusOK {
|
||||
return ""
|
||||
}
|
||||
result := gjson.Parse(body)
|
||||
return result.Value()
|
||||
}
|
||||
|
||||
func GetData(url, token string) interface{} {
|
||||
|
||||
body, code := httper2.ZeroTierGet(url, GetHead(token))
|
||||
|
||||
if code != http.StatusOK {
|
||||
return ""
|
||||
}
|
||||
result := gjson.Parse(body)
|
||||
return result.Value()
|
||||
}
|
||||
|
||||
func DeleteMember(url, token string) interface{} {
|
||||
|
||||
body, code := httper2.ZeroTierDelete(url, GetHead(token))
|
||||
|
||||
if code != http.StatusOK {
|
||||
return ""
|
||||
}
|
||||
result := gjson.Parse(body)
|
||||
return result.Value()
|
||||
}
|
||||
|
||||
func GetHead(token string) map[string]string {
|
||||
var head = make(map[string]string)
|
||||
head["Authorization"] = "Bearer " + token
|
||||
head["Content-Type"] = "application/json"
|
||||
return head
|
||||
}
|
||||
298
route/init.go
Normal file
298
route/init.go
Normal file
@@ -0,0 +1,298 @@
|
||||
package route
|
||||
|
||||
import (
|
||||
"encoding/xml"
|
||||
"fmt"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/IceWhaleTech/CasaOS/model"
|
||||
"github.com/IceWhaleTech/CasaOS/model/system_app"
|
||||
"github.com/IceWhaleTech/CasaOS/pkg/config"
|
||||
"github.com/IceWhaleTech/CasaOS/pkg/utils/command"
|
||||
"github.com/IceWhaleTech/CasaOS/pkg/utils/env_helper"
|
||||
"github.com/IceWhaleTech/CasaOS/pkg/utils/file"
|
||||
"github.com/IceWhaleTech/CasaOS/pkg/utils/port"
|
||||
"github.com/IceWhaleTech/CasaOS/service"
|
||||
model2 "github.com/IceWhaleTech/CasaOS/service/model"
|
||||
uuid "github.com/satori/go.uuid"
|
||||
)
|
||||
|
||||
func InitFunction() {
|
||||
go checkSystemApp()
|
||||
Update2_3()
|
||||
CheckSerialDiskMount()
|
||||
|
||||
CheckToken2_11()
|
||||
ImportApplications()
|
||||
ChangeAPIUrl()
|
||||
InitSystemApplication()
|
||||
|
||||
}
|
||||
|
||||
var syncIsExistence = false
|
||||
|
||||
func installSyncthing(appId string) {
|
||||
|
||||
var appInfo model.ServerAppList
|
||||
m := model.CustomizationPostData{}
|
||||
var dockerImage string
|
||||
var dockerImageVersion string
|
||||
appInfo = service.MyService.Casa().GetServerAppInfo(appId, "system", "us_en")
|
||||
dockerImage = appInfo.Image
|
||||
dockerImageVersion = appInfo.ImageVersion
|
||||
|
||||
if len(appInfo.ImageVersion) == 0 {
|
||||
dockerImageVersion = "latest"
|
||||
}
|
||||
|
||||
if appInfo.NetworkModel != "host" {
|
||||
for i := 0; i < len(appInfo.Ports); i++ {
|
||||
if p, _ := strconv.Atoi(appInfo.Ports[i].ContainerPort); port.IsPortAvailable(p, appInfo.Ports[i].Protocol) {
|
||||
appInfo.Ports[i].CommendPort = strconv.Itoa(p)
|
||||
} else {
|
||||
if appInfo.Ports[i].Protocol == "tcp" {
|
||||
if p, err := port.GetAvailablePort("tcp"); err == nil {
|
||||
appInfo.Ports[i].CommendPort = strconv.Itoa(p)
|
||||
}
|
||||
} else if appInfo.Ports[i].Protocol == "upd" {
|
||||
if p, err := port.GetAvailablePort("udp"); err == nil {
|
||||
appInfo.Ports[i].CommendPort = strconv.Itoa(p)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if appInfo.Ports[i].Type == 0 {
|
||||
appInfo.PortMap = appInfo.Ports[i].CommendPort
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for i := 0; i < len(appInfo.Devices); i++ {
|
||||
if !file.CheckNotExist(appInfo.Devices[i].ContainerPath) {
|
||||
appInfo.Devices[i].Path = appInfo.Devices[i].ContainerPath
|
||||
}
|
||||
}
|
||||
if len(appInfo.Tip) > 0 {
|
||||
appInfo.Tip = env_helper.ReplaceStringDefaultENV(appInfo.Tip)
|
||||
}
|
||||
|
||||
appInfo.MaxMemory = service.MyService.ZiMa().GetMemInfo().Total >> 20
|
||||
|
||||
id := uuid.NewV4().String()
|
||||
|
||||
installLog := model2.AppNotify{}
|
||||
|
||||
// step:下载镜像
|
||||
err := service.MyService.Docker().DockerPullImage(dockerImage+":"+dockerImageVersion, installLog)
|
||||
if err != nil {
|
||||
//pull image error
|
||||
fmt.Println("pull image error", err, dockerImage, dockerImageVersion)
|
||||
return
|
||||
}
|
||||
for !service.MyService.Docker().IsExistImage(dockerImage + ":" + dockerImageVersion) {
|
||||
time.Sleep(time.Second)
|
||||
}
|
||||
|
||||
m.CpuShares = 50
|
||||
m.Envs = appInfo.Envs
|
||||
m.Memory = int64(appInfo.MaxMemory)
|
||||
m.Origin = "system"
|
||||
m.PortMap = appInfo.PortMap
|
||||
m.Ports = appInfo.Ports
|
||||
m.Restart = "always"
|
||||
m.Volumes = appInfo.Volumes
|
||||
m.Label = id
|
||||
m.CustomId = id
|
||||
containerId, err := service.MyService.Docker().DockerContainerCreate(dockerImage+":"+dockerImageVersion, m, appInfo.NetworkModel)
|
||||
if err != nil {
|
||||
fmt.Println("container create error", err)
|
||||
// create container error
|
||||
return
|
||||
}
|
||||
|
||||
//step:start container
|
||||
err = service.MyService.Docker().DockerContainerStart(containerId)
|
||||
if err != nil {
|
||||
//start container error
|
||||
return
|
||||
}
|
||||
|
||||
checkSystemApp()
|
||||
}
|
||||
|
||||
// check if the system application is installed
|
||||
func checkSystemApp() {
|
||||
list := service.MyService.App().GetSystemAppList()
|
||||
for _, v := range list {
|
||||
info, err := service.MyService.Docker().DockerContainerInfo(v.ID)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
if strings.Contains(info.Config.Image, "linuxserver/syncthing") {
|
||||
if v.State != "running" {
|
||||
//step:start container
|
||||
service.MyService.Docker().DockerContainerStart(v.ID)
|
||||
}
|
||||
syncIsExistence = true
|
||||
if config.SystemConfigInfo.SyncPort != v.Labels["web"] {
|
||||
config.SystemConfigInfo.SyncPort = v.Labels["web"]
|
||||
}
|
||||
|
||||
path := ""
|
||||
for _, i := range info.HostConfig.Mounts {
|
||||
if i.Target == "/config" {
|
||||
path = i.Source
|
||||
|
||||
break
|
||||
}
|
||||
}
|
||||
content := file.ReadFullFile(path + "config.xml")
|
||||
syncConfig := &system_app.SyncConfig{}
|
||||
xml.Unmarshal(content, &syncConfig)
|
||||
config.SystemConfigInfo.SyncKey = syncConfig.Key
|
||||
break
|
||||
}
|
||||
}
|
||||
if !syncIsExistence {
|
||||
installSyncthing("74")
|
||||
}
|
||||
}
|
||||
func CheckSerialDiskMount() {
|
||||
// check mount point
|
||||
dbList := service.MyService.Disk().GetSerialAll()
|
||||
|
||||
list := service.MyService.Disk().LSBLK(true)
|
||||
mountPoint := make(map[string]string, len(dbList))
|
||||
//remount
|
||||
for _, v := range dbList {
|
||||
mountPoint[v.UUID] = v.MountPoint
|
||||
}
|
||||
for _, v := range list {
|
||||
command.ExecEnabledSMART(v.Path)
|
||||
if v.Children != nil {
|
||||
for _, h := range v.Children {
|
||||
if len(h.MountPoint) == 0 && len(v.Children) == 1 && h.FsType == "ext4" {
|
||||
if m, ok := mountPoint[h.UUID]; ok {
|
||||
//mount point check
|
||||
volume := m
|
||||
if !file.CheckNotExist(m) {
|
||||
for i := 0; file.CheckNotExist(volume); i++ {
|
||||
volume = m + strconv.Itoa(i+1)
|
||||
}
|
||||
}
|
||||
service.MyService.Disk().MountDisk(h.Path, volume)
|
||||
if volume != m {
|
||||
ms := model2.SerialDisk{}
|
||||
ms.UUID = v.UUID
|
||||
ms.MountPoint = volume
|
||||
service.MyService.Disk().UpdateMountPoint(ms)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
service.MyService.Disk().RemoveLSBLKCache()
|
||||
command.OnlyExec("source " + config.AppInfo.ProjectPath + "/shell/helper.sh ;AutoRemoveUnuseDir")
|
||||
}
|
||||
func Update2_3() {
|
||||
command.OnlyExec("source " + config.AppInfo.ProjectPath + "/shell/assist.sh")
|
||||
|
||||
}
|
||||
func CheckToken2_11() {
|
||||
if len(config.ServerInfo.Token) == 0 {
|
||||
token := uuid.NewV4().String
|
||||
config.ServerInfo.Token = token()
|
||||
config.Cfg.Section("server").Key("Token").SetValue(token())
|
||||
config.Cfg.SaveTo(config.SystemConfigInfo.ConfigPath)
|
||||
}
|
||||
if len(config.AppInfo.RootPath) == 0 {
|
||||
config.Cfg.Section("app").Key("RootPath").SetValue("/casaOS")
|
||||
config.AppInfo.RootPath = "/casaOS"
|
||||
config.Cfg.SaveTo(config.SystemConfigInfo.ConfigPath)
|
||||
}
|
||||
// if len(config.ServerInfo.Handshake) == 0 {
|
||||
// config.Cfg.Section("app").Key("RootPath").SetValue("/casaOS")
|
||||
// config.AppInfo.RootPath = "/casaOS"
|
||||
// config.Cfg.SaveTo(config.SystemConfigInfo.ConfigPath)
|
||||
// }
|
||||
sysType := runtime.GOOS
|
||||
if len(config.FileSettingInfo.DownloadDir) == 0 {
|
||||
downloadPath := "/DATA/Downloads"
|
||||
if sysType == "windows" {
|
||||
downloadPath = "C:\\CasaOS\\DATA\\Downloads"
|
||||
}
|
||||
if sysType == "darwin" {
|
||||
downloadPath = "./CasaOS/DATA/Downloads"
|
||||
}
|
||||
config.Cfg.Section("file").Key("DownloadDir").SetValue(downloadPath)
|
||||
config.FileSettingInfo.DownloadDir = downloadPath
|
||||
file.IsNotExistMkDir(config.FileSettingInfo.DownloadDir)
|
||||
config.Cfg.SaveTo(config.SystemConfigInfo.ConfigPath)
|
||||
}
|
||||
|
||||
if len(config.UserInfo.Description) == 0 {
|
||||
config.Cfg.Section("user").Key("Description").SetValue("nothing")
|
||||
config.UserInfo.Description = "nothing"
|
||||
config.Cfg.SaveTo(config.SystemConfigInfo.ConfigPath)
|
||||
}
|
||||
if len(config.ServerInfo.Handshake) == 0 {
|
||||
config.Cfg.Section("server").Key("Handshake").SetValue("socket.casaos.io")
|
||||
config.ServerInfo.Handshake = "socket.casaos.io"
|
||||
config.Cfg.SaveTo(config.SystemConfigInfo.ConfigPath)
|
||||
}
|
||||
|
||||
if service.MyService.ZiMa().GetSysInfo().KernelArch == "aarch64" && config.ServerInfo.USBAutoMount != "True" && strings.Contains(service.MyService.ZiMa().GetDeviceTree(), "Raspberry Pi") {
|
||||
service.MyService.System().UpdateUSBAutoMount("False")
|
||||
service.MyService.System().ExecUSBAutoMountShell("False")
|
||||
}
|
||||
|
||||
// str := []string{}
|
||||
// str = append(str, "ddd")
|
||||
// str = append(str, "aaa")
|
||||
// ddd := strings.Join(str, "|")
|
||||
// config.Cfg.Section("file").Key("ShareDir").SetValue(ddd)
|
||||
|
||||
// config.Cfg.SaveTo(config.SystemConfigInfo.ConfigPath)
|
||||
|
||||
}
|
||||
|
||||
func ImportApplications() {
|
||||
service.MyService.App().ImportApplications(true)
|
||||
}
|
||||
|
||||
// 0.3.1
|
||||
func ChangeAPIUrl() {
|
||||
|
||||
newAPIUrl := "https://api.casaos.io/casaos-api"
|
||||
if config.ServerInfo.ServerApi == "https://api.casaos.zimaboard.com" {
|
||||
config.ServerInfo.ServerApi = newAPIUrl
|
||||
config.Cfg.Section("server").Key("ServerApi").SetValue(newAPIUrl)
|
||||
config.Cfg.SaveTo(config.SystemConfigInfo.ConfigPath)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// 0.3.1
|
||||
func InitSystemApplication() {
|
||||
list := service.MyService.App().GetApplicationList()
|
||||
if len(list) != 2 {
|
||||
application := model2.ApplicationModel{}
|
||||
application.Name = "Files"
|
||||
application.Icon = "/ui/img/Files.svg"
|
||||
application.Type = "system"
|
||||
application.Order = 0
|
||||
service.MyService.App().CreateApplication(application)
|
||||
|
||||
application.Name = "CasaConnect"
|
||||
application.Icon = "/ui/img/CasaConnect.svg"
|
||||
application.Type = "system"
|
||||
application.Order = 0
|
||||
|
||||
service.MyService.App().CreateApplication(application)
|
||||
}
|
||||
}
|
||||
167
route/route.go
167
route/route.go
@@ -8,15 +8,19 @@ import (
|
||||
jwt2 "github.com/IceWhaleTech/CasaOS/pkg/utils/jwt"
|
||||
v1 "github.com/IceWhaleTech/CasaOS/route/v1"
|
||||
"github.com/IceWhaleTech/CasaOS/web"
|
||||
"github.com/gin-contrib/gzip"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
var swagHandler gin.HandlerFunc
|
||||
var OnlineDemo bool = false
|
||||
|
||||
func InitRouter() *gin.Engine {
|
||||
|
||||
r := gin.Default()
|
||||
|
||||
r.Use(middleware.Cors())
|
||||
r.Use(gzip.Gzip(gzip.DefaultCompression))
|
||||
gin.SetMode(config.ServerInfo.RunMode)
|
||||
|
||||
r.StaticFS("/ui", http.FS(web.Static))
|
||||
@@ -32,11 +36,13 @@ func InitRouter() *gin.Engine {
|
||||
|
||||
r.GET("/v1/guide/check", v1.GetGuideCheck)
|
||||
|
||||
r.GET("/debug", v1.GetSystemConfigDebug)
|
||||
r.GET("/v1/debug", v1.GetSystemConfigDebug)
|
||||
//set user
|
||||
r.POST("/v1/user/setusernamepwd", v1.Set_Name_Pwd)
|
||||
//get user info
|
||||
r.GET("/v1/user/info", v1.UserInfo)
|
||||
r.GET("/v1/user/info", v1.GetUserInfo)
|
||||
//get user info
|
||||
r.GET("/v1/person/shareid", v1.GetPersonShareId)
|
||||
v1Group := r.Group("/v1")
|
||||
|
||||
v1Group.Use(jwt2.JWT(swagHandler))
|
||||
@@ -46,13 +52,18 @@ func InitRouter() *gin.Engine {
|
||||
{
|
||||
|
||||
//chang head
|
||||
v1UserGroup.POST("/changhead", v1.Up_Load_Head)
|
||||
v1UserGroup.POST("/head", v1.PostUserHead)
|
||||
//chang user name
|
||||
v1UserGroup.PUT("/changusername", v1.Chang_User_Name)
|
||||
v1UserGroup.PUT("/username", v1.PutUserName)
|
||||
//chang pwd
|
||||
v1UserGroup.PUT("/changuserpwd", v1.Chang_User_Pwd)
|
||||
v1UserGroup.PUT("/password", v1.PutUserPwd)
|
||||
//edit user info
|
||||
v1UserGroup.POST("/changuserinfo", v1.Chang_User_Info)
|
||||
v1UserGroup.POST("/info", v1.PostUserChangeInfo)
|
||||
v1UserGroup.PUT("/nick", v1.PutUserChangeNick)
|
||||
v1UserGroup.PUT("/desc", v1.PutUserChangeDesc)
|
||||
v1UserGroup.POST("/person/info", v1.PostUserPersonInfo)
|
||||
|
||||
v1UserGroup.GET("/shareid", v1.GetUserShareID)
|
||||
|
||||
}
|
||||
|
||||
@@ -68,56 +79,10 @@ func InitRouter() *gin.Engine {
|
||||
|
||||
//获取网络信息
|
||||
v1ZiMaGroup.GET("/getnetinfo", v1.NetInfo)
|
||||
//获取网络信息
|
||||
v1ZiMaGroup.GET("/getinfo", v1.Info)
|
||||
|
||||
//获取系统信息
|
||||
v1ZiMaGroup.GET("/sysinfo", v1.SysInfo)
|
||||
}
|
||||
|
||||
v1ZeroTierGroup := v1Group.Group("/zerotier")
|
||||
v1ZeroTierGroup.Use()
|
||||
{
|
||||
//获取zerotier token
|
||||
v1ZeroTierGroup.POST("/login", v1.ZeroTierGetToken)
|
||||
//注册zerotier
|
||||
v1ZeroTierGroup.POST("/register", v1.ZeroTierRegister)
|
||||
//是否需要登录
|
||||
v1ZeroTierGroup.GET("/islogin", v1.ZeroTierIsNeedLogin)
|
||||
//获取网络列表
|
||||
v1ZeroTierGroup.GET("/list", v1.ZeroTierGetNetworkList)
|
||||
//加入网络
|
||||
v1ZeroTierGroup.POST("/join/:id", v1.ZeroTierJoinNetwork)
|
||||
//离开网络
|
||||
v1ZeroTierGroup.POST("/leave/:id", v1.ZeroTierLeaveNetwork)
|
||||
//详情
|
||||
v1ZeroTierGroup.GET("/info/:id", v1.ZeroTierGetNetworkGetInfo)
|
||||
////网络状态
|
||||
//v1ZeroTierGroup.GET("/status", v1.ZeroTierGetNetworkGetStatus)
|
||||
//修改网络类型
|
||||
//v1ZeroTierGroup.PUT("/type/:id", v1.ZeroTierEditType)
|
||||
//修改网络类型
|
||||
//v1ZeroTierGroup.PUT("/name/:id", v1.ZeroTierEditName)
|
||||
//修改v6 assign
|
||||
//v1ZeroTierGroup.PUT("/v6assign/:id", v1.ZeroTierEditV6Assign)
|
||||
//修改 broadcast
|
||||
//v1ZeroTierGroup.PUT("/broadcast/:id", v1.ZeroTierEditBroadcast)
|
||||
//create new network
|
||||
v1ZeroTierGroup.POST("/create", v1.ZeroTierCreateNetwork)
|
||||
//获取用户列表
|
||||
v1ZeroTierGroup.GET("/member/:id", v1.ZeroTierMemberList)
|
||||
//修改用户信息
|
||||
//v1ZeroTierGroup.PUT("/members/:id/auth/:mId", v1.ZeroTierMemberAuth)
|
||||
//修改网络用户name
|
||||
//v1ZeroTierGroup.PUT("/members/:id/name/:mId", v1.ZeroTierMemberName)
|
||||
v1ZeroTierGroup.DELETE("/members/:id/del/:mId", v1.ZeroTierMemberDelete)
|
||||
v1ZeroTierGroup.DELETE("/network/:id/del", v1.ZeroTierDeleteNetwork)
|
||||
//修改网络用户bridge功能
|
||||
//v1ZeroTierGroup.PUT("/members/:id/bridge/:mId", v1.ZeroTierMemberBridge)
|
||||
v1ZeroTierGroup.PUT("/edit/:id", v1.ZeroTierEdit)
|
||||
v1ZeroTierGroup.GET("/joined/list", v1.ZeroTierJoinedList)
|
||||
v1ZeroTierGroup.PUT("/member/:id/edit/:mId", v1.ZeroTierMemberEdit)
|
||||
|
||||
}
|
||||
v1DDNSGroup := v1Group.Group("/ddns")
|
||||
v1DDNSGroup.Use()
|
||||
{
|
||||
@@ -138,7 +103,9 @@ func InitRouter() *gin.Engine {
|
||||
v1AppGroup.Use()
|
||||
{
|
||||
//获取我的已安装的列表
|
||||
v1AppGroup.GET("/mylist", v1.MyAppList)
|
||||
v1AppGroup.GET("/my/list", v1.MyAppList)
|
||||
//
|
||||
v1AppGroup.GET("/usage", v1.AppUsageList)
|
||||
//app详情
|
||||
v1AppGroup.GET("/appinfo/:id", v1.AppInfo)
|
||||
//获取未安装的列表
|
||||
@@ -151,8 +118,8 @@ func InitRouter() *gin.Engine {
|
||||
v1AppGroup.GET("/category", v1.CategoryList)
|
||||
//容器相关
|
||||
v1AppGroup.GET("/terminal/:id", v1.DockerTerminal)
|
||||
//准备安装
|
||||
//v1AppGroup.GET("/ready/:id", v1.ReadyInstall)
|
||||
v1AppGroup.GET("/order", v1.GetAppOrder)
|
||||
v1AppGroup.POST("/order", v1.PostAppOrder)
|
||||
//app容器详情
|
||||
v1AppGroup.GET("/info/:id", v1.ContainerInfo)
|
||||
//app容器日志
|
||||
@@ -173,59 +140,80 @@ func InitRouter() *gin.Engine {
|
||||
v1AppGroup.GET("/update/:id/info", v1.ContainerUpdateInfo)
|
||||
v1AppGroup.GET("/rely/:id/info", v1.ContainerRelyInfo)
|
||||
v1AppGroup.GET("/install/config", v1.GetDockerInstallConfig)
|
||||
//v1AppGroup.POST("/custom/install", v1.CustomInstallApp)
|
||||
|
||||
v1AppGroup.PUT("/update/:id", v1.PutAppUpdate)
|
||||
v1AppGroup.POST("/share", v1.ShareAppFile)
|
||||
}
|
||||
|
||||
v1SysGroup := v1Group.Group("/sys")
|
||||
v1SysGroup.Use()
|
||||
{
|
||||
//获取检查版本是否需要升级
|
||||
v1SysGroup.GET("/check", v1.CheckVersion)
|
||||
v1SysGroup.GET("/hardware/info", v1.GetSystemHardwareInfo)
|
||||
v1SysGroup.GET("/client/version", v1.GetClientVersion)
|
||||
v1SysGroup.POST("/update", v1.SystemUpdate)
|
||||
v1SysGroup.GET("/sys", v1.Sys)
|
||||
v1SysGroup.GET("/wsssh", v1.WsSsh)
|
||||
v1SysGroup.GET("/config", v1.GetSystemConfig)
|
||||
v1SysGroup.GET("/error/logs", v1.GetCasaOSErrorLogs)
|
||||
v1SysGroup.POST("/config", v1.PostSetSystemConfig)
|
||||
v1SysGroup.GET("/widget/config", v1.GetWidgetConfig)
|
||||
v1SysGroup.POST("/widget/config", v1.PostSetWidgetConfig)
|
||||
v1SysGroup.GET("/port", v1.GetCasaOSPort)
|
||||
v1SysGroup.PUT("/port", v1.PutCasaOSPort)
|
||||
v1SysGroup.POST("/kill", v1.PostKillCasaOS)
|
||||
v1SysGroup.GET("/info", v1.Info)
|
||||
v1SysGroup.PUT("/usb/off", v1.PutSystemOffUSBAutoMount)
|
||||
v1SysGroup.PUT("/usb/on", v1.PutSystemOnUSBAutoMount)
|
||||
v1SysGroup.GET("/usb", v1.GetSystemUSBAutoMount)
|
||||
}
|
||||
v1FileGroup := v1Group.Group("/file")
|
||||
v1FileGroup.Use()
|
||||
{
|
||||
//修改文件名称/目录名称
|
||||
v1FileGroup.PUT("/rename", v1.RenamePath)
|
||||
v1FileGroup.GET("/read", v1.GetFilerContent)
|
||||
v1FileGroup.POST("/upload", v1.PostFileUpload)
|
||||
v1FileGroup.GET("/upload", v1.GetFileUpload)
|
||||
v1FileGroup.GET("/dirpath", v1.DirPath)
|
||||
//创建目录
|
||||
//create folder
|
||||
v1FileGroup.POST("/mkdir", v1.MkdirAll)
|
||||
v1FileGroup.POST("/create", v1.PostCreateFile)
|
||||
|
||||
v1FileGroup.GET("/download", v1.GetDownloadFile)
|
||||
v1FileGroup.GET("/new/download", v1.GetFileDownloadNew)
|
||||
v1FileGroup.POST("/operate", v1.PostOperateFileOrDir)
|
||||
v1FileGroup.DELETE("/delete", v1.DeleteFile)
|
||||
v1FileGroup.PUT("/update", v1.PutFileContent)
|
||||
v1FileGroup.GET("/image", v1.GetFileImage)
|
||||
|
||||
//v1FileGroup.GET("/download", v1.UserFileDownloadCommonService)
|
||||
}
|
||||
v1DiskGroup := v1Group.Group("/disk")
|
||||
v1DiskGroup.Use()
|
||||
{
|
||||
//获取磁盘列表
|
||||
v1DiskGroup.GET("/list", v1.GetPlugInDisk)
|
||||
v1DiskGroup.GET("/check", v1.GetDiskCheck)
|
||||
|
||||
v1DiskGroup.GET("/list", v1.GetDiskList)
|
||||
|
||||
//获取磁盘详情
|
||||
v1DiskGroup.GET("/info", v1.GetDiskInfo)
|
||||
|
||||
//格式化磁盘
|
||||
//format storage
|
||||
v1DiskGroup.POST("/format", v1.FormatDisk)
|
||||
|
||||
//添加分区
|
||||
v1DiskGroup.POST("/addpart", v1.AddPartition)
|
||||
// add storage
|
||||
v1DiskGroup.POST("/storage", v1.AddPartition)
|
||||
|
||||
//mount SATA disk
|
||||
v1DiskGroup.POST("/mount", v1.PostMountDisk)
|
||||
|
||||
//umount sata disk
|
||||
v1DiskGroup.POST("/umount", v1.PostDiskUmount)
|
||||
|
||||
//获取可以格式化的内容
|
||||
v1DiskGroup.GET("/type", v1.FormatDiskType)
|
||||
|
||||
//删除分区
|
||||
v1DiskGroup.DELETE("/delpart", v1.RemovePartition)
|
||||
v1DiskGroup.GET("/usb", v1.GetUSBList)
|
||||
|
||||
}
|
||||
v1ShareGroup := v1Group.Group("/share")
|
||||
@@ -246,25 +234,48 @@ func InitRouter() *gin.Engine {
|
||||
v1TaskGroup.PUT("/completion/:id", v1.PutTaskMarkerCompletion)
|
||||
|
||||
}
|
||||
v1ShortcutsGroup := v1Group.Group("/shortcuts")
|
||||
v1ShortcutsGroup.Use()
|
||||
{
|
||||
v1ShortcutsGroup.GET("/list", v1.GetShortcutsList)
|
||||
v1ShortcutsGroup.POST("/add", v1.PostShortcutsAdd)
|
||||
v1ShortcutsGroup.PUT("/edit", v1.PutShortcutsEdit)
|
||||
v1ShortcutsGroup.DELETE("/del/:id", v1.DeleteShortcutsDelete)
|
||||
}
|
||||
|
||||
v1NotifyGroup := v1Group.Group("/notify")
|
||||
v1NotifyGroup.Use()
|
||||
{
|
||||
v1NotifyGroup.GET("/ws", v1.NotifyWS)
|
||||
v1NotifyGroup.PUT("/read/:id", v1.PutNotifyRead)
|
||||
}
|
||||
v1SearchGroup := v1Group.Group("/search")
|
||||
v1SearchGroup.Use()
|
||||
|
||||
v1PersonGroup := v1Group.Group("/person")
|
||||
v1PersonGroup.Use()
|
||||
{
|
||||
v1SearchGroup.GET("/search", v1.GetSearchList)
|
||||
v1PersonGroup.GET("/detection", v1.GetPersonDetection)
|
||||
v1PersonGroup.GET("/users", v1.GetPersonFriend)
|
||||
v1PersonGroup.POST("/user/:shareids", v1.PostAddPersonFriend)
|
||||
v1PersonGroup.DELETE("/user/:shareid", v1.DeletePersonFriend)
|
||||
v1PersonGroup.GET("/directory", v1.GetPersonDirectory)
|
||||
v1PersonGroup.GET("/file", v1.GetPersonFile)
|
||||
v1PersonGroup.GET("/refile/:uuid", v1.GetPersonReFile)
|
||||
v1PersonGroup.PUT("/remarks/:shareid", v1.PutPersonRemarks)
|
||||
v1PersonGroup.GET("/list", v1.GetPersonDownloadList)
|
||||
v1PersonGroup.DELETE("/file/:uuid", v1.DeletePersonDownloadFile)
|
||||
|
||||
v1PersonGroup.POST("/share", v1.PostPersonShare)
|
||||
v1PersonGroup.POST("/file/:shareid", v1.PostPersonFile)
|
||||
v1PersonGroup.GET("/share", v1.GetPersonShare)
|
||||
v1PersonGroup.POST("/down/dir", v1.PostPersonDownDir)
|
||||
v1PersonGroup.GET("/down/dir", v1.GetPersonDownDir)
|
||||
v1PersonGroup.PUT("/block/:shareid", v1.PutPersonBlock)
|
||||
v1PersonGroup.GET("/public", v1.GetPersonPublic)
|
||||
v1PersonGroup.PUT("/friend/:shareid", v1.PutPersonAgreeFriend)
|
||||
v1PersonGroup.PUT("/write/:shareid", v1.PutPersonWrite)
|
||||
v1PersonGroup.GET("/image/thumbnail/:shareid", v1.GetPersonImageThumbnail)
|
||||
|
||||
}
|
||||
v1AnalyseGroup := v1Group.Group("/analyse")
|
||||
v1AnalyseGroup.Use()
|
||||
{
|
||||
v1AnalyseGroup.POST("/app", v1.PostAppAnalyse)
|
||||
}
|
||||
v1Group.GET("/sync/config", v1.GetSyncConfig)
|
||||
v1Group.Any("/syncthing/*url", v1.SyncToSyncthing)
|
||||
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
38
route/v1/analyse.go
Normal file
38
route/v1/analyse.go
Normal file
@@ -0,0 +1,38 @@
|
||||
package v1
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/IceWhaleTech/CasaOS/model"
|
||||
"github.com/IceWhaleTech/CasaOS/pkg/config"
|
||||
oasis_err2 "github.com/IceWhaleTech/CasaOS/pkg/utils/oasis_err"
|
||||
"github.com/IceWhaleTech/CasaOS/service"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
// @Summary post app analyse
|
||||
// @Produce application/json
|
||||
// @Accept multipart/form-data
|
||||
// @Tags analyse
|
||||
// @Param name formData string true "app name"
|
||||
// @Param type formData string true "action" Enums(open,delete)
|
||||
// @Security ApiKeyAuth
|
||||
// @Success 200 {string} string "ok"
|
||||
// @Router /analyse/app [post]
|
||||
func PostAppAnalyse(c *gin.Context) {
|
||||
if config.SystemConfigInfo.Analyse == "False" {
|
||||
c.JSON(http.StatusOK, &model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS)})
|
||||
return
|
||||
}
|
||||
name := c.PostForm("name")
|
||||
t := c.PostForm("type")
|
||||
language := c.GetHeader("Language")
|
||||
|
||||
if len(name) == 0 || len(t) == 0 {
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.INVALID_PARAMS, Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS)})
|
||||
return
|
||||
}
|
||||
|
||||
service.MyService.Casa().PushAppAnalyse(config.ServerInfo.Token, t, name, language)
|
||||
c.JSON(http.StatusOK, &model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS)})
|
||||
}
|
||||
162
route/v1/app.go
162
route/v1/app.go
@@ -1,15 +1,17 @@
|
||||
package v1
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"strconv"
|
||||
|
||||
"github.com/IceWhaleTech/CasaOS/model"
|
||||
"github.com/IceWhaleTech/CasaOS/pkg/utils/file"
|
||||
oasis_err2 "github.com/IceWhaleTech/CasaOS/pkg/utils/oasis_err"
|
||||
port2 "github.com/IceWhaleTech/CasaOS/pkg/utils/port"
|
||||
"github.com/IceWhaleTech/CasaOS/pkg/utils/sort"
|
||||
"github.com/IceWhaleTech/CasaOS/service"
|
||||
"github.com/gin-gonic/gin"
|
||||
"net/http"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
// @Summary 获取远程列表
|
||||
@@ -29,20 +31,34 @@ func AppList(c *gin.Context) {
|
||||
//service.MyService.Docker().DockerContainerCommit("test2")
|
||||
|
||||
index := c.DefaultQuery("index", "1")
|
||||
size := c.DefaultQuery("size", "10")
|
||||
size := c.DefaultQuery("size", "10000")
|
||||
t := c.DefaultQuery("type", "rank")
|
||||
categoryId := c.DefaultQuery("category_id", "0")
|
||||
key := c.DefaultQuery("key", "")
|
||||
list, count := service.MyService.OAPI().GetServerList(index, size, t, categoryId, key)
|
||||
for i := 0; i < len(list); i++ {
|
||||
ct, _ := service.MyService.Docker().DockerListByImage(list[i].Image, list[i].ImageVersion)
|
||||
if ct != nil {
|
||||
list[i].State = ct.State
|
||||
}
|
||||
}
|
||||
data := make(map[string]interface{}, 2)
|
||||
data["count"] = count
|
||||
data["items"] = list
|
||||
language := c.GetHeader("Language")
|
||||
recommend, list, community := service.MyService.Casa().GetServerList(index, size, t, categoryId, key, language)
|
||||
// for i := 0; i < len(recommend); i++ {
|
||||
// ct, _ := service.MyService.Docker().DockerListByImage(recommend[i].Image, recommend[i].ImageVersion)
|
||||
// if ct != nil {
|
||||
// recommend[i].State = ct.State
|
||||
// }
|
||||
// }
|
||||
// for i := 0; i < len(list); i++ {
|
||||
// ct, _ := service.MyService.Docker().DockerListByImage(list[i].Image, list[i].ImageVersion)
|
||||
// if ct != nil {
|
||||
// list[i].State = ct.State
|
||||
// }
|
||||
// }
|
||||
// for i := 0; i < len(community); i++ {
|
||||
// ct, _ := service.MyService.Docker().DockerListByImage(community[i].Image, community[i].ImageVersion)
|
||||
// if ct != nil {
|
||||
// community[i].State = ct.State
|
||||
// }
|
||||
// }
|
||||
data := make(map[string]interface{}, 3)
|
||||
data["recommend"] = recommend
|
||||
data["list"] = list
|
||||
data["community"] = community
|
||||
|
||||
c.JSON(http.StatusOK, &model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: data})
|
||||
}
|
||||
@@ -90,12 +106,29 @@ func PortCheck(c *gin.Context) {
|
||||
// @Param size query int false "size"
|
||||
// @Param position query bool false "是否是首页应用"
|
||||
// @Success 200 {string} string "ok"
|
||||
// @Router /app/mylist [get]
|
||||
// @Router /app/my/list [get]
|
||||
func MyAppList(c *gin.Context) {
|
||||
index, _ := strconv.Atoi(c.DefaultQuery("index", "1"))
|
||||
size, _ := strconv.Atoi(c.DefaultQuery("size", "0"))
|
||||
position, _ := strconv.ParseBool(c.DefaultQuery("position", "true"))
|
||||
list := service.MyService.App().GetMyList(index, size, position)
|
||||
list, unTranslation := service.MyService.App().GetMyList(index, size, position)
|
||||
|
||||
data := make(map[string]interface{}, 2)
|
||||
data["list"] = list
|
||||
data["local"] = unTranslation
|
||||
|
||||
c.JSON(http.StatusOK, &model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: data})
|
||||
}
|
||||
|
||||
// @Summary my app hardware usage list
|
||||
// @Produce application/json
|
||||
// @Accept application/json
|
||||
// @Tags app
|
||||
// @Security ApiKeyAuth
|
||||
// @Success 200 {string} string "ok"
|
||||
// @Router /app/usage [get]
|
||||
func AppUsageList(c *gin.Context) {
|
||||
list := service.MyService.App().GetHardwareUsage()
|
||||
c.JSON(http.StatusOK, &model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: list})
|
||||
}
|
||||
|
||||
@@ -110,51 +143,71 @@ func MyAppList(c *gin.Context) {
|
||||
func AppInfo(c *gin.Context) {
|
||||
|
||||
id := c.Param("id")
|
||||
info := service.MyService.App().GetServerAppInfo(id)
|
||||
language := c.GetHeader("Language")
|
||||
info := service.MyService.Casa().GetServerAppInfo(id, "", language)
|
||||
if info.NetworkModel != "host" {
|
||||
port, _ := port2.GetAvailablePort("tcp")
|
||||
info.PortMap = uint(port)
|
||||
for i := 0; i < len(info.Configures.TcpPorts); i++ {
|
||||
info.Configures.TcpPorts[i].CommendPort, _ = port2.GetAvailablePort("tcp")
|
||||
for i := 0; i < len(info.Ports); i++ {
|
||||
if p, _ := strconv.Atoi(info.Ports[i].ContainerPort); port2.IsPortAvailable(p, info.Ports[i].Protocol) {
|
||||
info.Ports[i].CommendPort = strconv.Itoa(p)
|
||||
} else {
|
||||
if info.Ports[i].Protocol == "tcp" {
|
||||
if p, err := port2.GetAvailablePort("tcp"); err == nil {
|
||||
info.Ports[i].CommendPort = strconv.Itoa(p)
|
||||
}
|
||||
} else if info.Ports[i].Protocol == "upd" {
|
||||
if p, err := port2.GetAvailablePort("udp"); err == nil {
|
||||
info.Ports[i].CommendPort = strconv.Itoa(p)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if info.Ports[i].Type == 0 {
|
||||
info.PortMap = info.Ports[i].CommendPort
|
||||
}
|
||||
for i := 0; i < len(info.Configures.UdpPorts); i++ {
|
||||
info.Configures.UdpPorts[i].CommendPort, _ = port2.GetAvailablePort("udp")
|
||||
}
|
||||
} else {
|
||||
info.PortMap = info.TcpPort
|
||||
for i := 0; i < len(info.Ports); i++ {
|
||||
if info.Ports[i].Type == 0 {
|
||||
info.PortMap = info.Ports[i].ContainerPort
|
||||
break
|
||||
}
|
||||
|
||||
for i := 0; i < len(info.Configures.Devices); i++ {
|
||||
if !file.CheckNotExist(info.Configures.Devices[i].ContainerPath) {
|
||||
info.Configures.Devices[i].Path = info.Configures.Devices[i].ContainerPath
|
||||
}
|
||||
}
|
||||
|
||||
portOrder := func(c1, c2 *model.Ports) bool {
|
||||
return c1.Type < c2.Type
|
||||
for i := 0; i < len(info.Devices); i++ {
|
||||
if !file.CheckNotExist(info.Devices[i].ContainerPath) {
|
||||
info.Devices[i].Path = info.Devices[i].ContainerPath
|
||||
}
|
||||
}
|
||||
// if len(info.Tip) > 0 {
|
||||
// info.Tip = env_helper.ReplaceStringDefaultENV(info.Tip)
|
||||
// }
|
||||
|
||||
envOrder := func(c1, c2 *model.Envs) bool {
|
||||
return c1.Type < c2.Type
|
||||
}
|
||||
// portOrder := func(c1, c2 *model.Ports) bool {
|
||||
// return c1.Type < c2.Type
|
||||
// }
|
||||
|
||||
volOrder := func(c1, c2 *model.Volume) bool {
|
||||
return c1.Type < c2.Type
|
||||
}
|
||||
// envOrder := func(c1, c2 *model.Envs) bool {
|
||||
// return c1.Type < c2.Type
|
||||
// }
|
||||
|
||||
devOrder := func(c1, c2 *model.Devices) bool {
|
||||
return c1.Type < c2.Type
|
||||
}
|
||||
// volOrder := func(c1, c2 *model.Volume) bool {
|
||||
// return c1.Type < c2.Type
|
||||
// }
|
||||
|
||||
// devOrder := func(c1, c2 *model.Devices) bool {
|
||||
// return c1.Type < c2.Type
|
||||
// }
|
||||
|
||||
//sort
|
||||
if info.NetworkModel != "host" {
|
||||
sort.PortsSort(portOrder).Sort(info.Configures.TcpPorts)
|
||||
sort.PortsSort(portOrder).Sort(info.Configures.UdpPorts)
|
||||
}
|
||||
// if info.NetworkModel != "host" {
|
||||
// sort.PortsSort(portOrder).Sort(info.Configures.TcpPorts)
|
||||
// sort.PortsSort(portOrder).Sort(info.Configures.UdpPorts)
|
||||
// }
|
||||
|
||||
sort.EnvSort(envOrder).Sort(info.Configures.Envs)
|
||||
sort.VolSort(volOrder).Sort(info.Configures.Volumes)
|
||||
sort.DevSort(devOrder).Sort(info.Configures.Devices)
|
||||
// sort.EnvSort(envOrder).Sort(info.Envs)
|
||||
// sort.VolSort(volOrder).Sort(info.Volumes.([]model.PathMap))
|
||||
// sort.DevSort(devOrder).Sort(info.Devices)
|
||||
|
||||
info.MaxMemory = service.MyService.ZiMa().GetMemInfo().Total >> 20
|
||||
|
||||
@@ -169,14 +222,27 @@ func AppInfo(c *gin.Context) {
|
||||
// @Success 200 {string} string "ok"
|
||||
// @Router /app/category [get]
|
||||
func CategoryList(c *gin.Context) {
|
||||
list := service.MyService.OAPI().GetServerCategoryList()
|
||||
list := service.MyService.Casa().GetServerCategoryList()
|
||||
var count uint = 0
|
||||
for _, category := range list {
|
||||
count += category.Count
|
||||
}
|
||||
|
||||
rear := append([]model.ServerCategoryList{}, list[0:]...)
|
||||
list = append(list[:0], model.ServerCategoryList{Count: count, Name: "All"})
|
||||
list = append(list[:0], model.ServerCategoryList{Count: count, Name: "All", Font: "apps"})
|
||||
list = append(list, rear...)
|
||||
c.JSON(http.StatusOK, &model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: list})
|
||||
}
|
||||
|
||||
// @Summary 分享该应用配置
|
||||
// @Produce application/json
|
||||
// @Accept application/json
|
||||
// @Tags app
|
||||
// @Security ApiKeyAuth
|
||||
// @Success 200 {string} string "ok"
|
||||
// @Router /app/share [post]
|
||||
func ShareAppFile(c *gin.Context) {
|
||||
str, _ := ioutil.ReadAll(c.Request.Body)
|
||||
content := service.MyService.Casa().ShareAppFile(str)
|
||||
c.JSON(http.StatusOK, json.RawMessage(content))
|
||||
}
|
||||
|
||||
@@ -64,7 +64,7 @@ func DDNSAddConfig(c *gin.Context) {
|
||||
})
|
||||
return
|
||||
}
|
||||
var m model2.DDNSUpdataDBModel
|
||||
var m model2.DDNSUpdateDBModel
|
||||
c.Bind(&m)
|
||||
if err := service.MyService.DDNS().SaveConfig(m); err != nil {
|
||||
c.JSON(http.StatusOK,
|
||||
|
||||
451
route/v1/disk.go
451
route/v1/disk.go
@@ -1,65 +1,163 @@
|
||||
package v1
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/IceWhaleTech/CasaOS/model"
|
||||
"github.com/IceWhaleTech/CasaOS/pkg/config"
|
||||
"github.com/IceWhaleTech/CasaOS/pkg/utils/file"
|
||||
"github.com/IceWhaleTech/CasaOS/pkg/utils/oasis_err"
|
||||
"github.com/IceWhaleTech/CasaOS/service"
|
||||
model2 "github.com/IceWhaleTech/CasaOS/service/model"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/shirou/gopsutil/v3/disk"
|
||||
"net/http"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
// @Summary 获取磁盘列表
|
||||
var diskMap = make(map[string]string)
|
||||
|
||||
// @Summary disk list
|
||||
// @Produce application/json
|
||||
// @Accept application/json
|
||||
// @Tags disk
|
||||
// @Security ApiKeyAuth
|
||||
// @Success 200 {string} string "ok"
|
||||
// @Router /disk/list [get]
|
||||
func GetPlugInDisk(c *gin.Context) {
|
||||
func GetDiskList(c *gin.Context) {
|
||||
list := service.MyService.Disk().LSBLK(false)
|
||||
dbList := service.MyService.Disk().GetSerialAll()
|
||||
part := make(map[string]int64, len(dbList))
|
||||
for _, v := range dbList {
|
||||
part[v.MountPoint] = v.CreatedAt
|
||||
}
|
||||
findSystem := 0
|
||||
|
||||
//ls := service.MyService.Disk().GetPlugInDisk()
|
||||
//fmt.Println(ls)
|
||||
//dd, _ := disk.Partitions(true)
|
||||
//fmt.Println(dd)
|
||||
//
|
||||
//dir, err := ioutil.ReadDir("/sys/block")
|
||||
//if err != nil {
|
||||
// panic(err)
|
||||
//}
|
||||
//
|
||||
//files := make([]string, 0)
|
||||
//
|
||||
////fmt.Println(regexp.MatchString("sd[a-z]*[0-9]", "sda"))
|
||||
//
|
||||
//for _, f := range dir {
|
||||
// if match, _ := regexp.MatchString("sd[a-z]", f.Name()); match {
|
||||
// files = append(files, f.Name())
|
||||
// }
|
||||
//}
|
||||
//fmt.Println(files)
|
||||
//filess := make([]string, 0)
|
||||
//for _, file := range files {
|
||||
// dirs, _ := ioutil.ReadDir("/sys/block/" + file)
|
||||
//
|
||||
// for _, f := range dirs {
|
||||
// if match, _ := regexp.MatchString("sd[a-z]*[0-9]", f.Name()); match {
|
||||
// filess = append(filess, f.Name())
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
//fmt.Println(filess)
|
||||
//
|
||||
//for _, s := range filess {
|
||||
// fmt.Println(disk.Usage("/dev/" + s))
|
||||
//}
|
||||
disks := []model.Drive{}
|
||||
storage := []model.Storage{}
|
||||
avail := []model.Drive{}
|
||||
for i := 0; i < len(list); i++ {
|
||||
disk := model.Drive{}
|
||||
if list[i].Rota {
|
||||
disk.DiskType = "HDD"
|
||||
} else {
|
||||
disk.DiskType = "SSD"
|
||||
}
|
||||
disk.Serial = list[i].Serial
|
||||
disk.Name = list[i].Name
|
||||
disk.Size = list[i].Size
|
||||
disk.Path = list[i].Path
|
||||
disk.Model = list[i].Model
|
||||
|
||||
lst := service.MyService.Disk().LSBLK()
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err.SUCCESS, Message: oasis_err.GetMsg(oasis_err.SUCCESS), Data: lst})
|
||||
if len(list[i].Children) > 0 && findSystem == 0 {
|
||||
for j := 0; j < len(list[i].Children); j++ {
|
||||
if len(list[i].Children[j].Children) > 0 {
|
||||
for _, v := range list[i].Children[j].Children {
|
||||
if v.MountPoint == "/" {
|
||||
stor := model.Storage{}
|
||||
stor.Name = "System"
|
||||
stor.MountPoint = v.MountPoint
|
||||
stor.Size = v.FSSize
|
||||
stor.Avail = v.FSAvail
|
||||
stor.Path = v.Path
|
||||
stor.Type = v.FsType
|
||||
stor.DriveName = "System"
|
||||
disk.Model = "System"
|
||||
if strings.Contains(v.SubSystems, "mmc") {
|
||||
disk.DiskType = "MMC"
|
||||
} else if strings.Contains(v.SubSystems, "usb") {
|
||||
disk.DiskType = "USB"
|
||||
}
|
||||
disk.Health = "true"
|
||||
|
||||
disks = append(disks, disk)
|
||||
storage = append(storage, stor)
|
||||
findSystem = 1
|
||||
break
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if list[i].Children[j].MountPoint == "/" {
|
||||
stor := model.Storage{}
|
||||
stor.Name = "System"
|
||||
stor.MountPoint = list[i].Children[j].MountPoint
|
||||
stor.Size = list[i].Children[j].FSSize
|
||||
stor.Avail = list[i].Children[j].FSAvail
|
||||
stor.Path = list[i].Children[j].Path
|
||||
stor.Type = list[i].Children[j].FsType
|
||||
stor.DriveName = "System"
|
||||
disk.Model = "System"
|
||||
if strings.Contains(list[i].Children[j].SubSystems, "mmc") {
|
||||
disk.DiskType = "MMC"
|
||||
} else if strings.Contains(list[i].Children[j].SubSystems, "usb") {
|
||||
disk.DiskType = "USB"
|
||||
}
|
||||
disk.Health = "true"
|
||||
|
||||
disks = append(disks, disk)
|
||||
storage = append(storage, stor)
|
||||
findSystem = 1
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
if findSystem == 1 {
|
||||
findSystem += 1
|
||||
continue
|
||||
}
|
||||
|
||||
if list[i].Tran == "sata" || list[i].Tran == "nvme" || list[i].Tran == "spi" || list[i].Tran == "sas" {
|
||||
temp := service.MyService.Disk().SmartCTL(list[i].Path)
|
||||
if reflect.DeepEqual(temp, model.SmartctlA{}) {
|
||||
temp.SmartStatus.Passed = true
|
||||
}
|
||||
if len(list[i].Children) == 1 && len(list[i].Children[0].MountPoint) > 0 {
|
||||
stor := model.Storage{}
|
||||
stor.MountPoint = list[i].Children[0].MountPoint
|
||||
stor.Size = list[i].Children[0].FSSize
|
||||
stor.Avail = list[i].Children[0].FSAvail
|
||||
stor.Path = list[i].Children[0].Path
|
||||
stor.Type = list[i].Children[0].FsType
|
||||
stor.DriveName = list[i].Name
|
||||
pathArr := strings.Split(list[i].Children[0].MountPoint, "/")
|
||||
if len(pathArr) == 3 {
|
||||
stor.Name = pathArr[2]
|
||||
}
|
||||
if t, ok := part[list[i].Children[0].MountPoint]; ok {
|
||||
stor.CreatedAt = t
|
||||
}
|
||||
storage = append(storage, stor)
|
||||
} else {
|
||||
//todo 长度有问题
|
||||
if len(list[i].Children) == 1 && list[i].Children[0].FsType == "ext4" {
|
||||
disk.NeedFormat = false
|
||||
avail = append(avail, disk)
|
||||
} else {
|
||||
disk.NeedFormat = true
|
||||
avail = append(avail, disk)
|
||||
}
|
||||
}
|
||||
|
||||
disk.Temperature = temp.Temperature.Current
|
||||
disk.Health = strconv.FormatBool(temp.SmartStatus.Passed)
|
||||
|
||||
disks = append(disks, disk)
|
||||
}
|
||||
}
|
||||
data := make(map[string]interface{}, 3)
|
||||
data["drive"] = disks
|
||||
data["storage"] = storage
|
||||
data["avail"] = avail
|
||||
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err.SUCCESS, Message: oasis_err.GetMsg(oasis_err.SUCCESS), Data: data})
|
||||
}
|
||||
|
||||
// @Summary 获取磁盘列表
|
||||
// @Summary get disk list
|
||||
// @Produce application/json
|
||||
// @Accept application/json
|
||||
// @Tags disk
|
||||
@@ -68,7 +166,7 @@ func GetPlugInDisk(c *gin.Context) {
|
||||
// @Router /disk/lists [get]
|
||||
func GetPlugInDisks(c *gin.Context) {
|
||||
|
||||
list := service.MyService.Disk().LSBLK()
|
||||
list := service.MyService.Disk().LSBLK(true)
|
||||
var result []*disk.UsageStat
|
||||
for _, item := range list {
|
||||
result = append(result, service.MyService.Disk().GetDiskInfoByPath(item.Path))
|
||||
@@ -76,12 +174,12 @@ func GetPlugInDisks(c *gin.Context) {
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err.SUCCESS, Message: oasis_err.GetMsg(oasis_err.SUCCESS), Data: result})
|
||||
}
|
||||
|
||||
// @Summary 磁盘详情
|
||||
// @Summary disk detail
|
||||
// @Produce application/json
|
||||
// @Accept application/json
|
||||
// @Tags disk
|
||||
// @Security ApiKeyAuth
|
||||
// @Param path query string true "要获取的磁盘详情 例如/dev/sda"
|
||||
// @Param path query string true "for example /dev/sda"
|
||||
// @Success 200 {string} string "ok"
|
||||
// @Router /disk/info [get]
|
||||
func GetDiskInfo(c *gin.Context) {
|
||||
@@ -93,31 +191,46 @@ func GetDiskInfo(c *gin.Context) {
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err.SUCCESS, Message: oasis_err.GetMsg(oasis_err.SUCCESS), Data: m})
|
||||
}
|
||||
|
||||
// @Summary 磁盘详情
|
||||
// @Summary format storage
|
||||
// @Produce application/json
|
||||
// @Accept multipart/form-data
|
||||
// @Tags disk
|
||||
// @Security ApiKeyAuth
|
||||
// @Param path formData string true "磁盘路径 例如/dev/sda1"
|
||||
// @Param path formData string true "e.g. /dev/sda1"
|
||||
// @Param pwd formData string true "user password"
|
||||
// @Param volume formData string true "mount point"
|
||||
// @Success 200 {string} string "ok"
|
||||
// @Router /disk/format [post]
|
||||
func FormatDisk(c *gin.Context) {
|
||||
path := c.PostForm("path")
|
||||
t := "ext4"
|
||||
pwd := c.PostForm("pwd")
|
||||
volume := c.PostForm("volume")
|
||||
|
||||
t := c.PostForm("type")
|
||||
if pwd != config.UserInfo.PWD {
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err.PWD_INVALID, Message: oasis_err.GetMsg(oasis_err.PWD_INVALID)})
|
||||
return
|
||||
}
|
||||
|
||||
if len(path) == 0 || len(t) == 0 {
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err.INVALID_PARAMS, Message: oasis_err.GetMsg(oasis_err.INVALID_PARAMS)})
|
||||
return
|
||||
}
|
||||
|
||||
//删除挂载点
|
||||
if _, ok := diskMap[path]; ok {
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err.DISK_BUSYING, Message: oasis_err.GetMsg(oasis_err.DISK_BUSYING)})
|
||||
return
|
||||
}
|
||||
diskMap[path] = "busying"
|
||||
service.MyService.Disk().UmountPointAndRemoveDir(path)
|
||||
|
||||
//格式化磁盘
|
||||
service.MyService.Disk().FormatDisk(path, t)
|
||||
|
||||
//重新挂载
|
||||
|
||||
format := service.MyService.Disk().FormatDisk(path, t)
|
||||
if len(format) == 0 {
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err.FORMAT_ERROR, Message: oasis_err.GetMsg(oasis_err.FORMAT_ERROR)})
|
||||
delete(diskMap, path)
|
||||
return
|
||||
}
|
||||
service.MyService.Disk().MountDisk(path, volume)
|
||||
service.MyService.Disk().RemoveLSBLKCache()
|
||||
delete(diskMap, path)
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err.SUCCESS, Message: oasis_err.GetMsg(oasis_err.SUCCESS)})
|
||||
}
|
||||
|
||||
@@ -154,25 +267,231 @@ func RemovePartition(c *gin.Context) {
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err.SUCCESS, Message: oasis_err.GetMsg(oasis_err.SUCCESS)})
|
||||
}
|
||||
|
||||
// @Summary 添加分区
|
||||
// @Summary add storage
|
||||
// @Produce application/json
|
||||
// @Accept multipart/form-data
|
||||
// @Tags disk
|
||||
// @Security ApiKeyAuth
|
||||
// @Param path formData string true "磁盘路径 例如/dev/sda"
|
||||
// @Param size formData string true "需要分区容量大小(MB)"
|
||||
// @Param num formData string true "磁盘符号"
|
||||
// @Param path formData string true "disk path e.g. /dev/sda"
|
||||
// @Param serial formData string true "serial"
|
||||
// @Param name formData string true "name"
|
||||
// @Param format formData bool true "need format(true)"
|
||||
// @Success 200 {string} string "ok"
|
||||
// @Router /disk/addpart [post]
|
||||
// @Router /disk/storage [post]
|
||||
func AddPartition(c *gin.Context) {
|
||||
name := c.PostForm("name")
|
||||
path := c.PostForm("path")
|
||||
size, _ := strconv.Atoi(c.DefaultPostForm("size", "0"))
|
||||
num := c.DefaultPostForm("num", "9")
|
||||
if len(path) == 0 {
|
||||
format, _ := strconv.ParseBool(c.PostForm("format"))
|
||||
if len(name) == 0 || len(path) == 0 {
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err.INVALID_PARAMS, Message: oasis_err.GetMsg(oasis_err.INVALID_PARAMS)})
|
||||
return
|
||||
}
|
||||
if _, ok := diskMap[path]; ok {
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err.DISK_BUSYING, Message: oasis_err.GetMsg(oasis_err.DISK_BUSYING)})
|
||||
return
|
||||
}
|
||||
if !file.CheckNotExist("/DATA/" + name) {
|
||||
// /mnt/name exist
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err.NAME_NOT_AVAILABLE, Message: oasis_err.GetMsg(oasis_err.NAME_NOT_AVAILABLE)})
|
||||
return
|
||||
}
|
||||
diskMap[path] = "busying"
|
||||
currentDisk := service.MyService.Disk().GetDiskInfo(path)
|
||||
if !format {
|
||||
if len(currentDisk.Children) != 1 || !(len(currentDisk.Children) > 0 && currentDisk.Children[0].FsType == "ext4") {
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err.DISK_NEEDS_FORMAT, Message: oasis_err.GetMsg(oasis_err.DISK_NEEDS_FORMAT)})
|
||||
delete(diskMap, path)
|
||||
return
|
||||
}
|
||||
} else {
|
||||
service.MyService.Disk().AddPartition(path)
|
||||
}
|
||||
|
||||
//size*1024*1024/512
|
||||
service.MyService.Disk().AddPartition(path, num, uint64(size*1024*2))
|
||||
formatBool := true
|
||||
for formatBool {
|
||||
currentDisk = service.MyService.Disk().GetDiskInfo(path)
|
||||
fmt.Println(currentDisk.Children)
|
||||
if len(currentDisk.Children) > 0 {
|
||||
formatBool = false
|
||||
break
|
||||
}
|
||||
time.Sleep(time.Second)
|
||||
}
|
||||
currentDisk = service.MyService.Disk().GetDiskInfo(path)
|
||||
if len(currentDisk.Children) != 1 {
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err.DISK_NEEDS_FORMAT, Message: oasis_err.GetMsg(oasis_err.DISK_NEEDS_FORMAT)})
|
||||
return
|
||||
}
|
||||
|
||||
mountPath := "/DATA/" + name
|
||||
m := model2.SerialDisk{}
|
||||
m.MountPoint = mountPath
|
||||
m.Path = currentDisk.Children[0].Path
|
||||
m.UUID = currentDisk.Children[0].UUID
|
||||
m.State = 0
|
||||
m.CreatedAt = time.Now().Unix()
|
||||
service.MyService.Disk().SaveMountPoint(m)
|
||||
|
||||
//mount dir
|
||||
service.MyService.Disk().MountDisk(currentDisk.Children[0].Path, mountPath)
|
||||
|
||||
service.MyService.Disk().RemoveLSBLKCache()
|
||||
|
||||
delete(diskMap, path)
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err.SUCCESS, Message: oasis_err.GetMsg(oasis_err.SUCCESS)})
|
||||
}
|
||||
|
||||
// @Summary add mount point
|
||||
// @Produce application/json
|
||||
// @Accept multipart/form-data
|
||||
// @Tags disk
|
||||
// @Security ApiKeyAuth
|
||||
// @Param path formData string true "for example: /dev/sda1"
|
||||
// @Param serial formData string true "disk id"
|
||||
// @Success 200 {string} string "ok"
|
||||
// @Router /disk/mount [post]
|
||||
func PostMountDisk(c *gin.Context) {
|
||||
// for example: path=/dev/sda1
|
||||
path := c.PostForm("path")
|
||||
serial := c.PostForm("serial")
|
||||
|
||||
mountPath := "/DATA/volume"
|
||||
var list = service.MyService.Disk().GetSerialAll()
|
||||
var pathMapList = make(map[string]string, len(list))
|
||||
for _, v := range list {
|
||||
pathMapList[v.MountPoint] = "1"
|
||||
}
|
||||
|
||||
for i := 0; i < len(list)+1; i++ {
|
||||
if _, ok := pathMapList[mountPath+strconv.Itoa(i)]; !ok {
|
||||
mountPath = mountPath + strconv.Itoa(i)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
//mount dir
|
||||
service.MyService.Disk().MountDisk(path, mountPath)
|
||||
|
||||
m := model2.SerialDisk{}
|
||||
m.MountPoint = mountPath
|
||||
m.Path = path
|
||||
m.UUID = serial
|
||||
m.State = 0
|
||||
//service.MyService.Disk().SaveMountPoint(m)
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err.SUCCESS, Message: oasis_err.GetMsg(oasis_err.SUCCESS)})
|
||||
}
|
||||
|
||||
// @Summary remove mount point
|
||||
// @Produce application/json
|
||||
// @Accept multipart/form-data
|
||||
// @Tags disk
|
||||
// @Security ApiKeyAuth
|
||||
// @Param path formData string true "e.g. /dev/sda1"
|
||||
// @Param mount_point formData string true "e.g. /mnt/volume1"
|
||||
// @Param pwd formData string true "user password"
|
||||
// @Success 200 {string} string "ok"
|
||||
// @Router /disk/umount [post]
|
||||
func PostDiskUmount(c *gin.Context) {
|
||||
|
||||
path := c.PostForm("path")
|
||||
mountPoint := c.PostForm("volume")
|
||||
pwd := c.PostForm("pwd")
|
||||
|
||||
if len(path) == 0 || len(mountPoint) == 0 {
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err.INVALID_PARAMS, Message: oasis_err.GetMsg(oasis_err.INVALID_PARAMS)})
|
||||
return
|
||||
}
|
||||
if pwd != config.UserInfo.PWD {
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err.PWD_INVALID, Message: oasis_err.GetMsg(oasis_err.PWD_INVALID)})
|
||||
return
|
||||
}
|
||||
|
||||
if _, ok := diskMap[path]; ok {
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err.DISK_BUSYING, Message: oasis_err.GetMsg(oasis_err.DISK_BUSYING)})
|
||||
return
|
||||
}
|
||||
|
||||
service.MyService.Disk().UmountPointAndRemoveDir(path)
|
||||
//delete data
|
||||
service.MyService.Disk().DeleteMountPoint(path, mountPoint)
|
||||
service.MyService.Disk().RemoveLSBLKCache()
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err.SUCCESS, Message: oasis_err.GetMsg(oasis_err.SUCCESS)})
|
||||
}
|
||||
|
||||
// @Summary confirm delete disk
|
||||
// @Produce application/json
|
||||
// @Accept application/json
|
||||
// @Tags disk
|
||||
// @Security ApiKeyAuth
|
||||
// @Param id path string true "id"
|
||||
// @Success 200 {string} string "ok"
|
||||
// @Router /disk/remove/{id} [delete]
|
||||
func DeleteDisk(c *gin.Context) {
|
||||
id := c.Param("id")
|
||||
service.MyService.Disk().DeleteMount(id)
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err.SUCCESS, Message: oasis_err.GetMsg(oasis_err.SUCCESS)})
|
||||
}
|
||||
|
||||
// @Summary check mount point
|
||||
// @Produce application/json
|
||||
// @Accept application/json
|
||||
// @Tags disk
|
||||
// @Security ApiKeyAuth
|
||||
// @Success 200 {string} string "ok"
|
||||
// @Router /disk/init [get]
|
||||
func GetDiskCheck(c *gin.Context) {
|
||||
|
||||
dbList := service.MyService.Disk().GetSerialAll()
|
||||
list := service.MyService.Disk().LSBLK(true)
|
||||
|
||||
mapList := make(map[string]string)
|
||||
|
||||
for _, v := range list {
|
||||
mapList[v.Serial] = "1"
|
||||
}
|
||||
|
||||
for _, v := range dbList {
|
||||
if _, ok := mapList[v.UUID]; !ok {
|
||||
//disk undefind
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err.ERROR, Message: oasis_err.GetMsg(oasis_err.ERROR), Data: "disk undefind"})
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err.SUCCESS, Message: oasis_err.GetMsg(oasis_err.SUCCESS)})
|
||||
}
|
||||
|
||||
// @Summary check mount point
|
||||
// @Produce application/json
|
||||
// @Accept application/json
|
||||
// @Tags disk
|
||||
// @Security ApiKeyAuth
|
||||
// @Success 200 {string} string "ok"
|
||||
// @Router /disk/usb [get]
|
||||
func GetUSBList(c *gin.Context) {
|
||||
list := service.MyService.Disk().LSBLK(false)
|
||||
data := []model.DriveUSB{}
|
||||
for _, v := range list {
|
||||
if v.Tran == "usb" {
|
||||
temp := model.DriveUSB{}
|
||||
temp.Model = v.Model
|
||||
temp.Name = v.Name
|
||||
temp.Size = v.Size
|
||||
mountTemp := true
|
||||
if len(v.Children) == 0 {
|
||||
mountTemp = false
|
||||
}
|
||||
for _, child := range v.Children {
|
||||
if len(child.MountPoint) > 0 {
|
||||
avail, _ := strconv.ParseUint(child.FSAvail, 10, 64)
|
||||
temp.Avail += avail
|
||||
} else {
|
||||
mountTemp = false
|
||||
}
|
||||
}
|
||||
temp.Mount = mountTemp
|
||||
data = append(data, temp)
|
||||
}
|
||||
}
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err.SUCCESS, Message: oasis_err.GetMsg(oasis_err.SUCCESS), Data: data})
|
||||
}
|
||||
|
||||
@@ -2,18 +2,21 @@ package v1
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
json2 "encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/IceWhaleTech/CasaOS/model"
|
||||
"github.com/IceWhaleTech/CasaOS/pkg/config"
|
||||
"github.com/IceWhaleTech/CasaOS/pkg/docker"
|
||||
upnp2 "github.com/IceWhaleTech/CasaOS/pkg/upnp"
|
||||
"github.com/IceWhaleTech/CasaOS/pkg/utils/file"
|
||||
ip_helper2 "github.com/IceWhaleTech/CasaOS/pkg/utils/ip_helper"
|
||||
"github.com/IceWhaleTech/CasaOS/pkg/utils/oasis_err"
|
||||
oasis_err2 "github.com/IceWhaleTech/CasaOS/pkg/utils/oasis_err"
|
||||
port2 "github.com/IceWhaleTech/CasaOS/pkg/utils/port"
|
||||
"github.com/IceWhaleTech/CasaOS/pkg/utils/random"
|
||||
@@ -143,6 +146,7 @@ func SpeedPush(c *gin.Context) {
|
||||
// @Router /app/install/{id} [post]
|
||||
func InstallApp(c *gin.Context) {
|
||||
appId := c.Param("id")
|
||||
language := c.GetHeader("Language")
|
||||
var appInfo model.ServerAppList
|
||||
m := model.CustomizationPostData{}
|
||||
c.BindJSON(&m)
|
||||
@@ -150,6 +154,27 @@ func InstallApp(c *gin.Context) {
|
||||
const CUSTOM = "custom"
|
||||
var dockerImage string
|
||||
var dockerImageVersion string
|
||||
|
||||
//check app name is exist
|
||||
|
||||
if m.Origin != "custom" {
|
||||
oldName := m.Label
|
||||
for i := 0; true; i++ {
|
||||
if i != 0 {
|
||||
m.Label = oldName + "-" + strconv.Itoa(i)
|
||||
}
|
||||
if _, err := service.MyService.Docker().DockerListByName(m.Label); err != nil {
|
||||
break
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if _, err := service.MyService.Docker().DockerListByName(m.Label); err == nil {
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.ERROR_APP_NAME_EXIST, Message: oasis_err2.GetMsg(oasis_err2.ERROR_APP_NAME_EXIST)})
|
||||
return
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//检查端口
|
||||
if len(m.PortMap) > 0 && m.PortMap != "0" {
|
||||
//c.JSON(http.StatusOK, model.Result{Success: oasis_err2.INVALID_PARAMS, Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS)})
|
||||
@@ -172,7 +197,7 @@ func InstallApp(c *gin.Context) {
|
||||
dockerImageVersion = "latest"
|
||||
}
|
||||
if m.Origin != "custom" {
|
||||
appInfo = service.MyService.App().GetServerAppInfo(appId)
|
||||
appInfo = service.MyService.Casa().GetServerAppInfo(appId, "", language)
|
||||
|
||||
} else {
|
||||
|
||||
@@ -216,7 +241,7 @@ func InstallApp(c *gin.Context) {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if m.Origin == "custom" {
|
||||
for _, device := range m.Devices {
|
||||
if file.CheckNotExist(device.Path) {
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.DEVICE_NOT_EXIST, Message: device.Path + "," + oasis_err2.GetMsg(oasis_err2.DEVICE_NOT_EXIST)})
|
||||
@@ -224,6 +249,16 @@ func InstallApp(c *gin.Context) {
|
||||
}
|
||||
|
||||
}
|
||||
} else {
|
||||
dev := []model.PathMap{}
|
||||
for _, device := range dev {
|
||||
if !file.CheckNotExist(device.Path) {
|
||||
dev = append(dev, device)
|
||||
}
|
||||
}
|
||||
m.Devices = dev
|
||||
}
|
||||
|
||||
//restart := c.PostForm("restart") //always 总是重启, unless-stopped 除非用户手动停止容器,否则总是重新启动, on-failure:仅当容器退出代码非零时重新启动
|
||||
//if len(restart) > 0 {
|
||||
//
|
||||
@@ -234,17 +269,18 @@ func InstallApp(c *gin.Context) {
|
||||
//
|
||||
//}
|
||||
id := uuid.NewV4().String()
|
||||
|
||||
m.CustomId = id
|
||||
var relyMap = make(map[string]string)
|
||||
go func() {
|
||||
installLog := model2.AppNotify{}
|
||||
installLog.CustomId = id
|
||||
installLog.State = 0
|
||||
installLog.CustomId = m.Label
|
||||
installLog.Message = "installing rely"
|
||||
installLog.Speed = 10
|
||||
installLog.Class = types.NOTIFY_APP
|
||||
installLog.Type = types.NOTIFY_TYPE_UNIMPORTANT
|
||||
installLog.CreatedAt = strconv.FormatInt(time.Now().Unix(), 10)
|
||||
installLog.UpdatedAt = strconv.FormatInt(time.Now().Unix(), 10)
|
||||
installLog.Id = uuid.NewV4().String()
|
||||
service.MyService.Notify().AddLog(installLog)
|
||||
if m.Origin != "custom" {
|
||||
for _, plugin := range appInfo.Plugins {
|
||||
@@ -266,12 +302,12 @@ func InstallApp(c *gin.Context) {
|
||||
rely.Type = types.RELY_TYPE_MYSQL
|
||||
rely.ContainerId = mysqlContainerId
|
||||
rely.CustomId = mid
|
||||
rely.ContainerCustomId = id
|
||||
var msqlConfig model2.MysqlConfigs
|
||||
rely.ContainerCustomId = m.Label
|
||||
var mysqlConfig model2.MysqlConfigs
|
||||
|
||||
//结构体转换
|
||||
copier.Copy(&msqlConfig, &mc)
|
||||
rely.Config = msqlConfig
|
||||
copier.Copy(&mysqlConfig, &mc)
|
||||
rely.Config = mysqlConfig
|
||||
service.MyService.Rely().Create(rely)
|
||||
|
||||
relyMap["mysql"] = mid
|
||||
@@ -279,16 +315,13 @@ func InstallApp(c *gin.Context) {
|
||||
} else {
|
||||
docker_base.MysqlDelete(mysqlContainerId)
|
||||
installLog.State = 0
|
||||
installLog.Speed = 30
|
||||
installLog.Message = err.Error()
|
||||
service.MyService.Notify().UpdateLog(installLog)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
installLog.Speed = 50
|
||||
installLog.Message = "pulling"
|
||||
service.MyService.Notify().UpdateLog(installLog)
|
||||
|
||||
@@ -296,7 +329,6 @@ func InstallApp(c *gin.Context) {
|
||||
err := service.MyService.Docker().DockerPullImage(dockerImage+":"+dockerImageVersion, installLog)
|
||||
if err != nil {
|
||||
installLog.State = 0
|
||||
installLog.Speed = 70
|
||||
installLog.Message = err.Error()
|
||||
installLog.Type = types.NOTIFY_TYPE_ERROR
|
||||
service.MyService.Notify().UpdateLog(installLog)
|
||||
@@ -322,36 +354,35 @@ func InstallApp(c *gin.Context) {
|
||||
// service.MyService.Notify().UpdateLog(installLog)
|
||||
// return
|
||||
// }
|
||||
containerId, err := service.MyService.Docker().DockerContainerCreate(dockerImage+":"+dockerImageVersion, id, m, appInfo.NetworkModel)
|
||||
installLog.ContainerId = containerId
|
||||
containerId, err := service.MyService.Docker().DockerContainerCreate(dockerImage+":"+dockerImageVersion, m, appInfo.NetworkModel)
|
||||
installLog.Name = appInfo.Title
|
||||
installLog.Icon = appInfo.Icon
|
||||
if err != nil {
|
||||
//service.MyService.Redis().Set(id, "{\"id\"\""+id+"\",\"state\":false,\"message\":\""+err.Error()+"\",\"speed\":80}", 100)
|
||||
installLog.State = 0
|
||||
installLog.Speed = 80
|
||||
installLog.Type = types.NOTIFY_TYPE_ERROR
|
||||
installLog.Message = err.Error()
|
||||
service.MyService.Notify().UpdateLog(installLog)
|
||||
return
|
||||
} else {
|
||||
//service.MyService.Redis().Set(id, "{\"id\":\""+id+"\",\"state\":true,\"message\":\"starting\",\"speed\":80}", 100)
|
||||
installLog.Speed = 80
|
||||
installLog.Message = "starting"
|
||||
service.MyService.Notify().UpdateLog(installLog)
|
||||
}
|
||||
|
||||
// echo -e "hellow\nworld" >>
|
||||
|
||||
//step:启动容器
|
||||
err = service.MyService.Docker().DockerContainerStart(id)
|
||||
err = service.MyService.Docker().DockerContainerStart(m.Label)
|
||||
if err != nil {
|
||||
//service.MyService.Redis().Set(id, "{\"id\"\""+id+"\",\"state\":false,\"message\":\""+err.Error()+"\",\"speed\":90}", 100)
|
||||
installLog.State = 0
|
||||
installLog.Type = types.NOTIFY_TYPE_ERROR
|
||||
installLog.Speed = 90
|
||||
installLog.Message = err.Error()
|
||||
service.MyService.Notify().UpdateLog(installLog)
|
||||
return
|
||||
} else {
|
||||
//service.MyService.Redis().Set(id, "{\"id\":\""+id+"\",\"state\":true,\"message\":\"setting upnp\",\"speed\":90}", 100)
|
||||
installLog.Speed = 90
|
||||
if m.Origin != CUSTOM {
|
||||
installLog.Message = "setting upnp"
|
||||
} else {
|
||||
@@ -396,13 +427,11 @@ func InstallApp(c *gin.Context) {
|
||||
if err != nil {
|
||||
//service.MyService.Redis().Set(id, "{\"id\"\""+id+"\",\"state\":false,\"message\":\""+err.Error()+"\",\"speed\":95}", 100)
|
||||
installLog.State = 0
|
||||
installLog.Speed = 95
|
||||
installLog.Type = types.NOTIFY_TYPE_ERROR
|
||||
installLog.Message = err.Error()
|
||||
service.MyService.Notify().UpdateLog(installLog)
|
||||
} else {
|
||||
//service.MyService.Redis().Set(id, "{\"id\":\""+id+"\",\"state\":true,\"message\":\"checking\",\"speed\":95}", 100)
|
||||
installLog.Speed = 95
|
||||
installLog.Message = "checking"
|
||||
service.MyService.Notify().UpdateLog(installLog)
|
||||
}
|
||||
@@ -410,18 +439,16 @@ func InstallApp(c *gin.Context) {
|
||||
}
|
||||
|
||||
//step: 启动成功 检查容器状态确认启动成功
|
||||
container, err := service.MyService.Docker().DockerContainerInfo(id)
|
||||
container, err := service.MyService.Docker().DockerContainerInfo(m.Label)
|
||||
if err != nil && container.ContainerJSONBase.State.Running {
|
||||
//service.MyService.Redis().Set(id, "{\"id\"\""+id+"\",\"state\":false,\"message\":\""+err.Error()+"\",\"speed\":100}", 100)
|
||||
installLog.State = 0
|
||||
installLog.Speed = 100
|
||||
installLog.Type = types.NOTIFY_TYPE_ERROR
|
||||
installLog.Message = err.Error()
|
||||
service.MyService.Notify().UpdateLog(installLog)
|
||||
return
|
||||
} else {
|
||||
//service.MyService.Redis().Set(id, "{\"id\":\""+id+"\",\"state\":true,\"message\":\"installed\",\"speed\":100}", 100)
|
||||
installLog.Speed = 100
|
||||
installLog.Message = "installed"
|
||||
service.MyService.Notify().UpdateLog(installLog)
|
||||
}
|
||||
@@ -429,13 +456,21 @@ func InstallApp(c *gin.Context) {
|
||||
rely := model.MapStrings{}
|
||||
|
||||
copier.Copy(&rely, &relyMap)
|
||||
// if m.Origin != "custom" {
|
||||
// for i := 0; i < len(m.Volumes); i++ {
|
||||
// m.Volumes[i].Path = docker.GetDir(id, m.Volumes[i].Path)
|
||||
// }
|
||||
// }
|
||||
|
||||
portsStr, _ := json2.Marshal(m.Ports)
|
||||
envsStr, _ := json2.Marshal(m.Envs)
|
||||
volumesStr, _ := json2.Marshal(m.Volumes)
|
||||
devicesStr, _ := json2.Marshal(m.Devices)
|
||||
cmd, _ := json2.Marshal(m.Cmd)
|
||||
capAdd, _ := json.Marshal(m.CapAdd)
|
||||
//step: 保存数据到数据库
|
||||
md := model2.AppListDBModel{
|
||||
CustomId: id,
|
||||
CustomId: "",
|
||||
Title: appInfo.Title,
|
||||
//ScreenshotLink: appInfo.ScreenshotLink,
|
||||
Slogan: appInfo.Tagline,
|
||||
@@ -463,15 +498,21 @@ func InstallApp(c *gin.Context) {
|
||||
Origin: m.Origin,
|
||||
CreatedAt: strconv.FormatInt(time.Now().Unix(), 10),
|
||||
UpdatedAt: strconv.FormatInt(time.Now().Unix(), 10),
|
||||
Cmd: string(cmd),
|
||||
CapAdd: string(capAdd),
|
||||
HostName: m.HostName,
|
||||
Privileged: m.Privileged,
|
||||
}
|
||||
//if appInfo.NetworkModel == "host" {
|
||||
// m.PortMap = m.Port
|
||||
//}
|
||||
service.MyService.App().SaveContainer(md)
|
||||
fmt.Println(md)
|
||||
//service.MyService.App().SaveContainer(md)
|
||||
config.CasaOSGlobalVariables.AppChange = true
|
||||
|
||||
}()
|
||||
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: id})
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: m.Label})
|
||||
|
||||
}
|
||||
|
||||
@@ -672,17 +713,23 @@ func UnInstallApp(c *gin.Context) {
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.INVALID_PARAMS, Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS)})
|
||||
return
|
||||
}
|
||||
info := service.MyService.App().GetUninstallInfo(appId)
|
||||
//info := service.MyService.App().GetUninstallInfo(appId)
|
||||
|
||||
info, err := service.MyService.Docker().DockerContainerInfo(appId)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.ERROR, Message: oasis_err2.GetMsg(oasis_err2.ERROR), Data: err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
//step:停止容器
|
||||
err := service.MyService.Docker().DockerContainerStop(appId)
|
||||
err = service.MyService.Docker().DockerContainerStop(appId)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.UNINSTALL_APP_ERROR, Message: oasis_err2.GetMsg(oasis_err2.UNINSTALL_APP_ERROR), Data: err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
//step:删除容器
|
||||
err = service.MyService.Docker().DockerContainerRemove(appId)
|
||||
err = service.MyService.Docker().DockerContainerRemove(appId, false)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.UNINSTALL_APP_ERROR, Message: oasis_err2.GetMsg(oasis_err2.UNINSTALL_APP_ERROR), Data: err.Error()})
|
||||
return
|
||||
@@ -690,17 +737,21 @@ func UnInstallApp(c *gin.Context) {
|
||||
|
||||
//存在镜像正在使用的情况
|
||||
// step:删除镜像
|
||||
service.MyService.Docker().DockerImageRemove(info.Image + ":" + info.Version)
|
||||
service.MyService.Docker().DockerImageRemove(info.Image)
|
||||
|
||||
//step: 删除本地数据
|
||||
service.MyService.App().RemoveContainerById(appId)
|
||||
if info.Origin != "custom" {
|
||||
|
||||
//service.MyService.App().RemoveContainerById(appId)
|
||||
if info.Config.Labels["origin"] != "custom" {
|
||||
fmt.Println(info.HostConfig.Mounts)
|
||||
//step: 删除文件夹
|
||||
service.MyService.App().DelAppConfigDir(appId)
|
||||
for _, v := range info.HostConfig.Mounts {
|
||||
if strings.Contains(v.Source, info.Name) {
|
||||
service.MyService.App().DelAppConfigDir(v.Source)
|
||||
}
|
||||
}
|
||||
|
||||
//step: 删除install log
|
||||
service.MyService.Notify().DelLog(appId)
|
||||
//service.MyService.Notify().DelLog(appId)
|
||||
|
||||
// for k, v := range info.Rely {
|
||||
//
|
||||
@@ -739,6 +790,13 @@ func UnInstallApp(c *gin.Context) {
|
||||
// }
|
||||
//}
|
||||
}
|
||||
config.CasaOSGlobalVariables.AppChange = true
|
||||
unInstallLog := model2.AppNotify{}
|
||||
unInstallLog.State = 0
|
||||
unInstallLog.CustomId = appId
|
||||
unInstallLog.Message = "uninstalled"
|
||||
unInstallLog.Id = uuid.NewV4().String()
|
||||
service.MyService.Notify().UpdateLog(unInstallLog)
|
||||
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS)})
|
||||
|
||||
@@ -762,7 +820,7 @@ func ChangAppState(c *gin.Context) {
|
||||
} else if state == "start" {
|
||||
err = service.MyService.Docker().DockerContainerStart(appId)
|
||||
} else if state == "restart" {
|
||||
err = service.MyService.Docker().DockerContainerStop(appId)
|
||||
service.MyService.Docker().DockerContainerStop(appId)
|
||||
err = service.MyService.Docker().DockerContainerStart(appId)
|
||||
}
|
||||
if err != nil {
|
||||
@@ -802,7 +860,6 @@ func ContainerLog(c *gin.Context) {
|
||||
func GetInstallSpeed(c *gin.Context) {
|
||||
id := c.Param("id")
|
||||
b := service.MyService.Notify().GetLog(id)
|
||||
b.Id = b.CustomId
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: b})
|
||||
}
|
||||
|
||||
@@ -859,19 +916,23 @@ func UpdateSetting(c *gin.Context) {
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.INVALID_PARAMS, Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS)})
|
||||
return
|
||||
}
|
||||
var cpd model.CustomizationPostData
|
||||
//var cpd model.CustomizationPostData
|
||||
|
||||
copier.Copy(&cpd, &m)
|
||||
//copier.Copy(&cpd, &m)
|
||||
|
||||
appInfo := service.MyService.App().GetAppDBInfo(id)
|
||||
//appInfo := service.MyService.App().GetAppDBInfo(id)
|
||||
//info, err := service.MyService.Docker().DockerContainerInfo(id)
|
||||
|
||||
var containerId string
|
||||
containerId = appInfo.ContainerId
|
||||
// //check app name is exist
|
||||
// if _, err := service.MyService.Docker().DockerListByName(m.Label); err == nil {
|
||||
// c.JSON(http.StatusOK, model.Result{Success: oasis_err2.ERROR_APP_NAME_EXIST, Message: oasis_err2.GetMsg(oasis_err2.ERROR_APP_NAME_EXIST)})
|
||||
// return
|
||||
// }
|
||||
|
||||
service.MyService.Docker().DockerContainerStop(id)
|
||||
|
||||
portMap, _ := strconv.Atoi(m.PortMap)
|
||||
if !port2.IsPortAvailable(portMap, "tcp") {
|
||||
service.MyService.Docker().DockerContainerStart(id)
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.ERROR, Message: "Duplicate port:" + m.PortMap})
|
||||
return
|
||||
}
|
||||
@@ -881,75 +942,54 @@ func UpdateSetting(c *gin.Context) {
|
||||
if u.Protocol == "udp" {
|
||||
t, _ := strconv.Atoi(u.CommendPort)
|
||||
if !port2.IsPortAvailable(t, "udp") {
|
||||
service.MyService.Docker().DockerContainerStart(id)
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.ERROR, Message: "Duplicate port:" + u.CommendPort})
|
||||
return
|
||||
}
|
||||
} else if u.Protocol == "tcp" {
|
||||
te, _ := strconv.Atoi(u.CommendPort)
|
||||
if !port2.IsPortAvailable(te, "tcp") {
|
||||
service.MyService.Docker().DockerContainerStart(id)
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.ERROR, Message: "Duplicate port:" + u.CommendPort})
|
||||
return
|
||||
}
|
||||
} else if u.Protocol == "both" {
|
||||
t, _ := strconv.Atoi(u.CommendPort)
|
||||
if !port2.IsPortAvailable(t, "udp") {
|
||||
service.MyService.Docker().DockerContainerStart(id)
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.ERROR, Message: "Duplicate port:" + u.CommendPort})
|
||||
return
|
||||
}
|
||||
|
||||
te, _ := strconv.Atoi(u.CommendPort)
|
||||
if !port2.IsPortAvailable(te, "tcp") {
|
||||
service.MyService.Docker().DockerContainerStart(id)
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.ERROR, Message: "Duplicate port:" + u.CommendPort})
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
service.MyService.Docker().DockerContainerUpdateName(id, id)
|
||||
//service.MyService.Docker().DockerContainerRemove(id, true)
|
||||
|
||||
//如果容器端口均未修改,这不进行处理
|
||||
portsStr, _ := json2.Marshal(m.Ports)
|
||||
containerId, err := service.MyService.Docker().DockerContainerCreate(m.Image, m, m.NetworkModel)
|
||||
if err != nil {
|
||||
service.MyService.Docker().DockerContainerUpdateName(m.Label, id)
|
||||
service.MyService.Docker().DockerContainerStart(id)
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.ERROR, Message: oasis_err2.GetMsg(oasis_err2.ERROR)})
|
||||
return
|
||||
}
|
||||
// echo -e "hellow\nworld" >>
|
||||
|
||||
envsStr, _ := json2.Marshal(m.Envs)
|
||||
volumesStr, _ := json2.Marshal(m.Volumes)
|
||||
devicesStr, _ := json2.Marshal(m.Devices)
|
||||
if !reflect.DeepEqual(string(portsStr), appInfo.Ports) || !reflect.DeepEqual(string(envsStr), appInfo.Envs) || !reflect.DeepEqual(string(volumesStr), appInfo.Volumes) || m.PortMap != appInfo.PortMap || m.NetworkModel != appInfo.NetModel {
|
||||
|
||||
var newUUid = uuid.NewV4().String()
|
||||
var err error
|
||||
|
||||
// networkName, err := service.MyService.Docker().GetNetWorkNameByNetWorkID(appInfo.NetModel)
|
||||
// if err != nil {
|
||||
// c.JSON(http.StatusOK, model.Result{Success: oasis_err2.ERROR, Message: oasis_err2.GetMsg(oasis_err2.ERROR)})
|
||||
// return
|
||||
// }
|
||||
containerId, err = service.MyService.Docker().DockerContainerCreate(appInfo.Image+":"+appInfo.Version, newUUid, cpd, m.NetworkModel)
|
||||
//step:启动容器
|
||||
err = service.MyService.Docker().DockerContainerStart(containerId)
|
||||
|
||||
if err != nil {
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.ERROR, Message: oasis_err2.GetMsg(oasis_err2.ERROR)})
|
||||
return
|
||||
}
|
||||
|
||||
err = service.MyService.Docker().DockerContainerRemove(id)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.ERROR, Message: oasis_err2.GetMsg(oasis_err2.ERROR)})
|
||||
return
|
||||
}
|
||||
|
||||
service.MyService.Docker().DockerContainerUpdateName(appInfo.CustomId, newUUid)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.ERROR, Message: oasis_err2.GetMsg(oasis_err2.ERROR)})
|
||||
return
|
||||
}
|
||||
|
||||
} else if !reflect.DeepEqual(string(devicesStr), appInfo.Devices) || m.CpuShares != appInfo.CpuShares || m.Memory != appInfo.Memory || m.Restart != appInfo.Restart {
|
||||
service.MyService.Docker().DockerContainerUpdate(cpd, id)
|
||||
}
|
||||
|
||||
err := service.MyService.Docker().DockerContainerStart(id)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.ERROR, Message: oasis_err2.GetMsg(oasis_err2.ERROR)})
|
||||
return
|
||||
}
|
||||
service.MyService.Docker().DockerContainerRemove(id, true)
|
||||
//更新upnp
|
||||
if m.Origin != CUSTOM {
|
||||
//if appInfo.EnableUPNP != appInfo.EnableUPNP {
|
||||
@@ -1015,27 +1055,96 @@ func UpdateSetting(c *gin.Context) {
|
||||
//}
|
||||
}
|
||||
|
||||
appInfo.ContainerId = containerId
|
||||
appInfo.PortMap = m.PortMap
|
||||
appInfo.Label = m.Label
|
||||
appInfo.Index = m.Index
|
||||
appInfo.Ports = string(portsStr)
|
||||
appInfo.Envs = string(envsStr)
|
||||
appInfo.Icon = m.Icon
|
||||
appInfo.Volumes = string(volumesStr)
|
||||
appInfo.Devices = string(devicesStr)
|
||||
appInfo.NetModel = m.NetworkModel
|
||||
appInfo.Position = m.Position
|
||||
appInfo.EnableUPNP = m.EnableUPNP
|
||||
appInfo.Restart = m.Restart
|
||||
appInfo.Memory = m.Memory
|
||||
appInfo.CpuShares = m.CpuShares
|
||||
appInfo.UpdatedAt = strconv.FormatInt(time.Now().Unix(), 10)
|
||||
service.MyService.App().UpdateApp(appInfo)
|
||||
//service.MyService.App().UpdateApp(appInfo)
|
||||
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS)})
|
||||
}
|
||||
|
||||
// @Summary update app version
|
||||
// @Produce application/json
|
||||
// @Accept multipart/form-data
|
||||
// @Tags app
|
||||
// @Param id path string true "容器id"
|
||||
// @Security ApiKeyAuth
|
||||
// @Success 200 {string} string "ok"
|
||||
// @Router /app/update/{id} [put]
|
||||
func PutAppUpdate(c *gin.Context) {
|
||||
id := c.Param("id")
|
||||
|
||||
if len(id) == 0 {
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.INVALID_PARAMS, Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS)})
|
||||
return
|
||||
}
|
||||
|
||||
inspect, err := service.MyService.Docker().DockerContainerInfo(id)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.ERROR, Message: oasis_err2.GetMsg(oasis_err2.ERROR), Data: err.Error()})
|
||||
return
|
||||
|
||||
}
|
||||
imageLatest := strings.Split(inspect.Config.Image, ":")[0] + ":latest"
|
||||
err = service.MyService.Docker().DockerPullImage(imageLatest, model2.AppNotify{})
|
||||
if err != nil {
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.ERROR, Message: oasis_err2.GetMsg(oasis_err2.ERROR), Data: err.Error()})
|
||||
return
|
||||
|
||||
}
|
||||
service.MyService.Docker().DockerContainerStop(id)
|
||||
service.MyService.Docker().DockerContainerUpdateName(id, id)
|
||||
//service.MyService.Docker().DockerContainerRemove(id, true)
|
||||
inspect.Image = imageLatest
|
||||
inspect.Config.Image = imageLatest
|
||||
containerId, err := service.MyService.Docker().DockerContainerCopyCreate(inspect)
|
||||
if err != nil {
|
||||
service.MyService.Docker().DockerContainerUpdateName(inspect.Name, id)
|
||||
service.MyService.Docker().DockerContainerStart(id)
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.ERROR, Message: oasis_err2.GetMsg(oasis_err2.ERROR)})
|
||||
return
|
||||
}
|
||||
|
||||
//step:启动容器
|
||||
err = service.MyService.Docker().DockerContainerStart(containerId)
|
||||
|
||||
if err != nil {
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.ERROR, Message: oasis_err2.GetMsg(oasis_err2.ERROR)})
|
||||
return
|
||||
}
|
||||
service.MyService.Docker().DockerContainerRemove(id, true)
|
||||
delete(service.NewVersionApp, id)
|
||||
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS)})
|
||||
}
|
||||
|
||||
// @Summary get app index
|
||||
// @Produce application/json
|
||||
// @Accept application/json
|
||||
// @Tags app
|
||||
// @Security ApiKeyAuth
|
||||
// @Success 200 {string} string "ok"
|
||||
// @Router /app/order [get]
|
||||
func GetAppOrder(c *gin.Context) {
|
||||
data := service.MyService.System().GetAppOrderFile()
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err.SUCCESS, Message: oasis_err.GetMsg(oasis_err.SUCCESS), Data: json.RawMessage(data)})
|
||||
}
|
||||
|
||||
// @Summary update app index
|
||||
// @Produce application/json
|
||||
// @Accept application/json
|
||||
// @Tags app
|
||||
// @Security ApiKeyAuth
|
||||
// @Success 200 {string} string "ok"
|
||||
// @Router /app/order [post]
|
||||
func PostAppOrder(c *gin.Context) {
|
||||
data := c.PostForm("data")
|
||||
service.MyService.System().UpAppOrderFile(data)
|
||||
c.JSON(http.StatusOK,
|
||||
model.Result{
|
||||
Success: oasis_err.SUCCESS,
|
||||
Message: oasis_err.GetMsg(oasis_err.SUCCESS),
|
||||
Data: json.RawMessage(data),
|
||||
})
|
||||
}
|
||||
|
||||
// @Summary 获取容器详情
|
||||
// @Produce application/json
|
||||
// @Accept application/json
|
||||
@@ -1124,46 +1233,89 @@ func ContainerRelyInfo(c *gin.Context) {
|
||||
// @Router /app/update/{id}/info [get]
|
||||
func ContainerUpdateInfo(c *gin.Context) {
|
||||
appId := c.Param("id")
|
||||
appInfo := service.MyService.App().GetAppDBInfo(appId)
|
||||
|
||||
//appInfo := service.MyService.App().GetAppDBInfo(appId)
|
||||
info, err := service.MyService.Docker().DockerContainerInfo(appId)
|
||||
if err != nil {
|
||||
//todo 需要自定义错误
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: err.Error()})
|
||||
return
|
||||
}
|
||||
var port model.PortArrey
|
||||
json2.Unmarshal([]byte(appInfo.Ports), &port)
|
||||
var port model.PortArray
|
||||
// json2.Unmarshal([]byte(appInfo.Ports), &port)
|
||||
|
||||
var envs model.EnvArrey
|
||||
json2.Unmarshal([]byte(appInfo.Envs), &envs)
|
||||
for k, v := range info.HostConfig.PortBindings {
|
||||
temp := model.PortMap{
|
||||
CommendPort: v[0].HostPort,
|
||||
ContainerPort: k.Port(),
|
||||
|
||||
var vol model.PathArrey
|
||||
json2.Unmarshal([]byte(appInfo.Volumes), &vol)
|
||||
Protocol: k.Proto(),
|
||||
}
|
||||
port = append(port, temp)
|
||||
}
|
||||
|
||||
var dir model.PathArrey
|
||||
json2.Unmarshal([]byte(appInfo.Devices), &dir)
|
||||
var envs model.EnvArray
|
||||
// json2.Unmarshal([]byte(appInfo.Envs), &envs)
|
||||
|
||||
for _, v := range info.Config.Env {
|
||||
|
||||
temp := model.Env{
|
||||
Name: strings.Split(v, "=")[0],
|
||||
Value: strings.Split(v, "=")[1],
|
||||
}
|
||||
envs = append(envs, temp)
|
||||
}
|
||||
|
||||
var vol model.PathArray
|
||||
// json2.Unmarshal([]byte(appInfo.Volumes), &vol)
|
||||
|
||||
for i := 0; i < len(info.Mounts); i++ {
|
||||
temp := model.PathMap{
|
||||
Path: strings.ReplaceAll(info.Mounts[i].Source, "$AppID", info.Name),
|
||||
ContainerPath: info.Mounts[i].Destination,
|
||||
}
|
||||
vol = append(vol, temp)
|
||||
}
|
||||
var driver model.PathArray
|
||||
|
||||
//volumesStr, _ := json2.Marshal(m.Volumes)
|
||||
//devicesStr, _ := json2.Marshal(m.Devices)
|
||||
for _, v := range info.HostConfig.Resources.Devices {
|
||||
temp := model.PathMap{
|
||||
Path: v.PathOnHost,
|
||||
ContainerPath: v.PathInContainer,
|
||||
}
|
||||
driver = append(driver, temp)
|
||||
}
|
||||
|
||||
m := model.CustomizationPostData{}
|
||||
m.Index = appInfo.Index
|
||||
m.Icon = appInfo.Icon
|
||||
m.Icon = info.Config.Labels["icon"]
|
||||
m.Ports = port
|
||||
m.Image = appInfo.Image + ":" + appInfo.Version
|
||||
m.Origin = appInfo.Origin
|
||||
m.NetworkModel = appInfo.NetModel
|
||||
m.Description = appInfo.Description
|
||||
m.Label = appInfo.Label
|
||||
m.PortMap = appInfo.PortMap
|
||||
m.Devices = dir //appInfo.Devices
|
||||
m.Image = info.Config.Image
|
||||
m.Origin = info.Config.Labels["origin"]
|
||||
if len(m.Origin) == 0 {
|
||||
m.Origin = "local"
|
||||
}
|
||||
m.NetworkModel = string(info.HostConfig.NetworkMode)
|
||||
m.Description = info.Config.Labels["desc"]
|
||||
m.Label = strings.ReplaceAll(info.Name, "/", "")
|
||||
m.PortMap = info.Config.Labels["web"]
|
||||
m.Devices = driver
|
||||
m.Envs = envs
|
||||
m.Memory = info.HostConfig.Memory >> 20
|
||||
m.CpuShares = info.HostConfig.CPUShares
|
||||
m.Volumes = vol //appInfo.Volumes
|
||||
m.Restart = info.HostConfig.RestartPolicy.Name
|
||||
m.EnableUPNP = appInfo.EnableUPNP
|
||||
m.Position = appInfo.Position
|
||||
m.EnableUPNP = false
|
||||
m.Index = info.Config.Labels["index"]
|
||||
m.Position = false
|
||||
m.CustomId = info.Config.Labels["custom_id"]
|
||||
if len(m.CustomId) == 0 {
|
||||
m.CustomId = uuid.NewV4().String()
|
||||
}
|
||||
m.CapAdd = info.HostConfig.CapAdd
|
||||
m.Cmd = info.Config.Cmd
|
||||
m.HostName = info.Config.Hostname
|
||||
m.Privileged = info.HostConfig.Privileged
|
||||
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: m})
|
||||
}
|
||||
|
||||
352
route/v1/file.go
352
route/v1/file.go
@@ -7,14 +7,19 @@ import (
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
url2 "net/url"
|
||||
"os"
|
||||
"path"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/IceWhaleTech/CasaOS/model"
|
||||
"github.com/IceWhaleTech/CasaOS/pkg/config"
|
||||
"github.com/IceWhaleTech/CasaOS/pkg/utils/file"
|
||||
oasis_err2 "github.com/IceWhaleTech/CasaOS/pkg/utils/oasis_err"
|
||||
"github.com/IceWhaleTech/CasaOS/service"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/spf13/afero"
|
||||
)
|
||||
|
||||
func downloadReadFile(c *gin.Context) {
|
||||
@@ -125,12 +130,12 @@ func GetLocalFile(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
// @Summary 下载文件
|
||||
// @Summary download
|
||||
// @Produce application/json
|
||||
// @Accept application/json
|
||||
// @Tags file
|
||||
// @Security ApiKeyAuth
|
||||
// @Param path query string true "路径"
|
||||
// @Param path query string true "path of file"
|
||||
// @Success 200 {string} string "ok"
|
||||
// @Router /file/download [get]
|
||||
func GetDownloadFile(c *gin.Context) {
|
||||
@@ -155,15 +160,57 @@ func GetDownloadFile(c *gin.Context) {
|
||||
//获取文件的名称
|
||||
fileName := path.Base(filePath)
|
||||
c.Header("Content-Type", "application/octet-stream")
|
||||
c.Header("Content-Disposition", "attachment; filename="+fileName)
|
||||
c.Header("Content-Disposition", "attachment; filename*=utf-8''"+url2.PathEscape(fileName))
|
||||
c.Header("Content-Transfer-Encoding", "binary")
|
||||
c.Header("Cache-Control", "no-cache")
|
||||
c.Header("Content-Type", "application/octet-stream")
|
||||
c.Header("Content-Disposition", "attachment; filename="+fileName)
|
||||
c.Header("Content-Transfer-Encoding", "binary")
|
||||
|
||||
c.File(filePath)
|
||||
}
|
||||
|
||||
// @Summary download
|
||||
// @Produce application/json
|
||||
// @Accept application/json
|
||||
// @Tags file
|
||||
// @Security ApiKeyAuth
|
||||
// @Param path query string true "path of file"
|
||||
// @Success 200 {string} string "ok"
|
||||
// @Router /file/new/download [get]
|
||||
func GetFileDownloadNew(c *gin.Context) {
|
||||
filePath := c.Query("path")
|
||||
if len(filePath) == 0 {
|
||||
c.JSON(http.StatusOK, model.Result{
|
||||
Success: oasis_err2.INVALID_PARAMS,
|
||||
Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS),
|
||||
})
|
||||
return
|
||||
}
|
||||
if !file.Exists(filePath) {
|
||||
c.JSON(http.StatusOK, model.Result{
|
||||
Success: oasis_err2.FILE_DOES_NOT_EXIST,
|
||||
Message: oasis_err2.GetMsg(oasis_err2.FILE_DOES_NOT_EXIST),
|
||||
})
|
||||
return
|
||||
}
|
||||
//打开文件
|
||||
fileStat, _ := os.Stat(filePath)
|
||||
var AppFs = afero.NewOsFs()
|
||||
fileT, _ := AppFs.Open(filePath)
|
||||
//fileTmp, _ := os.Open(filePath)
|
||||
//defer fileTmp.Close()
|
||||
//获取文件的名称
|
||||
//fileName := path.Base(filePath)
|
||||
|
||||
//c.Header("Content-Disposition", "attachment; filename*=utf-8''"+url2.PathEscape(fileName))
|
||||
//在线
|
||||
//c.Header("Content-Disposition", "inline")
|
||||
// extraHeaders := map[string]string{
|
||||
// "Content-Disposition": `attachment; filename="` + url2.PathEscape(fileName) + `"`,
|
||||
// }
|
||||
|
||||
//c.Header("Cache-Control", "private")
|
||||
//c.Header("Content-Type", "application/octet-stream")
|
||||
|
||||
http.ServeContent(c.Writer, c.Request, fileStat.Name(), fileStat.ModTime(), fileT)
|
||||
}
|
||||
|
||||
// @Summary 获取目录列表
|
||||
@@ -175,18 +222,58 @@ func GetDownloadFile(c *gin.Context) {
|
||||
// @Success 200 {string} string "ok"
|
||||
// @Router /file/dirpath [get]
|
||||
func DirPath(c *gin.Context) {
|
||||
path := c.DefaultQuery("path", "/")
|
||||
path := c.DefaultQuery("path", "")
|
||||
info := service.MyService.ZiMa().GetDirPath(path)
|
||||
if path == "/DATA/AppData" {
|
||||
list := service.MyService.Docker().DockerContainerList()
|
||||
apps := make(map[string]string, len(list))
|
||||
for _, v := range list {
|
||||
apps[strings.ReplaceAll(v.Names[0], "/", "")] = strings.ReplaceAll(v.Names[0], "/", "")
|
||||
}
|
||||
for i := 0; i < len(info); i++ {
|
||||
if v, ok := apps[info[i].Name]; ok {
|
||||
info[i].Label = v
|
||||
info[i].Type = "application"
|
||||
}
|
||||
}
|
||||
} else if path == "/DATA" {
|
||||
disk := make(map[string]string)
|
||||
lsblk := service.MyService.Disk().LSBLK(true)
|
||||
for _, v := range lsblk {
|
||||
if len(v.Children) > 0 {
|
||||
t := v.Tran
|
||||
for _, c := range v.Children {
|
||||
if len(c.Children) > 0 {
|
||||
for _, gc := range c.Children {
|
||||
if len(gc.MountPoint) > 0 {
|
||||
disk[gc.MountPoint] = t
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(c.MountPoint) > 0 {
|
||||
disk[c.MountPoint] = t
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
for i := 0; i < len(info); i++ {
|
||||
if v, ok := disk[info[i].Path]; ok {
|
||||
info[i].Type = v
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: info})
|
||||
}
|
||||
|
||||
// @Summary 重命名目录或文件
|
||||
// @Summary rename file or dir
|
||||
// @Produce application/json
|
||||
// @Accept application/json
|
||||
// @Tags file
|
||||
// @Security ApiKeyAuth
|
||||
// @Param oldpath formData string true "旧的路径"
|
||||
// @Param newpath formData string true "新路径"
|
||||
// @Param oldpath formData string true "path of old"
|
||||
// @Param newpath formData string true "path of new"
|
||||
// @Success 200 {string} string "ok"
|
||||
// @Router /file/rename [put]
|
||||
func RenamePath(c *gin.Context) {
|
||||
@@ -196,16 +283,16 @@ func RenamePath(c *gin.Context) {
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.INVALID_PARAMS, Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS)})
|
||||
return
|
||||
}
|
||||
service.MyService.ZiMa().RenameFile(op, np)
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS)})
|
||||
success, err := service.MyService.ZiMa().RenameFile(op, np)
|
||||
c.JSON(http.StatusOK, model.Result{Success: success, Message: oasis_err2.GetMsg(success), Data: err})
|
||||
}
|
||||
|
||||
// @Summary 创建文件夹
|
||||
// @Summary create folder
|
||||
// @Produce application/json
|
||||
// @Accept multipart/form-data
|
||||
// @Tags file
|
||||
// @Security ApiKeyAuth
|
||||
// @Param path formData string false "路径"
|
||||
// @Param path formData string true "path of folder"
|
||||
// @Success 200 {string} string "ok"
|
||||
// @Router /file/mkdir [post]
|
||||
func MkdirAll(c *gin.Context) {
|
||||
@@ -219,7 +306,7 @@ func MkdirAll(c *gin.Context) {
|
||||
c.JSON(http.StatusOK, model.Result{Success: code, Message: oasis_err2.GetMsg(code)})
|
||||
}
|
||||
|
||||
// @Summary 创建文件
|
||||
// @Summary create file
|
||||
// @Produce application/json
|
||||
// @Accept multipart/form-data
|
||||
// @Tags file
|
||||
@@ -238,21 +325,240 @@ func PostCreateFile(c *gin.Context) {
|
||||
c.JSON(http.StatusOK, model.Result{Success: code, Message: oasis_err2.GetMsg(code)})
|
||||
}
|
||||
|
||||
// @Summary 上传文件
|
||||
// @Summary upload file
|
||||
// @Produce application/json
|
||||
// @Accept multipart/form-data
|
||||
// @Tags file
|
||||
// @Security ApiKeyAuth
|
||||
// @Param path formData string false "路径"
|
||||
// @Param path formData string false "file path"
|
||||
// @Param file formData file true "file"
|
||||
// @Success 200 {string} string "ok"
|
||||
// @Router /file/mkdir [post]
|
||||
func PostFileUpload(c *gin.Context) {
|
||||
file, _, _ := c.Request.FormFile("file")
|
||||
//file.Read()
|
||||
// @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")
|
||||
//上传文件
|
||||
dirPath := ""
|
||||
hash := file.GetHashByContent([]byte(fileName))
|
||||
tempDir := config.AppInfo.RootPath + "/temp/" + hash + strconv.Itoa(totalChunks) + "/"
|
||||
if fileName != relative {
|
||||
dirPath = strings.TrimSuffix(relative, fileName)
|
||||
tempDir += dirPath
|
||||
file.MkDir(path + "/" + dirPath)
|
||||
}
|
||||
tempDir += chunkNumber
|
||||
if !file.CheckNotExist(tempDir) {
|
||||
c.JSON(200, model.Result{Success: 200, Message: oasis_err2.GetMsg(oasis_err2.FILE_ALREADY_EXISTS)})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(204, model.Result{Success: 204, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS)})
|
||||
}
|
||||
|
||||
// @Summary upload file
|
||||
// @Produce application/json
|
||||
// @Accept multipart/form-data
|
||||
// @Tags file
|
||||
// @Security ApiKeyAuth
|
||||
// @Param path formData string false "file path"
|
||||
// @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")
|
||||
dirPath := ""
|
||||
path := c.PostForm("path")
|
||||
|
||||
hash := file.GetHashByContent([]byte(fileName))
|
||||
|
||||
if len(path) == 0 {
|
||||
c.JSON(oasis_err2.INVALID_PARAMS, model.Result{Success: oasis_err2.INVALID_PARAMS, Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS)})
|
||||
return
|
||||
}
|
||||
tempDir := config.AppInfo.RootPath + "/temp/" + hash + strconv.Itoa(totalChunks) + "/"
|
||||
|
||||
if fileName != relative {
|
||||
dirPath = strings.TrimSuffix(relative, fileName)
|
||||
tempDir += dirPath
|
||||
file.MkDir(path + "/" + dirPath)
|
||||
}
|
||||
|
||||
path += "/" + relative
|
||||
|
||||
if !file.CheckNotExist(tempDir + chunkNumber) {
|
||||
file.RMDir(tempDir + chunkNumber)
|
||||
}
|
||||
|
||||
if totalChunks > 1 {
|
||||
file.IsNotExistMkDir(tempDir)
|
||||
|
||||
out, _ := os.OpenFile(tempDir+chunkNumber, os.O_WRONLY|os.O_CREATE, 0644)
|
||||
defer out.Close()
|
||||
_, err := io.Copy(out, f)
|
||||
if err != nil {
|
||||
c.JSON(oasis_err2.ERROR, model.Result{Success: oasis_err2.ERROR, Message: oasis_err2.GetMsg(oasis_err2.ERROR), Data: err.Error()})
|
||||
return
|
||||
}
|
||||
} else {
|
||||
out, _ := os.OpenFile(path, os.O_WRONLY|os.O_CREATE, 0644)
|
||||
defer out.Close()
|
||||
io.Copy(out, file)
|
||||
_, err := io.Copy(out, f)
|
||||
if err != nil {
|
||||
c.JSON(oasis_err2.ERROR, model.Result{Success: oasis_err2.ERROR, Message: oasis_err2.GetMsg(oasis_err2.ERROR), Data: err.Error()})
|
||||
return
|
||||
}
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS)})
|
||||
return
|
||||
}
|
||||
fileNum, err := ioutil.ReadDir(tempDir)
|
||||
if err != nil {
|
||||
c.JSON(oasis_err2.ERROR, model.Result{Success: oasis_err2.ERROR, Message: oasis_err2.GetMsg(oasis_err2.ERROR), Data: err.Error()})
|
||||
return
|
||||
}
|
||||
if totalChunks == len(fileNum) {
|
||||
file.SpliceFiles(tempDir, path, totalChunks, 1)
|
||||
file.RMDir(tempDir)
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS)})
|
||||
}
|
||||
|
||||
// @Summary copy or move file
|
||||
// @Produce application/json
|
||||
// @Accept multipart/form-data
|
||||
// @Tags file
|
||||
// @Security ApiKeyAuth
|
||||
// @Param from formData string true "from path"
|
||||
// @Param to formData string true "to path"
|
||||
// @Param type formData string true "action" Enums(move,copy)
|
||||
// @Success 200 {string} string "ok"
|
||||
// @Router /file/operate [post]
|
||||
func PostOperateFileOrDir(c *gin.Context) {
|
||||
from := c.PostForm("from")
|
||||
to := c.PostForm("to")
|
||||
t := c.PostForm("type")
|
||||
if len(from) == 0 || len(t) == 0 || len(to) == 0 {
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.INVALID_PARAMS, Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS)})
|
||||
return
|
||||
}
|
||||
if t == "move" {
|
||||
lastPath := from[strings.LastIndex(from, "/")+1:]
|
||||
if !file.CheckNotExist(to + "/" + lastPath) {
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.FILE_OR_DIR_EXISTS, Message: oasis_err2.GetMsg(oasis_err2.FILE_ALREADY_EXISTS)})
|
||||
return
|
||||
}
|
||||
err := os.Rename(from, to+"/"+lastPath)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.ERROR, Message: oasis_err2.GetMsg(oasis_err2.ERROR), Data: err.Error()})
|
||||
return
|
||||
}
|
||||
} else if t == "copy" {
|
||||
err := file.CopyDir(from, to)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.ERROR, Message: oasis_err2.GetMsg(oasis_err2.ERROR), Data: err.Error()})
|
||||
return
|
||||
}
|
||||
} else {
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.INVALID_PARAMS, Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS)})
|
||||
return
|
||||
}
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS)})
|
||||
}
|
||||
|
||||
// @Summary delete file
|
||||
// @Produce application/json
|
||||
// @Accept multipart/form-data
|
||||
// @Tags file
|
||||
// @Security ApiKeyAuth
|
||||
// @Param path query string true "path"
|
||||
// @Success 200 {string} string "ok"
|
||||
// @Router /file/delete [delete]
|
||||
func DeleteFile(c *gin.Context) {
|
||||
path := c.Query("path")
|
||||
//err := os.Remove(path)
|
||||
err := os.RemoveAll(path)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.FILE_DELETE_ERROR, Message: oasis_err2.GetMsg(oasis_err2.FILE_DELETE_ERROR), Data: err})
|
||||
return
|
||||
}
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS)})
|
||||
}
|
||||
|
||||
// @Summary update file
|
||||
// @Produce application/json
|
||||
// @Accept multipart/form-data
|
||||
// @Tags file
|
||||
// @Security ApiKeyAuth
|
||||
// @Param path formData string true "path"
|
||||
// @Param content formData string true "content"
|
||||
// @Success 200 {string} string "ok"
|
||||
// @Router /file/update [put]
|
||||
func PutFileContent(c *gin.Context) {
|
||||
path := c.PostForm("path")
|
||||
content := c.PostForm("content")
|
||||
if !file.Exists(path) {
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.FILE_ALREADY_EXISTS, Message: oasis_err2.GetMsg(oasis_err2.FILE_ALREADY_EXISTS)})
|
||||
return
|
||||
}
|
||||
//err := os.Remove(path)
|
||||
err := os.RemoveAll(path)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.FILE_DELETE_ERROR, Message: oasis_err2.GetMsg(oasis_err2.FILE_DELETE_ERROR), Data: err})
|
||||
return
|
||||
}
|
||||
err = file.CreateFileAndWriteContent(path, content)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.ERROR, Message: oasis_err2.GetMsg(oasis_err2.ERROR), Data: err})
|
||||
return
|
||||
}
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS)})
|
||||
}
|
||||
|
||||
// @Summary image thumbnail/original image
|
||||
// @Produce application/json
|
||||
// @Accept application/json
|
||||
// @Tags file
|
||||
// @Security ApiKeyAuth
|
||||
// @Param path query string true "path"
|
||||
// @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")
|
||||
if !file.Exists(path) {
|
||||
c.JSON(http.StatusInternalServerError, model.Result{Success: oasis_err2.FILE_ALREADY_EXISTS, Message: oasis_err2.GetMsg(oasis_err2.FILE_ALREADY_EXISTS)})
|
||||
return
|
||||
}
|
||||
if t == "thumbnail" {
|
||||
f, err := file.GetImage(path, 100, 0)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, model.Result{Success: oasis_err2.ERROR, Message: oasis_err2.GetMsg(oasis_err2.ERROR), Data: err.Error()})
|
||||
return
|
||||
}
|
||||
c.Writer.WriteString(string(f))
|
||||
return
|
||||
}
|
||||
f, err := os.Open(path)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, model.Result{Success: oasis_err2.ERROR, Message: oasis_err2.GetMsg(oasis_err2.ERROR), Data: err.Error()})
|
||||
return
|
||||
}
|
||||
defer f.Close()
|
||||
data, err := ioutil.ReadAll(f)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, model.Result{Success: oasis_err2.ERROR, Message: oasis_err2.GetMsg(oasis_err2.ERROR), Data: err.Error()})
|
||||
return
|
||||
}
|
||||
c.Writer.WriteString(string(data))
|
||||
}
|
||||
|
||||
@@ -1,15 +1,13 @@
|
||||
package v1
|
||||
|
||||
import (
|
||||
json2 "encoding/json"
|
||||
"github.com/IceWhaleTech/CasaOS/model"
|
||||
"github.com/IceWhaleTech/CasaOS/pkg/utils/oasis_err"
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/IceWhaleTech/CasaOS/service"
|
||||
"github.com/IceWhaleTech/CasaOS/types"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/gorilla/websocket"
|
||||
"net/http"
|
||||
"time"
|
||||
)
|
||||
|
||||
var upGrader = websocket.Upgrader{
|
||||
@@ -33,24 +31,17 @@ func NotifyWS(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
defer ws.Close()
|
||||
service.WebSocketConns = append(service.WebSocketConns, ws)
|
||||
|
||||
if !service.SocketRun {
|
||||
service.SocketRun = true
|
||||
service.SendMeg()
|
||||
}
|
||||
for {
|
||||
mt, message, err := ws.ReadMessage()
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
if string(message) != "notify" {
|
||||
return
|
||||
}
|
||||
for {
|
||||
list := service.MyService.Notify().GetList()
|
||||
json, _ := json2.Marshal(list)
|
||||
err = ws.WriteMessage(mt, json)
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
time.Sleep(time.Second * 2)
|
||||
}
|
||||
fmt.Println(mt, message, err)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// @Summary 标记notify已读
|
||||
@@ -62,9 +53,10 @@ func NotifyWS(c *gin.Context) {
|
||||
// @Router /notify/read/{id} [put]
|
||||
func PutNotifyRead(c *gin.Context) {
|
||||
id := c.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
|
||||
}
|
||||
// if len(id) == 0 {
|
||||
// c.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)
|
||||
}
|
||||
|
||||
803
route/v1/person.go
Normal file
803
route/v1/person.go
Normal file
@@ -0,0 +1,803 @@
|
||||
package v1
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/base64"
|
||||
"encoding/gob"
|
||||
"encoding/json"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"net/http"
|
||||
"os"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
natType "github.com/Curtis-Milo/nat-type-identifier-go"
|
||||
"github.com/IceWhaleTech/CasaOS/model"
|
||||
"github.com/IceWhaleTech/CasaOS/pkg/config"
|
||||
"github.com/IceWhaleTech/CasaOS/pkg/utils/file"
|
||||
"github.com/IceWhaleTech/CasaOS/pkg/utils/ip_helper"
|
||||
oasis_err2 "github.com/IceWhaleTech/CasaOS/pkg/utils/oasis_err"
|
||||
"github.com/IceWhaleTech/CasaOS/service"
|
||||
model2 "github.com/IceWhaleTech/CasaOS/service/model"
|
||||
"github.com/IceWhaleTech/CasaOS/types"
|
||||
"github.com/gin-gonic/gin"
|
||||
uuid "github.com/satori/go.uuid"
|
||||
)
|
||||
|
||||
// @Summary Retry the file that failed to download
|
||||
// @Produce application/json
|
||||
// @Accept application/json
|
||||
// @Tags person
|
||||
// @Param uui path string true "download uuid"
|
||||
// @Security ApiKeyAuth
|
||||
// @Success 200 {string} string "ok"
|
||||
// @Router /person/refile/{uuid} [get]
|
||||
func GetPersonReFile(c *gin.Context) {
|
||||
|
||||
uid := c.Param("uuid")
|
||||
_, err := uuid.FromString(uid)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.INVALID_PARAMS, Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS)})
|
||||
return
|
||||
}
|
||||
|
||||
task := service.MyService.Download().GetDownloadById(uid)
|
||||
if reflect.DeepEqual(task, model2.PersonDownloadDBModel{}) {
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.PERSON_REMOTE_ERROR, Message: oasis_err2.GetMsg(oasis_err2.PERSON_REMOTE_ERROR)})
|
||||
return
|
||||
}
|
||||
token := task.From
|
||||
if _, ok := service.UDPAddressMap[token]; !ok {
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.PERSON_REMOTE_ERROR, Message: oasis_err2.GetMsg(oasis_err2.PERSON_REMOTE_ERROR)})
|
||||
return
|
||||
}
|
||||
|
||||
m := model.MessageModel{}
|
||||
m.Data = task.Path
|
||||
m.From = config.ServerInfo.Token
|
||||
m.To = token
|
||||
m.Type = types.PERSONDOWNLOAD
|
||||
m.UUId = uid
|
||||
go service.Dial(m, false)
|
||||
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS)})
|
||||
}
|
||||
|
||||
// @Summary download file
|
||||
// @Produce application/json
|
||||
// @Accept application/json
|
||||
// @Tags person
|
||||
// @Param share_id query string true "opponent share_id"
|
||||
// @Param path query string true "file path"
|
||||
// @Param file_name query string true "file name"
|
||||
// @Param local_path query string true "local_path"
|
||||
// @Security ApiKeyAuth
|
||||
// @Success 200 {string} string "ok"
|
||||
// @Router /person/file [get]
|
||||
func GetPersonFile(c *gin.Context) {
|
||||
|
||||
path := c.Query("path")
|
||||
localPath := c.Query("local_path")
|
||||
token := c.Query("share_id")
|
||||
fileName := c.Query("file_name")
|
||||
_, err := uuid.FromString(token)
|
||||
if len(path) == 0 || err != nil || len(localPath) == 0 || len(fileName) == 0 {
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.INVALID_PARAMS, Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS)})
|
||||
return
|
||||
}
|
||||
if file.CheckNotExist(localPath) {
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.DIR_NOT_EXISTS, Message: oasis_err2.GetMsg(oasis_err2.DIR_NOT_EXISTS)})
|
||||
return
|
||||
}
|
||||
if _, ok := service.UDPAddressMap[token]; !ok {
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.PERSON_REMOTE_ERROR, Message: oasis_err2.GetMsg(oasis_err2.PERSON_REMOTE_ERROR)})
|
||||
return
|
||||
}
|
||||
|
||||
if _, ok := service.UDPAddressMap[token]; !ok {
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.PERSON_REMOTE_ERROR, Message: oasis_err2.GetMsg(oasis_err2.PERSON_REMOTE_ERROR)})
|
||||
return
|
||||
}
|
||||
|
||||
// task id
|
||||
uuid := uuid.NewV4().String()
|
||||
|
||||
task := model2.PersonDownloadDBModel{}
|
||||
task.UUID = uuid
|
||||
task.Name = fileName
|
||||
task.Length = 0
|
||||
task.From = token
|
||||
task.Path = path
|
||||
task.Size = 0
|
||||
task.State = types.DOWNLOADAWAIT
|
||||
task.Created = time.Now().Unix()
|
||||
task.Type = types.PERSONFILEDOWNLOAD
|
||||
task.LocalPath = localPath
|
||||
if service.MyService.Download().GetDownloadListByPath(task) > 0 {
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.PERSON_EXIST_DOWNLOAD, Message: oasis_err2.GetMsg(oasis_err2.PERSON_EXIST_DOWNLOAD)})
|
||||
return
|
||||
}
|
||||
service.MyService.Download().AddDownloadTask(task)
|
||||
|
||||
m := model.MessageModel{}
|
||||
m.Data = path
|
||||
m.From = config.ServerInfo.Token
|
||||
m.To = token
|
||||
m.Type = types.PERSONDOWNLOAD
|
||||
m.UUId = uuid
|
||||
go service.Dial(m, false)
|
||||
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS)})
|
||||
}
|
||||
|
||||
// @Summary delete download file records
|
||||
// @Produce application/json
|
||||
// @Accept application/json
|
||||
// @Tags person
|
||||
// @Param uuid path string true "download uuid"
|
||||
// @Security ApiKeyAuth
|
||||
// @Success 200 {string} string "ok"
|
||||
// @Router /person/file/{uuid} [delete]
|
||||
func DeletePersonDownloadFile(c *gin.Context) {
|
||||
|
||||
id := c.Param("uuid")
|
||||
_, err := uuid.FromString(id)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.INVALID_PARAMS, Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS)})
|
||||
return
|
||||
}
|
||||
|
||||
task := service.MyService.Download().GetDownloadById(id)
|
||||
if task.State == types.DOWNLOADING {
|
||||
m := model.MessageModel{}
|
||||
m.Data = ""
|
||||
m.From = config.ServerInfo.Token
|
||||
m.To = task.From
|
||||
m.Type = types.PERSONCANCEL
|
||||
m.UUId = task.UUID
|
||||
service.CancelList[task.UUID] = task.UUID
|
||||
service.Dial(m, false)
|
||||
}
|
||||
service.MyService.Download().DelDownload(id)
|
||||
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS)})
|
||||
}
|
||||
|
||||
// @Summary Get file download list
|
||||
// @Produce application/json
|
||||
// @Accept application/json
|
||||
// @Tags person
|
||||
// @Param state query int false "wait:0,downloading:1,pause:2,finish:3,error:4,finished:5" Enums(0,1,2,3,4,5)
|
||||
// @Security ApiKeyAuth
|
||||
// @Success 200 {object} []model2.PersonDownloadDBModel
|
||||
// @Router /person/list [get]
|
||||
func GetPersonDownloadList(c *gin.Context) {
|
||||
state := c.DefaultQuery("state", "")
|
||||
list := service.MyService.Download().GetDownloadListByState(state, types.PERSONFILEDOWNLOAD)
|
||||
//if it is downloading, it need to add 'already'
|
||||
for i := 0; i < len(list); i++ {
|
||||
if list[i].State == types.DOWNLOADING {
|
||||
tempDir := config.AppInfo.RootPath + "/temp" + "/" + list[i].UUID
|
||||
files, err := ioutil.ReadDir(tempDir)
|
||||
if err == nil {
|
||||
list[i].Already = len(files)
|
||||
}
|
||||
}
|
||||
list[i].Duration = time.Now().Unix() - list[i].Created
|
||||
}
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: list})
|
||||
}
|
||||
|
||||
// @Summary edit friend's remarks
|
||||
// @Produce application/json
|
||||
// @Accept application/json
|
||||
// @Tags person
|
||||
// @Param remarks formData string true "remarks name"
|
||||
// @Security ApiKeyAuth
|
||||
// @Success 200 {string} string "ok"
|
||||
// @Router /person/remarks/{shareid} [put]
|
||||
func PutPersonRemarks(c *gin.Context) {
|
||||
token := c.Param("shareid")
|
||||
_, err := uuid.FromString(token)
|
||||
mark := c.PostForm("remarks")
|
||||
if err != nil || len(mark) == 0 {
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.INVALID_PARAMS, Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS)})
|
||||
return
|
||||
}
|
||||
friend := model2.FriendModel{}
|
||||
friend.Token = token
|
||||
friend.Mark = mark
|
||||
service.MyService.Friend().EditFriendMark(friend)
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS)})
|
||||
}
|
||||
|
||||
// @Summary edit friend's
|
||||
// @Produce application/json
|
||||
// @Accept application/json
|
||||
// @Tags person
|
||||
// @Param write formData bool true "write"
|
||||
// @Security ApiKeyAuth
|
||||
// @Success 200 {string} string "ok"
|
||||
// @Router /person/write/{shareid} [put]
|
||||
func PutPersonWrite(c *gin.Context) {
|
||||
token := c.Param("shareid")
|
||||
_, err := uuid.FromString(token)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.INVALID_PARAMS, Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS)})
|
||||
return
|
||||
}
|
||||
write, _ := strconv.ParseBool(c.PostForm("write"))
|
||||
friend := model2.FriendModel{}
|
||||
friend.Token = token
|
||||
friend.Write = write
|
||||
service.MyService.Friend().EditFriendMark(friend)
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS)})
|
||||
}
|
||||
|
||||
// @Summary image thumbnail
|
||||
// @Produce application/json
|
||||
// @Accept application/json
|
||||
// @Tags person
|
||||
// @Param write formData bool true "write"
|
||||
// @Security ApiKeyAuth
|
||||
// @Success 200 {string} string "ok"
|
||||
// @Router /person/image/thumbnail/{shareid} [get]
|
||||
func GetPersonImageThumbnail(c *gin.Context) {
|
||||
token := c.Param("shareid")
|
||||
path := c.Query("path")
|
||||
_, err := uuid.FromString(token)
|
||||
if err != nil || len(path) == 0 {
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.INVALID_PARAMS, Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS)})
|
||||
return
|
||||
}
|
||||
uuid := uuid.NewV4().String()
|
||||
m := model.MessageModel{}
|
||||
m.Data = path
|
||||
m.From = config.ServerInfo.Token
|
||||
m.To = token
|
||||
m.Type = types.PERSONIMAGETHUMBNAIL
|
||||
m.UUId = uuid
|
||||
|
||||
img, err := service.Dial(m, false)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, model.Result{Success: oasis_err2.ERROR, Message: oasis_err2.GetMsg(oasis_err2.ERROR), Data: err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
// var buf bytes.Buffer
|
||||
//err = gob.NewEncoder(&buf).Encode(img.Data)
|
||||
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, model.Result{Success: oasis_err2.ERROR, Message: oasis_err2.GetMsg(oasis_err2.ERROR), Data: err.Error()})
|
||||
return
|
||||
}
|
||||
var buf bytes.Buffer
|
||||
err = gob.NewEncoder(&buf).Encode(img.Data)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, model.Result{Success: oasis_err2.ERROR, Message: oasis_err2.GetMsg(oasis_err2.ERROR), Data: err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
imageBuffer, _ := base64.StdEncoding.DecodeString(img.Data.(string))
|
||||
c.Writer.WriteString(string(imageBuffer))
|
||||
// c.String(http.StatusOK, "data:image/"+filesuffix+";base64,"+img.Data.(string))
|
||||
//c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: img.Data.(string)})
|
||||
}
|
||||
|
||||
// @Summary get my friend list
|
||||
// @Produce application/json
|
||||
// @Accept application/json
|
||||
// @Tags person
|
||||
// @Security ApiKeyAuth
|
||||
// @Success 200 {object} []model2.FriendModel
|
||||
// @Router /person/users [get]
|
||||
func GetPersonFriend(c *gin.Context) {
|
||||
list := service.MyService.Friend().GetFriendList()
|
||||
for i := 0; i < len(list); i++ {
|
||||
if v, ok := service.UDPAddressMap[list[i].Token]; ok && len(v) > 0 {
|
||||
list[i].OnLine = true
|
||||
if ip_helper.HasLocalIP(net.ParseIP(strings.Split(v, ":")[0])) {
|
||||
list[i].LocalIP = strings.Split(v, ":")[0]
|
||||
}
|
||||
}
|
||||
}
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: list})
|
||||
}
|
||||
|
||||
// @Summary network type detection
|
||||
// @Produce application/json
|
||||
// @Accept application/json
|
||||
// @Tags person
|
||||
// @Security ApiKeyAuth
|
||||
// @Success 200 {string} string "ok"
|
||||
// @Router /person/detection [get]
|
||||
func GetPersonDetection(c *gin.Context) {
|
||||
// - Blocked
|
||||
// - Open Internet
|
||||
// - Full Cone
|
||||
// - Symmetric UDP Firewall
|
||||
// - Restric NAT
|
||||
// - Restric Port NAT
|
||||
// - Symmetric NAT
|
||||
|
||||
result, err := natType.GetDeterminedNatType(true, 5, "stun.l.google.com")
|
||||
if err != nil {
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.ERROR, Message: oasis_err2.GetMsg(oasis_err2.ERROR), Data: err.Error()})
|
||||
return
|
||||
}
|
||||
//result := service.MyService.Person().GetPersionNetWorkTypeDetection()
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: result})
|
||||
}
|
||||
|
||||
// @Summary add friend
|
||||
// @Produce application/json
|
||||
// @Accept application/json
|
||||
// @Tags person
|
||||
// @Security ApiKeyAuth
|
||||
// @Success 200 {string} string "ok"
|
||||
// @Router /person/user/{shareids} [post]
|
||||
func PostAddPersonFriend(c *gin.Context) {
|
||||
token := c.Param("shareids")
|
||||
tokenList := strings.Split(token, ",")
|
||||
|
||||
for _, v := range tokenList {
|
||||
_, err := uuid.FromString(v)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.INVALID_PARAMS, Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS)})
|
||||
return
|
||||
}
|
||||
|
||||
if v == config.ServerInfo.Token {
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.PERSON_MYSELF, Message: oasis_err2.GetMsg(oasis_err2.PERSON_MYSELF)})
|
||||
return
|
||||
}
|
||||
|
||||
udb := service.MyService.Friend().GetFriendById(model2.FriendModel{Token: v})
|
||||
if !reflect.DeepEqual(udb, model2.FriendModel{Token: v}) {
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.PERSON_EXIST_FRIEND, Message: oasis_err2.GetMsg(oasis_err2.PERSON_EXIST_FRIEND)})
|
||||
return
|
||||
}
|
||||
|
||||
user := service.MyService.Casa().GetUserInfoByShareId(v)
|
||||
if reflect.DeepEqual(user, model.UserInfo{}) {
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.PERSON_NOT_EXIST_USER, Message: oasis_err2.GetMsg(oasis_err2.PERSON_NOT_EXIST_USER)})
|
||||
return
|
||||
}
|
||||
|
||||
message := model.MessageModel{}
|
||||
message.Type = types.PERSONCONNECTION
|
||||
message.Data = v
|
||||
message.From = config.ServerInfo.Token
|
||||
message.To = v
|
||||
message.UUId = uuid.NewV4().String()
|
||||
|
||||
go service.Dial(message, true)
|
||||
|
||||
msg := model.MessageModel{}
|
||||
msg.Type = types.PERSONGETIP
|
||||
msg.Data = ""
|
||||
msg.From = config.ServerInfo.Token
|
||||
msg.To = v
|
||||
msg.UUId = uuid.NewV4().String()
|
||||
|
||||
service.Dial(msg, true)
|
||||
|
||||
friend := model2.FriendModel{}
|
||||
friend.Token = v
|
||||
friend.Avatar = user.Avatar
|
||||
friend.Block = false
|
||||
friend.State = types.FRIENDSTATEWAIT
|
||||
friend.NickName = user.NickName
|
||||
friend.Profile = user.Desc
|
||||
friend.Version = user.Version
|
||||
service.MyService.Friend().AddFriend(friend)
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS)})
|
||||
}
|
||||
|
||||
// @Summary Get a list of directories
|
||||
// @Produce application/json
|
||||
// @Accept application/json
|
||||
// @Tags person
|
||||
// @Param share_id query string true "Opponent share_id"
|
||||
// @Param path query string true "dir path"
|
||||
// @Security ApiKeyAuth
|
||||
// @Success 200 {object} []model.Path
|
||||
// @Router /person/directory [get]
|
||||
func GetPersonDirectory(c *gin.Context) {
|
||||
path := c.Query("path")
|
||||
token := c.Query("share_id")
|
||||
_, err := uuid.FromString(token)
|
||||
if len(path) == 0 || err != nil {
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.INVALID_PARAMS, Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS)})
|
||||
return
|
||||
}
|
||||
if _, ok := service.UDPAddressMap[token]; !ok {
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.PERSON_REMOTE_ERROR, Message: oasis_err2.GetMsg(oasis_err2.PERSON_REMOTE_ERROR)})
|
||||
return
|
||||
}
|
||||
uuid := uuid.NewV4().String()
|
||||
m := model.MessageModel{}
|
||||
m.Data = path
|
||||
m.From = config.ServerInfo.Token
|
||||
m.To = token
|
||||
m.Type = types.PERSONDIRECTORY
|
||||
m.UUId = uuid
|
||||
result, err := service.Dial(m, false)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.ERROR, Message: oasis_err2.GetMsg(oasis_err2.ERROR), Data: err.Error()})
|
||||
return
|
||||
}
|
||||
dataModel := []model.Path{}
|
||||
if uuid == m.UUId {
|
||||
dataModelByte, _ := json.Marshal(result.Data)
|
||||
err := json.Unmarshal(dataModelByte, &dataModel)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.ERROR, Message: oasis_err2.GetMsg(oasis_err2.ERROR), Data: err.Error()})
|
||||
return
|
||||
}
|
||||
}
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: dataModel})
|
||||
}
|
||||
|
||||
// @Summary Modify the download storage directory
|
||||
// @Produce application/json
|
||||
// @Accept multipart/form-data
|
||||
// @Tags person
|
||||
// @Security ApiKeyAuth
|
||||
// @Param path formData string true "path"
|
||||
// @Success 200 {string} string "ok"
|
||||
// @Router /person/down/dir [post]
|
||||
func PostPersonDownDir(c *gin.Context) {
|
||||
|
||||
downPath := c.PostForm("path")
|
||||
|
||||
if len(downPath) == 0 {
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.INVALID_PARAMS, Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS)})
|
||||
return
|
||||
}
|
||||
if file.CheckNotExist(downPath) {
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.DIR_NOT_EXISTS, Message: oasis_err2.GetMsg(oasis_err2.DIR_NOT_EXISTS)})
|
||||
return
|
||||
}
|
||||
config.Cfg.Section("file").Key("DownloadDir").SetValue(downPath)
|
||||
config.Cfg.SaveTo(config.SystemConfigInfo.ConfigPath)
|
||||
config.FileSettingInfo.DownloadDir = downPath
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS)})
|
||||
}
|
||||
|
||||
// @Summary Get the download storage directory
|
||||
// @Produce application/json
|
||||
// @Accept application/json
|
||||
// @Tags person
|
||||
// @Security ApiKeyAuth
|
||||
// @Success 200 {string} string "ok"
|
||||
// @Router /person/down/dir [get]
|
||||
func GetPersonDownDir(c *gin.Context) {
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: config.FileSettingInfo.DownloadDir})
|
||||
}
|
||||
|
||||
// @Summary Modify the shared directory
|
||||
// @Produce application/json
|
||||
// @Accept multipart/form-data
|
||||
// @Tags person
|
||||
// @Security ApiKeyAuth
|
||||
// @Param share formData string true "share"
|
||||
// @Success 200 {string} string "ok"
|
||||
// @Router /person/share [post]
|
||||
func PostPersonShare(c *gin.Context) {
|
||||
|
||||
share := c.PostForm("share")
|
||||
|
||||
if len(share) == 0 {
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.INVALID_PARAMS, Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS)})
|
||||
return
|
||||
}
|
||||
|
||||
var list []string
|
||||
json.Unmarshal([]byte(share), &list)
|
||||
|
||||
if len(list) == 0 {
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.INVALID_PARAMS, Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS)})
|
||||
return
|
||||
}
|
||||
for _, v := range list {
|
||||
if !file.Exists(v) {
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.FILE_ALREADY_EXISTS, Message: oasis_err2.GetMsg(oasis_err2.FILE_ALREADY_EXISTS)})
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
config.Cfg.Section("file").Key("ShareDir").SetValue(strings.Join(list, "|"))
|
||||
config.Cfg.SaveTo(config.SystemConfigInfo.ConfigPath)
|
||||
config.FileSettingInfo.ShareDir = list
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS)})
|
||||
}
|
||||
|
||||
// @Summary Get the shared directory
|
||||
// @Produce application/json
|
||||
// @Accept application/json
|
||||
// @Tags person
|
||||
// @Security ApiKeyAuth
|
||||
// @Success 200 {string} string "ok"
|
||||
// @Router /person/share [get]
|
||||
func GetPersonShare(c *gin.Context) {
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: config.FileSettingInfo.ShareDir})
|
||||
}
|
||||
|
||||
// @Summary Get the shareid
|
||||
// @Produce application/json
|
||||
// @Accept application/json
|
||||
// @Tags person
|
||||
// @Security ApiKeyAuth
|
||||
// @Success 200 {string} string "ok"
|
||||
// @Router /person/shareid [get]
|
||||
func GetPersonShareId(c *gin.Context) {
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: config.ServerInfo.Token})
|
||||
}
|
||||
|
||||
// @Summary Modify disabled status
|
||||
// @Produce application/json
|
||||
// @Accept application/json
|
||||
// @Tags person
|
||||
// @Param block formData bool false "Disable or not,Default:false "
|
||||
// @Security ApiKeyAuth
|
||||
// @Success 200 {string} string "ok"
|
||||
// @Router /person/block/{shareid} [put]
|
||||
func PutPersonBlock(c *gin.Context) {
|
||||
token := c.Param("shareid")
|
||||
_, err := uuid.FromString(token)
|
||||
block, _ := strconv.ParseBool(c.PostForm("block"))
|
||||
if err != nil {
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.INVALID_PARAMS, Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS)})
|
||||
return
|
||||
}
|
||||
friend := model2.FriendModel{}
|
||||
friend.Token = token
|
||||
friend.Block = block
|
||||
service.MyService.Friend().EditFriendBlock(friend)
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS)})
|
||||
}
|
||||
|
||||
// @Summary Delete my friend
|
||||
// @Produce application/json
|
||||
// @Accept application/json
|
||||
// @Tags person
|
||||
// @Security ApiKeyAuth
|
||||
// @Success 200 {string} string "ok"
|
||||
// @Router /person/user/{shareid} [delete]
|
||||
func DeletePersonFriend(c *gin.Context) {
|
||||
token := c.Param("shareid")
|
||||
_, err := uuid.FromString(token)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.INVALID_PARAMS, Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS)})
|
||||
return
|
||||
}
|
||||
friend := model2.FriendModel{}
|
||||
friend.Token = token
|
||||
|
||||
service.MyService.Friend().DeleteFriend(friend)
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS)})
|
||||
}
|
||||
|
||||
// @Summary Get public person
|
||||
// @Produce application/json
|
||||
// @Accept application/json
|
||||
// @Tags person
|
||||
// @Security ApiKeyAuth
|
||||
// @Success 200 {string} string "ok"
|
||||
// @Router /person/public [get]
|
||||
func GetPersonPublic(c *gin.Context) {
|
||||
list := service.MyService.Casa().GetPersonPublic()
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: list})
|
||||
}
|
||||
|
||||
// @Summary upload file to friend
|
||||
// @Produce application/json
|
||||
// @Accept application/json
|
||||
// @Tags person
|
||||
// @Security ApiKeyAuth
|
||||
// @Param path formData string true "Destination path"
|
||||
// @Param local_path formData string true "Full path of the file to be uploaded"
|
||||
// @Success 200 {string} string "ok"
|
||||
// @Router /person/file/{shareid} [post]
|
||||
func PostPersonFile(c *gin.Context) {
|
||||
token := c.Param("shareid")
|
||||
_, err := uuid.FromString(token)
|
||||
path := c.PostForm("path")
|
||||
localPath := c.PostForm("local_path")
|
||||
if err != nil {
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.INVALID_PARAMS, Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS)})
|
||||
return
|
||||
}
|
||||
if !file.Exists(localPath) {
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.FILE_DOES_NOT_EXIST, Message: oasis_err2.GetMsg(oasis_err2.FILE_DOES_NOT_EXIST)})
|
||||
return
|
||||
}
|
||||
uuid := uuid.NewV4().String()
|
||||
m := model.MessageModel{}
|
||||
m.Data = path
|
||||
m.From = config.ServerInfo.Token
|
||||
m.To = token
|
||||
m.Type = types.PERSONUPLOAD
|
||||
m.UUId = uuid
|
||||
go service.UDPSendData(m, localPath)
|
||||
|
||||
f, _ := os.Stat(localPath)
|
||||
|
||||
task := model2.PersonDownloadDBModel{}
|
||||
task.UUID = uuid
|
||||
task.Name = f.Name()
|
||||
task.Length = 0
|
||||
task.From = token
|
||||
task.Path = path
|
||||
task.Size = f.Size()
|
||||
task.State = types.DOWNLOADFINISHED
|
||||
task.Created = time.Now().Unix()
|
||||
task.Type = types.PERSONFILEUPLOAD
|
||||
task.LocalPath = localPath
|
||||
if service.MyService.Download().GetDownloadListByPath(task) > 0 {
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.PERSON_EXIST_DOWNLOAD, Message: oasis_err2.GetMsg(oasis_err2.PERSON_EXIST_DOWNLOAD)})
|
||||
return
|
||||
}
|
||||
service.MyService.Download().AddDownloadTask(task)
|
||||
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS)})
|
||||
}
|
||||
|
||||
// @Summary agree add friend
|
||||
// @Produce application/json
|
||||
// @Accept application/json
|
||||
// @Tags person
|
||||
// @Security ApiKeyAuth
|
||||
// @Success 200 {string} string "ok"
|
||||
// @Router /person/friend/{shareid} [put]
|
||||
func PutPersonAgreeFriend(c *gin.Context) {
|
||||
token := c.Param("shareid")
|
||||
_, err := uuid.FromString(token)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.INVALID_PARAMS, Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS)})
|
||||
return
|
||||
}
|
||||
|
||||
user := service.MyService.Friend().GetFriendById(model2.FriendModel{Token: token})
|
||||
|
||||
if user.State != types.FRIENDSTATEREQUEST {
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.COMMAND_ERROR_INVALID_OPERATION, Message: oasis_err2.GetMsg(oasis_err2.COMMAND_ERROR_INVALID_OPERATION)})
|
||||
return
|
||||
}
|
||||
service.MyService.Friend().AgreeFrined(user.Token)
|
||||
|
||||
uuid := uuid.NewV4().String()
|
||||
m := model.MessageModel{}
|
||||
m.Data = ""
|
||||
m.From = config.ServerInfo.Token
|
||||
m.To = token
|
||||
m.Type = types.PERSONAGREEFRIEND
|
||||
m.UUId = uuid
|
||||
go service.Dial(m, true)
|
||||
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS)})
|
||||
}
|
||||
|
||||
// // @Summary upload file
|
||||
// // @Produce application/json
|
||||
// // @Accept multipart/form-data
|
||||
// // @Tags person
|
||||
// // @Security ApiKeyAuth
|
||||
// // @Param path formData string false "file path"
|
||||
// // @Param file formData file true "file"
|
||||
// // @Success 200 {string} string "ok"
|
||||
// // @Router /person/upload/{shareid} [get]
|
||||
// func GetPersonFileUpload(c *gin.Context) {
|
||||
|
||||
// token := c.Param("shareid")
|
||||
// _, err := uuid.FromString(token)
|
||||
// path := c.Query("path")
|
||||
// if err != nil {
|
||||
// c.JSON(http.StatusOK, model.Result{Success: oasis_err2.INVALID_PARAMS, Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS)})
|
||||
// return
|
||||
// }
|
||||
|
||||
// relative := c.Query("relativePath")
|
||||
// fileName := c.Query("filename")
|
||||
// chunkNumber := c.Query("chunkNumber")
|
||||
// totalChunks, _ := strconv.Atoi(c.DefaultQuery("totalChunks", "0"))
|
||||
// dirPath := ""
|
||||
// hash := file.GetHashByContent([]byte(fileName))
|
||||
// tempDir := "/casaOS/temp/" + hash + strconv.Itoa(totalChunks) + "/"
|
||||
// if fileName != relative {
|
||||
// dirPath = strings.TrimSuffix(relative, fileName)
|
||||
// tempDir += dirPath
|
||||
// file.MkDir(path + "/" + dirPath)
|
||||
// }
|
||||
// tempDir += chunkNumber
|
||||
// if !file.CheckNotExist(tempDir) {
|
||||
// c.JSON(200, model.Result{Success: 200, Message: oasis_err2.GetMsg(oasis_err2.FILE_ALREADY_EXISTS)})
|
||||
// return
|
||||
// }
|
||||
|
||||
// c.JSON(204, model.Result{Success: 204, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS)})
|
||||
// }
|
||||
|
||||
// // @Summary upload file
|
||||
// // @Produce application/json
|
||||
// // @Accept multipart/form-data
|
||||
// // @Tags person
|
||||
// // @Security ApiKeyAuth
|
||||
// // @Param path formData string false "file path"
|
||||
// // @Param file formData file true "file"
|
||||
// // @Success 200 {string} string "ok"
|
||||
// // @Router /person/upload [post]
|
||||
// func PostPersonFileUpload(c *gin.Context) {
|
||||
// token := c.Param("shareid")
|
||||
// _, err := uuid.FromString(token)
|
||||
// if err != nil {
|
||||
// c.JSON(http.StatusOK, model.Result{Success: oasis_err2.INVALID_PARAMS, Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS)})
|
||||
// return
|
||||
// }
|
||||
// f, _, _ := c.Request.FormFile("file")
|
||||
// relative := c.PostForm("relativePath")
|
||||
// fileName := c.PostForm("filename")
|
||||
// totalChunks, _ := strconv.Atoi(c.DefaultPostForm("totalChunks", "0"))
|
||||
// chunkNumber := c.PostForm("chunkNumber")
|
||||
// dirPath := ""
|
||||
// path := c.PostForm("path")
|
||||
|
||||
// hash := file.GetHashByContent([]byte(fileName))
|
||||
|
||||
// if len(path) == 0 {
|
||||
// c.JSON(oasis_err2.INVALID_PARAMS, model.Result{Success: oasis_err2.INVALID_PARAMS, Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS)})
|
||||
// return
|
||||
// }
|
||||
// tempDir := "/casaOS/temp/" + hash + strconv.Itoa(totalChunks) + "/"
|
||||
|
||||
// if fileName != relative {
|
||||
// dirPath = strings.TrimSuffix(relative, fileName)
|
||||
// tempDir += dirPath
|
||||
// file.MkDir(path + "/" + dirPath)
|
||||
// }
|
||||
|
||||
// path += "/" + relative
|
||||
|
||||
// if !file.CheckNotExist(tempDir + chunkNumber) {
|
||||
// file.RMDir(tempDir + chunkNumber)
|
||||
// }
|
||||
|
||||
// if totalChunks > 1 {
|
||||
// file.IsNotExistMkDir(tempDir)
|
||||
|
||||
// out, _ := os.OpenFile(tempDir+chunkNumber, os.O_WRONLY|os.O_CREATE, 0644)
|
||||
// defer out.Close()
|
||||
// _, err := io.Copy(out, f)
|
||||
// if err != nil {
|
||||
// c.JSON(oasis_err2.ERROR, model.Result{Success: oasis_err2.ERROR, Message: oasis_err2.GetMsg(oasis_err2.ERROR), Data: err.Error()})
|
||||
// return
|
||||
// }
|
||||
// } else {
|
||||
// out, _ := os.OpenFile(path, os.O_WRONLY|os.O_CREATE, 0644)
|
||||
// defer out.Close()
|
||||
// _, err := io.Copy(out, f)
|
||||
// if err != nil {
|
||||
// c.JSON(oasis_err2.ERROR, model.Result{Success: oasis_err2.ERROR, Message: oasis_err2.GetMsg(oasis_err2.ERROR), Data: err.Error()})
|
||||
// return
|
||||
// }
|
||||
// c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS)})
|
||||
// return
|
||||
// }
|
||||
|
||||
// fileNum, err := ioutil.ReadDir(tempDir)
|
||||
// if err != nil {
|
||||
// c.JSON(oasis_err2.ERROR, model.Result{Success: oasis_err2.ERROR, Message: oasis_err2.GetMsg(oasis_err2.ERROR), Data: err.Error()})
|
||||
// return
|
||||
// }
|
||||
// if totalChunks == len(fileNum) {
|
||||
// file.RMDir(tempDir)
|
||||
// }
|
||||
|
||||
// c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS)})
|
||||
// }
|
||||
35
route/v1/sync.go
Normal file
35
route/v1/sync.go
Normal file
@@ -0,0 +1,35 @@
|
||||
package v1
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"net/http/httputil"
|
||||
"net/url"
|
||||
"strings"
|
||||
|
||||
"github.com/IceWhaleTech/CasaOS/model"
|
||||
"github.com/IceWhaleTech/CasaOS/pkg/config"
|
||||
"github.com/IceWhaleTech/CasaOS/pkg/utils/oasis_err"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
func SyncToSyncthing(c *gin.Context) {
|
||||
u := c.Param("url")
|
||||
target := "http://" + strings.Split(c.Request.Host, ":")[0] + ":" + config.SystemConfigInfo.SyncPort
|
||||
remote, err := url.Parse(target)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
proxy := httputil.NewSingleHostReverseProxy(remote)
|
||||
c.Request.Header.Add("X-API-Key", config.SystemConfigInfo.SyncKey)
|
||||
//c.Request.Header.Add("X-API-Key", config.SystemConfigInfo.SyncKey)
|
||||
c.Request.URL.Path = u
|
||||
|
||||
proxy.ServeHTTP(c.Writer, c.Request)
|
||||
}
|
||||
|
||||
func GetSyncConfig(c *gin.Context) {
|
||||
data := make(map[string]string)
|
||||
data["key"] = config.SystemConfigInfo.SyncKey
|
||||
data["port"] = config.SystemConfigInfo.SyncPort
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err.SUCCESS, Message: oasis_err.GetMsg(oasis_err.SUCCESS), Data: data})
|
||||
}
|
||||
@@ -4,12 +4,18 @@ import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"os"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
"unsafe"
|
||||
|
||||
"github.com/IceWhaleTech/CasaOS/model"
|
||||
"github.com/IceWhaleTech/CasaOS/pkg/config"
|
||||
"github.com/IceWhaleTech/CasaOS/pkg/utils/oasis_err"
|
||||
oasis_err2 "github.com/IceWhaleTech/CasaOS/pkg/utils/oasis_err"
|
||||
port2 "github.com/IceWhaleTech/CasaOS/pkg/utils/port"
|
||||
"github.com/IceWhaleTech/CasaOS/pkg/utils/version"
|
||||
"github.com/IceWhaleTech/CasaOS/service"
|
||||
model2 "github.com/IceWhaleTech/CasaOS/service/model"
|
||||
@@ -17,7 +23,7 @@ import (
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
// @Summary 系统信息
|
||||
// @Summary check version
|
||||
// @Produce application/json
|
||||
// @Accept application/json
|
||||
// @Tags sys
|
||||
@@ -28,13 +34,12 @@ func CheckVersion(c *gin.Context) {
|
||||
need, version := version.IsNeedUpdate()
|
||||
if need {
|
||||
installLog := model2.AppNotify{}
|
||||
installLog.CustomId = ""
|
||||
installLog.State = 0
|
||||
installLog.Message = "New version " + version.Version + " is ready, ready to upgrade"
|
||||
installLog.Speed = 100
|
||||
installLog.Type = types.NOTIFY_TYPE_NEED_CONFIRM
|
||||
installLog.CreatedAt = strconv.FormatInt(time.Now().Unix(), 10)
|
||||
installLog.UpdatedAt = strconv.FormatInt(time.Now().Unix(), 10)
|
||||
installLog.Name = "CasaOS System"
|
||||
service.MyService.Notify().AddLog(installLog)
|
||||
}
|
||||
data := make(map[string]interface{}, 1)
|
||||
@@ -45,6 +50,32 @@ func CheckVersion(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
// @Summary check client version
|
||||
// @Produce application/json
|
||||
// @Accept application/json
|
||||
// @Tags sys
|
||||
// @Security ApiKeyAuth
|
||||
// @Success 200 {string} string "ok"
|
||||
// @Router /sys/client/version [get]
|
||||
func GetClientVersion(c *gin.Context) {
|
||||
need, version := version.IsClientNeedUpdate()
|
||||
if need {
|
||||
installLog := model2.AppNotify{}
|
||||
installLog.State = 0
|
||||
installLog.Message = "New version " + version.Version + " is ready, ready to upgrade"
|
||||
installLog.Type = types.NOTIFY_TYPE_NEED_CONFIRM
|
||||
installLog.CreatedAt = strconv.FormatInt(time.Now().Unix(), 10)
|
||||
installLog.UpdatedAt = strconv.FormatInt(time.Now().Unix(), 10)
|
||||
installLog.Name = "CasaOS System"
|
||||
service.MyService.Notify().AddLog(installLog)
|
||||
}
|
||||
data := make(map[string]interface{}, 1)
|
||||
data["is_need"] = need
|
||||
data["version"] = version
|
||||
data["current_version"] = types.CURRENTVERSION
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err.SUCCESS, Message: oasis_err.GetMsg(oasis_err.SUCCESS), Data: data})
|
||||
}
|
||||
|
||||
// @Summary 系统信息
|
||||
// @Produce application/json
|
||||
// @Accept application/json
|
||||
@@ -69,7 +100,6 @@ func GetSystemConfig(c *gin.Context) {
|
||||
// @Produce application/json
|
||||
// @Accept application/json
|
||||
// @Tags sys
|
||||
// @Param file query line false "get the number of log lines"
|
||||
// @Security ApiKeyAuth
|
||||
// @Success 200 {string} string "ok"
|
||||
// @Router /sys/error/logs [get]
|
||||
@@ -82,7 +112,7 @@ func GetCasaOSErrorLogs(c *gin.Context) {
|
||||
// @Produce application/json
|
||||
// @Accept multipart/form-data
|
||||
// @Tags sys
|
||||
// @Param file formData file true "用户头像"
|
||||
// @Param config formData string true "config json string"
|
||||
// @Security ApiKeyAuth
|
||||
// @Success 200 {string} string "ok"
|
||||
// @Router /sys/changhead [post]
|
||||
@@ -104,12 +134,33 @@ func GetSystemConfigDebug(c *gin.Context) {
|
||||
|
||||
array := service.MyService.System().GetSystemConfigDebug()
|
||||
disk := service.MyService.ZiMa().GetDiskInfo()
|
||||
array = append(array, fmt.Sprintf("disk,totle:%v,used:%v,UsedPercent:%v", disk.Total>>20, disk.Used>>20, disk.UsedPercent))
|
||||
sys := service.MyService.ZiMa().GetSysInfo()
|
||||
//todo 准备sync需要显示的数据(镜像,容器)
|
||||
var systemAppStatus string
|
||||
images := service.MyService.Docker().IsExistImage("linuxserver/syncthing")
|
||||
systemAppStatus += "Sync img: " + strconv.FormatBool(images) + "\n\t"
|
||||
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err.SUCCESS, Message: oasis_err.GetMsg(oasis_err.SUCCESS), Data: array})
|
||||
}
|
||||
func Sys(c *gin.Context) {
|
||||
service.DockerPull()
|
||||
list := service.MyService.App().GetSystemAppList()
|
||||
for _, v := range list {
|
||||
systemAppStatus += v.Image + ",\n\t"
|
||||
}
|
||||
|
||||
systemAppStatus += "Sync Key length: " + strconv.Itoa(len(config.SystemConfigInfo.SyncKey))
|
||||
|
||||
var bugContent string = fmt.Sprintf(`
|
||||
- OS: %s
|
||||
- CasaOS Version: %s
|
||||
- Disk Total: %v
|
||||
- Disk Used: %v
|
||||
- Sync State: %s
|
||||
- System Info: %s
|
||||
- Browser: $Browser$
|
||||
- Version: $Version$
|
||||
`, sys.OS, types.CURRENTVERSION, disk.Total>>20, disk.Used>>20, systemAppStatus, array)
|
||||
|
||||
// array = append(array, fmt.Sprintf("disk,total:%v,used:%v,UsedPercent:%v", disk.Total>>20, disk.Used>>20, disk.UsedPercent))
|
||||
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err.SUCCESS, Message: oasis_err.GetMsg(oasis_err.SUCCESS), Data: bugContent})
|
||||
}
|
||||
|
||||
//widget配置
|
||||
@@ -127,7 +178,6 @@ func GetWidgetConfig(c *gin.Context) {
|
||||
func PostSetWidgetConfig(c *gin.Context) {
|
||||
buf := make([]byte, 1024)
|
||||
n, _ := c.Request.Body.Read(buf)
|
||||
|
||||
service.MyService.System().UpSystemConfig("", string(buf[0:n]))
|
||||
c.JSON(http.StatusOK,
|
||||
model.Result{
|
||||
@@ -137,6 +187,58 @@ func PostSetWidgetConfig(c *gin.Context) {
|
||||
})
|
||||
}
|
||||
|
||||
// @Summary get casaos server port
|
||||
// @Produce application/json
|
||||
// @Accept application/json
|
||||
// @Tags sys
|
||||
// @Security ApiKeyAuth
|
||||
// @Success 200 {string} string "ok"
|
||||
// @Router /sys/port [get]
|
||||
func GetCasaOSPort(c *gin.Context) {
|
||||
c.JSON(http.StatusOK,
|
||||
model.Result{
|
||||
Success: oasis_err.SUCCESS,
|
||||
Message: oasis_err.GetMsg(oasis_err.SUCCESS),
|
||||
Data: config.ServerInfo.HttpPort,
|
||||
})
|
||||
}
|
||||
|
||||
// @Summary edit casaos server port
|
||||
// @Produce application/json
|
||||
// @Accept application/json
|
||||
// @Tags sys
|
||||
// @Security ApiKeyAuth
|
||||
// @Param port formData string true "port"
|
||||
// @Success 200 {string} string "ok"
|
||||
// @Router /sys/port [put]
|
||||
func PutCasaOSPort(c *gin.Context) {
|
||||
port, err := strconv.Atoi(c.PostForm("port"))
|
||||
if err != nil {
|
||||
c.JSON(http.StatusOK,
|
||||
model.Result{
|
||||
Success: oasis_err.ERROR,
|
||||
Message: err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
isAvailable := port2.IsPortAvailable(port, "tcp")
|
||||
if !isAvailable {
|
||||
c.JSON(http.StatusOK,
|
||||
model.Result{
|
||||
Success: oasis_err.PORT_IS_OCCUPIED,
|
||||
Message: oasis_err.GetMsg(oasis_err.PORT_IS_OCCUPIED),
|
||||
})
|
||||
return
|
||||
}
|
||||
service.MyService.System().UpSystemPort(strconv.Itoa(port))
|
||||
c.JSON(http.StatusOK,
|
||||
model.Result{
|
||||
Success: oasis_err.SUCCESS,
|
||||
Message: oasis_err.GetMsg(oasis_err.SUCCESS),
|
||||
})
|
||||
}
|
||||
|
||||
// @Summary 检查是否进入引导状态
|
||||
// @Produce application/json
|
||||
// @Accept application/json
|
||||
@@ -158,3 +260,223 @@ func GetGuideCheck(c *gin.Context) {
|
||||
Data: data,
|
||||
})
|
||||
}
|
||||
|
||||
// @Summary active killing casaos
|
||||
// @Produce application/json
|
||||
// @Accept application/json
|
||||
// @Tags sys
|
||||
// @Security ApiKeyAuth
|
||||
// @Success 200 {string} string "ok"
|
||||
// @Router /sys/kill [post]
|
||||
func PostKillCasaOS(c *gin.Context) {
|
||||
os.Exit(0)
|
||||
}
|
||||
|
||||
// @Summary Turn off usb auto-mount
|
||||
// @Produce application/json
|
||||
// @Accept application/json
|
||||
// @Tags sys
|
||||
// @Security ApiKeyAuth
|
||||
// @Success 200 {string} string "ok"
|
||||
// @Router /sys/usb/off [put]
|
||||
func PutSystemOffUSBAutoMount(c *gin.Context) {
|
||||
service.MyService.System().UpdateUSBAutoMount("False")
|
||||
service.MyService.System().ExecUSBAutoMountShell("False")
|
||||
c.JSON(http.StatusOK,
|
||||
model.Result{
|
||||
Success: oasis_err.SUCCESS,
|
||||
Message: oasis_err.GetMsg(oasis_err.SUCCESS),
|
||||
})
|
||||
}
|
||||
|
||||
// @Summary Turn off usb auto-mount
|
||||
// @Produce application/json
|
||||
// @Accept application/json
|
||||
// @Tags sys
|
||||
// @Security ApiKeyAuth
|
||||
// @Success 200 {string} string "ok"
|
||||
// @Router /sys/usb [get]
|
||||
func GetSystemUSBAutoMount(c *gin.Context) {
|
||||
state := "True"
|
||||
if config.ServerInfo.USBAutoMount == "False" {
|
||||
state = "False"
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK,
|
||||
model.Result{
|
||||
Success: oasis_err.SUCCESS,
|
||||
Message: oasis_err.GetMsg(oasis_err.SUCCESS),
|
||||
Data: state,
|
||||
})
|
||||
}
|
||||
|
||||
// @Summary get system hardware info
|
||||
// @Produce application/json
|
||||
// @Accept application/json
|
||||
// @Tags sys
|
||||
// @Security ApiKeyAuth
|
||||
// @Success 200 {string} string "ok"
|
||||
// @Router /sys/hardware/info [get]
|
||||
func GetSystemHardwareInfo(c *gin.Context) {
|
||||
|
||||
data := make(map[string]string, 1)
|
||||
data["drive_model"] = service.MyService.ZiMa().GetDeviceTree()
|
||||
c.JSON(http.StatusOK,
|
||||
model.Result{
|
||||
Success: oasis_err.SUCCESS,
|
||||
Message: oasis_err.GetMsg(oasis_err.SUCCESS),
|
||||
Data: data,
|
||||
})
|
||||
}
|
||||
|
||||
// @Summary Turn off usb auto-mount
|
||||
// @Produce application/json
|
||||
// @Accept application/json
|
||||
// @Tags sys
|
||||
// @Security ApiKeyAuth
|
||||
// @Success 200 {string} string "ok"
|
||||
// @Router /sys/usb/on [put]
|
||||
func PutSystemOnUSBAutoMount(c *gin.Context) {
|
||||
service.MyService.System().UpdateUSBAutoMount("True")
|
||||
service.MyService.System().ExecUSBAutoMountShell("True")
|
||||
c.JSON(http.StatusOK,
|
||||
model.Result{
|
||||
Success: oasis_err.SUCCESS,
|
||||
Message: oasis_err.GetMsg(oasis_err.SUCCESS),
|
||||
})
|
||||
}
|
||||
|
||||
// @Summary system info
|
||||
// @Produce application/json
|
||||
// @Accept application/json
|
||||
// @Tags sys
|
||||
// @Security ApiKeyAuth
|
||||
// @Success 200 {string} string "ok"
|
||||
// @Router /sys/info [get]
|
||||
func Info(c *gin.Context) {
|
||||
var data = make(map[string]interface{}, 6)
|
||||
|
||||
list := service.MyService.Disk().LSBLK(true)
|
||||
|
||||
summary := model.Summary{}
|
||||
healthy := true
|
||||
findSystem := 0
|
||||
|
||||
for i := 0; i < len(list); i++ {
|
||||
if len(list[i].Children) > 0 && findSystem == 0 {
|
||||
|
||||
for j := 0; j < len(list[i].Children); j++ {
|
||||
|
||||
if len(list[i].Children[j].Children) > 0 {
|
||||
for _, v := range list[i].Children[j].Children {
|
||||
if v.MountPoint == "/" {
|
||||
s, _ := strconv.ParseUint(v.FSSize, 10, 64)
|
||||
a, _ := strconv.ParseUint(v.FSAvail, 10, 64)
|
||||
u, _ := strconv.ParseUint(v.FSUsed, 10, 64)
|
||||
summary.Size += s
|
||||
summary.Avail += a
|
||||
summary.Used += u
|
||||
findSystem = 1
|
||||
break
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if list[i].Children[j].MountPoint == "/" {
|
||||
s, _ := strconv.ParseUint(list[i].Children[j].FSSize, 10, 64)
|
||||
a, _ := strconv.ParseUint(list[i].Children[j].FSAvail, 10, 64)
|
||||
u, _ := strconv.ParseUint(list[i].Children[j].FSUsed, 10, 64)
|
||||
summary.Size += s
|
||||
summary.Avail += a
|
||||
summary.Used += u
|
||||
findSystem = 1
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
if findSystem == 1 {
|
||||
findSystem += 1
|
||||
continue
|
||||
}
|
||||
if list[i].Tran == "sata" || list[i].Tran == "nvme" || list[i].Tran == "spi" || list[i].Tran == "sas" {
|
||||
temp := service.MyService.Disk().SmartCTL(list[i].Path)
|
||||
if reflect.DeepEqual(temp, model.SmartctlA{}) {
|
||||
continue
|
||||
}
|
||||
|
||||
//list[i].Temperature = temp.Temperature.Current
|
||||
if !temp.SmartStatus.Passed {
|
||||
healthy = false
|
||||
}
|
||||
if len(list[i].Children) > 0 {
|
||||
for _, v := range list[i].Children {
|
||||
s, _ := strconv.ParseUint(v.FSSize, 10, 64)
|
||||
a, _ := strconv.ParseUint(v.FSAvail, 10, 64)
|
||||
u, _ := strconv.ParseUint(v.FSUsed, 10, 64)
|
||||
summary.Size += s
|
||||
summary.Avail += a
|
||||
summary.Used += u
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
summary.Health = healthy
|
||||
data["disk"] = summary
|
||||
usbList := service.MyService.Disk().LSBLK(false)
|
||||
usb := []model.DriveUSB{}
|
||||
for _, v := range usbList {
|
||||
if v.Tran == "usb" {
|
||||
temp := model.DriveUSB{}
|
||||
temp.Model = v.Model
|
||||
temp.Name = v.Name
|
||||
temp.Size = v.Size
|
||||
mountTemp := true
|
||||
if len(v.Children) == 0 {
|
||||
mountTemp = false
|
||||
}
|
||||
for _, child := range v.Children {
|
||||
if len(child.MountPoint) > 0 {
|
||||
avail, _ := strconv.ParseUint(child.FSAvail, 10, 64)
|
||||
temp.Avail += avail
|
||||
used, _ := strconv.ParseUint(child.FSUsed, 10, 64)
|
||||
temp.Used += used
|
||||
} else {
|
||||
mountTemp = false
|
||||
}
|
||||
}
|
||||
temp.Mount = mountTemp
|
||||
usb = append(usb, temp)
|
||||
}
|
||||
}
|
||||
data["usb"] = usb
|
||||
cpu := service.MyService.ZiMa().GetCpuPercent()
|
||||
num := service.MyService.ZiMa().GetCpuCoreNum()
|
||||
cpuData := make(map[string]interface{})
|
||||
cpuData["percent"] = cpu
|
||||
cpuData["num"] = num
|
||||
data["cpu"] = cpuData
|
||||
data["mem"] = service.MyService.ZiMa().GetMemInfo()
|
||||
|
||||
//拼装网络信息
|
||||
netList := service.MyService.ZiMa().GetNetInfo()
|
||||
newNet := []model.IOCountersStat{}
|
||||
nets := service.MyService.ZiMa().GetNet(true)
|
||||
for _, n := range netList {
|
||||
for _, netCardName := range nets {
|
||||
if n.Name == netCardName {
|
||||
item := *(*model.IOCountersStat)(unsafe.Pointer(&n))
|
||||
item.State = strings.TrimSpace(service.MyService.ZiMa().GetNetState(n.Name))
|
||||
item.Time = time.Now().Unix()
|
||||
newNet = append(newNet, item)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
data["net"] = newNet
|
||||
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: data})
|
||||
}
|
||||
|
||||
138
route/v1/user.go
138
route/v1/user.go
@@ -40,7 +40,7 @@ func Set_Name_Pwd(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
//开始设置
|
||||
err := user_service.SetUser(username, pwd, "", "", "")
|
||||
err := user_service.SetUser(username, pwd, "", "", "", "")
|
||||
if err != nil {
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: fmt.Sprintf("%v", err)})
|
||||
return
|
||||
@@ -102,7 +102,7 @@ func Login(c *gin.Context) {
|
||||
// @Security ApiKeyAuth
|
||||
// @Success 200 {string} string "ok"
|
||||
// @Router /user/changhead [post]
|
||||
func Up_Load_Head(c *gin.Context) {
|
||||
func PostUserHead(c *gin.Context) {
|
||||
file, _, _ := c.Request.FormFile("file")
|
||||
user_service.UpLoadFile(file, config.UserInfo.Head)
|
||||
c.JSON(http.StatusOK,
|
||||
@@ -121,15 +121,19 @@ func Up_Load_Head(c *gin.Context) {
|
||||
// @Param oldname formData string true "Old user name"
|
||||
// @Security ApiKeyAuth
|
||||
// @Success 200 {string} string "ok"
|
||||
// @Router /user/changusername [put]
|
||||
func Chang_User_Name(c *gin.Context) {
|
||||
// @Router /user/username [put]
|
||||
func PutUserName(c *gin.Context) {
|
||||
if config.ServerInfo.LockAccount {
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.ACCOUNT_LOCK, Message: oasis_err2.GetMsg(oasis_err2.ACCOUNT_LOCK)})
|
||||
return
|
||||
}
|
||||
oldname := c.PostForm("oldname")
|
||||
username := c.PostForm("username")
|
||||
if len(username) == 0 || config.UserInfo.UserName != oldname {
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.ERROR, Message: oasis_err2.GetMsg(oasis_err2.ERROR)})
|
||||
return
|
||||
}
|
||||
user_service.SetUser(username, "", "", "", "")
|
||||
user_service.SetUser(username, "", "", "", "", "")
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS)})
|
||||
}
|
||||
|
||||
@@ -138,68 +142,145 @@ func Chang_User_Name(c *gin.Context) {
|
||||
// @Accept multipart/form-data
|
||||
// @Tags user
|
||||
// @Param pwd formData string true "Password"
|
||||
// @Param oldpwd formData string true "Old password"
|
||||
// @Param old_pwd formData string true "Old password"
|
||||
// @Security ApiKeyAuth
|
||||
// @Success 200 {string} string "ok"
|
||||
// @Router /user/changuserpwd [put]
|
||||
func Chang_User_Pwd(c *gin.Context) {
|
||||
oldpwd := c.PostForm("oldpwd")
|
||||
// @Router /user/password [put]
|
||||
func PutUserPwd(c *gin.Context) {
|
||||
oldPwd := c.PostForm("old_pwd")
|
||||
pwd := c.PostForm("pwd")
|
||||
if config.UserInfo.PWD != oldpwd {
|
||||
if config.UserInfo.PWD != oldPwd {
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.PWD_INVALID_OLD, Message: oasis_err2.GetMsg(oasis_err2.PWD_INVALID_OLD)})
|
||||
return
|
||||
}
|
||||
if config.ServerInfo.LockAccount {
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.ACCOUNT_LOCK, Message: oasis_err2.GetMsg(oasis_err2.ACCOUNT_LOCK)})
|
||||
return
|
||||
}
|
||||
if len(pwd) == 0 {
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.PWD_IS_EMPTY, Message: oasis_err2.GetMsg(oasis_err2.PWD_IS_EMPTY)})
|
||||
return
|
||||
}
|
||||
user_service.SetUser("", pwd, "", "", "")
|
||||
user_service.SetUser("", pwd, "", "", "", "")
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS)})
|
||||
}
|
||||
|
||||
// @Summary 修改用户信息
|
||||
// @Summary edit user info
|
||||
// @Produce application/json
|
||||
// @Accept multipart/form-data
|
||||
// @Tags user
|
||||
// @Param username formData string false "User Name"
|
||||
// @Param user_name formData string false "User Name"
|
||||
// @Param email formData string false "Email"
|
||||
// @Param description formData string false "Description"
|
||||
// @Param pwd formData string false "Password"
|
||||
// @Param oldpwd formData string false "Old password"
|
||||
// @Param old_pwd formData string false "Old password"
|
||||
// @Param nick_name formData string false "nick name"
|
||||
// @Security ApiKeyAuth
|
||||
// @Success 200 {string} string "ok"
|
||||
// @Router /user/changuserinfo [post]
|
||||
func Chang_User_Info(c *gin.Context) {
|
||||
username := c.PostForm("username")
|
||||
// @Router /user/info [post]
|
||||
func PostUserChangeInfo(c *gin.Context) {
|
||||
username := c.PostForm("user_name")
|
||||
email := c.PostForm("email")
|
||||
description := c.PostForm("description")
|
||||
oldpwd := c.PostForm("oldpwd")
|
||||
nickName := c.PostForm("nick_name")
|
||||
oldpwd := c.PostForm("old_pwd")
|
||||
pwd := c.PostForm("pwd")
|
||||
if len(pwd) > 0 && config.UserInfo.PWD != oldpwd {
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.PWD_INVALID, Message: oasis_err2.GetMsg(oasis_err2.PWD_INVALID)})
|
||||
return
|
||||
}
|
||||
user_service.SetUser(username, pwd, "", email, description)
|
||||
data := make(map[string]string, 2)
|
||||
user_service.SetUser(username, pwd, "", email, description, nickName)
|
||||
data := make(map[string]string, 4)
|
||||
|
||||
data["token"] = jwt2.GetToken(username, pwd)
|
||||
data["user_name"] = username
|
||||
data["head"] = config.UserInfo.Head
|
||||
data["nick_name"] = config.UserInfo.NickName
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: data})
|
||||
}
|
||||
|
||||
// @Summary 获取用户详情
|
||||
// @Summary edit user nick
|
||||
// @Produce application/json
|
||||
// @Accept multipart/form-data
|
||||
// @Tags user
|
||||
// @Param nick_name formData string false "nick name"
|
||||
// @Security ApiKeyAuth
|
||||
// @Success 200 {string} string "ok"
|
||||
// @Router /user/nick [put]
|
||||
func PutUserChangeNick(c *gin.Context) {
|
||||
|
||||
nickName := c.PostForm("nick_name")
|
||||
|
||||
if len(nickName) == 0 {
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.INVALID_PARAMS, Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS)})
|
||||
return
|
||||
}
|
||||
user_service.SetUser("", "", "", "", "", nickName)
|
||||
data := make(map[string]string, 1)
|
||||
data["nick_name"] = config.UserInfo.NickName
|
||||
go service.MyService.Casa().PushUserInfo()
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: data})
|
||||
}
|
||||
|
||||
// @Summary edit user description
|
||||
// @Produce application/json
|
||||
// @Accept multipart/form-data
|
||||
// @Tags user
|
||||
// @Param description formData string false "Description"
|
||||
// @Security ApiKeyAuth
|
||||
// @Success 200 {string} string "ok"
|
||||
// @Router /user/desc [put]
|
||||
func PutUserChangeDesc(c *gin.Context) {
|
||||
desc := c.PostForm("description")
|
||||
|
||||
if len(desc) == 0 {
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.INVALID_PARAMS, Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS)})
|
||||
return
|
||||
}
|
||||
user_service.SetUser("", "", "", "", desc, "")
|
||||
data := make(map[string]string, 1)
|
||||
data["description"] = config.UserInfo.Description
|
||||
go service.MyService.Casa().PushUserInfo()
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: data})
|
||||
}
|
||||
|
||||
// @Summary Modify user person information (Initialization use)
|
||||
// @Produce application/json
|
||||
// @Accept multipart/form-data
|
||||
// @Tags user
|
||||
// @Param nick_name formData string false "user nick name"
|
||||
// @Param description formData string false "Description"
|
||||
// @Security ApiKeyAuth
|
||||
// @Success 200 {string} string "ok"
|
||||
// @Router /user/person/info [post]
|
||||
func PostUserPersonInfo(c *gin.Context) {
|
||||
desc := c.PostForm("description")
|
||||
nickName := c.PostForm("nick_name")
|
||||
if len(desc) == 0 || len(nickName) == 0 {
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.INVALID_PARAMS, Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS)})
|
||||
return
|
||||
}
|
||||
user_service.SetUser("", "", "", "", desc, nickName)
|
||||
data := make(map[string]string, 2)
|
||||
data["description"] = config.UserInfo.Description
|
||||
data["nick_name"] = config.UserInfo.NickName
|
||||
go service.MyService.Casa().PushUserInfo()
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: data})
|
||||
}
|
||||
|
||||
// @Summary get user info
|
||||
// @Produce application/json
|
||||
// @Accept mapplication/json
|
||||
// @Tags user
|
||||
// @Success 200 {string} string "ok"
|
||||
// @Router /user/info [get]
|
||||
func UserInfo(c *gin.Context) {
|
||||
var u = make(map[string]string, 2)
|
||||
func GetUserInfo(c *gin.Context) {
|
||||
var u = make(map[string]string, 5)
|
||||
u["user_name"] = config.UserInfo.UserName
|
||||
u["head"] = config.UserInfo.Head
|
||||
u["email"] = config.UserInfo.Email
|
||||
u["description"] = config.UserInfo.Description
|
||||
u["nick_name"] = config.UserInfo.NickName
|
||||
c.JSON(http.StatusOK,
|
||||
model.Result{
|
||||
Success: oasis_err2.SUCCESS,
|
||||
@@ -207,3 +288,14 @@ func UserInfo(c *gin.Context) {
|
||||
Data: u,
|
||||
})
|
||||
}
|
||||
|
||||
// @Summary Get my shareId
|
||||
// @Produce application/json
|
||||
// @Accept application/json
|
||||
// @Tags user
|
||||
// @Security ApiKeyAuth
|
||||
// @Success 200 {string} string "ok"
|
||||
// @Router /user/shareid [get]
|
||||
func GetUserShareID(c *gin.Context) {
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: config.ServerInfo.Token})
|
||||
}
|
||||
|
||||
@@ -1,459 +0,0 @@
|
||||
package v1
|
||||
|
||||
import (
|
||||
json2 "encoding/json"
|
||||
"github.com/IceWhaleTech/CasaOS/model"
|
||||
"github.com/IceWhaleTech/CasaOS/pkg/config"
|
||||
oasis_err2 "github.com/IceWhaleTech/CasaOS/pkg/utils/oasis_err"
|
||||
"github.com/IceWhaleTech/CasaOS/service"
|
||||
"github.com/gin-gonic/gin"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
// @Summary 登录zerotier获取token
|
||||
// @Produce application/json
|
||||
// @Accept multipart/form-data
|
||||
// @Tags zerotier
|
||||
// @Param username formData string true "User name"
|
||||
// @Param pwd formData string true "password"
|
||||
// @Security ApiKeyAuth
|
||||
// @Success 200 {string} string "ok"
|
||||
// @Router /zerotier/login [post]
|
||||
func ZeroTierGetToken(c *gin.Context) {
|
||||
username := c.PostForm("username")
|
||||
pwd := c.PostForm("pwd")
|
||||
if len(username) == 0 || len(pwd) == 0 {
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.INVALID_PARAMS, Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS)})
|
||||
return
|
||||
}
|
||||
errInfo := service.MyService.ZeroTier().GetToken(username, pwd)
|
||||
|
||||
if len(errInfo) == 0 {
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.ERROR, Message: oasis_err2.GetMsg(oasis_err2.GET_TOKEN_ERROR)})
|
||||
} else {
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS)})
|
||||
}
|
||||
}
|
||||
|
||||
// @Summary 注册zerotier
|
||||
// @Produce application/json
|
||||
// @Accept multipart/form-data
|
||||
// @Tags zerotier
|
||||
// @Param firstName formData string true "first name"
|
||||
// @Param pwd formData string true "password"
|
||||
// @Param email formData string true "email"
|
||||
// @Param lastName formData string true "last name"
|
||||
// @Security ApiKeyAuth
|
||||
// @Success 200 {string} string "ok"
|
||||
// @Router /zerotier/register [post]
|
||||
func ZeroTierRegister(c *gin.Context) {
|
||||
firstName := c.PostForm("firstName")
|
||||
pwd := c.PostForm("pwd")
|
||||
email := c.PostForm("email")
|
||||
lastName := c.PostForm("lastName")
|
||||
if len(firstName) == 0 || len(pwd) == 0 || len(email) == 0 || len(lastName) == 0 {
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.INVALID_PARAMS, Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS)})
|
||||
return
|
||||
}
|
||||
errInfo := service.MyService.ZeroTier().ZeroTierRegister(email, lastName, firstName, pwd)
|
||||
if len(errInfo) == 0 {
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS)})
|
||||
} else {
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.ERROR, Message: errInfo})
|
||||
}
|
||||
}
|
||||
|
||||
// @Summary 是否需要登录zerotier
|
||||
// @Produce application/json
|
||||
// @Accept application/json
|
||||
// @Tags zerotier
|
||||
// @Security ApiKeyAuth
|
||||
// @Success 200 {string} string "false:需要登录,true:不需要登录"
|
||||
// @Router /zerotier/islogin [get]
|
||||
func ZeroTierIsNeedLogin(c *gin.Context) {
|
||||
if len(config.ZeroTierInfo.Token) == 0 {
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: false})
|
||||
} else {
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: true})
|
||||
}
|
||||
}
|
||||
|
||||
// @Summary 获取zerotier网络列表
|
||||
// @Produce application/json
|
||||
// @Accept application/json
|
||||
// @Tags zerotier
|
||||
// @Security ApiKeyAuth
|
||||
// @Success 200 {string} string "ok"
|
||||
// @Router /zerotier/list [get]
|
||||
func ZeroTierGetNetworkList(c *gin.Context) {
|
||||
jsonList, joined := service.MyService.ZeroTier().ZeroTierNetworkList(config.ZeroTierInfo.Token)
|
||||
rdata := make(map[string]interface{})
|
||||
rdata["network_list"] = jsonList
|
||||
rdata["joined"] = joined
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: rdata})
|
||||
}
|
||||
|
||||
// @Summary 获取zerotier网络详情
|
||||
// @Produce application/json
|
||||
// @Accept application/json
|
||||
// @Tags zerotier
|
||||
// @Security ApiKeyAuth
|
||||
// @Param id path string true "network id"
|
||||
// @Success 200 {string} string "ok"
|
||||
// @Router /zerotier/info/{id} [get]
|
||||
func ZeroTierGetNetworkGetInfo(c *gin.Context) {
|
||||
id := c.Param("id")
|
||||
if len(id) == 0 {
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.INVALID_PARAMS, Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS)})
|
||||
return
|
||||
}
|
||||
info, joined := service.MyService.ZeroTier().ZeroTierGetInfo(config.ZeroTierInfo.Token, id)
|
||||
rdata := make(map[string]interface{})
|
||||
rdata["info"] = info
|
||||
rdata["joined"] = joined
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: rdata})
|
||||
}
|
||||
|
||||
//// @Summary 获取zerotier网络状态
|
||||
//// @Produce application/json
|
||||
//// @Accept application/json
|
||||
//// @Tags zerotier
|
||||
//// @Security ApiKeyAuth
|
||||
//// @Success 200 {string} string "ok"
|
||||
//// @Router /zerotier/status [get]
|
||||
//func ZeroTierGetNetworkGetStatus(c *gin.Context) {
|
||||
// status := service.MyService.ZeroTier().ZeroTierGetStatus(config.ZeroTierInfo.Token)
|
||||
// c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: status})
|
||||
//}
|
||||
|
||||
//// @Summary 修改网络类型
|
||||
//// @Produce application/json
|
||||
//// @Accept application/json
|
||||
//// @Tags zerotier
|
||||
//// @Security ApiKeyAuth
|
||||
//// @Param id path string true "network id"
|
||||
//// @Param type formData string true "Private true/false"
|
||||
//// @Success 200 {string} string "ok"
|
||||
//// @Router /zerotier/type/{id} [put]
|
||||
//func ZeroTierEditType(c *gin.Context) {
|
||||
// id := c.Param("id")
|
||||
// t := c.PostForm("type")
|
||||
// if len(id) == 0 || len(t) == 0 {
|
||||
// c.JSON(http.StatusOK, model.Result{Success: oasis_err2.INVALID_PARAMS, Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS)})
|
||||
// return
|
||||
// }
|
||||
// postData := `{"config":{"private":` + t + `}}`
|
||||
// info := service.MyService.ZeroTier().EditNetwork(config.ZeroTierInfo.Token, postData, id)
|
||||
// c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: info})
|
||||
//}
|
||||
|
||||
//// @Summary 修改名称
|
||||
//// @Produce application/json
|
||||
//// @Accept application/json
|
||||
//// @Tags zerotier
|
||||
//// @Security ApiKeyAuth
|
||||
//// @Param id path string true "network id"
|
||||
//// @Param name formData string true "需要过滤特殊字符串"
|
||||
//// @Success 200 {string} string "ok"
|
||||
//// @Router /zerotier/name/{id} [put]
|
||||
//func ZeroTierEditName(c *gin.Context) {
|
||||
// id := c.Param("id")
|
||||
// name := c.PostForm("name")
|
||||
// if len(id) == 0 || len(name) == 0 {
|
||||
// c.JSON(http.StatusOK, model.Result{Success: oasis_err2.INVALID_PARAMS, Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS)})
|
||||
// return
|
||||
// }
|
||||
// postData := `{"config":{"name":"` + name + `"}}`
|
||||
// info := service.MyService.ZeroTier().EditNetwork(config.ZeroTierInfo.Token, postData, id)
|
||||
// c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: info})
|
||||
//}
|
||||
|
||||
//// @Summary V6Assign (注意三个属性需要一起传过来,不传的会被zerotier设置成false)
|
||||
//// @Produce application/json
|
||||
//// @Accept application/json
|
||||
//// @Tags zerotier
|
||||
//// @Security ApiKeyAuth
|
||||
//// @Param id path string true "network id"
|
||||
//// @Param v6plan formData string false "true/false"
|
||||
//// @Param rfc formData string false "true/false"
|
||||
//// @Param auto formData string false "true/false"
|
||||
//// @Success 200 {string} string "ok"
|
||||
//// @Router /zerotier/v6assign/{id} [put]
|
||||
//func ZeroTierEditV6Assign(c *gin.Context) {
|
||||
// id := c.Param("id")
|
||||
// v6plan := c.PostForm("v6plan")
|
||||
// rfc := c.PostForm("rfc")
|
||||
// auto := c.PostForm("auto")
|
||||
// if len(id) == 0 {
|
||||
// c.JSON(http.StatusOK, model.Result{Success: oasis_err2.INVALID_PARAMS, Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS)})
|
||||
// return
|
||||
// }
|
||||
// var spicing string
|
||||
// if len(v6plan) > 0 {
|
||||
// spicing = `"6plane":` + v6plan
|
||||
// }
|
||||
// if len(rfc) > 0 {
|
||||
// if len(spicing) > 0 {
|
||||
// spicing += ","
|
||||
// }
|
||||
// spicing += `"rfc4193":` + rfc
|
||||
// }
|
||||
//
|
||||
// if len(auto) > 0 {
|
||||
// if len(spicing) > 0 {
|
||||
// spicing += ","
|
||||
// }
|
||||
// spicing += `"zt":` + auto
|
||||
// }
|
||||
// postData := `{"config":{"v6AssignMode":{` + spicing + `}}}`
|
||||
// info := service.MyService.ZeroTier().EditNetwork(config.ZeroTierInfo.Token, postData, id)
|
||||
// c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: info})
|
||||
//}
|
||||
|
||||
//// @Summary Broadcast
|
||||
//// @Produce application/json
|
||||
//// @Accept application/json
|
||||
//// @Tags zerotier
|
||||
//// @Security ApiKeyAuth
|
||||
//// @Param id path string true "network id"
|
||||
//// @Param broadcast formData string true "true/false"
|
||||
//// @Success 200 {string} string "ok"
|
||||
//// @Router /zerotier/broadcast/{id} [put]
|
||||
//func ZeroTierEditBroadcast(c *gin.Context) {
|
||||
// id := c.Param("id")
|
||||
// broadcast := c.PostForm("broadcast")
|
||||
// if len(id) == 0 || len(broadcast) == 0 {
|
||||
// c.JSON(http.StatusOK, model.Result{Success: oasis_err2.INVALID_PARAMS, Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS)})
|
||||
// return
|
||||
// }
|
||||
// postData := `{"config":{"enableBroadcast":` + broadcast + `}}`
|
||||
// info := service.MyService.ZeroTier().EditNetwork(config.ZeroTierInfo.Token, postData, id)
|
||||
// c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: info})
|
||||
//}
|
||||
|
||||
// @Summary 网络列表
|
||||
// @Produce application/json
|
||||
// @Accept application/json
|
||||
// @Tags zerotier
|
||||
// @Security ApiKeyAuth
|
||||
// @Param id path string true "network id"
|
||||
// @Success 200 {string} string "ok"
|
||||
// @Router /zerotier/member/{id} [get]
|
||||
func ZeroTierMemberList(c *gin.Context) {
|
||||
id := c.Param("id")
|
||||
if len(id) == 0 {
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.INVALID_PARAMS, Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS)})
|
||||
return
|
||||
}
|
||||
info := service.MyService.ZeroTier().MemberList(config.ZeroTierInfo.Token, id)
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: info})
|
||||
}
|
||||
|
||||
// @Summary create new network
|
||||
// @Produce application/json
|
||||
// @Accept application/json
|
||||
// @Tags zerotier
|
||||
// @Security ApiKeyAuth
|
||||
// @Success 200 {string} string "ok"
|
||||
// @Router /zerotier/create [post]
|
||||
func ZeroTierCreateNetwork(c *gin.Context) {
|
||||
info := service.MyService.ZeroTier().CreateNetwork(config.ZeroTierInfo.Token)
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: info})
|
||||
}
|
||||
|
||||
//// @Summary 通过/拒绝客户端
|
||||
//// @Produce application/json
|
||||
//// @Accept application/json
|
||||
//// @Tags zerotier
|
||||
//// @Security ApiKeyAuth
|
||||
//// @Param id path string true "network id"
|
||||
//// @Param mId path string true "member_id"
|
||||
//// @Param auth formData string true "true/false"
|
||||
//// @Success 200 {string} string "ok"
|
||||
//// @Router /zerotier/member/{id}/auth/{mId} [put]
|
||||
//func ZeroTierMemberAuth(c *gin.Context) {
|
||||
// id := c.Param("id")
|
||||
// mId := c.Param("mId")
|
||||
// auth := c.PostForm("auth")
|
||||
// if len(id) == 0 || len(mId) == 0 || len(auth) == 0 {
|
||||
// c.JSON(http.StatusOK, model.Result{Success: oasis_err2.INVALID_PARAMS, Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS)})
|
||||
// return
|
||||
// }
|
||||
// postData := `{"config":{"authorized":` + auth + `}}`
|
||||
// info := service.MyService.ZeroTier().EditNetworkMember(config.ZeroTierInfo.Token, postData, id, mId)
|
||||
// c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: info})
|
||||
//}
|
||||
|
||||
//// @Summary 修改名字
|
||||
//// @Produce application/json
|
||||
//// @Accept application/json
|
||||
//// @Tags zerotier
|
||||
//// @Security ApiKeyAuth
|
||||
//// @Param id path string true "network id"
|
||||
//// @Param mId path string true "member_id"
|
||||
//// @Param name formData string true "name"
|
||||
//// @Success 200 {string} string "ok"
|
||||
//// @Router /zerotier/member/{id}/name/{mId} [put]
|
||||
//func ZeroTierMemberName(c *gin.Context) {
|
||||
// id := c.Param("id")
|
||||
// mId := c.Param("mId")
|
||||
// name := c.PostForm("name")
|
||||
// if len(id) == 0 || len(mId) == 0 || len(name) == 0 {
|
||||
// c.JSON(http.StatusOK, model.Result{Success: oasis_err2.INVALID_PARAMS, Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS)})
|
||||
// return
|
||||
// }
|
||||
// postData := `{"name":"` + name + `"}`
|
||||
// info := service.MyService.ZeroTier().EditNetworkMember(config.ZeroTierInfo.Token, postData, id, mId)
|
||||
// c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: info})
|
||||
//}
|
||||
|
||||
//// @Summary 修改桥接
|
||||
//// @Produce application/json
|
||||
//// @Accept application/json
|
||||
//// @Tags zerotier
|
||||
//// @Security ApiKeyAuth
|
||||
//// @Param id path string true "network id"
|
||||
//// @Param mId path string true "member_id"
|
||||
//// @Param bridge formData string true "true/false"
|
||||
//// @Success 200 {string} string "ok"
|
||||
//// @Router /zerotier/member/{id}/bridge/{mId} [put]
|
||||
//func ZeroTierMemberBridge(c *gin.Context) {
|
||||
// id := c.Param("id")
|
||||
// mId := c.Param("mId")
|
||||
// bridge := c.PostForm("bridge")
|
||||
// if len(id) == 0 || len(mId) == 0 || len(bridge) == 0 {
|
||||
// c.JSON(http.StatusOK, model.Result{Success: oasis_err2.INVALID_PARAMS, Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS)})
|
||||
// return
|
||||
// }
|
||||
// postData := `{"config":{"activeBridge":` + bridge + `}}`
|
||||
// info := service.MyService.ZeroTier().EditNetworkMember(config.ZeroTierInfo.Token, postData, id, mId)
|
||||
// c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: info})
|
||||
//}
|
||||
|
||||
// @Summary 修改网络
|
||||
// @Produce application/json
|
||||
// @Accept application/json
|
||||
// @Tags zerotier
|
||||
// @Security ApiKeyAuth
|
||||
// @Param id path string true "network id"
|
||||
// @Param json formData string true "json数据"
|
||||
// @Success 200 {string} string "ok"
|
||||
// @Router /zerotier/edit/{id} [put]
|
||||
func ZeroTierEdit(c *gin.Context) {
|
||||
id := c.Param("id")
|
||||
json := c.PostForm("json")
|
||||
if len(id) == 0 || len(json) == 0 {
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.INVALID_PARAMS, Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS)})
|
||||
return
|
||||
}
|
||||
info := service.MyService.ZeroTier().EditNetwork(config.ZeroTierInfo.Token, json, id)
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: info})
|
||||
}
|
||||
|
||||
// @Summary 获取已加入的网络
|
||||
// @Produce application/json
|
||||
// @Accept application/json
|
||||
// @Tags zerotier
|
||||
// @Security ApiKeyAuth
|
||||
// @Success 200 {string} string "ok"
|
||||
// @Router /zerotier/joined/list [get]
|
||||
func ZeroTierJoinedList(c *gin.Context) {
|
||||
info := service.MyService.ZeroTier().GetJoinNetworks()
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: json2.RawMessage(info)})
|
||||
}
|
||||
|
||||
// @Summary 修改网络用户信息
|
||||
// @Produce application/json
|
||||
// @Accept application/json
|
||||
// @Tags zerotier
|
||||
// @Security ApiKeyAuth
|
||||
// @Param id path string true "network id"
|
||||
// @Param mId path string true "mId"
|
||||
// @Param json formData string true "json数据"
|
||||
// @Success 200 {string} string "ok"
|
||||
// @Router /zerotier/member/{id}/edit/{mId} [put]
|
||||
func ZeroTierMemberEdit(c *gin.Context) {
|
||||
id := c.Param("id")
|
||||
mId := c.Param("mId")
|
||||
json := c.PostForm("json")
|
||||
if len(id) == 0 || len(json) == 0 || len(mId) == 0 {
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.INVALID_PARAMS, Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS)})
|
||||
return
|
||||
}
|
||||
info := service.MyService.ZeroTier().EditNetworkMember(config.ZeroTierInfo.Token, json, id, mId)
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: info})
|
||||
}
|
||||
|
||||
// @Summary 删除网络中的用户
|
||||
// @Produce application/json
|
||||
// @Accept application/json
|
||||
// @Tags zerotier
|
||||
// @Security ApiKeyAuth
|
||||
// @Param id path string true "network id"
|
||||
// @Param mId path string true "member_id"
|
||||
// @Success 200 {string} string "ok"
|
||||
// @Router /zerotier/member/{id}/del/{mId} [delete]
|
||||
func ZeroTierMemberDelete(c *gin.Context) {
|
||||
id := c.Param("id")
|
||||
mId := c.Param("mId")
|
||||
if len(id) == 0 || len(mId) == 0 {
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.INVALID_PARAMS, Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS)})
|
||||
return
|
||||
}
|
||||
info := service.MyService.ZeroTier().DeleteMember(config.ZeroTierInfo.Token, id, mId)
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: info})
|
||||
}
|
||||
|
||||
// @Summary 删除网络
|
||||
// @Produce application/json
|
||||
// @Accept application/json
|
||||
// @Tags zerotier
|
||||
// @Security ApiKeyAuth
|
||||
// @Param id path string true "network id"
|
||||
// @Success 200 {string} string "ok"
|
||||
// @Router /zerotier/network/{id}/del [delete]
|
||||
func ZeroTierDeleteNetwork(c *gin.Context) {
|
||||
id := c.Param("id")
|
||||
if len(id) == 0 {
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.INVALID_PARAMS, Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS)})
|
||||
return
|
||||
}
|
||||
info := service.MyService.ZeroTier().DeleteNetwork(config.ZeroTierInfo.Token, id)
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: info})
|
||||
}
|
||||
|
||||
// @Summary 加入网络
|
||||
// @Produce application/json
|
||||
// @Accept multipart/form-data
|
||||
// @Tags zerotier
|
||||
// @Param id path string true "network id"
|
||||
// @Security ApiKeyAuth
|
||||
// @Success 200 {string} string "ok"
|
||||
// @Router /zerotier/join/{id} [post]
|
||||
func ZeroTierJoinNetwork(c *gin.Context) {
|
||||
networkId := c.Param("id")
|
||||
service.MyService.ZeroTier().ZeroTierJoinNetwork(networkId)
|
||||
if len(networkId) == 0 {
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.INVALID_PARAMS, Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS)})
|
||||
return
|
||||
}
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS)})
|
||||
}
|
||||
|
||||
// @Summary 获取zerotier网络列表
|
||||
// @Produce application/json
|
||||
// @Accept multipart/form-data
|
||||
// @Tags zerotier
|
||||
// @Param id path string true "network id"
|
||||
// @Security ApiKeyAuth
|
||||
// @Success 200 {string} string "ok"
|
||||
// @Router /zerotier/leave/{id} [post]
|
||||
func ZeroTierLeaveNetwork(c *gin.Context) {
|
||||
networkId := c.Param("id")
|
||||
service.MyService.ZeroTier().ZeroTierLeaveNetwork(networkId)
|
||||
if len(networkId) == 0 {
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.INVALID_PARAMS, Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS)})
|
||||
return
|
||||
}
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS)})
|
||||
}
|
||||
@@ -1,15 +1,15 @@
|
||||
package v1
|
||||
|
||||
import (
|
||||
"github.com/IceWhaleTech/CasaOS/model"
|
||||
oasis_err2 "github.com/IceWhaleTech/CasaOS/pkg/utils/oasis_err"
|
||||
"github.com/IceWhaleTech/CasaOS/service"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/shirou/gopsutil/v3/disk"
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
"unsafe"
|
||||
|
||||
"github.com/IceWhaleTech/CasaOS/model"
|
||||
oasis_err2 "github.com/IceWhaleTech/CasaOS/pkg/utils/oasis_err"
|
||||
"github.com/IceWhaleTech/CasaOS/service"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
// @Summary 获取cpu信息
|
||||
@@ -73,7 +73,7 @@ func NetInfo(c *gin.Context) {
|
||||
if n.Name == netCardName {
|
||||
item := *(*model.IOCountersStat)(unsafe.Pointer(&n))
|
||||
item.State = strings.TrimSpace(service.MyService.ZiMa().GetNetState(n.Name))
|
||||
item.DateTime = time.Now()
|
||||
item.Time = time.Now().Unix()
|
||||
newNet = append(newNet, item)
|
||||
break
|
||||
}
|
||||
@@ -83,48 +83,6 @@ func NetInfo(c *gin.Context) {
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: newNet})
|
||||
}
|
||||
|
||||
// @Summary 获取信息
|
||||
// @Produce application/json
|
||||
// @Accept application/json
|
||||
// @Tags zima
|
||||
// @Security ApiKeyAuth
|
||||
// @Success 200 {string} string "ok"
|
||||
// @Router /zima/getinfo [get]
|
||||
func Info(c *gin.Context) {
|
||||
var data = make(map[string]interface{}, 4)
|
||||
|
||||
var diskArr []*disk.UsageStat
|
||||
diskArr = append(diskArr, service.MyService.ZiMa().GetDiskInfo())
|
||||
data["disk"] = diskArr
|
||||
cpu := service.MyService.ZiMa().GetCpuPercent()
|
||||
num := service.MyService.ZiMa().GetCpuCoreNum()
|
||||
cpuData := make(map[string]interface{})
|
||||
cpuData["percent"] = cpu
|
||||
cpuData["num"] = num
|
||||
data["cpu"] = cpuData
|
||||
data["mem"] = service.MyService.ZiMa().GetMemInfo()
|
||||
|
||||
//拼装网络信息
|
||||
netList := service.MyService.ZiMa().GetNetInfo()
|
||||
newNet := []model.IOCountersStat{}
|
||||
nets := service.MyService.ZiMa().GetNet(true)
|
||||
for _, n := range netList {
|
||||
for _, netCardName := range nets {
|
||||
if n.Name == netCardName {
|
||||
item := *(*model.IOCountersStat)(unsafe.Pointer(&n))
|
||||
item.State = strings.TrimSpace(service.MyService.ZiMa().GetNetState(n.Name))
|
||||
item.DateTime = time.Now()
|
||||
newNet = append(newNet, item)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
data["net"] = newNet
|
||||
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: data})
|
||||
}
|
||||
|
||||
// @Summary 获取信息系统信息
|
||||
// @Produce application/json
|
||||
// @Accept application/json
|
||||
|
||||
486
service/app.go
486
service/app.go
@@ -2,35 +2,51 @@ package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
json2 "encoding/json"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/IceWhaleTech/CasaOS/model"
|
||||
"github.com/IceWhaleTech/CasaOS/pkg/config"
|
||||
"github.com/IceWhaleTech/CasaOS/pkg/docker"
|
||||
"github.com/IceWhaleTech/CasaOS/pkg/utils/command"
|
||||
httper2 "github.com/IceWhaleTech/CasaOS/pkg/utils/httper"
|
||||
loger2 "github.com/IceWhaleTech/CasaOS/pkg/utils/loger"
|
||||
model2 "github.com/IceWhaleTech/CasaOS/service/model"
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/filters"
|
||||
client2 "github.com/docker/docker/client"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/tidwall/gjson"
|
||||
uuid "github.com/satori/go.uuid"
|
||||
"gorm.io/gorm"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
type AppService interface {
|
||||
GetMyList(index, size int, position bool) *[]model2.MyAppList
|
||||
CreateApplication(m model2.ApplicationModel) model2.ApplicationModel
|
||||
GetApplicationList() (m []model2.ApplicationModel)
|
||||
GetApplicationById(id string) (m model2.ApplicationModel)
|
||||
UpdateApplicationOrderById(id string, order int)
|
||||
GetMyList(index, size int, position bool) (*[]model2.MyAppList, *[]model2.MyAppList)
|
||||
GetCasaOSCount() int
|
||||
SaveContainer(m model2.AppListDBModel)
|
||||
GetServerAppInfo(id string) model.ServerAppList
|
||||
GetUninstallInfo(id string) model2.AppListDBModel
|
||||
RemoveContainerById(id string)
|
||||
DeleteApp(id string)
|
||||
GetContainerInfo(name string) (types.Container, error)
|
||||
GetAppDBInfo(id string) model2.AppListDBModel
|
||||
UpdateApp(m model2.AppListDBModel)
|
||||
GetSimpleContainerInfo(name string) (types.Container, error)
|
||||
DelAppConfigDir(id string)
|
||||
DelAppConfigDir(path string)
|
||||
GetSystemAppList() []types.Container
|
||||
GetHardwareUsageSteam()
|
||||
GetHardwareUsage() []model.DockerStatsModel
|
||||
GetAppStats(id string) string
|
||||
GetAllDBApps() []model2.AppListDBModel
|
||||
ImportApplications(casaApp bool)
|
||||
CheckNewImage()
|
||||
}
|
||||
|
||||
type appStruct struct {
|
||||
@@ -38,8 +54,253 @@ type appStruct struct {
|
||||
log loger2.OLog
|
||||
}
|
||||
|
||||
func (a *appStruct) GetApplicationById(id string) (m model2.ApplicationModel) {
|
||||
a.db.Where("id = ?", id).First(&m)
|
||||
return
|
||||
}
|
||||
|
||||
func (a *appStruct) UpdateApplicationOrderById(id string, order int) {
|
||||
a.db.Model(&model2.ApplicationModel{}).Where("id = ?", id).Update("order", order)
|
||||
}
|
||||
|
||||
func (a *appStruct) CreateApplication(m model2.ApplicationModel) model2.ApplicationModel {
|
||||
a.db.Create(&m)
|
||||
return m
|
||||
}
|
||||
func (a *appStruct) GetApplicationList() (m []model2.ApplicationModel) {
|
||||
a.db.Find(&m)
|
||||
return
|
||||
}
|
||||
|
||||
func (a *appStruct) CheckNewImage() {
|
||||
list := MyService.Docker().DockerContainerList()
|
||||
for _, v := range list {
|
||||
inspect, err := MyService.Docker().DockerImageInfo(strings.Split(v.Image, ":")[0])
|
||||
if err != nil {
|
||||
NewVersionApp[v.ID] = inspect.ID
|
||||
continue
|
||||
}
|
||||
if inspect.ID == v.ImageID {
|
||||
delete(NewVersionApp, v.ID)
|
||||
continue
|
||||
}
|
||||
NewVersionApp[v.ID] = inspect.ID
|
||||
}
|
||||
|
||||
}
|
||||
func (a *appStruct) ImportApplications(casaApp bool) {
|
||||
if casaApp {
|
||||
list := MyService.App().GetAllDBApps()
|
||||
for _, app := range list {
|
||||
info, err := MyService.Docker().DockerContainerInfo(app.CustomId)
|
||||
if err != nil {
|
||||
MyService.App().DeleteApp(app.CustomId)
|
||||
continue
|
||||
}
|
||||
//info.NetworkSettings
|
||||
info.Config.Labels["casaos"] = "casaos"
|
||||
info.Config.Labels["web"] = app.PortMap
|
||||
info.Config.Labels["icon"] = app.Icon
|
||||
info.Config.Labels["desc"] = app.Description
|
||||
info.Config.Labels["index"] = app.Index
|
||||
info.Config.Labels["custom_id"] = app.CustomId
|
||||
info.Name = app.Title
|
||||
container_id, err := MyService.Docker().DockerContainerCopyCreate(info)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
continue
|
||||
}
|
||||
MyService.App().DeleteApp(app.CustomId)
|
||||
MyService.Docker().DockerContainerStop(app.CustomId)
|
||||
MyService.Docker().DockerContainerRemove(app.CustomId, false)
|
||||
MyService.Docker().DockerContainerStart(container_id)
|
||||
|
||||
}
|
||||
} else {
|
||||
list := MyService.Docker().DockerContainerList()
|
||||
for _, app := range list {
|
||||
info, err := MyService.Docker().DockerContainerInfo(app.ID)
|
||||
if err != nil || info.Config.Labels["casaos"] == "casaos" {
|
||||
continue
|
||||
}
|
||||
info.Config.Labels["casaos"] = "casaos"
|
||||
info.Config.Labels["web"] = ""
|
||||
info.Config.Labels["icon"] = ""
|
||||
info.Config.Labels["desc"] = ""
|
||||
info.Config.Labels["index"] = ""
|
||||
info.Config.Labels["custom_id"] = uuid.NewV4().String()
|
||||
|
||||
_, err = MyService.Docker().DockerContainerCopyCreate(info)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// allcontainer := MyService.Docker().DockerContainerList()
|
||||
// for _, app := range allcontainer {
|
||||
// info, err := MyService.Docker().DockerContainerInfo(app.ID)
|
||||
// if err != nil {
|
||||
// continue
|
||||
// }
|
||||
// MyService.Docker().DockerContainerStop(app.ID)
|
||||
// MyService.Docker().DockerContainerRemove(app.ID, false)
|
||||
// //info.NetworkSettings
|
||||
// info.Config.Labels["custom_id"] = uuid.NewV4().String()
|
||||
// container_id, err := MyService.Docker().DockerContainerCopyCreate(info)
|
||||
// if err != nil {
|
||||
// fmt.Println(err)
|
||||
// continue
|
||||
// }
|
||||
// MyService.Docker().DockerContainerStart(container_id)
|
||||
//}
|
||||
|
||||
}
|
||||
|
||||
func (a *appStruct) GetCasaOSCount() int {
|
||||
//获取docker应用
|
||||
cli, err := client2.NewClientWithOpts(client2.FromEnv, client2.WithTimeout(time.Second*5))
|
||||
if err != nil {
|
||||
a.log.Error("初始化client失败", "app.getmylist", "line:36", err)
|
||||
return 0
|
||||
}
|
||||
defer cli.Close()
|
||||
fts := filters.NewArgs()
|
||||
fts.Add("label", "casaos=casaos")
|
||||
//fts.Add("label", "casaos:casaos")
|
||||
|
||||
containers, err := cli.ContainerList(context.Background(), types.ContainerListOptions{Filters: fts, Limit: 200})
|
||||
if err != nil {
|
||||
a.log.Error("获取docker容器失败", "app.getmylist", "line:42", err)
|
||||
return 0
|
||||
}
|
||||
|
||||
systemApp := MyService.App().GetApplicationList()
|
||||
return len(containers) + len(systemApp)
|
||||
}
|
||||
|
||||
//获取我的应用列表
|
||||
func (a *appStruct) GetMyList(index, size int, position bool) *[]model2.MyAppList {
|
||||
func (a *appStruct) GetMyList(index, size int, position bool) (*[]model2.MyAppList, *[]model2.MyAppList) {
|
||||
//获取docker应用
|
||||
cli, err := client2.NewClientWithOpts(client2.FromEnv, client2.WithTimeout(time.Second*5))
|
||||
if err != nil {
|
||||
a.log.Error("初始化client失败", "app.getmylist", "line:36", err)
|
||||
}
|
||||
defer cli.Close()
|
||||
// fts := filters.NewArgs()
|
||||
// fts.Add("label", "casaos=casaos")
|
||||
//fts.Add("label", "casaos")
|
||||
//fts.Add("casaos", "casaos")
|
||||
containers, err := cli.ContainerList(context.Background(), types.ContainerListOptions{All: true})
|
||||
if err != nil {
|
||||
a.log.Error("获取docker容器失败", "app.getmylist", "line:42", err)
|
||||
}
|
||||
//获取本地数据库应用
|
||||
|
||||
unTranslation := []model2.MyAppList{}
|
||||
|
||||
list := []model2.MyAppList{}
|
||||
|
||||
systemApp := MyService.App().GetApplicationList()
|
||||
for _, v := range systemApp {
|
||||
list = append(list, model2.MyAppList{
|
||||
Name: v.Name,
|
||||
Icon: v.Icon,
|
||||
State: strconv.Itoa(v.State),
|
||||
Id: strconv.Itoa(v.Id),
|
||||
CustomId: strconv.Itoa(v.Id),
|
||||
Port: "",
|
||||
//Order: strconv.Itoa(v.Order),
|
||||
Index: "/",
|
||||
Image: "",
|
||||
Type: v.Type,
|
||||
NewVersion: false,
|
||||
})
|
||||
}
|
||||
|
||||
for _, m := range containers {
|
||||
if m.Labels["casaos"] == "casaos" {
|
||||
if m.Labels["origin"] == "system" {
|
||||
continue
|
||||
}
|
||||
_, newVersion := NewVersionApp[m.ID]
|
||||
list = append(list, model2.MyAppList{
|
||||
Name: strings.ReplaceAll(m.Names[0], "/", ""),
|
||||
Icon: m.Labels["icon"],
|
||||
State: m.State,
|
||||
CustomId: m.Labels["custom_id"],
|
||||
Id: m.ID,
|
||||
Port: m.Labels["web"],
|
||||
Index: m.Labels["index"],
|
||||
//Order: m.Labels["order"],
|
||||
Image: m.Image,
|
||||
NewVersion: newVersion,
|
||||
Type: m.Labels["origin"],
|
||||
//Slogan: m.Slogan,
|
||||
//Rely: m.Rely,
|
||||
})
|
||||
} else {
|
||||
unTranslation = append(unTranslation, model2.MyAppList{
|
||||
Name: strings.ReplaceAll(m.Names[0], "/", ""),
|
||||
Icon: "",
|
||||
State: m.State,
|
||||
CustomId: m.ID,
|
||||
Id: m.ID,
|
||||
Port: "",
|
||||
NewVersion: false,
|
||||
Image: m.Image,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
//lMap := make(map[string]interface{})
|
||||
// for _, dbModel := range lm {
|
||||
// if position {
|
||||
// if dbModel.Position {
|
||||
// lMap[dbModel.ContainerId] = dbModel
|
||||
// }
|
||||
// } else {
|
||||
// lMap[dbModel.ContainerId] = dbModel
|
||||
// }
|
||||
// }
|
||||
// for _, container := range containers {
|
||||
|
||||
// if lMap[container.ID] != nil && container.Labels["origin"] != "system" {
|
||||
// m := lMap[container.ID].(model2.AppListDBModel)
|
||||
// if len(m.Label) == 0 {
|
||||
// m.Label = m.Title
|
||||
// }
|
||||
|
||||
// // info, err := cli.ContainerInspect(context.Background(), container.ID)
|
||||
// // var tm string
|
||||
// // if err != nil {
|
||||
// // tm = time.Now().String()
|
||||
// // } else {
|
||||
// // tm = info.State.StartedAt
|
||||
// //}
|
||||
// list = append(list, model2.MyAppList{
|
||||
// Name: m.Label,
|
||||
// Icon: m.Icon,
|
||||
// State: container.State,
|
||||
// CustomId: strings.ReplaceAll(container.Names[0], "/", ""),
|
||||
// Port: m.PortMap,
|
||||
// Index: m.Index,
|
||||
// //UpTime: tm,
|
||||
// Image: m.Image,
|
||||
// Slogan: m.Slogan,
|
||||
// //Rely: m.Rely,
|
||||
// })
|
||||
// }
|
||||
|
||||
// }
|
||||
|
||||
return &list, &unTranslation
|
||||
|
||||
}
|
||||
|
||||
//system application list
|
||||
func (a *appStruct) GetSystemAppList() []types.Container {
|
||||
//获取docker应用
|
||||
cli, err := client2.NewClientWithOpts(client2.FromEnv)
|
||||
if err != nil {
|
||||
@@ -47,61 +308,30 @@ func (a *appStruct) GetMyList(index, size int, position bool) *[]model2.MyAppLis
|
||||
}
|
||||
defer cli.Close()
|
||||
fts := filters.NewArgs()
|
||||
fts.Add("label", "origin")
|
||||
fts.Add("label", "origin=system")
|
||||
containers, err := cli.ContainerList(context.Background(), types.ContainerListOptions{All: true, Filters: fts})
|
||||
if err != nil {
|
||||
a.log.Error("获取docker容器失败", "app.getmylist", "line:42", err)
|
||||
a.log.Error("获取docker容器失败", "app.sys", "line:123", err)
|
||||
}
|
||||
|
||||
//获取本地数据库应用
|
||||
|
||||
// var lm []model2.AppListDBModel
|
||||
// a.db.Table(model2.CONTAINERTABLENAME).Select("title,icon,port_map,`index`,container_id,position,label,slogan,image,volumes").Find(&lm)
|
||||
|
||||
//list := []model2.MyAppList{}
|
||||
//lMap := make(map[string]interface{})
|
||||
// for _, dbModel := range lm {
|
||||
// lMap[dbModel.ContainerId] = dbModel
|
||||
// }
|
||||
|
||||
return containers
|
||||
|
||||
}
|
||||
func (a *appStruct) GetAllDBApps() []model2.AppListDBModel {
|
||||
var lm []model2.AppListDBModel
|
||||
a.db.Table(model2.CONTAINERTABLENAME).Select("title,icon,port_map,`index`,container_id,position,label,slogan").Find(&lm)
|
||||
|
||||
list := []model2.MyAppList{}
|
||||
lMap := make(map[string]interface{})
|
||||
for _, dbModel := range lm {
|
||||
if position {
|
||||
if dbModel.Position {
|
||||
lMap[dbModel.ContainerId] = dbModel
|
||||
}
|
||||
} else {
|
||||
lMap[dbModel.ContainerId] = dbModel
|
||||
}
|
||||
}
|
||||
for _, container := range containers {
|
||||
|
||||
if lMap[container.ID] != nil {
|
||||
var m model2.AppListDBModel
|
||||
m = lMap[container.ID].(model2.AppListDBModel)
|
||||
if len(m.Label) == 0 {
|
||||
m.Label = m.Title
|
||||
}
|
||||
|
||||
info, err := cli.ContainerInspect(context.Background(), container.ID)
|
||||
var tm string
|
||||
if err != nil {
|
||||
tm = time.Now().String()
|
||||
} else {
|
||||
tm = info.State.StartedAt
|
||||
}
|
||||
list = append(list, model2.MyAppList{
|
||||
Name: m.Label,
|
||||
Icon: m.Icon,
|
||||
State: container.State,
|
||||
CustomId: strings.ReplaceAll(container.Names[0], "/", ""),
|
||||
Port: m.PortMap,
|
||||
Index: m.Index,
|
||||
UpTime: tm,
|
||||
Slogan: m.Slogan,
|
||||
//Rely: m.Rely,
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return &list
|
||||
|
||||
a.db.Table(model2.CONTAINERTABLENAME).Select("custom_id,title,icon,container_id,label,slogan,image,port_map").Find(&lm)
|
||||
return lm
|
||||
}
|
||||
|
||||
//获取我的应用列表
|
||||
@@ -115,7 +345,7 @@ func (a *appStruct) GetContainerInfo(name string) (types.Container, error) {
|
||||
filters.Add("name", name)
|
||||
containers, err := cli.ContainerList(context.Background(), types.ContainerListOptions{All: true, Filters: filters})
|
||||
if err != nil {
|
||||
a.log.Error("获取docker容器失败", "app.getmylist", "line:42", err)
|
||||
a.log.Error("获取docker容器失败", "app.getcontainerinfo", "line:182", err)
|
||||
}
|
||||
|
||||
if len(containers) > 0 {
|
||||
@@ -135,6 +365,10 @@ func (a *appStruct) GetSimpleContainerInfo(name string) (types.Container, error)
|
||||
filters := filters.NewArgs()
|
||||
filters.Add("name", name)
|
||||
containers, err := cli.ContainerList(context.Background(), types.ContainerListOptions{All: true, Filters: filters})
|
||||
if err != nil {
|
||||
return types.Container{}, err
|
||||
}
|
||||
|
||||
if len(containers) > 0 {
|
||||
return containers[0], nil
|
||||
}
|
||||
@@ -155,27 +389,6 @@ func (a *appStruct) GetUninstallInfo(id string) model2.AppListDBModel {
|
||||
return m
|
||||
}
|
||||
|
||||
func (a *appStruct) GetServerAppInfo(id string) model.ServerAppList {
|
||||
|
||||
head := make(map[string]string)
|
||||
|
||||
t := make(chan string)
|
||||
|
||||
go func() {
|
||||
str := httper2.Get(config.ServerInfo.ServerApi+"/token", nil)
|
||||
|
||||
t <- gjson.Get(str, "data").String()
|
||||
}()
|
||||
head["Authorization"] = <-t
|
||||
|
||||
infoS := httper2.Get(config.ServerInfo.ServerApi+"/v1/app/info/"+id, head)
|
||||
|
||||
info := model.ServerAppList{}
|
||||
json2.Unmarshal([]byte(gjson.Get(infoS, "data").String()), &info)
|
||||
|
||||
return info
|
||||
}
|
||||
|
||||
//创建容器成功后保存容器
|
||||
func (a *appStruct) SaveContainer(m model2.AppListDBModel) {
|
||||
a.db.Table(model2.CONTAINERTABLENAME).Create(&m)
|
||||
@@ -185,14 +398,119 @@ func (a *appStruct) UpdateApp(m model2.AppListDBModel) {
|
||||
a.db.Table(model2.CONTAINERTABLENAME).Save(&m)
|
||||
}
|
||||
|
||||
func (a *appStruct) DelAppConfigDir(id string) {
|
||||
command.OnlyExec("source " + config.AppInfo.ProjectPath + "/shell/helper.sh ;DelAppConfigDir " + docker.GetDir(id, "/config"))
|
||||
func (a *appStruct) DelAppConfigDir(path string) {
|
||||
command.OnlyExec("source " + config.AppInfo.ProjectPath + "/shell/helper.sh ;DelAppConfigDir " + path)
|
||||
}
|
||||
|
||||
func (a *appStruct) RemoveContainerById(id string) {
|
||||
func (a *appStruct) DeleteApp(id string) {
|
||||
a.db.Table(model2.CONTAINERTABLENAME).Where("custom_id = ?", id).Delete(&model2.AppListDBModel{})
|
||||
}
|
||||
|
||||
var dataStats sync.Map
|
||||
|
||||
var isFinish bool = false
|
||||
|
||||
func (a *appStruct) GetAppStats(id string) string {
|
||||
cli, err := client2.NewClientWithOpts(client2.FromEnv)
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
defer cli.Close()
|
||||
con, err := cli.ContainerStats(context.Background(), id, false)
|
||||
if err != nil {
|
||||
return err.Error()
|
||||
}
|
||||
defer con.Body.Close()
|
||||
c, _ := ioutil.ReadAll(con.Body)
|
||||
return string(c)
|
||||
}
|
||||
|
||||
func (a *appStruct) GetHardwareUsage() []model.DockerStatsModel {
|
||||
|
||||
steam := true
|
||||
for !isFinish {
|
||||
if steam {
|
||||
steam = false
|
||||
go func() {
|
||||
a.GetHardwareUsageSteam()
|
||||
}()
|
||||
}
|
||||
runtime.Gosched()
|
||||
}
|
||||
list := []model.DockerStatsModel{}
|
||||
|
||||
dataStats.Range(func(key, value interface{}) bool {
|
||||
list = append(list, value.(model.DockerStatsModel))
|
||||
return true
|
||||
})
|
||||
return list
|
||||
|
||||
}
|
||||
|
||||
func (a *appStruct) GetHardwareUsageSteam() {
|
||||
|
||||
cli, err := client2.NewClientWithOpts(client2.FromEnv)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer cli.Close()
|
||||
|
||||
ctx := context.Background()
|
||||
ctx, cancel := context.WithCancel(ctx)
|
||||
|
||||
fts := filters.NewArgs()
|
||||
fts.Add("label", "casaos=casaos")
|
||||
//fts.Add("label", "casaos")
|
||||
//fts.Add("casaos", "casaos")
|
||||
containers, err := cli.ContainerList(context.Background(), types.ContainerListOptions{All: true, Filters: fts})
|
||||
if err != nil {
|
||||
a.log.Error("获取docker容器失败", "app.getmylist", "line:42", err)
|
||||
}
|
||||
for i := 0; i < 100; i++ {
|
||||
if config.CasaOSGlobalVariables.AppChange {
|
||||
config.CasaOSGlobalVariables.AppChange = false
|
||||
|
||||
dataStats.Range(func(key, value interface{}) bool {
|
||||
dataStats.Delete(key)
|
||||
return true
|
||||
})
|
||||
}
|
||||
var wg sync.WaitGroup
|
||||
for _, v := range containers {
|
||||
wg.Add(1)
|
||||
go func(v types.Container, i int) {
|
||||
defer wg.Done()
|
||||
stats, err := cli.ContainerStats(ctx, v.ID, true)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
decode := json.NewDecoder(stats.Body)
|
||||
var data interface{}
|
||||
if err := decode.Decode(&data); err == io.EOF {
|
||||
return
|
||||
}
|
||||
m, _ := dataStats.Load(v.ID)
|
||||
dockerStats := model.DockerStatsModel{}
|
||||
if m != nil {
|
||||
dockerStats.Pre = m.(model.DockerStatsModel).Data
|
||||
}
|
||||
dockerStats.Data = data
|
||||
dockerStats.Icon = v.Labels["icon"]
|
||||
dockerStats.Title = strings.ReplaceAll(v.Names[0], "/", "")
|
||||
dataStats.Store(v.ID, dockerStats)
|
||||
if i == 99 {
|
||||
stats.Body.Close()
|
||||
}
|
||||
}(v, i)
|
||||
}
|
||||
wg.Wait()
|
||||
isFinish = true
|
||||
time.Sleep(time.Second * 3)
|
||||
}
|
||||
isFinish = false
|
||||
cancel()
|
||||
}
|
||||
|
||||
func NewAppService(db *gorm.DB, logger loger2.OLog) AppService {
|
||||
return &appStruct{db: db, log: logger}
|
||||
}
|
||||
|
||||
9
service/app_test.go
Normal file
9
service/app_test.go
Normal file
@@ -0,0 +1,9 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestGetCasaOSCount(t *testing.T) {
|
||||
|
||||
}
|
||||
235
service/casa.go
Normal file
235
service/casa.go
Normal file
@@ -0,0 +1,235 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
json2 "encoding/json"
|
||||
"fmt"
|
||||
"strconv"
|
||||
|
||||
"github.com/IceWhaleTech/CasaOS/model"
|
||||
"github.com/IceWhaleTech/CasaOS/pkg/config"
|
||||
httper2 "github.com/IceWhaleTech/CasaOS/pkg/utils/httper"
|
||||
model2 "github.com/IceWhaleTech/CasaOS/service/model"
|
||||
"github.com/IceWhaleTech/CasaOS/types"
|
||||
"github.com/tidwall/gjson"
|
||||
)
|
||||
|
||||
type CasaService interface {
|
||||
GetServerList(index, size, tp, categoryId, key, language string) (recommend, list, community []model.ServerAppList)
|
||||
GetServerCategoryList() []model.ServerCategoryList
|
||||
GetTaskList(size int) []model2.TaskDBModel
|
||||
GetServerAppInfo(id, t string, language string) model.ServerAppList
|
||||
ShareAppFile(body []byte) string
|
||||
PushHeart(id, t string, language string)
|
||||
PushAppAnalyse(uuid, t string, name, language string)
|
||||
PushConnectionStatus(uuid, err string, from, to, event string)
|
||||
PushUserInfo()
|
||||
GetUserInfoByShareId(shareId string) model.UserInfo
|
||||
GetPersonPublic() (list []model.FriendsModel)
|
||||
}
|
||||
|
||||
type casaService struct {
|
||||
}
|
||||
|
||||
func (o *casaService) ShareAppFile(body []byte) string {
|
||||
head := make(map[string]string)
|
||||
|
||||
head["Authorization"] = GetToken()
|
||||
|
||||
content := httper2.Post(config.ServerInfo.ServerApi+"/v1/community/add", body, "application/json", head)
|
||||
return content
|
||||
}
|
||||
|
||||
func (o *casaService) GetTaskList(size int) []model2.TaskDBModel {
|
||||
head := make(map[string]string)
|
||||
|
||||
head["Authorization"] = GetToken()
|
||||
|
||||
listS := httper2.Get(config.ServerInfo.ServerApi+"/v1/task/list/"+strconv.Itoa(size), head)
|
||||
|
||||
list := []model2.TaskDBModel{}
|
||||
json2.Unmarshal([]byte(gjson.Get(listS, "data").String()), &list)
|
||||
|
||||
return list
|
||||
}
|
||||
|
||||
func (o *casaService) GetServerList(index, size, tp, categoryId, key, language string) (recommend, list, community []model.ServerAppList) {
|
||||
|
||||
keyName := fmt.Sprintf("list_%s_%s_%s_%s_%s", index, size, tp, categoryId, language)
|
||||
|
||||
if result, ok := Cache.Get(keyName); ok {
|
||||
res, ok := result.(string)
|
||||
if ok {
|
||||
json2.Unmarshal([]byte(gjson.Get(res, "data.list").String()), &list)
|
||||
json2.Unmarshal([]byte(gjson.Get(res, "data.recommend").String()), &recommend)
|
||||
json2.Unmarshal([]byte(gjson.Get(res, "data.community").String()), &community)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
head := make(map[string]string)
|
||||
|
||||
head["Authorization"] = GetToken()
|
||||
|
||||
listS := httper2.Get(config.ServerInfo.ServerApi+"/v2/app/newlist?index="+index+"&size="+size+"&rank="+tp+"&category_id="+categoryId+"&key="+key+"&language="+language, head)
|
||||
|
||||
json2.Unmarshal([]byte(gjson.Get(listS, "data.list").String()), &list)
|
||||
json2.Unmarshal([]byte(gjson.Get(listS, "data.recommend").String()), &recommend)
|
||||
json2.Unmarshal([]byte(gjson.Get(listS, "data.community").String()), &community)
|
||||
|
||||
if len(list) > 0 {
|
||||
Cache.SetDefault(keyName, listS)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (o *casaService) GetServerCategoryList() []model.ServerCategoryList {
|
||||
|
||||
head := make(map[string]string)
|
||||
head["Authorization"] = GetToken()
|
||||
|
||||
listS := httper2.Get(config.ServerInfo.ServerApi+"/v2/app/category", head)
|
||||
|
||||
list := []model.ServerCategoryList{}
|
||||
|
||||
json2.Unmarshal([]byte(gjson.Get(listS, "data").String()), &list)
|
||||
|
||||
return list
|
||||
}
|
||||
func (o *casaService) GetServerAppInfo(id, t string, language string) model.ServerAppList {
|
||||
|
||||
head := make(map[string]string)
|
||||
|
||||
head["Authorization"] = GetToken()
|
||||
infoS := httper2.Get(config.ServerInfo.ServerApi+"/v2/app/info/"+id+"?t="+t+"&language="+language, head)
|
||||
|
||||
info := model.ServerAppList{}
|
||||
json2.Unmarshal([]byte(gjson.Get(infoS, "data").String()), &info)
|
||||
|
||||
return info
|
||||
}
|
||||
func GetToken() string {
|
||||
t := make(chan string)
|
||||
keyName := "casa_token"
|
||||
|
||||
var auth string
|
||||
if result, ok := Cache.Get(keyName); ok {
|
||||
auth, ok = result.(string)
|
||||
if ok {
|
||||
|
||||
return auth
|
||||
}
|
||||
}
|
||||
go func() {
|
||||
str := httper2.Get(config.ServerInfo.ServerApi+"/token", nil)
|
||||
t <- gjson.Get(str, "data").String()
|
||||
}()
|
||||
auth = <-t
|
||||
|
||||
Cache.SetDefault(keyName, auth)
|
||||
return auth
|
||||
}
|
||||
|
||||
func (o *casaService) PushHeart(id, t string, language string) {
|
||||
|
||||
m := model.CasaOSHeart{}
|
||||
m.UuId = id
|
||||
m.Type = t
|
||||
b, _ := json.Marshal(m)
|
||||
|
||||
head := make(map[string]string)
|
||||
|
||||
head["Authorization"] = GetToken()
|
||||
|
||||
infoS := httper2.Post(config.ServerInfo.ServerApi+"/v1/analyse/heart", b, "application/json", head)
|
||||
|
||||
info := model.ServerAppList{}
|
||||
json2.Unmarshal([]byte(gjson.Get(infoS, "data").String()), &info)
|
||||
|
||||
}
|
||||
|
||||
func (o *casaService) PushAppAnalyse(uuid, t string, name, language string) {
|
||||
|
||||
m := model.AppAnalyse{}
|
||||
m.UUId = uuid
|
||||
m.Type = t
|
||||
m.Name = name
|
||||
m.Language = language
|
||||
m.Version = types.CURRENTVERSION
|
||||
b, _ := json.Marshal(m)
|
||||
|
||||
head := make(map[string]string)
|
||||
|
||||
head["Authorization"] = GetToken()
|
||||
|
||||
infoS := httper2.Post(config.ServerInfo.ServerApi+"/v1/analyse/app", b, "application/json", head)
|
||||
|
||||
info := model.ServerAppList{}
|
||||
json2.Unmarshal([]byte(gjson.Get(infoS, "data").String()), &info)
|
||||
|
||||
}
|
||||
func (o *casaService) PushConnectionStatus(uuid, err string, from, to, event string) {
|
||||
|
||||
m := model.ConnectionStatus{}
|
||||
m.UUId = uuid
|
||||
m.Error = err
|
||||
m.From = from
|
||||
m.To = to
|
||||
m.Event = event
|
||||
b, _ := json.Marshal(m)
|
||||
|
||||
head := make(map[string]string)
|
||||
|
||||
head["Authorization"] = GetToken()
|
||||
|
||||
infoS := httper2.Post(config.ServerInfo.ServerApi+"/v1/analyse/connect", b, "application/json", head)
|
||||
|
||||
info := model.ServerAppList{}
|
||||
json2.Unmarshal([]byte(gjson.Get(infoS, "data").String()), &info)
|
||||
|
||||
}
|
||||
func (o *casaService) PushUserInfo() {
|
||||
m := model.UserInfo{}
|
||||
m.Desc = config.UserInfo.Description
|
||||
m.Avatar = config.UserInfo.Avatar
|
||||
m.NickName = config.UserInfo.NickName
|
||||
m.ShareId = config.ServerInfo.Token
|
||||
b, _ := json.Marshal(m)
|
||||
|
||||
head := make(map[string]string)
|
||||
|
||||
head["Authorization"] = GetToken()
|
||||
|
||||
infoS := httper2.Post(config.ServerInfo.ServerApi+"/v1/user/info", b, "application/json", head)
|
||||
|
||||
info := model.ServerAppList{}
|
||||
json2.Unmarshal([]byte(gjson.Get(infoS, "data").String()), &info)
|
||||
|
||||
}
|
||||
|
||||
func (o *casaService) GetUserInfoByShareId(shareId string) model.UserInfo {
|
||||
|
||||
head := make(map[string]string)
|
||||
|
||||
head["Authorization"] = GetToken()
|
||||
|
||||
infoS := httper2.Get(config.ServerInfo.ServerApi+"/v1/user/info/"+shareId, head)
|
||||
|
||||
info := model.UserInfo{}
|
||||
json2.Unmarshal([]byte(gjson.Get(infoS, "data").String()), &info)
|
||||
return info
|
||||
}
|
||||
func (o *casaService) GetPersonPublic() (list []model.FriendsModel) {
|
||||
head := make(map[string]string)
|
||||
|
||||
head["Authorization"] = GetToken()
|
||||
|
||||
listS := httper2.Get(config.ServerInfo.ServerApi+"/v1/person/public", head)
|
||||
|
||||
json2.Unmarshal([]byte(gjson.Get(listS, "data").String()), &list)
|
||||
|
||||
return list
|
||||
}
|
||||
func NewCasaService() CasaService {
|
||||
return &casaService{}
|
||||
}
|
||||
1
service/data_ handling.go
Normal file
1
service/data_ handling.go
Normal file
@@ -0,0 +1 @@
|
||||
package service
|
||||
@@ -1,12 +1,13 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"os/exec"
|
||||
|
||||
ip_helper2 "github.com/IceWhaleTech/CasaOS/pkg/utils/ip_helper"
|
||||
loger2 "github.com/IceWhaleTech/CasaOS/pkg/utils/loger"
|
||||
"github.com/IceWhaleTech/CasaOS/service/ddns"
|
||||
"github.com/IceWhaleTech/CasaOS/service/model"
|
||||
"gorm.io/gorm"
|
||||
"os/exec"
|
||||
)
|
||||
|
||||
type ddnsStruct struct {
|
||||
@@ -20,17 +21,15 @@ type DDNSService interface {
|
||||
GetConfigList() *[]model.DDNSList
|
||||
DeleteConfig(id uint) bool
|
||||
GetType(name string) (uint, string)
|
||||
SaveConfig(model model.DDNSUpdataDBModel) error
|
||||
SaveConfig(model model.DDNSUpdateDBModel) error
|
||||
}
|
||||
|
||||
//判断当前添加的是否存在
|
||||
func (d *ddnsStruct) IsExis(t int, domain string, host string) bool {
|
||||
var count int64
|
||||
d.db.Table(model.DDNSLISTTABLENAME).Where("type=? AND domain=? AND host=?", t, domain, host).Count(&count)
|
||||
if count > 0 {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
|
||||
return count > 0
|
||||
}
|
||||
|
||||
//前台获取已配置的ddns列表
|
||||
@@ -41,7 +40,7 @@ func (d *ddnsStruct) GetConfigList() *[]model.DDNSList {
|
||||
}
|
||||
|
||||
func (d *ddnsStruct) DeleteConfig(id uint) bool {
|
||||
d.db.Delete(&model.DDNSUpdataDBModel{Id: id})
|
||||
d.db.Delete(&model.DDNSUpdateDBModel{Id: id})
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -66,12 +65,12 @@ func (d *ddnsStruct) GetType(name string) (uint, string) {
|
||||
}
|
||||
|
||||
//保存配置到数据库
|
||||
func (d *ddnsStruct) GetDockerRootDir(model model.DDNSUpdataDBModel) error {
|
||||
func (d *ddnsStruct) GetDockerRootDir(model model.DDNSUpdateDBModel) error {
|
||||
return d.db.Create(&model).Error
|
||||
}
|
||||
|
||||
//保存配置到数据库
|
||||
func (d *ddnsStruct) SaveConfig(model model.DDNSUpdataDBModel) error {
|
||||
func (d *ddnsStruct) SaveConfig(model model.DDNSUpdateDBModel) error {
|
||||
return d.db.Create(&model).Error
|
||||
}
|
||||
|
||||
@@ -87,7 +86,7 @@ func chackPing(b chan bool, url string) {
|
||||
}
|
||||
|
||||
//更新列表
|
||||
func UpdataDDNSList(db *gorm.DB) {
|
||||
func UpdateDDNSList(db *gorm.DB) {
|
||||
var s []model.DDNSCoreList
|
||||
db.Table(model.DDNSLISTTABLENAME).Select("o_ddns_type.name as name,o_ddns_type.api_host as api_host,o_ddns.id,`host`,domain,user_name,`password`,`key`,secret,type").Joins("left join o_ddns_type on o_ddns.type=o_ddns_type.id").Scan(&s)
|
||||
for _, item := range s {
|
||||
|
||||
@@ -31,4 +31,3 @@ func SetOauth(request *http.Request, value string) {
|
||||
func SetXFilter(request *http.Request, value string) {
|
||||
request.Header.Set("X-Filter", value)
|
||||
}
|
||||
|
||||
|
||||
222
service/disk.go
222
service/disk.go
@@ -3,28 +3,73 @@ package service
|
||||
import (
|
||||
json2 "encoding/json"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/IceWhaleTech/CasaOS/model"
|
||||
"github.com/IceWhaleTech/CasaOS/pkg/config"
|
||||
command2 "github.com/IceWhaleTech/CasaOS/pkg/utils/command"
|
||||
loger2 "github.com/IceWhaleTech/CasaOS/pkg/utils/loger"
|
||||
model2 "github.com/IceWhaleTech/CasaOS/service/model"
|
||||
"github.com/shirou/gopsutil/v3/disk"
|
||||
"github.com/tidwall/gjson"
|
||||
"strconv"
|
||||
"strings"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type DiskService interface {
|
||||
GetPlugInDisk() []string
|
||||
LSBLK() []model.LSBLKModel
|
||||
FormatDisk(path, format string) string
|
||||
UmountPointAndRemoveDir(path string) string
|
||||
LSBLK(isUseCache bool) []model.LSBLKModel
|
||||
SmartCTL(path string) model.SmartctlA
|
||||
FormatDisk(path, format string) []string
|
||||
UmountPointAndRemoveDir(path string) []string
|
||||
GetDiskInfo(path string) model.LSBLKModel
|
||||
DelPartition(path, num string) string
|
||||
AddPartition(path, num string, size uint64) string
|
||||
AddPartition(path string) string
|
||||
GetDiskInfoByPath(path string) *disk.UsageStat
|
||||
MountDisk(path, volume string)
|
||||
GetSerialAll() []model2.SerialDisk
|
||||
SaveMountPoint(m model2.SerialDisk)
|
||||
DeleteMountPoint(path, mountPoint string)
|
||||
DeleteMount(id string)
|
||||
UpdateMountPoint(m model2.SerialDisk)
|
||||
RemoveLSBLKCache()
|
||||
}
|
||||
type diskService struct {
|
||||
log loger2.OLog
|
||||
db *gorm.DB
|
||||
}
|
||||
|
||||
func (d *diskService) RemoveLSBLKCache() {
|
||||
key := "system_lsblk"
|
||||
Cache.Delete(key)
|
||||
}
|
||||
func (d *diskService) SmartCTL(path string) model.SmartctlA {
|
||||
|
||||
key := "system_smart_" + path
|
||||
if result, ok := Cache.Get(key); ok {
|
||||
|
||||
res, ok := result.(model.SmartctlA)
|
||||
if ok {
|
||||
return res
|
||||
}
|
||||
}
|
||||
var m model.SmartctlA
|
||||
str := command2.ExecSmartCTLByPath(path)
|
||||
if str == nil {
|
||||
d.log.Error("smartctl exec error,smartctl")
|
||||
return m
|
||||
}
|
||||
|
||||
err := json2.Unmarshal([]byte(str), &m)
|
||||
if err != nil {
|
||||
d.log.Error("json ummarshal error", err)
|
||||
}
|
||||
if !reflect.DeepEqual(m, model.SmartctlA{}) {
|
||||
Cache.Add(key, m, time.Second*10)
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
||||
//通过脚本获取外挂磁盘
|
||||
@@ -33,18 +78,15 @@ func (d *diskService) GetPlugInDisk() []string {
|
||||
}
|
||||
|
||||
//格式化硬盘
|
||||
func (d *diskService) FormatDisk(path, format string) string {
|
||||
|
||||
func (d *diskService) FormatDisk(path, format string) []string {
|
||||
r := command2.ExecResultStrArray("source " + config.AppInfo.ProjectPath + "/shell/helper.sh ;FormatDisk " + path + " " + format)
|
||||
fmt.Println(r)
|
||||
return ""
|
||||
return r
|
||||
}
|
||||
|
||||
//移除挂载点,删除目录
|
||||
func (d *diskService) UmountPointAndRemoveDir(path string) string {
|
||||
func (d *diskService) UmountPointAndRemoveDir(path string) []string {
|
||||
r := command2.ExecResultStrArray("source " + config.AppInfo.ProjectPath + "/shell/helper.sh ;UMountPorintAndRemoveDir " + path)
|
||||
fmt.Println(r)
|
||||
return ""
|
||||
return r
|
||||
}
|
||||
|
||||
//删除分区
|
||||
@@ -54,63 +96,93 @@ func (d *diskService) DelPartition(path, num string) string {
|
||||
return ""
|
||||
}
|
||||
|
||||
//添加分区
|
||||
func (d *diskService) AddPartition(path, num string, size uint64) string {
|
||||
|
||||
var maxSector uint64 = 0
|
||||
|
||||
chiList := command2.ExecResultStrArray("source " + config.AppInfo.ProjectPath + "/shell/helper.sh ;GetPartitionSectors " + path)
|
||||
if len(chiList) == 0 {
|
||||
d.log.Error("chiList length error")
|
||||
}
|
||||
for i := 0; i < len(chiList); i++ {
|
||||
tempArr := strings.Split(chiList[i], ",")
|
||||
tempSector, _ := strconv.ParseUint(tempArr[2], 10, 64)
|
||||
if tempSector > maxSector {
|
||||
maxSector = tempSector
|
||||
}
|
||||
}
|
||||
|
||||
r := command2.ExecResultStrArray("source ./shell/helper.sh ;AddPartition " + path + " " + num + " " + strconv.FormatUint(maxSector+1, 10) + " " + strconv.FormatUint(size+maxSector+1, 10))
|
||||
fmt.Println(r)
|
||||
//part
|
||||
func (d *diskService) AddPartition(path string) string {
|
||||
command2.ExecResultStrArray("source " + config.AppInfo.ProjectPath + "/shell/helper.sh ;AddPartition " + path)
|
||||
return ""
|
||||
}
|
||||
|
||||
func (d *diskService) AddAllPartition(path string) {
|
||||
|
||||
}
|
||||
|
||||
//获取硬盘详情
|
||||
func (d *diskService) GetDiskInfoByPath(path string) *disk.UsageStat {
|
||||
diskInfo, err := disk.Usage(path + "1")
|
||||
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
fmt.Println(path)
|
||||
fmt.Println(diskInfo)
|
||||
diskInfo.UsedPercent, _ = strconv.ParseFloat(fmt.Sprintf("%.1f", diskInfo.UsedPercent), 64)
|
||||
diskInfo.InodesUsedPercent, _ = strconv.ParseFloat(fmt.Sprintf("%.1f", diskInfo.InodesUsedPercent), 64)
|
||||
return diskInfo
|
||||
}
|
||||
|
||||
//获取磁盘信息
|
||||
func (d *diskService) LSBLK() []model.LSBLKModel {
|
||||
//get disk details
|
||||
func (d *diskService) LSBLK(isUseCache bool) []model.LSBLKModel {
|
||||
key := "system_lsblk"
|
||||
var n []model.LSBLKModel
|
||||
|
||||
if result, ok := Cache.Get(key); ok && isUseCache {
|
||||
|
||||
res, ok := result.([]model.LSBLKModel)
|
||||
if ok {
|
||||
return res
|
||||
}
|
||||
}
|
||||
|
||||
str := command2.ExecLSBLK()
|
||||
if str == nil {
|
||||
d.log.Error("lsblk exec error")
|
||||
d.log.Error("lsblk exec error,lsblk")
|
||||
return nil
|
||||
}
|
||||
var m []model.LSBLKModel
|
||||
// strStr := `{
|
||||
// "blockdevices": [
|
||||
// {"name":"loop0", "kname":"loop0", "path":"/dev/loop0", "maj:min":"7:0", "fsavail":"0", "fssize":"62M", "fstype":"squashfs", "fsused":"62M", "fsuse%":"100%", "fsver":"4.0", "mountpoint":"/snap/core20/1405", "label":null, "uuid":null, "ptuuid":null, "pttype":null, "parttype":null, "parttypename":null, "partlabel":null, "partuuid":null, "partflags":null, "ra":128, "ro":true, "rm":false, "hotplug":false, "model":null, "serial":null, "size":619, "state":null, "owner":"root", "group":"disk", "mode":"brw-rw----", "alignment":0, "min-io":512, "opt-io":0, "phy-sec":512, "log-sec":512, "rota":false, "sched":"mq-deadline", "rq-size":256, "type":"loop", "disc-aln":0, "disc-gran":"4K", "disc-max":"4G", "disc-zero":false, "wsame":"0B", "wwn":null, "rand":false, "pkname":null, "hctl":null, "tran":null, "subsystems":"block", "rev":null, "vendor":null, "zoned":"none", "dax":false},
|
||||
// {"name":"loop1", "kname":"loop1", "path":"/dev/loop1", "maj:min":"7:1", "fsavail":"0", "fssize":"55.6M", "fstype":"squashfs", "fsused":"55.6M", "fsuse%":"100%", "fsver":"4.0", "mountpoint":"/snap/core18/2344", "label":null, "uuid":null, "ptuuid":null, "pttype":null, "parttype":null, "parttypename":null, "partlabel":null, "partuuid":null, "partflags":null, "ra":128, "ro":true, "rm":false, "hotplug":false, "model":null, "serial":null, "size":55, "state":null, "owner":"root", "group":"disk", "mode":"brw-rw----", "alignment":0, "min-io":512, "opt-io":0, "phy-sec":512, "log-sec":512, "rota":false, "sched":"mq-deadline", "rq-size":256, "type":"loop", "disc-aln":0, "disc-gran":"4K", "disc-max":"4G", "disc-zero":false, "wsame":"0B", "wwn":null, "rand":false, "pkname":null, "hctl":null, "tran":null, "subsystems":"block", "rev":null, "vendor":null, "zoned":"none", "dax":false},
|
||||
// {"name":"loop2", "kname":"loop2", "path":"/dev/loop2", "maj:min":"7:2", "fsavail":"0", "fssize":"44.8M", "fstype":"squashfs", "fsused":"44.8M", "fsuse%":"100%", "fsver":"4.0", "mountpoint":"/snap/snapd/15314", "label":null, "uuid":null, "ptuuid":null, "pttype":null, "parttype":null, "parttypename":null, "partlabel":null, "partuuid":null, "partflags":null, "ra":128, "ro":true, "rm":false, "hotplug":false, "model":null, "serial":null, "size":446, "state":null, "owner":"root", "group":"disk", "mode":"brw-rw----", "alignment":0, "min-io":512, "opt-io":0, "phy-sec":512, "log-sec":512, "rota":false, "sched":"mq-deadline", "rq-size":256, "type":"loop", "disc-aln":0, "disc-gran":"4K", "disc-max":"4G", "disc-zero":false, "wsame":"0B", "wwn":null, "rand":false, "pkname":null, "hctl":null, "tran":null, "subsystems":"block", "rev":null, "vendor":null, "zoned":"none", "dax":false},
|
||||
// {"name":"loop3", "kname":"loop3", "path":"/dev/loop3", "maj:min":"7:3", "fsavail":"0", "fssize":"78.9M", "fstype":"squashfs", "fsused":"78.9M", "fsuse%":"100%", "fsver":"4.0", "mountpoint":"/snap/lxd/22754", "label":null, "uuid":null, "ptuuid":null, "pttype":null, "parttype":null, "parttypename":null, "partlabel":null, "partuuid":null, "partflags":null, "ra":128, "ro":true, "rm":false, "hotplug":false, "model":null, "serial":null, "size":788, "state":null, "owner":"root", "group":"disk", "mode":"brw-rw----", "alignment":0, "min-io":512, "opt-io":0, "phy-sec":512, "log-sec":512, "rota":false, "sched":"mq-deadline", "rq-size":256, "type":"loop", "disc-aln":0, "disc-gran":"4K", "disc-max":"4G", "disc-zero":false, "wsame":"0B", "wwn":null, "rand":false, "pkname":null, "hctl":null, "tran":null, "subsystems":"block", "rev":null, "vendor":null, "zoned":"none", "dax":false},
|
||||
// {"name":"loop4", "kname":"loop4", "path":"/dev/loop4", "maj:min":"7:4", "fsavail":"0", "fssize":"43.8M", "fstype":"squashfs", "fsused":"43.8M", "fsuse%":"100%", "fsver":"4.0", "mountpoint":"/snap/snapd/15177", "label":null, "uuid":null, "ptuuid":null, "pttype":null, "parttype":null, "parttypename":null, "partlabel":null, "partuuid":null, "partflags":null, "ra":128, "ro":true, "rm":false, "hotplug":false, "model":null, "serial":null, "size":436, "state":null, "owner":"root", "group":"disk", "mode":"brw-rw----", "alignment":0, "min-io":512, "opt-io":0, "phy-sec":512, "log-sec":512, "rota":false, "sched":"mq-deadline", "rq-size":256, "type":"loop", "disc-aln":0, "disc-gran":"4K", "disc-max":"4G", "disc-zero":false, "wsame":"0B", "wwn":null, "rand":false, "pkname":null, "hctl":null, "tran":null, "subsystems":"block", "rev":null, "vendor":null, "zoned":"none", "dax":false},
|
||||
// {"name":"loop5", "kname":"loop5", "path":"/dev/loop5", "maj:min":"7:5", "fsavail":"0", "fssize":"55.5M", "fstype":"squashfs", "fsused":"55.5M", "fsuse%":"100%", "fsver":"4.0", "mountpoint":"/snap/core18/1997", "label":null, "uuid":null, "ptuuid":null, "pttype":null, "parttype":null, "parttypename":null, "partlabel":null, "partuuid":null, "partflags":null, "ra":128, "ro":true, "rm":false, "hotplug":false, "model":null, "serial":null, "size":554, "state":null, "owner":"root", "group":"disk", "mode":"brw-rw----", "alignment":0, "min-io":512, "opt-io":0, "phy-sec":512, "log-sec":512, "rota":false, "sched":"mq-deadline", "rq-size":256, "type":"loop", "disc-aln":0, "disc-gran":"4K", "disc-max":"4G", "disc-zero":false, "wsame":"0B", "wwn":null, "rand":false, "pkname":null, "hctl":null, "tran":null, "subsystems":"block", "rev":null, "vendor":null, "zoned":"none", "dax":false},
|
||||
// {"name":"loop6", "kname":"loop6", "path":"/dev/loop6", "maj:min":"7:6", "fsavail":"0", "fssize":"80M", "fstype":"squashfs", "fsused":"80M", "fsuse%":"100%", "fsver":"4.0", "mountpoint":"/snap/lxd/22826", "label":null, "uuid":null, "ptuuid":null, "pttype":null, "parttype":null, "parttypename":null, "partlabel":null, "partuuid":null, "partflags":null, "ra":128, "ro":true, "rm":false, "hotplug":false, "model":null, "serial":null, "size":799, "state":null, "owner":"root", "group":"disk", "mode":"brw-rw----", "alignment":0, "min-io":512, "opt-io":0, "phy-sec":512, "log-sec":512, "rota":false, "sched":"mq-deadline", "rq-size":256, "type":"loop", "disc-aln":0, "disc-gran":"4K", "disc-max":"4G", "disc-zero":false, "wsame":"0B", "wwn":null, "rand":false, "pkname":null, "hctl":null, "tran":null, "subsystems":"block", "rev":null, "vendor":null, "zoned":"none", "dax":false},
|
||||
// {"name":"sda", "kname":"sda", "path":"/dev/sda", "maj:min":"8:0", "fsavail":null, "fssize":null, "fstype":null, "fsused":null, "fsuse%":null, "fsver":null, "mountpoint":null, "label":null, "uuid":null, "ptuuid":"1596101a-e20d-4296-96e2-0870efce554a", "pttype":"gpt", "parttype":null, "parttypename":null, "partlabel":null, "partuuid":null, "partflags":null, "ra":128, "ro":false, "rm":false, "hotplug":false, "model":"ST1000DM003-1ER1", "serial":"Z4YCS1B6", "size":9315, "state":"running", "owner":"root", "group":"disk", "mode":"brw-rw----", "alignment":0, "min-io":4096, "opt-io":0, "phy-sec":4096, "log-sec":512, "rota":true, "sched":"mq-deadline", "rq-size":64, "type":"disk", "disc-aln":0, "disc-gran":"0B", "disc-max":"0B", "disc-zero":false, "wsame":"0B", "wwn":"0x5000c50090db103a", "rand":true, "pkname":null, "hctl":"0:0:0:0", "tran":"sata", "subsystems":"block:scsi:pci", "rev":"CC61", "vendor":"ATA ", "zoned":"none", "dax":false,
|
||||
// "children": [
|
||||
// {"name":"sda1", "kname":"sda1", "path":"/dev/sda1", "maj:min":"8:1", "fsavail":null, "fssize":null, "fstype":null, "fsused":null, "fsuse%":null, "fsver":null, "mountpoint":null, "label":null, "uuid":null, "ptuuid":"1596101a-e20d-4296-96e2-0870efce554a", "pttype":"gpt", "parttype":null, "parttypename":null, "partlabel":null, "partuuid":null, "partflags":null, "ra":128, "ro":false, "rm":false, "hotplug":false, "model":null, "serial":null, "size":9315, "state":null, "owner":"root", "group":"disk", "mode":"brw-rw----", "alignment":3072, "min-io":4096, "opt-io":0, "phy-sec":4096, "log-sec":512, "rota":true, "sched":"mq-deadline", "rq-size":64, "type":"part", "disc-aln":0, "disc-gran":"0B", "disc-max":"0B", "disc-zero":false, "wsame":"0B", "wwn":"0x5000c50090db103a", "rand":true, "pkname":"sda", "hctl":null, "tran":null, "subsystems":"block:scsi:pci", "rev":null, "vendor":null, "zoned":"none", "dax":false}
|
||||
// ]
|
||||
// },
|
||||
// {"name":"sdb", "kname":"sdb", "path":"/dev/sdb", "maj:min":"8:16", "fsavail":null, "fssize":null, "fstype":null, "fsused":null, "fsuse%":null, "fsver":null, "mountpoint":null, "label":null, "uuid":null, "ptuuid":"baed02d0-e92d-4a00-9609-f94f31271a0e", "pttype":"gpt", "parttype":null, "parttypename":null, "partlabel":null, "partuuid":null, "partflags":null, "ra":128, "ro":false, "rm":false, "hotplug":false, "model":"ST1000DM003-1ER1", "serial":"W4Y51MFH", "size":9315, "state":"running", "owner":"root", "group":"disk", "mode":"brw-rw----", "alignment":0, "min-io":4096, "opt-io":0, "phy-sec":4096, "log-sec":512, "rota":true, "sched":"mq-deadline", "rq-size":64, "type":"disk", "disc-aln":0, "disc-gran":"0B", "disc-max":"0B", "disc-zero":false, "wsame":"0B", "wwn":"0x5000c5008acd2f00", "rand":true, "pkname":null, "hctl":"1:0:0:0", "tran":"sata", "subsystems":"block:scsi:pci", "rev":"CC46", "vendor":"ATA ", "zoned":"none", "dax":false,
|
||||
// "children": [
|
||||
// {"name":"sdb1", "kname":"sdb1", "path":"/dev/sdb1", "maj:min":"8:17", "fsavail":null, "fssize":null, "fstype":"zfs_member", "fsused":null, "fsuse%":null, "fsver":"5000", "mountpoint":null, "label":null, "uuid":null, "ptuuid":"baed02d0-e92d-4a00-9609-f94f31271a0e", "pttype":"gpt", "parttype":"0fc63daf-8483-4772-8e79-3d69d8477de4", "parttypename":"Linux filesystem", "partlabel":"primary", "partuuid":"57880cc0-2695-41c3-bf14-7161693e5bff", "partflags":null, "ra":128, "ro":false, "rm":false, "hotplug":false, "model":null, "serial":null, "size":9315, "state":null, "owner":"root", "group":"disk", "mode":"brw-rw----", "alignment":3072, "min-io":4096, "opt-io":0, "phy-sec":4096, "log-sec":512, "rota":true, "sched":"mq-deadline", "rq-size":64, "type":"part", "disc-aln":0, "disc-gran":"0B", "disc-max":"0B", "disc-zero":false, "wsame":"0B", "wwn":"0x5000c5008acd2f00", "rand":true, "pkname":"sdb", "hctl":null, "tran":null, "subsystems":"block:scsi:pci", "rev":null, "vendor":null, "zoned":"none", "dax":false}
|
||||
// ]
|
||||
// },
|
||||
// {"name":"nvme0n1", "kname":"nvme0n1", "path":"/dev/nvme0n1", "maj:min":"259:0", "fsavail":null, "fssize":null, "fstype":null, "fsused":null, "fsuse%":null, "fsver":null, "mountpoint":null, "label":null, "uuid":null, "ptuuid":"338abc31-a3d4-4af2-9342-b53268d9e5ac", "pttype":"gpt", "parttype":null, "parttypename":null, "partlabel":null, "partuuid":null, "partflags":null, "ra":128, "ro":false, "rm":false, "hotplug":false, "model":"LITEON CL1-8D128-HP", "serial":"UJDJA01PJDH3UI", "size":1192, "state":"live", "owner":"root", "group":"disk", "mode":"brw-rw----", "alignment":0, "min-io":512, "opt-io":0, "phy-sec":512, "log-sec":512, "rota":false, "sched":"none", "rq-size":255, "type":"disk", "disc-aln":0, "disc-gran":"512B", "disc-max":"2T", "disc-zero":false, "wsame":"0B", "wwn":"eui.0023035630392fe7", "rand":false, "pkname":null, "hctl":null, "tran":"nvme", "subsystems":"block:nvme:pci", "rev":null, "vendor":null, "zoned":"none", "dax":false,
|
||||
// "children": [
|
||||
// {"name":"nvme0n1p1", "kname":"nvme0n1p1", "path":"/dev/nvme0n1p1", "maj:min":"259:1", "fsavail":null, "fssize":null, "fstype":null, "fsused":null, "fsuse%":null, "fsver":null, "mountpoint":null, "label":null, "uuid":null, "ptuuid":"338abc31-a3d4-4af2-9342-b53268d9e5ac", "pttype":"gpt", "parttype":"21686148-6449-6e6f-744e-656564454649", "parttypename":"BIOS boot", "partlabel":null, "partuuid":"b2bac638-9468-449f-9669-79be44e3c80d", "partflags":null, "ra":128, "ro":false, "rm":false, "hotplug":false, "model":null, "serial":null, "size":1, "state":null, "owner":"root", "group":"disk", "mode":"brw-rw----", "alignment":0, "min-io":512, "opt-io":0, "phy-sec":512, "log-sec":512, "rota":false, "sched":"none", "rq-size":255, "type":"part", "disc-aln":0, "disc-gran":"512B", "disc-max":"2T", "disc-zero":false, "wsame":"0B", "wwn":"eui.0023035630392fe7", "rand":false, "pkname":"nvme0n1", "hctl":null, "tran":"nvme", "subsystems":"block:nvme:pci", "rev":null, "vendor":null, "zoned":"none", "dax":false},
|
||||
// {"name":"nvme0n1p2", "kname":"nvme0n1p2", "path":"/dev/nvme0n1p2", "maj:min":"259:2", "fsavail":"1.2G", "fssize":"1.4G", "fstype":"ext4", "fsused":"131.5M", "fsuse%":"9%", "fsver":"1.0", "mountpoint":"/boot", "label":null, "uuid":"cd8164e9-bf7a-4684-8a3b-1d9f209b4930", "ptuuid":"338abc31-a3d4-4af2-9342-b53268d9e5ac", "pttype":"gpt", "parttype":"0fc63daf-8483-4772-8e79-3d69d8477de4", "parttypename":"Linux filesystem", "partlabel":null, "partuuid":"42ed9ed6-1221-4bea-901a-bc2f7b7cb9e1", "partflags":null, "ra":128, "ro":false, "rm":false, "hotplug":false, "model":null, "serial":null, "size":15, "state":null, "owner":"root", "group":"disk", "mode":"brw-rw----", "alignment":0, "min-io":512, "opt-io":0, "phy-sec":512, "log-sec":512, "rota":false, "sched":"none", "rq-size":255, "type":"part", "disc-aln":0, "disc-gran":"512B", "disc-max":"2T", "disc-zero":false, "wsame":"0B", "wwn":"eui.0023035630392fe7", "rand":false, "pkname":"nvme0n1", "hctl":null, "tran":"nvme", "subsystems":"block:nvme:pci", "rev":null, "vendor":null, "zoned":"none", "dax":false},
|
||||
// {"name":"nvme0n1p3", "kname":"nvme0n1p3", "path":"/dev/nvme0n1p3", "maj:min":"259:3", "fsavail":null, "fssize":null, "fstype":"LVM2_member", "fsused":null, "fsuse%":null, "fsver":"LVM2 001", "mountpoint":null, "label":null, "uuid":"0G7ryL-p2Ks-i9HS-wvEO-lXHs-oyZX-1KIlZO", "ptuuid":"338abc31-a3d4-4af2-9342-b53268d9e5ac", "pttype":"gpt", "parttype":"0fc63daf-8483-4772-8e79-3d69d8477de4", "parttypename":"Linux filesystem", "partlabel":null, "partuuid":"f6ae2e8c-14ae-4d94-89f1-2c154e909843", "partflags":null, "ra":128, "ro":false, "rm":false, "hotplug":false, "model":null, "serial":null, "size":1177, "state":null, "owner":"root", "group":"disk", "mode":"brw-rw----", "alignment":0, "min-io":512, "opt-io":0, "phy-sec":512, "log-sec":512, "rota":false, "sched":"none", "rq-size":255, "type":"part", "disc-aln":0, "disc-gran":"512B", "disc-max":"2T", "disc-zero":false, "wsame":"0B", "wwn":"eui.0023035630392fe7", "rand":false, "pkname":"nvme0n1", "hctl":null, "tran":"nvme", "subsystems":"block:nvme:pci", "rev":null, "vendor":null, "zoned":"none", "dax":false,
|
||||
// "children": [
|
||||
// {"name":"ubuntu--vg-ubuntu--lv", "kname":"dm-0", "path":"/dev/mapper/ubuntu--vg-ubuntu--lv", "maj:min":"253:0", "fsavail":"78.6G", "fssize":"115.4G", "fstype":"ext4", "fsused":"30.9G", "fsuse%":"27%", "fsver":"1.0", "mountpoint":"/", "label":null, "uuid":"e8a9082f-3643-4820-a5e5-05817d7738c6", "ptuuid":null, "pttype":null, "parttype":null, "parttypename":null, "partlabel":null, "partuuid":null, "partflags":null, "ra":128, "ro":false, "rm":false, "hotplug":false, "model":null, "serial":null, "size":1177, "state":"running", "owner":"root", "group":"disk", "mode":"brw-rw----", "alignment":0, "min-io":512, "opt-io":0, "phy-sec":512, "log-sec":512, "rota":false, "sched":null, "rq-size":128, "type":"lvm", "disc-aln":0, "disc-gran":"512B", "disc-max":"2T", "disc-zero":false, "wsame":"0B", "wwn":null, "rand":false, "pkname":"nvme0n1p3", "hctl":null, "tran":null, "subsystems":"block", "rev":null, "vendor":null, "zoned":"none", "dax":false}
|
||||
// ]
|
||||
// }
|
||||
// ]
|
||||
// }
|
||||
// ]
|
||||
// }`
|
||||
// fmt.Println(gjson.Get(strStr, "blockdevices").String())
|
||||
err := json2.Unmarshal([]byte(gjson.Get(string(str), "blockdevices").String()), &m)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
d.log.Error("json ummarshal error", err)
|
||||
}
|
||||
|
||||
var n []model.LSBLKModel
|
||||
|
||||
var c []model.LSBLKModel
|
||||
|
||||
var fsused uint64
|
||||
|
||||
var health = true
|
||||
for _, i := range m {
|
||||
if i.Children != nil {
|
||||
if i.Type != "loop" && !i.RO {
|
||||
fsused = 0
|
||||
for _, child := range i.Children {
|
||||
if child.RM {
|
||||
@@ -133,7 +205,9 @@ func (d *diskService) LSBLK() []model.LSBLKModel {
|
||||
i.Children = c
|
||||
if fsused > 0 {
|
||||
i.UsedPercent, err = strconv.ParseFloat(fmt.Sprintf("%.4f", float64(fsused)/float64(i.Size)), 64)
|
||||
fmt.Println(err)
|
||||
if err != nil {
|
||||
d.log.Fatal("diskservice_lsblk_fsused", err)
|
||||
}
|
||||
}
|
||||
n = append(n, i)
|
||||
health = true
|
||||
@@ -141,15 +215,19 @@ func (d *diskService) LSBLK() []model.LSBLKModel {
|
||||
fsused = 0
|
||||
}
|
||||
}
|
||||
if len(n) > 0 {
|
||||
Cache.Add(key, n, time.Second*100)
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
func (d *diskService) GetDiskInfo(path string) model.LSBLKModel {
|
||||
str := command2.ExecLSBLKByPath(path)
|
||||
if str == nil {
|
||||
d.log.Error("lsblk exec error")
|
||||
d.log.Error("lsblk exec error,str")
|
||||
return model.LSBLKModel{}
|
||||
}
|
||||
|
||||
var ml []model.LSBLKModel
|
||||
err := json2.Unmarshal([]byte(gjson.Get(string(str), "blockdevices").String()), &ml)
|
||||
if err != nil {
|
||||
@@ -157,9 +235,13 @@ func (d *diskService) GetDiskInfo(path string) model.LSBLKModel {
|
||||
d.log.Error("json ummarshal error", err)
|
||||
return model.LSBLKModel{}
|
||||
}
|
||||
//todo 需要判断长度
|
||||
m := ml[0]
|
||||
//声明数组
|
||||
|
||||
m := model.LSBLKModel{}
|
||||
if len(ml) > 0 {
|
||||
m = ml[0]
|
||||
}
|
||||
return m
|
||||
// 下面为计算是否可以继续分区的部分,暂时不需要
|
||||
chiArr := make(map[string]string)
|
||||
chiList := command2.ExecResultStrArray("source " + config.AppInfo.ProjectPath + "/shell/helper.sh ;GetPartitionSectors " + m.Path)
|
||||
if len(chiList) == 0 {
|
||||
@@ -170,7 +252,6 @@ func (d *diskService) GetDiskInfo(path string) model.LSBLKModel {
|
||||
tempArr := strings.Split(chiList[i], ",")
|
||||
chiArr[tempArr[0]] = chiList[i]
|
||||
}
|
||||
|
||||
var maxSector uint64 = 0
|
||||
for i := 0; i < len(m.Children); i++ {
|
||||
tempArr := strings.Split(chiArr[m.Children[i].Path], ",")
|
||||
@@ -179,13 +260,13 @@ func (d *diskService) GetDiskInfo(path string) model.LSBLKModel {
|
||||
if m.Children[i].EndSector > maxSector {
|
||||
maxSector = m.Children[i].EndSector
|
||||
}
|
||||
|
||||
}
|
||||
diskEndSector := command2.ExecResultStrArray("source " + config.AppInfo.ProjectPath + "/shell/helper.sh ;GetDiskSizeAndSectors " + m.Path)
|
||||
|
||||
if len(diskEndSector) < 2 {
|
||||
d.log.Error("diskEndSector length error")
|
||||
}
|
||||
|
||||
diskEndSectorInt, _ := strconv.ParseUint(diskEndSector[len(diskEndSector)-1], 10, 64)
|
||||
if (diskEndSectorInt-maxSector)*m.MinIO/1024/1024 > 100 {
|
||||
//添加可以分区情况
|
||||
@@ -196,17 +277,38 @@ func (d *diskService) GetDiskInfo(path string) model.LSBLKModel {
|
||||
return m
|
||||
}
|
||||
|
||||
//func GetDiskInfo(path string) *disk.UsageStat {
|
||||
// diskInfo, _ := disk.Usage(path)
|
||||
// diskInfo.UsedPercent, _ = strconv.ParseFloat(fmt.Sprintf("%.1f", diskInfo.UsedPercent), 64)
|
||||
// diskInfo.InodesUsedPercent, _ = strconv.ParseFloat(fmt.Sprintf("%.1f", diskInfo.InodesUsedPercent), 64)
|
||||
// return diskInfo
|
||||
//}
|
||||
|
||||
//func (d *diskService) GetPlugInDisk() []string {
|
||||
// return disk.Partitions(false)
|
||||
//}
|
||||
|
||||
func NewDiskService(log loger2.OLog) DiskService {
|
||||
return &diskService{log: log}
|
||||
func (d *diskService) MountDisk(path, volume string) {
|
||||
r := command2.ExecResultStr("source " + config.AppInfo.ProjectPath + "/shell/helper.sh ;do_mount " + path + " " + volume)
|
||||
fmt.Print(r)
|
||||
}
|
||||
|
||||
func (d *diskService) SaveMountPoint(m model2.SerialDisk) {
|
||||
d.db.Where("uuid = ?", m.UUID).Delete(&model2.SerialDisk{})
|
||||
d.db.Create(&m)
|
||||
}
|
||||
|
||||
func (d *diskService) UpdateMountPoint(m model2.SerialDisk) {
|
||||
d.db.Model(&model2.SerialDisk{}).Where("uui = ?", m.UUID).Update("mount_point", m.MountPoint)
|
||||
}
|
||||
|
||||
func (d *diskService) DeleteMount(id string) {
|
||||
|
||||
d.db.Delete(&model2.SerialDisk{}).Where("id = ?", id)
|
||||
}
|
||||
|
||||
func (d *diskService) DeleteMountPoint(path, mountPoint string) {
|
||||
|
||||
d.db.Where("path = ? AND mount_point = ?", path, mountPoint).Delete(&model2.SerialDisk{})
|
||||
|
||||
command2.OnlyExec("source " + config.AppInfo.ProjectPath + "/shell/helper.sh ;do_umount " + path)
|
||||
}
|
||||
|
||||
func (d *diskService) GetSerialAll() []model2.SerialDisk {
|
||||
var m []model2.SerialDisk
|
||||
d.db.Find(&m)
|
||||
return m
|
||||
}
|
||||
|
||||
func NewDiskService(log loger2.OLog, db *gorm.DB) DiskService {
|
||||
return &diskService{log: log, db: db}
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ import (
|
||||
"encoding/binary"
|
||||
json2 "encoding/json"
|
||||
"fmt"
|
||||
"regexp"
|
||||
"reflect"
|
||||
"syscall"
|
||||
|
||||
model2 "github.com/IceWhaleTech/CasaOS/service/model"
|
||||
@@ -16,10 +16,12 @@ import (
|
||||
"github.com/containerd/containerd/cio"
|
||||
"github.com/containerd/containerd/namespaces"
|
||||
"github.com/containerd/containerd/oci"
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"github.com/IceWhaleTech/CasaOS/model"
|
||||
"github.com/IceWhaleTech/CasaOS/pkg/docker"
|
||||
command2 "github.com/IceWhaleTech/CasaOS/pkg/utils/command"
|
||||
"github.com/IceWhaleTech/CasaOS/pkg/utils/env_helper"
|
||||
"github.com/IceWhaleTech/CasaOS/pkg/utils/file"
|
||||
loger2 "github.com/IceWhaleTech/CasaOS/pkg/utils/loger"
|
||||
|
||||
@@ -44,22 +46,25 @@ import (
|
||||
type DockerService interface {
|
||||
DockerPullImage(imageName string, m model2.AppNotify) error
|
||||
IsExistImage(imageName string) bool
|
||||
DockerContainerCreate(imageName string, containerDbId string, m model.CustomizationPostData, net string) (containerId string, err error)
|
||||
DockerContainerCreate(imageName string, m model.CustomizationPostData, net string) (containerId string, err error)
|
||||
DockerContainerCopyCreate(info *types.ContainerJSON) (containerId string, err error)
|
||||
DockerContainerStart(name string) error
|
||||
DockerContainerStats(name string) (string, error)
|
||||
DockerListByName(name string) (*types.Container, error)
|
||||
DockerListByImage(image, version string) (*types.Container, error)
|
||||
DockerContainerInfo(name string) (*types.ContainerJSON, error)
|
||||
DockerImageRemove(name string) error
|
||||
DockerContainerRemove(name string) error
|
||||
DockerContainerRemove(name string, update bool) error
|
||||
DockerContainerStop(id string) error
|
||||
DockerContainerUpdateName(name, id string) (err error)
|
||||
DockerContainerUpdate(m model.CustomizationPostData, id string) (err error)
|
||||
DockerContainerLog(name string) (string, error)
|
||||
DockerContainerCommit(name string)
|
||||
DockerContainerList() []types.Container
|
||||
DockerNetworkModelList() []types.NetworkResource
|
||||
DockerImageInfo(image string)
|
||||
DockerImageInfo(image string) (types.ImageInspect, error)
|
||||
GetNetWorkNameByNetWorkID(id string) (string, error)
|
||||
ContainerExecShell(container_id string) string
|
||||
}
|
||||
|
||||
type dockerService struct {
|
||||
@@ -67,15 +72,33 @@ type dockerService struct {
|
||||
log loger2.OLog
|
||||
}
|
||||
|
||||
func DockerPs() {
|
||||
func (ds *dockerService) DockerContainerList() []types.Container {
|
||||
cli, err := client2.NewClientWithOpts(client2.FromEnv, client2.WithTimeout(time.Second*5))
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
defer cli.Close()
|
||||
containers, err := cli.ContainerList(context.Background(), types.ContainerListOptions{All: true})
|
||||
if err != nil {
|
||||
return containers
|
||||
}
|
||||
return containers
|
||||
}
|
||||
|
||||
func (ds *dockerService) ContainerExecShell(container_id string) string {
|
||||
cli, _ := client2.NewClientWithOpts(client2.FromEnv)
|
||||
containers, err := cli.ContainerList(context.Background(), types.ContainerListOptions{})
|
||||
exec, err := cli.ContainerExecCreate(context.Background(), container_id, types.ExecConfig{
|
||||
User: "1000:1000",
|
||||
Cmd: []string{"echo -e \"hellow\nworld\" >> /a.txt"},
|
||||
})
|
||||
if err != nil {
|
||||
os.Exit(5)
|
||||
}
|
||||
for _, container := range containers {
|
||||
fmt.Printf("%s %s\n", container.ID[:10], container.Image)
|
||||
err = cli.ContainerExecStart(context.Background(), exec.ID, types.ExecStartCheck{})
|
||||
if err != nil {
|
||||
fmt.Println("exec script error ", err)
|
||||
}
|
||||
return exec.ID
|
||||
}
|
||||
|
||||
//创建默认网络
|
||||
@@ -99,7 +122,7 @@ func (ds *dockerService) GetNetWorkNameByNetWorkID(id string) (string, error) {
|
||||
defer cli.Close()
|
||||
filter := filters.NewArgs()
|
||||
filter.Add("id", id)
|
||||
d, err := cli.NetworkList(context.Background(), types.NetworkListOptions{filter})
|
||||
d, err := cli.NetworkList(context.Background(), types.NetworkListOptions{Filters: filter})
|
||||
if err == nil && len(d) > 0 {
|
||||
return d[0].Name, nil
|
||||
}
|
||||
@@ -112,10 +135,7 @@ func DockerPull() {
|
||||
cli, _ := client2.NewClientWithOpts(client2.FromEnv)
|
||||
defer cli.Close()
|
||||
|
||||
authConfig := types.AuthConfig{
|
||||
Username: "cn-north-4@M4OW0IULZ3U6PCQPBUZC",
|
||||
Password: "7390181a1565f90927bbd98038436b57d6ebc66a3828d7a11dfda42b9c19d91d",
|
||||
}
|
||||
authConfig := types.AuthConfig{}
|
||||
encodedJSON, err := json2.Marshal(authConfig)
|
||||
fmt.Println(err)
|
||||
|
||||
@@ -150,7 +170,7 @@ func DockerEx() {
|
||||
importResponse.Close()
|
||||
println(string(response))
|
||||
if string(response) != "response" {
|
||||
fmt.Println("expected response to contain 'response', got %s", string(response))
|
||||
fmt.Printf("expected response to contain 'response', got %s", string(response))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -167,19 +187,16 @@ func DockerEx() {
|
||||
//
|
||||
//}
|
||||
|
||||
func (ds *dockerService) DockerImageInfo(image string) {
|
||||
func (ds *dockerService) DockerImageInfo(image string) (types.ImageInspect, error) {
|
||||
cli, err := client2.NewClientWithOpts(client2.FromEnv)
|
||||
|
||||
//but := bytes.Buffer{}
|
||||
d, b, err := cli.ImageInspectWithRaw(context.Background(), image)
|
||||
st, _ := json2.Marshal(d.Config)
|
||||
fmt.Println(string(st))
|
||||
fmt.Println("换行")
|
||||
fmt.Println(string(b))
|
||||
if err != nil {
|
||||
fmt.Print(err)
|
||||
return types.ImageInspect{}, err
|
||||
}
|
||||
|
||||
inspect, _, err := cli.ImageInspectWithRaw(context.Background(), image)
|
||||
if err != nil {
|
||||
return inspect, err
|
||||
}
|
||||
return inspect, nil
|
||||
}
|
||||
|
||||
func MsqlExec(container string) error {
|
||||
@@ -258,6 +275,8 @@ func DockerLogs() {
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
defer i.Close()
|
||||
|
||||
hdr := make([]byte, 8)
|
||||
for {
|
||||
_, err := i.Read(hdr)
|
||||
@@ -276,7 +295,6 @@ func DockerLogs() {
|
||||
_, err = i.Read(dat)
|
||||
fmt.Fprint(w, string(dat))
|
||||
}
|
||||
defer i.Close()
|
||||
}
|
||||
|
||||
//正式内容
|
||||
@@ -325,14 +343,28 @@ func (ds *dockerService) DockerPullImage(imageName string, m model2.AppNotify) e
|
||||
}
|
||||
break
|
||||
}
|
||||
if !reflect.DeepEqual(m, model2.AppNotify{}) {
|
||||
m.Type = types2.NOTIFY_TYPE_INSTALL_LOG
|
||||
m.State = 0
|
||||
m.Speed = 70
|
||||
m.Message = string(buf[:n])
|
||||
MyService.Notify().UpdateLog(m)
|
||||
}
|
||||
|
||||
}
|
||||
return err
|
||||
}
|
||||
func (ds *dockerService) DockerContainerCopyCreate(info *types.ContainerJSON) (containerId string, err error) {
|
||||
cli, err := client2.NewClientWithOpts(client2.FromEnv)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer cli.Close()
|
||||
container, err := cli.ContainerCreate(context.Background(), info.Config, info.HostConfig, &network.NetworkingConfig{info.NetworkSettings.Networks}, nil, info.Name)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return container.ID, err
|
||||
}
|
||||
|
||||
//param imageName 镜像名称
|
||||
//param containerDbId 数据库的id
|
||||
@@ -340,9 +372,9 @@ func (ds *dockerService) DockerPullImage(imageName string, m model2.AppNotify) e
|
||||
//param mapPort 容器主端口映射到外部的端口
|
||||
//param tcp 容器其他tcp端口
|
||||
//param udp 容器其他udp端口
|
||||
func (ds *dockerService) DockerContainerCreate(imageName string, containerDbId string, m model.CustomizationPostData, net string) (containerId string, err error) {
|
||||
func (ds *dockerService) DockerContainerCreate(imageName string, m model.CustomizationPostData, net string) (containerId string, err error) {
|
||||
if len(net) == 0 {
|
||||
net = "oasis"
|
||||
net = "bridge"
|
||||
}
|
||||
|
||||
cli, err := client2.NewClientWithOpts(client2.FromEnv)
|
||||
@@ -356,18 +388,18 @@ func (ds *dockerService) DockerContainerCreate(imageName string, containerDbId s
|
||||
// if net != "host" {
|
||||
// portMaps[nat.Port(fmt.Sprint(m.Port)+"/tcp")] = []nat.PortBinding{{HostIP: "", HostPort: m.PortMap}}
|
||||
// }
|
||||
port := ""
|
||||
//port := ""
|
||||
for _, portMap := range m.Ports {
|
||||
if portMap.CommendPort == m.PortMap && portMap.Protocol == "tcp" || portMap.Protocol == "both" {
|
||||
port = portMap.ContainerPort
|
||||
}
|
||||
// if portMap.CommendPort == m.PortMap && portMap.Protocol == "tcp" || portMap.Protocol == "both" {
|
||||
// port = portMap.ContainerPort
|
||||
// }
|
||||
if portMap.Protocol == "tcp" {
|
||||
|
||||
tContainer, _ := strconv.Atoi(portMap.ContainerPort)
|
||||
if tContainer > 0 {
|
||||
ports[nat.Port(portMap.ContainerPort+"/tcp")] = struct{}{}
|
||||
if net != "host" {
|
||||
portMaps[nat.Port(portMap.ContainerPort+"/tcp")] = []nat.PortBinding{{HostIP: "0.0.0.0", HostPort: portMap.CommendPort}}
|
||||
portMaps[nat.Port(portMap.ContainerPort+"/tcp")] = []nat.PortBinding{{HostPort: portMap.CommendPort}}
|
||||
}
|
||||
}
|
||||
} else if portMap.Protocol == "both" {
|
||||
@@ -376,7 +408,7 @@ func (ds *dockerService) DockerContainerCreate(imageName string, containerDbId s
|
||||
if tContainer > 0 {
|
||||
ports[nat.Port(portMap.ContainerPort+"/tcp")] = struct{}{}
|
||||
if net != "host" {
|
||||
portMaps[nat.Port(portMap.ContainerPort+"/tcp")] = []nat.PortBinding{{HostIP: "0.0.0.0", HostPort: portMap.CommendPort}}
|
||||
portMaps[nat.Port(portMap.ContainerPort+"/tcp")] = []nat.PortBinding{{HostPort: portMap.CommendPort}}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -384,7 +416,7 @@ func (ds *dockerService) DockerContainerCreate(imageName string, containerDbId s
|
||||
if uContainer > 0 {
|
||||
ports[nat.Port(portMap.ContainerPort+"/udp")] = struct{}{}
|
||||
if net != "host" {
|
||||
portMaps[nat.Port(portMap.ContainerPort+"/udp")] = []nat.PortBinding{{HostIP: "0.0.0.0", HostPort: portMap.CommendPort}}
|
||||
portMaps[nat.Port(portMap.ContainerPort+"/udp")] = []nat.PortBinding{{HostPort: portMap.CommendPort}}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -393,7 +425,7 @@ func (ds *dockerService) DockerContainerCreate(imageName string, containerDbId s
|
||||
if uContainer > 0 {
|
||||
ports[nat.Port(portMap.ContainerPort+"/udp")] = struct{}{}
|
||||
if net != "host" {
|
||||
portMaps[nat.Port(portMap.ContainerPort+"/udp")] = []nat.PortBinding{{HostIP: "0.0.0.0", HostPort: portMap.CommendPort}}
|
||||
portMaps[nat.Port(portMap.ContainerPort+"/udp")] = []nat.PortBinding{{HostPort: portMap.CommendPort}}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -402,6 +434,10 @@ func (ds *dockerService) DockerContainerCreate(imageName string, containerDbId s
|
||||
|
||||
var envArr []string
|
||||
for _, e := range m.Envs {
|
||||
if strings.HasPrefix(e.Value, "$") {
|
||||
envArr = append(envArr, e.Name+"="+env_helper.ReplaceDefaultENV(e.Value, MyService.System().GetTimeZone()))
|
||||
continue
|
||||
}
|
||||
if len(e.Value) > 0 {
|
||||
if e.Value == "port_map" {
|
||||
envArr = append(envArr, e.Name+"="+m.PortMap)
|
||||
@@ -420,7 +456,7 @@ func (ds *dockerService) DockerContainerCreate(imageName string, containerDbId s
|
||||
}
|
||||
for _, p := range m.Devices {
|
||||
if len(p.Path) > 0 {
|
||||
res.Devices = append(res.Devices, container.DeviceMapping{PathOnHost: p.Path, PathInContainer: p.ContainerPath})
|
||||
res.Devices = append(res.Devices, container.DeviceMapping{PathOnHost: p.Path, PathInContainer: p.ContainerPath, CgroupPermissions: "rwm"})
|
||||
}
|
||||
}
|
||||
hostConfingBind := []string{}
|
||||
@@ -429,26 +465,28 @@ func (ds *dockerService) DockerContainerCreate(imageName string, containerDbId s
|
||||
for _, v := range m.Volumes {
|
||||
path := v.Path
|
||||
if len(path) == 0 {
|
||||
path = docker.GetDir(containerDbId, v.ContainerPath)
|
||||
path = docker.GetDir(m.Label, v.Path)
|
||||
if len(path) == 0 {
|
||||
continue
|
||||
}
|
||||
}
|
||||
reg1 := regexp.MustCompile(`([^<>/\\\|:""\*\?]+\.\w+$)`)
|
||||
result1 := reg1.FindAllStringSubmatch(path, -1)
|
||||
if len(result1) == 0 {
|
||||
path = strings.ReplaceAll(path, "$AppID", m.Label)
|
||||
//reg1 := regexp.MustCompile(`([^<>/\\\|:""\*\?]+\.\w+$)`)
|
||||
//result1 := reg1.FindAllStringSubmatch(path, -1)
|
||||
//if len(result1) == 0 {
|
||||
err = file.IsNotExistMkDir(path)
|
||||
if err != nil {
|
||||
ds.log.Error("mkdir error", err)
|
||||
continue
|
||||
}
|
||||
} else {
|
||||
err = file.IsNotExistCreateFile(path)
|
||||
if err != nil {
|
||||
ds.log.Error("mkdir error", err)
|
||||
continue
|
||||
}
|
||||
}
|
||||
//}
|
||||
// else {
|
||||
// err = file.IsNotExistCreateFile(path)
|
||||
// if err != nil {
|
||||
// ds.log.Error("mkdir error", err)
|
||||
// continue
|
||||
// }
|
||||
// }
|
||||
|
||||
volumes = append(volumes, mount.Mount{
|
||||
Type: mount.TypeBind,
|
||||
@@ -464,25 +502,36 @@ func (ds *dockerService) DockerContainerCreate(imageName string, containerDbId s
|
||||
if len(m.Restart) > 0 {
|
||||
rp.Name = m.Restart
|
||||
}
|
||||
//fmt.Print(port)
|
||||
healthTest := []string{}
|
||||
if len(port) > 0 {
|
||||
healthTest = []string{"CMD-SHELL", "curl -f http://localhost:" + port + m.Index + " || exit 1"}
|
||||
}
|
||||
// healthTest := []string{}
|
||||
// if len(port) > 0 {
|
||||
// healthTest = []string{"CMD-SHELL", "curl -f http://localhost:" + port + m.Index + " || exit 1"}
|
||||
// }
|
||||
|
||||
health := &container.HealthConfig{
|
||||
Test: healthTest,
|
||||
//Test: []string{},
|
||||
StartPeriod: 0,
|
||||
Retries: 1000,
|
||||
// health := &container.HealthConfig{
|
||||
// Test: healthTest,
|
||||
// StartPeriod: 0,
|
||||
// Retries: 1000,
|
||||
// }
|
||||
// fmt.Print(health)
|
||||
if len(m.HostName) == 0 {
|
||||
m.HostName = m.Label
|
||||
}
|
||||
config := &container.Config{
|
||||
Image: imageName,
|
||||
Labels: map[string]string{"origin": m.Origin, m.Origin: m.Origin},
|
||||
Labels: map[string]string{"origin": m.Origin, m.Origin: m.Origin, "casaos": "casaos"},
|
||||
Env: envArr,
|
||||
Healthcheck: health,
|
||||
// Healthcheck: health,
|
||||
Hostname: m.HostName,
|
||||
Cmd: m.Cmd,
|
||||
}
|
||||
hostConfig := &container.HostConfig{Resources: res, Mounts: volumes, RestartPolicy: rp, NetworkMode: container.NetworkMode(net)}
|
||||
|
||||
config.Labels["web"] = m.PortMap
|
||||
config.Labels["icon"] = m.Icon
|
||||
config.Labels["desc"] = m.Description
|
||||
config.Labels["index"] = m.Index
|
||||
config.Labels["custom_id"] = m.CustomId
|
||||
//config.Labels["order"] = strconv.Itoa(MyService.App().GetCasaOSCount() + 1)
|
||||
hostConfig := &container.HostConfig{Resources: res, Mounts: volumes, RestartPolicy: rp, NetworkMode: container.NetworkMode(net), Privileged: m.Privileged, CapAdd: m.CapAdd}
|
||||
//if net != "host" {
|
||||
config.ExposedPorts = ports
|
||||
hostConfig.PortBindings = portMaps
|
||||
@@ -493,7 +542,7 @@ func (ds *dockerService) DockerContainerCreate(imageName string, containerDbId s
|
||||
hostConfig,
|
||||
&network.NetworkingConfig{EndpointsConfig: map[string]*network.EndpointSettings{net: {NetworkID: "", Aliases: []string{}}}},
|
||||
nil,
|
||||
containerDbId)
|
||||
m.Label)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
@@ -501,7 +550,7 @@ func (ds *dockerService) DockerContainerCreate(imageName string, containerDbId s
|
||||
}
|
||||
|
||||
//删除容器
|
||||
func (ds *dockerService) DockerContainerRemove(name string) error {
|
||||
func (ds *dockerService) DockerContainerRemove(name string, update bool) error {
|
||||
cli, err := client2.NewClientWithOpts(client2.FromEnv)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -510,10 +559,12 @@ func (ds *dockerService) DockerContainerRemove(name string) error {
|
||||
err = cli.ContainerRemove(context.Background(), name, types.ContainerRemoveOptions{})
|
||||
|
||||
//路径处理
|
||||
if !update {
|
||||
path := docker.GetDir(name, "/config")
|
||||
if !file.CheckNotExist(path) {
|
||||
file.RMDir(path)
|
||||
}
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -674,6 +725,9 @@ func (ds *dockerService) DockerListByName(name string) (*types.Container, error)
|
||||
if err != nil {
|
||||
return &types.Container{}, err
|
||||
}
|
||||
if len(containers) == 0 {
|
||||
return &types.Container{}, errors.New("not found")
|
||||
}
|
||||
return &containers[0], nil
|
||||
}
|
||||
|
||||
@@ -738,7 +792,7 @@ func (ds *dockerService) DockerContainerUpdate(m model.CustomizationPostData, id
|
||||
res.CPUShares = m.CpuShares
|
||||
}
|
||||
for _, p := range m.Devices {
|
||||
res.Devices = append(res.Devices, container.DeviceMapping{PathOnHost: p.Path, PathInContainer: p.ContainerPath})
|
||||
res.Devices = append(res.Devices, container.DeviceMapping{PathOnHost: p.Path, PathInContainer: p.ContainerPath, CgroupPermissions: "rwm"})
|
||||
}
|
||||
_, err = cli.ContainerUpdate(context.Background(), id, container.UpdateConfig{RestartPolicy: rp, Resources: res})
|
||||
if err != nil {
|
||||
@@ -773,7 +827,7 @@ func (ds *dockerService) DockerNetworkModelList() []types.NetworkResource {
|
||||
networks, _ := cli.NetworkList(context.Background(), types.NetworkListOptions{})
|
||||
return networks
|
||||
}
|
||||
func NewDcokerService(log loger2.OLog) DockerService {
|
||||
func NewDockerService(log loger2.OLog) DockerService {
|
||||
return &dockerService{rootDir: command2.ExecResultStr(`source ./shell/helper.sh ;GetDockerRootDir`), log: log}
|
||||
}
|
||||
|
||||
@@ -817,7 +871,6 @@ func Containerd() {
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
fmt.Println("333")
|
||||
fmt.Println(err)
|
||||
}
|
||||
defer container.Delete(ctx, containerd.WithSnapshotCleanup)
|
||||
@@ -825,7 +878,6 @@ func Containerd() {
|
||||
// create a task from the container
|
||||
task, err := container.NewTask(ctx, cio.NewCreator(cio.WithStdio))
|
||||
if err != nil {
|
||||
fmt.Println("444")
|
||||
fmt.Println(err)
|
||||
}
|
||||
defer task.Delete(ctx)
|
||||
@@ -838,7 +890,6 @@ func Containerd() {
|
||||
|
||||
// call start on the task to execute the redis server
|
||||
if err = task.Start(ctx); err != nil {
|
||||
fmt.Println("555")
|
||||
fmt.Println(err)
|
||||
}
|
||||
|
||||
@@ -848,7 +899,6 @@ func Containerd() {
|
||||
|
||||
// kill the process and get the exit status
|
||||
if err = task.Kill(ctx, syscall.SIGTERM); err != nil {
|
||||
fmt.Println("666")
|
||||
fmt.Println(err)
|
||||
}
|
||||
|
||||
@@ -857,7 +907,6 @@ func Containerd() {
|
||||
status := <-exitStatusC
|
||||
code, _, err := status.Result()
|
||||
if err != nil {
|
||||
fmt.Println("777")
|
||||
fmt.Println(err)
|
||||
}
|
||||
fmt.Printf("redis-server exited with status: %d\n", code)
|
||||
|
||||
@@ -3,7 +3,7 @@ package docker_base
|
||||
import "github.com/IceWhaleTech/CasaOS/model"
|
||||
|
||||
//过滤mysql关键字
|
||||
func MysqlFilter(c MysqlConfig, envs model.EnvArrey) model.EnvArrey {
|
||||
func MysqlFilter(c MysqlConfig, envs model.EnvArray) model.EnvArray {
|
||||
for i := 0; i < len(envs); i++ {
|
||||
switch envs[i].Value {
|
||||
case "$MYSQL_HOST":
|
||||
|
||||
@@ -7,5 +7,3 @@ type MysqlConfig struct {
|
||||
DataBasePassword string `json:"data_base_password"`
|
||||
DataBaseDB string `json:"data_base_db"`
|
||||
}
|
||||
|
||||
|
||||
|
||||
33
service/down_record.go
Normal file
33
service/down_record.go
Normal file
@@ -0,0 +1,33 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
model2 "github.com/IceWhaleTech/CasaOS/service/model"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type DownRecordService interface {
|
||||
AddDownRecord(m model2.PersonDownRecordDBModel)
|
||||
GetDownloadListByFrom(id string) []model2.PersonDownRecordDBModel
|
||||
GetDownloadListByPath(path string) (list []model2.PersonDownRecordDBModel)
|
||||
}
|
||||
type downRecordService struct {
|
||||
db *gorm.DB
|
||||
}
|
||||
|
||||
func (d *downRecordService) AddDownRecord(m model2.PersonDownRecordDBModel) {
|
||||
d.db.Create(&m)
|
||||
}
|
||||
|
||||
func (d *downRecordService) GetDownloadListByFrom(id string) []model2.PersonDownRecordDBModel {
|
||||
var m []model2.PersonDownRecordDBModel
|
||||
d.db.Model(m).Where("from = ?", id).Find(&m)
|
||||
return m
|
||||
}
|
||||
func (d *downRecordService) GetDownloadListByPath(path string) (list []model2.PersonDownRecordDBModel) {
|
||||
d.db.Where("path = ?", path).Find(&list)
|
||||
return
|
||||
}
|
||||
|
||||
func NewDownRecordService(db *gorm.DB) DownRecordService {
|
||||
return &downRecordService{db: db}
|
||||
}
|
||||
66
service/download.go
Normal file
66
service/download.go
Normal file
@@ -0,0 +1,66 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
model2 "github.com/IceWhaleTech/CasaOS/service/model"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type DownloadService interface {
|
||||
AddDownloadTask(m model2.PersonDownloadDBModel) //添加下载任务
|
||||
EditDownloadState(m model2.PersonDownloadDBModel) //只修改状态
|
||||
SaveDownload(m model2.PersonDownloadDBModel)
|
||||
DelDownload(uuid string)
|
||||
GetDownloadById(uuid string) model2.PersonDownloadDBModel
|
||||
GetDownloadListByState(state string, t int) []model2.PersonDownloadDBModel
|
||||
SetDownloadError(m model2.PersonDownloadDBModel)
|
||||
GetDownloadListByPath(m model2.PersonDownloadDBModel) int
|
||||
}
|
||||
type downloadService struct {
|
||||
db *gorm.DB
|
||||
}
|
||||
|
||||
func (d *downloadService) GetDownloadListByPath(m model2.PersonDownloadDBModel) int {
|
||||
var list []model2.PersonDownloadDBModel
|
||||
d.db.Select("path").Where("path = ? AND `from` = ? AND state = 0", m.Path, m.From).Find(&list)
|
||||
return len(list)
|
||||
}
|
||||
|
||||
func (d *downloadService) AddDownloadTask(m model2.PersonDownloadDBModel) {
|
||||
|
||||
d.db.Create(&m)
|
||||
}
|
||||
func (d *downloadService) EditDownloadState(m model2.PersonDownloadDBModel) {
|
||||
|
||||
d.db.Model(&m).Where("uuid = ?", m.UUID).Update("state", m.State)
|
||||
}
|
||||
|
||||
//failed during download
|
||||
func (d *downloadService) SetDownloadError(m model2.PersonDownloadDBModel) {
|
||||
d.db.Model(&m).Updates(m)
|
||||
}
|
||||
|
||||
func (d *downloadService) DelDownload(uuid string) {
|
||||
var m model2.PersonDownloadDBModel
|
||||
d.db.Where("uuid = ?", uuid).Delete(&m)
|
||||
}
|
||||
func (d *downloadService) GetDownloadById(uuid string) model2.PersonDownloadDBModel {
|
||||
var m model2.PersonDownloadDBModel
|
||||
d.db.Model(m).Where("uuid = ?", uuid).First(&m)
|
||||
return m
|
||||
}
|
||||
func (d *downloadService) GetDownloadListByState(state string, t int) (list []model2.PersonDownloadDBModel) {
|
||||
if len(state) == 0 {
|
||||
d.db.Where("type = ?", t).Find(&list)
|
||||
} else {
|
||||
d.db.Where("state = ? AND type= ?", state, t).Find(&list)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (d *downloadService) SaveDownload(m model2.PersonDownloadDBModel) {
|
||||
d.db.Save(&m)
|
||||
}
|
||||
func NewDownloadService(db *gorm.DB) DownloadService {
|
||||
return &downloadService{db: db}
|
||||
}
|
||||
85
service/file.go
Normal file
85
service/file.go
Normal file
@@ -0,0 +1,85 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
)
|
||||
|
||||
// type InteruptReader struct {
|
||||
// r io.Reader
|
||||
// interupt chan int
|
||||
// }
|
||||
|
||||
// func NewInteruptReader(r io.Reader) InteruptReader {
|
||||
// return InteruptReader{
|
||||
// r,
|
||||
// make(chan int),
|
||||
// }
|
||||
// }
|
||||
|
||||
// func (r InteruptReader) Read(p []byte) (n int, err error) {
|
||||
// if r.r == nil {
|
||||
// return 0, io.EOF
|
||||
// }
|
||||
// select {
|
||||
// case <-r.interupt:
|
||||
// return r.r.Read(p)
|
||||
// default:
|
||||
// r.r = nil
|
||||
// return 0, io.EOF
|
||||
// }
|
||||
// }
|
||||
|
||||
// func (r InteruptReader) Cancel() {
|
||||
// r.interupt <- 0
|
||||
// }
|
||||
|
||||
type reader struct {
|
||||
ctx context.Context
|
||||
r io.Reader
|
||||
}
|
||||
|
||||
// NewReader wraps an io.Reader to handle context cancellation.
|
||||
//
|
||||
// Context state is checked BEFORE every Read.
|
||||
func NewReader(ctx context.Context, r io.Reader) io.Reader {
|
||||
if r, ok := r.(*reader); ok && ctx == r.ctx {
|
||||
return r
|
||||
}
|
||||
return &reader{ctx: ctx, r: r}
|
||||
}
|
||||
|
||||
func (r *reader) Read(p []byte) (n int, err error) {
|
||||
select {
|
||||
case <-r.ctx.Done():
|
||||
return 0, r.ctx.Err()
|
||||
default:
|
||||
return r.r.Read(p)
|
||||
}
|
||||
}
|
||||
|
||||
type writer struct {
|
||||
ctx context.Context
|
||||
w io.Writer
|
||||
}
|
||||
|
||||
type copier struct {
|
||||
writer
|
||||
}
|
||||
|
||||
func NewWriter(ctx context.Context, w io.Writer) io.Writer {
|
||||
if w, ok := w.(*copier); ok && ctx == w.ctx {
|
||||
return w
|
||||
}
|
||||
return &copier{writer{ctx: ctx, w: w}}
|
||||
}
|
||||
|
||||
// Write implements io.Writer, but with context awareness.
|
||||
func (w *writer) Write(p []byte) (n int, err error) {
|
||||
select {
|
||||
case <-w.ctx.Done():
|
||||
return 0, w.ctx.Err()
|
||||
default:
|
||||
return w.w.Write(p)
|
||||
}
|
||||
}
|
||||
81
service/file_test.go
Normal file
81
service/file_test.go
Normal file
@@ -0,0 +1,81 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"os"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
var ctx context.Context
|
||||
var cancel context.CancelFunc
|
||||
|
||||
func TestNewInteruptReader(t *testing.T) {
|
||||
ctx, cancel = context.WithCancel(context.Background())
|
||||
|
||||
go func() {
|
||||
// 在初始上下文的基础上创建一个有取消功能的上下文
|
||||
// ctx, cancel := context.WithCancel(ctx)
|
||||
fmt.Println("开始")
|
||||
fIn, err := os.Open("/Users/liangjianli/Downloads/demo_data.tar.gz")
|
||||
if err != nil {
|
||||
|
||||
}
|
||||
defer fIn.Close()
|
||||
fmt.Println("创建新文件")
|
||||
fOut, err := os.Create("/Users/liangjianli/Downloads/demo_data1.tar.gz")
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
|
||||
defer fOut.Close()
|
||||
|
||||
fmt.Println("准备复制")
|
||||
// _, err = io.Copy(out, NewReader(ctx, f))
|
||||
// time.Sleep(time.Second * 2)
|
||||
//ctx.Done()
|
||||
// cancel()
|
||||
|
||||
// interrupt context after 500ms
|
||||
|
||||
// interrupt context with SIGTERM (CTRL+C)
|
||||
//sigs := make(chan os.Signal, 1)
|
||||
//signal.Notify(sigs, os.Interrupt)
|
||||
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
// Reader that fails when context is canceled
|
||||
in := NewReader(ctx, fIn)
|
||||
// Writer that fails when context is canceled
|
||||
out := NewWriter(ctx, fOut)
|
||||
|
||||
//time.Sleep(2 * time.Second)
|
||||
|
||||
//cancel()
|
||||
|
||||
n, err := io.Copy(out, in)
|
||||
log.Println(n, "bytes copied.")
|
||||
if err != nil {
|
||||
fmt.Println("Err:", err)
|
||||
}
|
||||
|
||||
fmt.Println("Closing.")
|
||||
}()
|
||||
|
||||
go func() {
|
||||
//<-sigs
|
||||
time.Sleep(time.Second)
|
||||
fmt.Println("退出")
|
||||
ddd()
|
||||
}()
|
||||
time.Sleep(time.Second * 10)
|
||||
}
|
||||
|
||||
func ddd() {
|
||||
cancel()
|
||||
}
|
||||
155
service/friend.go
Normal file
155
service/friend.go
Normal file
@@ -0,0 +1,155 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/IceWhaleTech/CasaOS/model"
|
||||
"github.com/IceWhaleTech/CasaOS/pkg/config"
|
||||
"github.com/IceWhaleTech/CasaOS/pkg/quic_helper"
|
||||
model2 "github.com/IceWhaleTech/CasaOS/service/model"
|
||||
"github.com/IceWhaleTech/CasaOS/types"
|
||||
"github.com/lucas-clemente/quic-go"
|
||||
uuid "github.com/satori/go.uuid"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type FriendService interface {
|
||||
AddFriend(m model2.FriendModel)
|
||||
DeleteFriend(m model2.FriendModel)
|
||||
EditFriendMark(m model2.FriendModel)
|
||||
EditFriendWrite(m model2.FriendModel)
|
||||
EditFriendBlock(m model2.FriendModel)
|
||||
GetFriendById(m model2.FriendModel) model2.FriendModel
|
||||
GetFriendList() (list []model2.FriendModel)
|
||||
GetFriendListRemote() (list []model2.FriendModel)
|
||||
UpdateAddFriendType(m model2.FriendModel)
|
||||
AgreeFrined(id string)
|
||||
GetFriendByToken(token string) model2.FriendModel
|
||||
UpdateOrCreate(m model2.FriendModel)
|
||||
InternalInspection(ips []string, token string)
|
||||
}
|
||||
|
||||
type friendService struct {
|
||||
db *gorm.DB
|
||||
}
|
||||
|
||||
func (p *friendService) AgreeFrined(id string) {
|
||||
var m model2.FriendModel
|
||||
p.db.Model(&m).Where("token = ?", id).Update("state", types.FRIENDSTATEDEFAULT)
|
||||
}
|
||||
func (p *friendService) AddFriend(m model2.FriendModel) {
|
||||
p.db.Create(&m)
|
||||
}
|
||||
func (p *friendService) DeleteFriend(m model2.FriendModel) {
|
||||
p.db.Where("token = ?", m.Token).Delete(&m)
|
||||
}
|
||||
func (p *friendService) EditFriendMark(m model2.FriendModel) {
|
||||
p.db.Model(&m).Where("token = ?", m.Token).Update("mark", m.Mark)
|
||||
}
|
||||
func (p *friendService) EditFriendWrite(m model2.FriendModel) {
|
||||
p.db.Model(&m).Where("token = ?", m.Token).Update("write", m.Write)
|
||||
}
|
||||
func (p *friendService) EditFriendBlock(m model2.FriendModel) {
|
||||
p.db.Model(&m).Where("token = ?", m.Token).Update("block", m.Block)
|
||||
}
|
||||
func (p *friendService) GetFriendById(m model2.FriendModel) model2.FriendModel {
|
||||
p.db.Model(m).Where("token = ?", m.Token).First(&m)
|
||||
return m
|
||||
}
|
||||
|
||||
func (p *friendService) GetFriendList() (list []model2.FriendModel) {
|
||||
p.db.Select("nick_name", "avatar", "profile", "token", "state", "mark", "block", "version").Find(&list)
|
||||
return list
|
||||
}
|
||||
func (p *friendService) GetFriendListRemote() (list []model2.FriendModel) {
|
||||
p.db.Select("nick_name", "avatar", "profile", "token", "state", "mark", "block", "version").Where("internal_ip == '' OR internal_ip is null").Find(&list)
|
||||
return list
|
||||
}
|
||||
func (p *friendService) GetFriendListInternal() (list []model2.FriendModel) {
|
||||
p.db.Select("nick_name", "avatar", "profile", "token", "state", "mark", "block", "version").Where("internal_ip != ''").Find(&list)
|
||||
return list
|
||||
}
|
||||
func (p *friendService) UpdateOrCreate(m model2.FriendModel) {
|
||||
friend := model2.FriendModel{}
|
||||
p.db.Where("token = ?", m.Token).First(&friend)
|
||||
if reflect.DeepEqual(friend, model2.FriendModel{}) {
|
||||
p.db.Create(&m)
|
||||
} else {
|
||||
p.db.Model(&m).Updates(m)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func (p *friendService) UpdateAddFriendType(m model2.FriendModel) {
|
||||
p.db.Model(&m).Updates(m)
|
||||
}
|
||||
|
||||
func (p *friendService) GetFriendByToken(token string) model2.FriendModel {
|
||||
var m model2.FriendModel
|
||||
p.db.Model(&m).Where("token = ?", token).First(&m)
|
||||
return m
|
||||
}
|
||||
|
||||
func (p *friendService) InternalInspection(ips []string, token string) {
|
||||
for _, v := range ips {
|
||||
fmt.Println("开始遍历 ip:", v)
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
||||
defer cancel()
|
||||
|
||||
dstAddr, err := net.ResolveUDPAddr("udp", v)
|
||||
if err != nil {
|
||||
fmt.Println("1", err.Error())
|
||||
continue
|
||||
}
|
||||
port, err := strconv.Atoi(config.ServerInfo.UDPPort)
|
||||
if err != nil {
|
||||
fmt.Println("2", err)
|
||||
continue
|
||||
}
|
||||
srcAddr := &net.UDPAddr{
|
||||
IP: net.IPv4zero, Port: port}
|
||||
ticket := token
|
||||
session, err := quic.DialContext(ctx, UDPConn, dstAddr, srcAddr.String(), quic_helper.GetClientTlsConfig(ticket), quic_helper.GetQUICConfig())
|
||||
if err != nil {
|
||||
fmt.Println("3", err, v)
|
||||
continue
|
||||
}
|
||||
|
||||
stream, err := session.OpenStreamSync(ctx)
|
||||
if err != nil {
|
||||
fmt.Println("4", err)
|
||||
continue
|
||||
}
|
||||
uuid := uuid.NewV4().String()
|
||||
SayHello(stream, token)
|
||||
msg := model.MessageModel{
|
||||
Type: types.PERSONPING,
|
||||
Data: "",
|
||||
From: config.ServerInfo.Token,
|
||||
To: token,
|
||||
UUId: uuid,
|
||||
}
|
||||
|
||||
SendData(stream, msg)
|
||||
|
||||
go ReadContent(stream)
|
||||
result := <-Message
|
||||
fmt.Println("ping返回结果:", result, msg)
|
||||
stream.Close()
|
||||
if !reflect.DeepEqual(result, model.MessageModel{}) && result.Data.(string) == token && result.From == token {
|
||||
fmt.Println("获取到正确的ip", v)
|
||||
UDPAddressMap[result.From] = v
|
||||
p.db.Model(&model2.FriendModel{}).Where("token = ?", token).Update("internal_ip", v)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func NewFriendService(db *gorm.DB) FriendService {
|
||||
return &friendService{db: db}
|
||||
}
|
||||
20
service/model/o_application.go
Normal file
20
service/model/o_application.go
Normal file
@@ -0,0 +1,20 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"time"
|
||||
)
|
||||
|
||||
type ApplicationModel struct {
|
||||
Id int `gorm:"column:id;primary_key" json:"id"`
|
||||
Name string `json:"name"`
|
||||
Icon string `json:"icon"`
|
||||
State int `json:"state"`
|
||||
Type string `json:"type"`
|
||||
Order int `json:"order"`
|
||||
CreatedAt time.Time `gorm:"<-:create" json:"created_at"`
|
||||
UpdatedAt time.Time `gorm:"<-:create;<-:update" json:"updated_at"`
|
||||
}
|
||||
|
||||
func (p *ApplicationModel) TableName() string {
|
||||
return "o_application"
|
||||
}
|
||||
@@ -1,11 +1,8 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"github.com/IceWhaleTech/CasaOS/model"
|
||||
)
|
||||
|
||||
const CONTAINERTABLENAME = "o_container"
|
||||
|
||||
//Soon to be removed
|
||||
type AppListDBModel struct {
|
||||
CustomId string `gorm:"column:custom_id;primary_key" json:"custom_id"`
|
||||
Title string `json:"title"`
|
||||
@@ -26,10 +23,6 @@ type AppListDBModel struct {
|
||||
PortMap string `json:"port_map"`
|
||||
Label string `json:"label"`
|
||||
EnableUPNP bool `json:"enable_upnp"`
|
||||
//Envs model.EnvArrey `json:"envs" bson:"envs"`
|
||||
//Ports model.PortArrey `json:"ports" bson:"ports"`
|
||||
//Volumes model.PathArrey `json:"volumes" bson:"volumes"`
|
||||
//Devices model.PathArrey `json:"devices" bson:"devices"`
|
||||
Envs string `json:"envs"`
|
||||
Ports string `json:"ports"`
|
||||
Volumes string `json:"volumes"`
|
||||
@@ -45,6 +38,10 @@ type AppListDBModel struct {
|
||||
Restart string `json:"restart"`
|
||||
//Rely model.MapStrings `gorm:"type:json" json:"rely"` //[{"mysql":"id"},{"mysql":"id"}]
|
||||
Origin string `json:"origin"`
|
||||
HostName string `json:"host_name"`
|
||||
Privileged bool `json:"privileged"`
|
||||
CapAdd string `json:"cap_add"`
|
||||
Cmd string `gorm:"type:json" json:"cmd"`
|
||||
}
|
||||
|
||||
func (p *AppListDBModel) TableName() string {
|
||||
@@ -52,13 +49,19 @@ func (p *AppListDBModel) TableName() string {
|
||||
}
|
||||
|
||||
type MyAppList struct {
|
||||
Id string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Icon string `json:"icon"`
|
||||
State string `json:"state"`
|
||||
CustomId string `gorm:"column:custom_id;primary_key" json:"custom_id"`
|
||||
Index string `json:"index"`
|
||||
//Order string `json:"order"`
|
||||
Port string `json:"port"`
|
||||
UpTime string `json:"up_time"`
|
||||
Slogan string `json:"slogan"`
|
||||
Rely model.MapStrings `json:"rely"` //[{"mysql":"id"},{"mysql":"id"}]
|
||||
Type string `json:"type"`
|
||||
//Rely model.MapStrings `json:"rely"` //[{"mysql":"id"},{"mysql":"id"}]
|
||||
Image string `json:"image"`
|
||||
Volumes string `json:"volumes"`
|
||||
NewVersion bool `json:"new_version"`
|
||||
}
|
||||
|
||||
@@ -2,11 +2,11 @@ package model
|
||||
|
||||
import "time"
|
||||
|
||||
func (p *DDNSUpdataDBModel) TableName() string {
|
||||
func (p *DDNSUpdateDBModel) TableName() string {
|
||||
return "o_ddns"
|
||||
}
|
||||
|
||||
type DDNSUpdataDBModel struct {
|
||||
type DDNSUpdateDBModel struct {
|
||||
Id uint `gorm:"column:id;primary_key" json:"id"`
|
||||
Ipv4 string `gorm:"-"`
|
||||
Ipv6 string `gorm:"-"`
|
||||
@@ -41,7 +41,7 @@ type DDNSList struct {
|
||||
type DDNSCoreList struct {
|
||||
Id uint `gorm:"column:id;primary_key" json:"id"`
|
||||
Domain string `json:"domain" form:"domain"`
|
||||
Name string `json:"domain" form:"name"`
|
||||
Name string `json:"name" form:"name"`
|
||||
Type uint `json:"type"`
|
||||
Key string `json:"key"`
|
||||
Message string `json:"message"`
|
||||
|
||||
15
service/model/o_disk.go
Normal file
15
service/model/o_disk.go
Normal file
@@ -0,0 +1,15 @@
|
||||
package model
|
||||
|
||||
//SerialAdvanced Technology Attachment (STAT)
|
||||
type SerialDisk struct {
|
||||
Id uint `gorm:"column:id;primary_key" json:"id"`
|
||||
UUID string `json:"uuid"`
|
||||
Path string `json:"path"`
|
||||
State int `json:"state"`
|
||||
MountPoint string `json:"mount_point"`
|
||||
CreatedAt int64 `json:"created_at"`
|
||||
}
|
||||
|
||||
func (p *SerialDisk) TableName() string {
|
||||
return "o_disk"
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user