mirror of
https://github.com/IceWhaleTech/CasaOS.git
synced 2025-12-23 04:54:41 +00:00
Compare commits
180 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
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 | ||
|
|
d7d53d639b | ||
|
|
d2ff1b0506 | ||
|
|
7191735737 | ||
|
|
21f3fd85d9 | ||
|
|
ba77e07e36 | ||
|
|
0d6e7ca339 | ||
|
|
b1d5d9858b | ||
|
|
4f06be0e45 | ||
|
|
812ffd56a8 | ||
|
|
6ba845eec5 | ||
|
|
4fa72289ed | ||
|
|
5cdd842a3e | ||
|
|
cc5504c0a9 | ||
|
|
b3aa22605d | ||
|
|
32e00b17b1 | ||
|
|
16108f03ac | ||
|
|
e7f990b224 | ||
|
|
c5d824c4ba | ||
|
|
39ccbe251f | ||
|
|
e69d2e587b | ||
|
|
8a28d3c589 | ||
|
|
8fe0e4aa73 | ||
|
|
30a23a93a2 | ||
|
|
53157fbb1f | ||
|
|
fb15695dab | ||
|
|
5f5091f1e2 | ||
|
|
df92766c74 | ||
|
|
cc8b3e8f06 | ||
|
|
a116db8dbd | ||
|
|
d697547cb7 | ||
|
|
01960c0391 | ||
|
|
953c393e71 | ||
|
|
0873f7dd46 | ||
|
|
8d93a7f320 | ||
|
|
801eca0a14 | ||
|
|
a3ec7b70c9 | ||
|
|
4a77548b23 | ||
|
|
15ccade3d3 | ||
|
|
587fb6fb8a | ||
|
|
5bcb663ac8 | ||
|
|
cbd945536d | ||
|
|
081e9213c2 | ||
|
|
966fae2d4c | ||
|
|
dc4f9ea990 | ||
|
|
05b9c75714 | ||
|
|
4aeeea2325 | ||
|
|
72531cf6c2 | ||
|
|
9ad9be8c61 | ||
|
|
1aa15932a0 | ||
|
|
dbc6a4265a | ||
|
|
edea1f144a | ||
|
|
85c59c03cf | ||
|
|
a1f57bf1d1 | ||
|
|
e6f2c46c28 | ||
|
|
55c6c21aa3 | ||
|
|
40617185e9 | ||
|
|
c3dba45e17 | ||
|
|
83f58366a6 | ||
|
|
3fa09dad8e | ||
|
|
f0f0eb2ef0 | ||
|
|
436b87f8a8 | ||
|
|
f0888ef2ac | ||
|
|
03e23ec203 |
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
|
||||
148
.github/workflows/casa.yml
vendored
Normal file
148
.github/workflows/casa.yml
vendored
Normal file
@@ -0,0 +1,148 @@
|
||||
# This is a basic workflow to help you get started with Actions
|
||||
|
||||
name: Build CasaOS
|
||||
|
||||
on:
|
||||
repository_dispatch:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
ssh:
|
||||
description: 'SSH connection to Actions'
|
||||
required: false
|
||||
default: 'false'
|
||||
|
||||
#on:
|
||||
# push:
|
||||
# branches:
|
||||
# - 'main'
|
||||
# tags:
|
||||
# - 'v*'
|
||||
env:
|
||||
REPO_URL: https://github.com/IceWhaleTech/CasaOS.git
|
||||
REPO_BRANCH: main
|
||||
PACK_SH_URL: https://raw.githubusercontent.com/jerrykuku/actions-casa/main/pack.sh
|
||||
PACK_SH: pack.sh
|
||||
TZ: Asia/Shanghai
|
||||
|
||||
jobs:
|
||||
xgo:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
go_version:
|
||||
- 1.17.1
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
|
||||
# - name: Get release
|
||||
# id: get_release
|
||||
# uses: bruceadams/get-release@v1.2.3
|
||||
# env:
|
||||
# GITHUB_TOKEN: ${{ github.token }}
|
||||
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
fetch-depth: 0
|
||||
submodules: true
|
||||
# - name: Initialization environment
|
||||
# env:
|
||||
# DEBIAN_FRONTEND: noninteractive
|
||||
# run: |
|
||||
# sudo timedatectl set-timezone "$TZ"
|
||||
# sudo mkdir -p /workdir
|
||||
# sudo chown $USER:$GROUPS /workdir
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# - name: Clone source code
|
||||
# working-directory: /workdir
|
||||
# run: |
|
||||
# df -hT $PWD
|
||||
# git clone $REPO_URL -b $REPO_BRANCH --recursive casa
|
||||
# ln -sf /workdir/casa $GITHUB_WORKSPACE/casa
|
||||
# ls
|
||||
|
||||
|
||||
- name: Set enviroment for github-release
|
||||
run: |
|
||||
echo "VERSION=$(cat types/system.go | grep CURRENTVERSION | awk '$2 == "CURRENTVERSION"{print $4}' | sed 's/"//g')" >>$GITHUB_ENV
|
||||
echo "BODY=$(cat types/system.go | grep BODY | awk -F= '{print $2}' | sed 's/"//g')" >>$GITHUB_ENV
|
||||
|
||||
|
||||
|
||||
- name: Use Node.js
|
||||
uses: actions/setup-node@v2
|
||||
with:
|
||||
node-version: '14'
|
||||
|
||||
- name: Build frontend with nodejs and yarn
|
||||
run: |
|
||||
cd UI
|
||||
ls
|
||||
yarn install
|
||||
yarn build
|
||||
|
||||
- name: list work
|
||||
run: pwd
|
||||
|
||||
- name: Build with xgo
|
||||
uses: crazy-max/ghaction-xgo@v1
|
||||
with:
|
||||
xgo_version: v0.7.5
|
||||
go_version: ${{ matrix.go_version }}
|
||||
dest: build
|
||||
prefix: casa
|
||||
targets: linux/amd64,linux/arm64,linux/arm-7
|
||||
v: true
|
||||
x: false
|
||||
race: false
|
||||
ldflags: -s -w
|
||||
buildmode: default
|
||||
#
|
||||
# - name: List Files
|
||||
# run: |
|
||||
# ls
|
||||
# mkdir build
|
||||
# ls
|
||||
# echo "::set-output name=status::success"
|
||||
|
||||
- name: Pack builds
|
||||
run: |
|
||||
wget $PACK_SH_URL
|
||||
chmod +x $PACK_SH
|
||||
./$PACK_SH
|
||||
echo "::set-output name=status::success"
|
||||
- name: list work
|
||||
run: ls
|
||||
|
||||
|
||||
- name: Update release
|
||||
uses: meeDamian/github-release@2.0
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
files: >
|
||||
linux-amd64-casaos.tar.gz
|
||||
linux-arm64-casaos.tar.gz
|
||||
linux-arm-7-casaos.tar.gz
|
||||
tag: v${{ env.VERSION }}
|
||||
body: >
|
||||
${{ env.BODY }}
|
||||
name: v${{ env.VERSION }}
|
||||
gzip: false
|
||||
allow_override: false
|
||||
prerelease: true
|
||||
# - name: Upload linux-amd64-casaos.tar.gz
|
||||
# id: upload_assets_amd64
|
||||
# uses: shogo82148/actions-upload-release-asset@v1
|
||||
# with:
|
||||
# upload_url: ${{ steps.get_release.outputs.upload_url }}
|
||||
# asset_path: /workdir/casa/upload/linux-amd64-casaos.tar.gz
|
||||
#
|
||||
# - name: Upload linux-arm64-casaos.tar.gz
|
||||
# id: upload_assets_arm64
|
||||
# uses: shogo82148/actions-upload-release-asset@v1
|
||||
# with:
|
||||
# upload_url: ${{ steps.get_release.outputs.upload_url }}
|
||||
# asset_path: /workdir/casa/upload/linux-arm64-casaos.tar.gz
|
||||
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 }}
|
||||
|
||||
|
||||
5
.gitignore
vendored
5
.gitignore
vendored
@@ -20,6 +20,7 @@
|
||||
|
||||
# IntelliJ project files
|
||||
.idea
|
||||
.vscode
|
||||
*.iml
|
||||
out
|
||||
gen
|
||||
@@ -28,3 +29,7 @@ gen
|
||||
/out/
|
||||
/db/
|
||||
/docs/
|
||||
/conf/conf.ini
|
||||
__debug_bin
|
||||
main
|
||||
CasaOS
|
||||
|
||||
5
.gitmodules
vendored
5
.gitmodules
vendored
@@ -1,3 +1,4 @@
|
||||
[submodule "CasaOS-UI"]
|
||||
path = CasaOS-UI
|
||||
[submodule "UI"]
|
||||
path = UI
|
||||
url = https://github.com/IceWhaleTech/CasaOS-UI.git
|
||||
branch = main
|
||||
Submodule CasaOS-UI deleted from 6139d87e80
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.
|
||||
95
README.md
95
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,25 +6,61 @@
|
||||
[](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.
|
||||
|
||||

|
||||

|
||||
|
||||
## Features
|
||||
## 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)
|
||||
- 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
|
||||
- Automatic Docker application management
|
||||
- App Store for private cloud 🚧
|
||||
- Quick Docker app installation with only three steps, plus automatic management
|
||||
- App Store for Home Cloud 🚧
|
||||
- Home data/digital asset management 🚧
|
||||
- Smart home manager 🚧
|
||||
|
||||
🚧 is under development.
|
||||
|
||||
We are actively moving forward with development, and you are more than welcome to share any idea in the [Discord server](https://discord.gg/Gx4BCEtHjx)!
|
||||
We are actively moving forward with development, and you are more than welcome to share any idea with us!
|
||||
|
||||
|
||||
## Community
|
||||
@@ -35,48 +71,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
|
||||
@@ -84,4 +83,4 @@ curl -fsSL https://get.icewhale.io/casaos.sh | bash
|
||||
- Ober Zhang
|
||||
- Zyaire Ann
|
||||
- John Guan
|
||||
- More seats vacant for the right person
|
||||
- Right here, waiting for YOU!
|
||||
1
UI
Submodule
1
UI
Submodule
Submodule UI added at a6074812f4
@@ -1,52 +1,42 @@
|
||||
[app]
|
||||
PAGE_SIZE = 10
|
||||
RuntimeRootPath = runtime/
|
||||
;LogSavePath = /casaOS/logs/server/
|
||||
LogSavePath = /oasis/logs/server/
|
||||
LogSavePath = /casaOS/logs/server/
|
||||
LogSaveName = log
|
||||
LogFileExt = log
|
||||
; 必须的格式
|
||||
DateStrFormat = 20060102
|
||||
DateTimeFormat = 2006-01-02 15:04:05
|
||||
TimeFormat = 15:04:05
|
||||
DateFormat = 2006-01-02
|
||||
;ProjectPath = /casaOS/server
|
||||
ProjectPath = /oasis/server
|
||||
ProjectPath = /casaOS/server
|
||||
|
||||
|
||||
[server]
|
||||
HttpPort = 8089
|
||||
RunMode = debug
|
||||
;ServerApi = http://113.52.135.30:8090
|
||||
;ServerApi = https://casaos.zimaboard.com
|
||||
;ServerApi = http://192.168.2.167:8090
|
||||
ServerApi = http://192.168.2.142:8090
|
||||
RunMode = release
|
||||
ServerApi = https://api.casaos.zimaboard.com
|
||||
|
||||
[user]
|
||||
UserName = admin
|
||||
PWD = zimaboard
|
||||
Email = aaa@222.ddd
|
||||
Description = ddddddd
|
||||
Email = user@gmail.com
|
||||
Description = description
|
||||
Initialized = false
|
||||
Token = eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6ImVyZXJlIiwicGFzc3dvcmQiOiJhZHNmZGYiLCJleHAiOjE2MjQwMDU0ODEsImlzcyI6Imdpbi1ibG9nIn0.JNsCccZuFCwlSMLJg62iOIB2xymk_k7xGa11xhZ07bc
|
||||
|
||||
[zerotier]
|
||||
UserName = ddddd
|
||||
PWD =
|
||||
UserName = user
|
||||
PWD = pwd
|
||||
Token = yBKYyavr2RdFAIVN7iTpzlsB1o6CqTgm
|
||||
|
||||
[redis]
|
||||
Host = 192.168.2.167:6379
|
||||
Host = 127.0.0.1:6379
|
||||
Password =
|
||||
MaxIdle = 30
|
||||
MaxActive = 30
|
||||
IdleTimeout = 200
|
||||
|
||||
[system]
|
||||
AutoUpdate = true
|
||||
SearchSwitch = true
|
||||
WidgetsSwitch = false
|
||||
ShortcutsSwitch = true
|
||||
SearchEngine = baidu
|
||||
Background = http://baidu.com1
|
||||
BackgroundType = d
|
||||
ConfigStr =
|
||||
WidgetList =
|
||||
|
||||
2901
docs/docs.go
2901
docs/docs.go
File diff suppressed because it is too large
Load Diff
2839
docs/swagger.json
2839
docs/swagger.json
File diff suppressed because it is too large
Load Diff
1753
docs/swagger.yaml
1753
docs/swagger.yaml
File diff suppressed because it is too large
Load Diff
24
go.mod
24
go.mod
@@ -7,9 +7,8 @@ require (
|
||||
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/alecthomas/template v0.0.0-20190718012654-fb15b899a751
|
||||
github.com/bits-and-blooms/bitset v1.2.1 // indirect
|
||||
github.com/containerd/containerd v1.5.5
|
||||
github.com/containerd/containerd v1.5.7
|
||||
github.com/containerd/continuity v0.2.0 // indirect
|
||||
github.com/docker/docker v20.10.7+incompatible
|
||||
github.com/docker/go-connections v0.4.0
|
||||
@@ -18,9 +17,7 @@ require (
|
||||
github.com/gin-gonic/gin v1.7.2
|
||||
github.com/go-ini/ini v1.62.0
|
||||
github.com/go-ole/go-ole v1.2.5 // indirect
|
||||
github.com/go-openapi/jsonreference v0.19.6 // indirect
|
||||
github.com/go-openapi/spec v0.20.3 // indirect
|
||||
github.com/go-openapi/swag v0.19.15 // indirect
|
||||
github.com/go-openapi/spec v0.20.4 // indirect
|
||||
github.com/go-playground/validator/v10 v10.6.1 // indirect
|
||||
github.com/gogo/googleapis v1.4.1 // indirect
|
||||
github.com/golang-jwt/jwt v3.2.2+incompatible
|
||||
@@ -35,11 +32,11 @@ require (
|
||||
github.com/klauspost/compress v1.13.6 // indirect
|
||||
github.com/leodido/go-urn v1.2.1 // indirect
|
||||
github.com/mailru/easyjson v0.7.7 // indirect
|
||||
github.com/mattn/go-isatty v0.0.13 // indirect
|
||||
github.com/mattn/go-isatty v0.0.14 // indirect
|
||||
github.com/moby/term v0.0.0-20210619224110-3f7ff695adc6 // indirect
|
||||
github.com/morikuni/aec v1.0.0 // indirect
|
||||
github.com/opencontainers/runc 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
|
||||
@@ -50,21 +47,20 @@ require (
|
||||
github.com/smartystreets/assertions v1.2.0 // indirect
|
||||
github.com/smartystreets/goconvey v1.6.4 // indirect
|
||||
github.com/swaggo/gin-swagger v1.3.0
|
||||
github.com/swaggo/swag v1.7.0
|
||||
github.com/tidwall/gjson v1.8.0
|
||||
github.com/tidwall/pretty v1.2.0 // indirect
|
||||
github.com/swaggo/swag v1.7.3
|
||||
github.com/tidwall/gjson v1.10.2
|
||||
github.com/tidwall/sjson v1.2.3
|
||||
github.com/tklauser/go-sysconf v0.3.6 // indirect
|
||||
github.com/ugorji/go v1.2.6 // indirect
|
||||
go.opencensus.io v0.23.0 // indirect
|
||||
golang.org/x/crypto v0.0.0-20210817164053-32db794688a5
|
||||
golang.org/x/mod v0.5.0 // indirect
|
||||
golang.org/x/net v0.0.0-20210924151903-3ad01bbaa167 // indirect
|
||||
golang.org/x/net v0.0.0-20211020060615-d418f374d309 // indirect
|
||||
golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f
|
||||
golang.org/x/sys v0.0.0-20210927052749-1cf2251ac284 // indirect
|
||||
golang.org/x/sys v0.0.0-20211020174200-9d6173849985 // indirect
|
||||
golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b // indirect
|
||||
golang.org/x/text v0.3.7 // indirect
|
||||
golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac // indirect
|
||||
golang.org/x/tools v0.1.5 // indirect
|
||||
golang.org/x/tools v0.1.7 // indirect
|
||||
google.golang.org/appengine v1.6.7 // indirect
|
||||
google.golang.org/genproto v0.0.0-20210924002016-3dee208752a0 // indirect
|
||||
google.golang.org/grpc v1.41.0 // indirect
|
||||
|
||||
57
go.sum
57
go.sum
@@ -68,7 +68,7 @@ github.com/Microsoft/hcsshim v0.8.9/go.mod h1:5692vkUqntj1idxauYlpoINNKeqCiG6Sg3
|
||||
github.com/Microsoft/hcsshim v0.8.14/go.mod h1:NtVKoYxQuTLx6gEq0L96c9Ju4JbRJ4nY2ow3VK6a9Lg=
|
||||
github.com/Microsoft/hcsshim v0.8.15/go.mod h1:x38A4YbHbdxJtc0sF6oIz+RG0npwSCAvn69iY6URG00=
|
||||
github.com/Microsoft/hcsshim v0.8.16/go.mod h1:o5/SZqmR7x9JNKsW3pu+nqHm0MF8vbA+VxGOoXdC600=
|
||||
github.com/Microsoft/hcsshim v0.8.18/go.mod h1:+w2gRZ5ReXQhFOrvSQeNfhrYB/dg3oDwTOcER2fw4I4=
|
||||
github.com/Microsoft/hcsshim v0.8.21/go.mod h1:+w2gRZ5ReXQhFOrvSQeNfhrYB/dg3oDwTOcER2fw4I4=
|
||||
github.com/Microsoft/hcsshim v0.8.22 h1:CulZ3GW8sNJExknToo+RWD+U+6ZM5kkNfuxywSDPd08=
|
||||
github.com/Microsoft/hcsshim v0.8.22/go.mod h1:91uVCVzvX2QD16sMCenoxxXo6L1wJnLMX2PSufFMtF0=
|
||||
github.com/Microsoft/hcsshim/test v0.0.0-20201218223536-d3e5debf77da/go.mod h1:5hlzMzRKMLyo42nCZ9oml8AdTlq/0cvIaBv6tK1RehU=
|
||||
@@ -168,8 +168,8 @@ github.com/containerd/containerd v1.5.0-beta.3/go.mod h1:/wr9AVtEM7x9c+n0+stptlo
|
||||
github.com/containerd/containerd v1.5.0-beta.4/go.mod h1:GmdgZd2zA2GYIBZ0w09ZvgqEq8EfBp/m3lcVZIvPHhI=
|
||||
github.com/containerd/containerd v1.5.0-rc.0/go.mod h1:V/IXoMqNGgBlabz3tHD2TWDoTJseu1FGOKuoA4nNb2s=
|
||||
github.com/containerd/containerd v1.5.1/go.mod h1:0DOxVqwDy2iZvrZp2JUx/E+hS0UNTVn7dJnIOwtYR4g=
|
||||
github.com/containerd/containerd v1.5.5 h1:q1gxsZsGZ8ddVe98yO6pR21b5xQSMiR61lD0W96pgQo=
|
||||
github.com/containerd/containerd v1.5.5/go.mod h1:oSTh0QpT1w6jYcGmbiSbxv9OSQYaa88mPyWIuU79zyo=
|
||||
github.com/containerd/containerd v1.5.7 h1:rQyoYtj4KddB3bxG6SAqd4+08gePNyJjRqvOIfV3rkM=
|
||||
github.com/containerd/containerd v1.5.7/go.mod h1:gyvv6+ugqY25TiXxcZC3L5yOeYgEw0QMhscqVp1AR9c=
|
||||
github.com/containerd/continuity v0.0.0-20190426062206-aaeac12a7ffc/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y=
|
||||
github.com/containerd/continuity v0.0.0-20190815185530-f2a389ac0a02/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y=
|
||||
github.com/containerd/continuity v0.0.0-20191127005431-f65d91d395eb/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y=
|
||||
@@ -335,19 +335,17 @@ github.com/go-openapi/jsonreference v0.17.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3Hfo
|
||||
github.com/go-openapi/jsonreference v0.19.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I=
|
||||
github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc=
|
||||
github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8=
|
||||
github.com/go-openapi/jsonreference v0.19.4/go.mod h1:RdybgQwPxbL4UEjuAruzK1x3nE69AqPYEJeo/TWfEeg=
|
||||
github.com/go-openapi/jsonreference v0.19.5/go.mod h1:RdybgQwPxbL4UEjuAruzK1x3nE69AqPYEJeo/TWfEeg=
|
||||
github.com/go-openapi/jsonreference v0.19.6 h1:UBIxjkht+AWIgYzCDSv2GN+E/togfwXUJFRTWhl2Jjs=
|
||||
github.com/go-openapi/jsonreference v0.19.6/go.mod h1:diGHMEHg2IqXZGKxqyvWdfWU/aim5Dprw5bqpKkTvns=
|
||||
github.com/go-openapi/spec v0.19.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI=
|
||||
github.com/go-openapi/spec v0.19.3/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo=
|
||||
github.com/go-openapi/spec v0.19.14/go.mod h1:gwrgJS15eCUgjLpMjBJmbZezCsw88LmgeEip0M63doA=
|
||||
github.com/go-openapi/spec v0.20.3 h1:uH9RQ6vdyPSs2pSy9fL8QPspDF2AMIMPtmK5coSSjtQ=
|
||||
github.com/go-openapi/spec v0.20.3/go.mod h1:gG4F8wdEDN+YPBMVnzE85Rbhf+Th2DTvA9nFPQ5AYEg=
|
||||
github.com/go-openapi/spec v0.20.4 h1:O8hJrt0UMnhHcluhIdUgCLRWyM2x7QkBXRvOs7m+O1M=
|
||||
github.com/go-openapi/spec v0.20.4/go.mod h1:faYFR1CvsJZ0mNsmsphTMSoRrNV3TEDoAM7FOEWeq8I=
|
||||
github.com/go-openapi/swag v0.17.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg=
|
||||
github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
|
||||
github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
|
||||
github.com/go-openapi/swag v0.19.11/go.mod h1:Uc0gKkdR+ojzsEpjh39QChyu92vPgIr72POcgHMAgSY=
|
||||
github.com/go-openapi/swag v0.19.14/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ=
|
||||
github.com/go-openapi/swag v0.19.15 h1:D2NRCBzS9/pEY3gP9Nl8aDqGUcPFrwG2p+CNFrLyrCM=
|
||||
github.com/go-openapi/swag v0.19.15/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ=
|
||||
@@ -367,6 +365,7 @@ github.com/godbus/dbus v0.0.0-20180201030542-885f9cc04c9c/go.mod h1:/YcGZj5zSblf
|
||||
github.com/godbus/dbus v0.0.0-20190422162347-ade71ed3457e/go.mod h1:bBOAhwG1umN6/6ZUMtDFBMQR8jRg9O75tm9K00oMsK4=
|
||||
github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
||||
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
||||
github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
|
||||
github.com/gogo/googleapis v1.2.0/go.mod h1:Njal3psf3qN6dwBtQfUmBZh2ybovJ0tlu3o/AC7HYjU=
|
||||
github.com/gogo/googleapis v1.4.0/go.mod h1:5YRNX2z1oM5gXdAkurHa942MDgEJyk02w4OecKY87+c=
|
||||
github.com/gogo/googleapis v1.4.1 h1:1Yx4Myt7BxzvUr5ldGSbwYiZG6t9wGBZ+8/fX3Wvtq0=
|
||||
@@ -484,6 +483,7 @@ github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJ
|
||||
github.com/imdario/mergo v0.3.8/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
|
||||
github.com/imdario/mergo v0.3.10/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
|
||||
github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
|
||||
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/jinzhu/copier v0.3.2 h1:QdBOCbaouLDYaIPFfi1bKv5F5tPpeTwXe4sD0jqtz5w=
|
||||
@@ -547,8 +547,8 @@ github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNx
|
||||
github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
||||
github.com/mattn/go-isatty v0.0.13 h1:qdl+GuBjcsKKDco5BsxPJlId98mSWNKqYA+Co0SC1yA=
|
||||
github.com/mattn/go-isatty v0.0.13/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
||||
github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y=
|
||||
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=
|
||||
@@ -613,7 +613,6 @@ github.com/opencontainers/runc v0.1.1/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59P
|
||||
github.com/opencontainers/runc v1.0.0-rc8.0.20190926000215-3e425f80a8c9/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U=
|
||||
github.com/opencontainers/runc v1.0.0-rc9/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U=
|
||||
github.com/opencontainers/runc v1.0.0-rc93/go.mod h1:3NOsor4w32B2tC0Zbl8Knk4Wg84SM2ImC1fxBuqJ/H0=
|
||||
github.com/opencontainers/runc v1.0.1/go.mod h1:aTaHFFwQXuA71CiyxOdFFIorAoemI04suvGRQFzWTD0=
|
||||
github.com/opencontainers/runc v1.0.2 h1:opHZMaswlyxz1OuGpBE53Dwe4/xF7EZTY0A2L/FpCOg=
|
||||
github.com/opencontainers/runc v1.0.2/go.mod h1:aTaHFFwQXuA71CiyxOdFFIorAoemI04suvGRQFzWTD0=
|
||||
github.com/opencontainers/runtime-spec v0.1.2-0.20190507144316-5b71a03e2700/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
|
||||
@@ -629,6 +628,8 @@ 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/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=
|
||||
@@ -685,6 +686,7 @@ github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdh
|
||||
github.com/seccomp/libseccomp-golang v0.9.1/go.mod h1:GbW5+tmTXfcxTToHLXlScSlAvWlF4P2Ca7zGrPiEpWo=
|
||||
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/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
|
||||
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=
|
||||
@@ -733,19 +735,20 @@ github.com/swaggo/files v0.0.0-20190704085106-630677cd5c14/go.mod h1:gxQT6pBGRuI
|
||||
github.com/swaggo/gin-swagger v1.3.0 h1:eOmp7r57oUgZPw2dJOjcGNMse9cvXcI4tTqBcnZtPsI=
|
||||
github.com/swaggo/gin-swagger v1.3.0/go.mod h1:oy1BRA6WvgtCp848lhxce7BnWH4C8Bxa0m5SkWx+cS0=
|
||||
github.com/swaggo/swag v1.5.1/go.mod h1:1Bl9F/ZBpVWh22nY0zmYyASPO1lI/zIwRDrpZU+tv8Y=
|
||||
github.com/swaggo/swag v1.7.0 h1:5bCA/MTLQoIqDXXyHfOpMeDvL9j68OY/udlK4pQoo4E=
|
||||
github.com/swaggo/swag v1.7.0/go.mod h1:BdPIL73gvS9NBsdi7M1JOxLvlbfvNRaBP8m6WT6Aajo=
|
||||
github.com/swaggo/swag v1.7.3 h1:ucB7irEdRrhjmW+Z1Ss4GjO68oPKQFjSgOR8BCAvcbU=
|
||||
github.com/swaggo/swag v1.7.3/go.mod h1:zD8h6h4SPv7t3l+4BKdRquqW1ASWjKZgT6Qv9z3kNqI=
|
||||
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/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/tidwall/sjson v1.2.3 h1:5+deguEhHSEjmuICXZ21uSSsXotWMA0orU783+Z7Cp8=
|
||||
github.com/tidwall/sjson v1.2.3/go.mod h1:5WdjKx3AQMvCJ4RG6/2UYT7dLrGvJUV1x4jdTAyGvZs=
|
||||
github.com/tklauser/go-sysconf v0.3.4/go.mod h1:Cl2c8ZRWfHD5IrfHo9VN+FX9kCFjIOyVklgXycLB6ek=
|
||||
github.com/tklauser/go-sysconf v0.3.6 h1:oc1sJWvKkmvIxhDHeKWvZS4f6AW+YcoguSfRF2/Hmo4=
|
||||
github.com/tklauser/go-sysconf v0.3.6/go.mod h1:MkWzOF4RMCshBAMXuhXJs64Rte09mITnppBXY/rYEFI=
|
||||
@@ -787,7 +790,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=
|
||||
github.com/yvasiyarov/newrelic_platform_go v0.0.0-20140908184405-b21fdbd4370f/go.mod h1:GlGEuHIJweS1mbCqG+7vt2nvWLzLLnRHbXz5JKd/Qbg=
|
||||
@@ -903,8 +906,9 @@ 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-20210924151903-3ad01bbaa167 h1:eDd+TJqbgfXruGQ5sJRU7tEtp/58OAx4+Ayjxg4SM+4=
|
||||
golang.org/x/net v0.0.0-20210924151903-3ad01bbaa167/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
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-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
@@ -991,6 +995,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-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=
|
||||
golang.org/x/sys v0.0.0-20210316164454-77fc1eacc6aa/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
@@ -1002,8 +1007,10 @@ golang.org/x/sys v0.0.0-20210426230700-d19ff857e887/go.mod h1:h1NjWce9XRLGQEsW7w
|
||||
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210927052749-1cf2251ac284 h1:lBPNCmq8u4zFP3huKCmUQ2Fx8kcY4X+O12UgGnyKsrg=
|
||||
golang.org/x/sys v0.0.0-20210927052749-1cf2251ac284/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211020174200-9d6173849985 h1:LOlKVhfDyahgmqa97awczplwkjzNaELFg3zRIJ13RYo=
|
||||
golang.org/x/sys v0.0.0-20211020174200-9d6173849985/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b h1:9zKuko04nR4gjZ4+DNjHqRlAJqbJETHwiNKDqTfOjfE=
|
||||
golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
@@ -1072,10 +1079,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-20201120155355-20be4ac4bd6e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.1.5 h1:ouewzE6p+/VEB31YYnTbEJdi8pFqKp4P4n85vwo3DHA=
|
||||
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
|
||||
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=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
|
||||
32
main.go
32
main.go
@@ -3,53 +3,65 @@ package main
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"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"
|
||||
"github.com/gin-gonic/gin"
|
||||
|
||||
"github.com/robfig/cron"
|
||||
"gorm.io/gorm"
|
||||
"net/http"
|
||||
"time"
|
||||
)
|
||||
|
||||
var sqliteDB *gorm.DB
|
||||
|
||||
var swagHandler gin.HandlerFunc
|
||||
var configFlag = flag.String("c", "", "config address")
|
||||
|
||||
var showUserInfo = flag.Bool("show-user-info", false, "show user info")
|
||||
|
||||
func init() {
|
||||
flag.Parse()
|
||||
config.InitSetup(*configFlag)
|
||||
config.UpdateSetup()
|
||||
loger2.LogSetup()
|
||||
sqliteDB = sqlite.GetDb(config.AppInfo.ProjectPath)
|
||||
//gredis.GetRedisConn(config.RedisInfo),
|
||||
service.MyService = service.NewService(sqliteDB, loger2.NewOLoger())
|
||||
service.Cache = cache.Init()
|
||||
route.InitFunction()
|
||||
}
|
||||
|
||||
// @title Oasis API
|
||||
// @title casaOS API
|
||||
// @version 1.0.0
|
||||
// @contact.name lauren.pan
|
||||
// @contact.url https://www.zimaboard.com
|
||||
// @contact.email lauren.pan@icewhale.org
|
||||
// @description Oasis v1版本api
|
||||
// @host 192.168.2.114:8089
|
||||
// @description casaOS v1版本api
|
||||
// @host 192.168.2.217:8089
|
||||
// @securityDefinitions.apikey ApiKeyAuth
|
||||
// @in header
|
||||
// @name Authorization
|
||||
// @BasePath /v1
|
||||
func main() {
|
||||
if *showUserInfo {
|
||||
fmt.Println("CasaOS User Info")
|
||||
fmt.Println("UserName:" + config.UserInfo.UserName)
|
||||
fmt.Println("Password:" + config.UserInfo.PWD)
|
||||
return
|
||||
}
|
||||
//model.Setup()
|
||||
//gredis.Setup()
|
||||
r := route.InitRouter(swagHandler)
|
||||
service.SyncTask(sqliteDB)
|
||||
r := route.InitRouter()
|
||||
//service.SyncTask(sqliteDB)
|
||||
cron2 := cron.New() //创建一个cron实例
|
||||
//执行定时任务(每5秒执行一次)
|
||||
err := cron2.AddFunc("0 0 0 1/1 * *", func() {
|
||||
//service.UpdataDDNSList(mysqldb)
|
||||
service.SyncTask(sqliteDB)
|
||||
//service.SyncTask(sqliteDB)
|
||||
})
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
|
||||
@@ -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")
|
||||
//设置缓存时间
|
||||
|
||||
58
model/app.go
58
model/app.go
@@ -7,32 +7,38 @@ import (
|
||||
)
|
||||
|
||||
type ServerAppList struct {
|
||||
Id uint `gorm:"column:id;primary_key" json:"id"`
|
||||
Title string `json:"title"`
|
||||
Description string `json:"description"`
|
||||
Tagline string `json:"tagline"`
|
||||
Tags Strings `gorm:"type:json" json:"tags"`
|
||||
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"`
|
||||
ImageVersion string `json:"image_version"`
|
||||
Tip string `json:"tip"`
|
||||
Configures configures `gorm:"type:json" json:"configures"`
|
||||
NetworkModel string `json:"network_mode"`
|
||||
Image string `json:"image"`
|
||||
Index string `json:"index"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
State string `json:"state"`
|
||||
Author string `json:"author"`
|
||||
MinMemory int `json:"min_memory"`
|
||||
MinDisk int `json:"min_disk"`
|
||||
MaxMemory uint64 `json:"max_memory"`
|
||||
Thumbnail string `json:"thumbnail"`
|
||||
Healthy string `json:"healthy"`
|
||||
Plugins Strings `json:"plugins"`
|
||||
Id uint `gorm:"column:id;primary_key" json:"id"`
|
||||
Title string `json:"title"`
|
||||
Description string `json:"description"`
|
||||
Tagline string `json:"tagline"`
|
||||
Tags Strings `gorm:"type:json" json:"tags"`
|
||||
Icon string `json:"icon"`
|
||||
ScreenshotLink Strings `gorm:"type:json" json:"screenshot_link"`
|
||||
Category string `json:"category"`
|
||||
CategoryFont string `json:"category_font"`
|
||||
PortMap string `json:"port_map"`
|
||||
ImageVersion string `json:"image_version"`
|
||||
Tip string `json:"tip"`
|
||||
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"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
State string `json:"state"`
|
||||
Author string `json:"author"`
|
||||
MinMemory int `json:"min_memory"`
|
||||
MinDisk int `json:"min_disk"`
|
||||
MaxMemory uint64 `json:"max_memory"`
|
||||
Thumbnail string `json:"thumbnail"`
|
||||
Healthy string `json:"healthy"`
|
||||
Plugins Strings `json:"plugins"`
|
||||
Origin string `json:"origin"`
|
||||
Type int `json:"type"`
|
||||
Developer string `json:"developer"`
|
||||
}
|
||||
|
||||
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"`
|
||||
}
|
||||
|
||||
@@ -21,11 +21,46 @@ type LSBLKModel struct {
|
||||
Health string `json:"health"`
|
||||
HotPlug bool `json:"hotplug"`
|
||||
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 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"`
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -103,10 +109,10 @@ type CustomizationPostData struct {
|
||||
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"`
|
||||
|
||||
7
model/search.go
Normal file
7
model/search.go
Normal file
@@ -0,0 +1,7 @@
|
||||
package model
|
||||
|
||||
type SearchFileInfo struct {
|
||||
Path string `json:"path"`
|
||||
Name string `json:"name"`
|
||||
Type int `json:"type"`
|
||||
}
|
||||
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"`
|
||||
}
|
||||
@@ -15,13 +15,15 @@ type UserModel struct {
|
||||
Head string
|
||||
Email string
|
||||
Description string
|
||||
Initialized bool
|
||||
}
|
||||
|
||||
//服务配置
|
||||
type ServerModel struct {
|
||||
HttpPort string
|
||||
RunMode string
|
||||
ServerApi string
|
||||
HttpPort string
|
||||
RunMode string
|
||||
ServerApi string
|
||||
LockAccount bool
|
||||
}
|
||||
|
||||
//服务配置
|
||||
@@ -60,11 +62,13 @@ type RedisModel struct {
|
||||
}
|
||||
|
||||
type SystemConfig struct {
|
||||
SearchSwitch bool `json:"search_switch"` //搜索开关
|
||||
SearchEngine string `json:"search_engine"` //搜索引擎
|
||||
ShortcutsSwitch bool `json:"shortcuts_switch"`
|
||||
WidgetsSwitch bool `json:"widgets_switch"`
|
||||
BackgroundType string `json:"background_type"`
|
||||
Background string `json:"background"`
|
||||
AutoUpdate bool `json:"auto_update"`
|
||||
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"`
|
||||
}
|
||||
|
||||
type CasaOSGlobalVariables struct {
|
||||
AppChange bool
|
||||
}
|
||||
|
||||
@@ -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"`
|
||||
}
|
||||
@@ -1,6 +1,10 @@
|
||||
package model
|
||||
|
||||
import "time"
|
||||
|
||||
type Path struct {
|
||||
Name string `json:"name"`
|
||||
Path string `json:"path"`
|
||||
Name string `json:"name"`
|
||||
Path string `json:"path"`
|
||||
IsDir bool `json:"is_dir"`
|
||||
Date time.Time `json:"date"`
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
@@ -2,14 +2,15 @@ package config
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/IceWhaleTech/CasaOS/model"
|
||||
"github.com/go-ini/ini"
|
||||
"log"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
|
||||
"github.com/IceWhaleTech/CasaOS/model"
|
||||
"github.com/go-ini/ini"
|
||||
)
|
||||
|
||||
//系统配置
|
||||
@@ -32,6 +33,8 @@ var ServerInfo = &model.ServerModel{}
|
||||
|
||||
var SystemConfigInfo = &model.SystemConfig{}
|
||||
|
||||
var CasaOSGlobalVariables = &model.CasaOSGlobalVariables{}
|
||||
|
||||
var Cfg *ini.File
|
||||
|
||||
//初始化设置,获取系统的部分信息。
|
||||
@@ -55,6 +58,7 @@ func InitSetup(config string) {
|
||||
mapTo("redis", RedisInfo)
|
||||
mapTo("server", ServerInfo)
|
||||
mapTo("system", SystemConfigInfo)
|
||||
SystemConfigInfo.ConfigPath = configDir
|
||||
// AppInfo.ProjectPath = getCurrentDirectory() //os.Getwd()
|
||||
|
||||
}
|
||||
|
||||
15
pkg/config/update.go
Normal file
15
pkg/config/update.go
Normal file
@@ -0,0 +1,15 @@
|
||||
package config
|
||||
|
||||
import "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"}
|
||||
for _, v := range dirArray {
|
||||
file.IsNotExistMkDir(v)
|
||||
}
|
||||
}
|
||||
|
||||
func UpdateSetup() {
|
||||
mkdirDATAAll()
|
||||
}
|
||||
@@ -4,30 +4,35 @@ import (
|
||||
"bytes"
|
||||
json2 "encoding/json"
|
||||
"fmt"
|
||||
"github.com/gorilla/websocket"
|
||||
"github.com/sirupsen/logrus"
|
||||
"golang.org/x/crypto/ssh"
|
||||
"io"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/gorilla/websocket"
|
||||
"github.com/sirupsen/logrus"
|
||||
"golang.org/x/crypto/ssh"
|
||||
)
|
||||
|
||||
func NewSshClient() (*ssh.Client, error) {
|
||||
func NewSshClient(user, password string) (*ssh.Client, error) {
|
||||
|
||||
// connet to ssh
|
||||
// addr = fmt.Sprintf("%s:%d", host, port)
|
||||
|
||||
config := &ssh.ClientConfig{
|
||||
Timeout: time.Second * 5,
|
||||
User: "root",
|
||||
User: user,
|
||||
HostKeyCallback: ssh.InsecureIgnoreHostKey(),
|
||||
//HostKeyCallback: ,
|
||||
//HostKeyCallback: hostKeyCallBackFunc(h.Host),
|
||||
}
|
||||
//if h.Type == "password" {
|
||||
config.Auth = []ssh.AuthMethod{ssh.Password("123456")}
|
||||
config.Auth = []ssh.AuthMethod{ssh.Password(password)}
|
||||
//} else {
|
||||
// config.Auth = []ssh.AuthMethod{publicKeyAuthFunc(h.Key)}
|
||||
//}
|
||||
addr := fmt.Sprintf("%s:%d", "192.168.2.142", 22)
|
||||
addr := fmt.Sprintf("%s:%d", "127.0.0.1", 22)
|
||||
c, err := ssh.Dial("tcp", addr, config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -98,6 +103,98 @@ const (
|
||||
wsMsgResize = "resize"
|
||||
)
|
||||
|
||||
//ReceiveWsMsg receive websocket msg do some handling then write into ssh.session.stdin
|
||||
func ReceiveWsMsgUser(wsConn *websocket.Conn, logBuff *bytes.Buffer) string {
|
||||
//tells other go routine quit
|
||||
username := ""
|
||||
for {
|
||||
|
||||
//read websocket msg
|
||||
_, wsData, err := wsConn.ReadMessage()
|
||||
if err != nil {
|
||||
|
||||
return ""
|
||||
}
|
||||
|
||||
msgObj := wsMsg{}
|
||||
if err := json2.Unmarshal(wsData, &msgObj); err != nil {
|
||||
msgObj.Type = "cmd"
|
||||
msgObj.Cmd = string(wsData)
|
||||
}
|
||||
//if err := json.Unmarshal(wsData, &msgObj); err != nil {
|
||||
// logrus.WithError(err).WithField("wsData", string(wsData)).Error("unmarshal websocket message failed")
|
||||
//}
|
||||
switch msgObj.Type {
|
||||
case wsMsgCmd:
|
||||
//handle xterm.js stdin
|
||||
//decodeBytes, err := base64.StdEncoding.DecodeString(msgObj.Cmd)
|
||||
decodeBytes := []byte(msgObj.Cmd)
|
||||
if msgObj.Cmd == "\u007f" {
|
||||
if len(username) == 0 {
|
||||
continue
|
||||
}
|
||||
wsConn.WriteMessage(websocket.TextMessage, []byte("\b\x1b[K"))
|
||||
username = username[:len(username)-1]
|
||||
continue
|
||||
}
|
||||
if msgObj.Cmd == "\r" {
|
||||
return username
|
||||
}
|
||||
username += msgObj.Cmd
|
||||
|
||||
if err := wsConn.WriteMessage(websocket.TextMessage, decodeBytes); err != nil {
|
||||
logrus.WithError(err).Error("ws cmd bytes write to ssh.stdin pipe failed")
|
||||
}
|
||||
//write input cmd to log buffer
|
||||
if _, err := logBuff.Write(decodeBytes); err != nil {
|
||||
logrus.WithError(err).Error("write received cmd into log buffer failed")
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
func ReceiveWsMsgPassword(wsConn *websocket.Conn, logBuff *bytes.Buffer) string {
|
||||
//tells other go routine quit
|
||||
password := ""
|
||||
for {
|
||||
|
||||
//read websocket msg
|
||||
_, wsData, err := wsConn.ReadMessage()
|
||||
if err != nil {
|
||||
logrus.WithError(err).Error("reading webSocket message failed")
|
||||
return ""
|
||||
}
|
||||
|
||||
msgObj := wsMsg{}
|
||||
if err := json2.Unmarshal(wsData, &msgObj); err != nil {
|
||||
msgObj.Type = "cmd"
|
||||
msgObj.Cmd = string(wsData)
|
||||
}
|
||||
//if err := json.Unmarshal(wsData, &msgObj); err != nil {
|
||||
// logrus.WithError(err).WithField("wsData", string(wsData)).Error("unmarshal websocket message failed")
|
||||
//}
|
||||
switch msgObj.Type {
|
||||
case wsMsgCmd:
|
||||
//handle xterm.js stdin
|
||||
//decodeBytes, err := base64.StdEncoding.DecodeString(msgObj.Cmd)
|
||||
if msgObj.Cmd == "\r" {
|
||||
return password
|
||||
}
|
||||
|
||||
if msgObj.Cmd == "\u007f" {
|
||||
if len(password) == 0 {
|
||||
continue
|
||||
}
|
||||
password = password[:len(password)-1]
|
||||
continue
|
||||
}
|
||||
password += msgObj.Cmd
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
//ReceiveWsMsg receive websocket msg do some handling then write into ssh.session.stdin
|
||||
func (ssConn *SshConn) ReceiveWsMsg(wsConn *websocket.Conn, logBuff *bytes.Buffer, exitCh chan bool) {
|
||||
//tells other go routine quit
|
||||
@@ -187,6 +284,64 @@ func flushComboOutput(w *wsBufferWriter, wsConn *websocket.Conn) error {
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
//ReceiveWsMsg receive websocket msg do some handling then write into ssh.session.stdin
|
||||
func (ssConn *SshConn) Login(wsConn *websocket.Conn, logBuff *bytes.Buffer, exitCh chan bool) {
|
||||
//tells other go routine quit
|
||||
defer setQuit(exitCh)
|
||||
for {
|
||||
select {
|
||||
case <-exitCh:
|
||||
return
|
||||
default:
|
||||
//read websocket msg
|
||||
_, wsData, err := wsConn.ReadMessage()
|
||||
if err != nil {
|
||||
logrus.WithError(err).Error("reading webSocket message failed")
|
||||
return
|
||||
}
|
||||
//unmashal bytes into struct
|
||||
//msgObj := wsMsg{
|
||||
// Type: "cmd",
|
||||
// Cmd: "",
|
||||
// Rows: 50,
|
||||
// Cols: 180,
|
||||
//}
|
||||
msgObj := wsMsg{}
|
||||
if err := json2.Unmarshal(wsData, &msgObj); err != nil {
|
||||
msgObj.Type = "cmd"
|
||||
msgObj.Cmd = string(wsData)
|
||||
}
|
||||
//if err := json.Unmarshal(wsData, &msgObj); err != nil {
|
||||
// logrus.WithError(err).WithField("wsData", string(wsData)).Error("unmarshal websocket message failed")
|
||||
//}
|
||||
switch msgObj.Type {
|
||||
|
||||
case wsMsgResize:
|
||||
//handle xterm.js size change
|
||||
if msgObj.Cols > 0 && msgObj.Rows > 0 {
|
||||
if err := ssConn.Session.WindowChange(msgObj.Rows, msgObj.Cols); err != nil {
|
||||
logrus.WithError(err).Error("ssh pty change windows size failed")
|
||||
}
|
||||
}
|
||||
case wsMsgCmd:
|
||||
//handle xterm.js stdin
|
||||
//decodeBytes, err := base64.StdEncoding.DecodeString(msgObj.Cmd)
|
||||
decodeBytes := []byte(msgObj.Cmd)
|
||||
if err != nil {
|
||||
logrus.WithError(err).Error("websock cmd string base64 decoding failed")
|
||||
}
|
||||
if _, err := ssConn.StdinPipe.Write(decodeBytes); err != nil {
|
||||
logrus.WithError(err).Error("ws cmd bytes write to ssh.stdin pipe failed")
|
||||
}
|
||||
//write input cmd to log buffer
|
||||
if _, err := logBuff.Write(decodeBytes); err != nil {
|
||||
logrus.WithError(err).Error("write received cmd into log buffer failed")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
func (ssConn *SshConn) SessionWait(quitChan chan bool) {
|
||||
if err := ssConn.Session.Wait(); err != nil {
|
||||
logrus.WithError(err).Error("ssh session wait failed")
|
||||
@@ -241,7 +396,7 @@ func WsReaderCopy(reader *websocket.Conn, writer io.Writer) {
|
||||
if err = json2.Unmarshal(p, &msgObj); err != nil {
|
||||
writer.Write(p)
|
||||
} else if msgObj.Type == wsMsgResize {
|
||||
writer.Write([]byte("stty rows " + strconv.Itoa(msgObj.Rows) + " && stty cols " + strconv.Itoa(msgObj.Cols) + " \r" ))
|
||||
writer.Write([]byte("stty rows " + strconv.Itoa(msgObj.Rows) + " && stty cols " + strconv.Itoa(msgObj.Cols) + " \r"))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,7 +6,6 @@ import (
|
||||
"golang.org/x/oauth2"
|
||||
)
|
||||
|
||||
|
||||
func GetGithubClient() *github.Client {
|
||||
ctx := context.Background()
|
||||
ts := oauth2.StaticTokenSource(
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
package github
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestGetRepos(t *testing.T) {
|
||||
GetRepos()
|
||||
}
|
||||
@@ -1,9 +1,10 @@
|
||||
package gredis
|
||||
|
||||
import (
|
||||
"github.com/gomodule/redigo/redis"
|
||||
"oasis/model"
|
||||
"time"
|
||||
|
||||
"github.com/IceWhaleTech/CasaOS/model"
|
||||
"github.com/gomodule/redigo/redis"
|
||||
)
|
||||
|
||||
func GetRedisConn(m *model.RedisModel) *redis.Pool {
|
||||
|
||||
@@ -2,11 +2,12 @@ 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
|
||||
@@ -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{})
|
||||
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)
|
||||
@@ -86,4 +86,4 @@ func resolve(resultStr string) string {
|
||||
}
|
||||
}
|
||||
return controlURL
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
package upnp
|
||||
|
||||
import (
|
||||
ip_helper2 "oasis/pkg/utils/ip_helper"
|
||||
"testing"
|
||||
|
||||
ip_helper2 "github.com/IceWhaleTech/CasaOS/pkg/utils/ip_helper"
|
||||
)
|
||||
|
||||
func TestGetCtrlUrl(t *testing.T) {
|
||||
|
||||
@@ -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到组播地址出错")
|
||||
}
|
||||
|
||||
@@ -5,4 +5,4 @@ import "testing"
|
||||
func TestGateway(t *testing.T) {
|
||||
|
||||
Gateway()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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")
|
||||
@@ -160,4 +155,4 @@ func delbuildRequest(remotePort int, protocol,host,ctlUrl string) *http.Request
|
||||
request.Header = header
|
||||
request.Header.Set("Content-Length", strconv.Itoa(len([]byte(bodyStr))))
|
||||
return request
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,10 +7,10 @@ import (
|
||||
|
||||
type Upnp struct {
|
||||
LocalHost string `json:"local_host"`
|
||||
GatewayName string `json:"gateway_name"` //网关名称
|
||||
GatewayHost string `json:"gateway_host"` //网关ip和端口
|
||||
GatewayName string `json:"gateway_name"` //网关名称
|
||||
GatewayHost string `json:"gateway_host"` //网关ip和端口
|
||||
DeviceDescUrl string `json:"device_desc_url"` //设备描述url
|
||||
CtrlUrl string `json:"ctrl_url"` //控制请求url
|
||||
CtrlUrl string `json:"ctrl_url"` //控制请求url
|
||||
}
|
||||
|
||||
func Testaaa() {
|
||||
@@ -23,4 +23,3 @@ func Testaaa() {
|
||||
fmt.Println("gateway ip address: ", upnpMan.Gateway.Host)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -6,4 +6,4 @@ import (
|
||||
|
||||
func TestTestaaa(t *testing.T) {
|
||||
(Testaaa())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,27 @@ 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)
|
||||
fmt.Println("output", string(output))
|
||||
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", ""))
|
||||
}
|
||||
@@ -50,6 +50,7 @@ func MkDir(src string) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
os.Chmod(src, 0777)
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -100,10 +101,9 @@ func MustOpen(fileName, filePath string) (*os.File, error) {
|
||||
return f, nil
|
||||
}
|
||||
|
||||
|
||||
// 判断所给路径文件/文件夹是否存在
|
||||
func Exists(path string) bool {
|
||||
_, err := os.Stat(path) //os.Stat获取文件信息
|
||||
_, err := os.Stat(path) //os.Stat获取文件信息
|
||||
if err != nil {
|
||||
if os.IsExist(err) {
|
||||
return true
|
||||
@@ -126,3 +126,36 @@ func IsDir(path string) bool {
|
||||
func IsFile(path string) bool {
|
||||
return !IsDir(path)
|
||||
}
|
||||
|
||||
func CreateFile(path string) error {
|
||||
file, err := os.Create(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer file.Close()
|
||||
return nil
|
||||
}
|
||||
|
||||
// IsNotExistMkDir create a directory if it does not exist
|
||||
func IsNotExistCreateFile(src string) error {
|
||||
if notExist := CheckNotExist(src); notExist == true {
|
||||
if err := CreateFile(src); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
176
pkg/utils/file/reader.go
Normal file
176
pkg/utils/file/reader.go
Normal file
@@ -0,0 +1,176 @@
|
||||
package file
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
)
|
||||
|
||||
var (
|
||||
buffSize = 1 << 20
|
||||
)
|
||||
|
||||
// ReadLineFromEnd --
|
||||
type ReadLineFromEnd struct {
|
||||
f *os.File
|
||||
|
||||
fileSize int
|
||||
bwr *bytes.Buffer
|
||||
lineBuff []byte
|
||||
swapBuff []byte
|
||||
|
||||
isFirst bool
|
||||
}
|
||||
|
||||
// NewReadLineFromEnd --
|
||||
func NewReadLineFromEnd(name string) (rd *ReadLineFromEnd, err error) {
|
||||
f, err := os.Open(name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
info, err := f.Stat()
|
||||
if info.IsDir() {
|
||||
return nil, fmt.Errorf("not file")
|
||||
}
|
||||
fileSize := int(info.Size())
|
||||
rd = &ReadLineFromEnd{
|
||||
f: f,
|
||||
fileSize: fileSize,
|
||||
bwr: bytes.NewBuffer([]byte{}),
|
||||
lineBuff: make([]byte, 0),
|
||||
swapBuff: make([]byte, buffSize),
|
||||
isFirst: true,
|
||||
}
|
||||
return rd, nil
|
||||
}
|
||||
|
||||
// ReadLine 结尾包含'\n'
|
||||
func (c *ReadLineFromEnd) ReadLine() (line []byte, err error) {
|
||||
var ok bool
|
||||
for {
|
||||
ok, err = c.buff()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if ok {
|
||||
break
|
||||
}
|
||||
}
|
||||
line, err = c.bwr.ReadBytes('\n')
|
||||
if err == io.EOF && c.fileSize > 0 {
|
||||
err = nil
|
||||
}
|
||||
return line, err
|
||||
}
|
||||
|
||||
// Close --
|
||||
func (c *ReadLineFromEnd) Close() (err error) {
|
||||
return c.f.Close()
|
||||
}
|
||||
|
||||
func (c *ReadLineFromEnd) buff() (ok bool, err error) {
|
||||
if c.fileSize == 0 {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
if c.bwr.Len() >= buffSize {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
offset := 0
|
||||
if c.fileSize > buffSize {
|
||||
offset = c.fileSize - buffSize
|
||||
}
|
||||
_, err = c.f.Seek(int64(offset), 0)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
n, err := c.f.Read(c.swapBuff)
|
||||
if err != nil && err != io.EOF {
|
||||
return false, err
|
||||
}
|
||||
if c.fileSize < n {
|
||||
n = c.fileSize
|
||||
}
|
||||
if n == 0 {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
for {
|
||||
m := bytes.LastIndex(c.swapBuff[:n], []byte{'\n'})
|
||||
if m == -1 {
|
||||
break
|
||||
}
|
||||
if m < n-1 {
|
||||
err = c.writeLine(c.swapBuff[m+1 : n])
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
ok = true
|
||||
} else if m == n-1 && !c.isFirst {
|
||||
err = c.writeLine(nil)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
ok = true
|
||||
}
|
||||
n = m
|
||||
if n == 0 {
|
||||
break
|
||||
}
|
||||
}
|
||||
if n > 0 {
|
||||
reverseBytes(c.swapBuff[:n])
|
||||
c.lineBuff = append(c.lineBuff, c.swapBuff[:n]...)
|
||||
}
|
||||
if offset == 0 {
|
||||
err = c.writeLine(nil)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
ok = true
|
||||
}
|
||||
c.fileSize = offset
|
||||
if c.isFirst {
|
||||
c.isFirst = false
|
||||
}
|
||||
return ok, nil
|
||||
}
|
||||
|
||||
func (c *ReadLineFromEnd) writeLine(b []byte) (err error) {
|
||||
if len(b) > 0 {
|
||||
_, err = c.bwr.Write(b)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if len(c.lineBuff) > 0 {
|
||||
reverseBytes(c.lineBuff)
|
||||
_, err = c.bwr.Write(c.lineBuff)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
c.lineBuff = c.lineBuff[:0]
|
||||
}
|
||||
_, err = c.bwr.Write([]byte{'\n'})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func reverseBytes(b []byte) {
|
||||
n := len(b)
|
||||
if n <= 1 {
|
||||
return
|
||||
}
|
||||
for i := 0; i < n; i++ {
|
||||
k := n - 1
|
||||
if k != i {
|
||||
b[i], b[k] = b[k], b[i]
|
||||
}
|
||||
n--
|
||||
}
|
||||
}
|
||||
@@ -3,12 +3,13 @@ package httper
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"github.com/IceWhaleTech/CasaOS/pkg/config"
|
||||
"github.com/tidwall/gjson"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/IceWhaleTech/CasaOS/pkg/config"
|
||||
"github.com/tidwall/gjson"
|
||||
)
|
||||
|
||||
//发送GET请求
|
||||
@@ -52,10 +53,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)
|
||||
}
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
package jwt
|
||||
|
||||
import (
|
||||
jwt "github.com/golang-jwt/jwt"
|
||||
"time"
|
||||
|
||||
jwt "github.com/golang-jwt/jwt"
|
||||
)
|
||||
|
||||
type Claims struct {
|
||||
@@ -15,8 +16,7 @@ var jwtSecret []byte
|
||||
|
||||
//创建token
|
||||
func GenerateToken(username, password string) (string, error) {
|
||||
nowTime := time.Now()
|
||||
expireTime := nowTime.Add(3 * time.Hour)
|
||||
expireTime := time.Now().AddDate(999, 0, 0)
|
||||
clims := Claims{
|
||||
username,
|
||||
password,
|
||||
|
||||
@@ -2,12 +2,12 @@ package jwt
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/IceWhaleTech/CasaOS/model"
|
||||
loger2 "github.com/IceWhaleTech/CasaOS/pkg/utils/loger"
|
||||
oasis_err2 "github.com/IceWhaleTech/CasaOS/pkg/utils/oasis_err"
|
||||
"github.com/gin-gonic/gin"
|
||||
"net/http"
|
||||
"time"
|
||||
)
|
||||
|
||||
func JWT(swagHandler gin.HandlerFunc) gin.HandlerFunc {
|
||||
@@ -22,13 +22,15 @@ func JWT(swagHandler gin.HandlerFunc) gin.HandlerFunc {
|
||||
code = oasis_err2.INVALID_PARAMS
|
||||
}
|
||||
if swagHandler == nil {
|
||||
claims, err := ParseToken(token)
|
||||
//claims, err := ParseToken(token)
|
||||
_, err := ParseToken(token)
|
||||
if err != nil {
|
||||
code = oasis_err2.ERROR_AUTH_TOKEN
|
||||
|
||||
} else if time.Now().Unix() > claims.ExpiresAt {
|
||||
code = oasis_err2.ERROR_AUTH_TOKEN
|
||||
}
|
||||
//else if time.Now().Unix() > claims.ExpiresAt {
|
||||
// code = oasis_err2.ERROR_AUTH_TOKEN
|
||||
//}
|
||||
}
|
||||
|
||||
if code != oasis_err2.SUCCESS {
|
||||
|
||||
@@ -2,13 +2,13 @@ package loger
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/IceWhaleTech/CasaOS/pkg/config"
|
||||
file2 "github.com/IceWhaleTech/CasaOS/pkg/utils/file"
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"time"
|
||||
|
||||
"github.com/IceWhaleTech/CasaOS/pkg/config"
|
||||
file2 "github.com/IceWhaleTech/CasaOS/pkg/utils/file"
|
||||
)
|
||||
|
||||
//定义一个int的别名
|
||||
@@ -20,6 +20,7 @@ type OLog interface {
|
||||
Warn(v ...interface{})
|
||||
Error(v ...interface{})
|
||||
Fatal(v ...interface{})
|
||||
Path() string
|
||||
}
|
||||
|
||||
type oLog struct {
|
||||
@@ -47,9 +48,8 @@ const (
|
||||
func LogSetup() {
|
||||
var err error
|
||||
filePath := fmt.Sprintf("%s", config.AppInfo.LogSavePath)
|
||||
fileName := fmt.Sprintf("%s%s.%s",
|
||||
fileName := fmt.Sprintf("%s.%s",
|
||||
config.AppInfo.LogSaveName,
|
||||
time.Now().Format(config.AppInfo.DateStrFormat),
|
||||
config.AppInfo.LogFileExt,
|
||||
)
|
||||
F, err = file2.MustOpen(fileName, filePath)
|
||||
@@ -60,7 +60,14 @@ func LogSetup() {
|
||||
logger = log.New(F, DefaultPrefix, log.LstdFlags)
|
||||
|
||||
}
|
||||
|
||||
func (o *oLog) Path() string {
|
||||
filePath := fmt.Sprintf("%s", config.AppInfo.LogSavePath)
|
||||
fileName := fmt.Sprintf("%s.%s",
|
||||
config.AppInfo.LogSaveName,
|
||||
config.AppInfo.LogFileExt,
|
||||
)
|
||||
return filePath + fileName
|
||||
}
|
||||
func (o *oLog) Debug(v ...interface{}) {
|
||||
setPrefix(DEBUG)
|
||||
logger.Println(v)
|
||||
|
||||
@@ -7,14 +7,27 @@ const (
|
||||
ERROR_AUTH_TOKEN = 401
|
||||
|
||||
//user
|
||||
PWD_INVALID = 10001
|
||||
PWD_INVALID = 10001
|
||||
PWD_IS_EMPTY = 10002
|
||||
|
||||
PWD_INVALID_OLD = 10003
|
||||
ACCOUNT_LOCK = 10004
|
||||
//system
|
||||
DIR_ALREADY_EXISTS = 20001
|
||||
DIR_ALREADY_EXISTS = 20001
|
||||
FILE_ALREADY_EXISTS = 20002
|
||||
FILE_OR_DIR_EXISTS = 20003
|
||||
PORT_IS_OCCUPIED = 20004
|
||||
|
||||
//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
|
||||
@@ -31,29 +44,41 @@ const (
|
||||
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: "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 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",
|
||||
|
||||
//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",
|
||||
FILE_READ_ERROR: "File read error",
|
||||
SHORTCUTS_URL_ERROR: "URL error",
|
||||
}
|
||||
|
||||
//获取错误信息
|
||||
|
||||
@@ -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,8 +1,9 @@
|
||||
package sort
|
||||
|
||||
import (
|
||||
"github.com/IceWhaleTech/CasaOS/model"
|
||||
"sort"
|
||||
|
||||
"github.com/IceWhaleTech/CasaOS/model"
|
||||
)
|
||||
|
||||
// 数据集类型, 与上一篇排序文章(多字段单独排序)比较, less字段的数据类型不再是 func(p1, p2 *Change) bool
|
||||
|
||||
@@ -2,13 +2,14 @@ package version
|
||||
|
||||
import (
|
||||
json2 "encoding/json"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/IceWhaleTech/CasaOS/model"
|
||||
"github.com/IceWhaleTech/CasaOS/pkg/config"
|
||||
"github.com/IceWhaleTech/CasaOS/pkg/utils/httper"
|
||||
"github.com/IceWhaleTech/CasaOS/types"
|
||||
"github.com/tidwall/gjson"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func IsNeedUpdate() (bool, model.Version) {
|
||||
@@ -35,3 +36,23 @@ func IsNeedUpdate() (bool, model.Version) {
|
||||
}
|
||||
return false, version
|
||||
}
|
||||
|
||||
//a版本大于b版本
|
||||
func VersionCompared(a string, b string) bool {
|
||||
v1 := strings.Split(a, ".")
|
||||
v2 := strings.Split(b, ".")
|
||||
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
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
//go:build doc
|
||||
// +build doc
|
||||
|
||||
package route
|
||||
@@ -5,9 +6,10 @@ package route
|
||||
import (
|
||||
_ "github.com/IceWhaleTech/CasaOS/docs"
|
||||
ginSwagger "github.com/swaggo/gin-swagger"
|
||||
"github.com/swaggo/gin-swagger/swaggerFiles"
|
||||
swaggerFiles "github.com/swaggo/gin-swagger/swaggerFiles"
|
||||
)
|
||||
|
||||
func init() {
|
||||
// swagHandler = ginSwagger.WrapHandler(swaggerFiles.Handler)
|
||||
swagHandler = ginSwagger.WrapHandler(swaggerFiles.Handler)
|
||||
}
|
||||
|
||||
235
route/init.go
Normal file
235
route/init.go
Normal file
@@ -0,0 +1,235 @@
|
||||
package route
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"encoding/xml"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/IceWhaleTech/CasaOS/model"
|
||||
"github.com/IceWhaleTech/CasaOS/model/system_app"
|
||||
"github.com/IceWhaleTech/CasaOS/pkg/config"
|
||||
"github.com/IceWhaleTech/CasaOS/pkg/docker"
|
||||
"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()
|
||||
|
||||
}
|
||||
|
||||
var syncIsExistence = false
|
||||
|
||||
func installSyncthing(appId string) {
|
||||
|
||||
var appInfo model.ServerAppList
|
||||
m := model.CustomizationPostData{}
|
||||
var dockerImage string
|
||||
var dockerImageVersion string
|
||||
appInfo = service.MyService.OAPI().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
|
||||
|
||||
containerId, err := service.MyService.Docker().DockerContainerCreate(dockerImage+":"+dockerImageVersion, id, m, appInfo.NetworkModel)
|
||||
if err != nil {
|
||||
fmt.Println("container create error", err)
|
||||
// create container error
|
||||
return
|
||||
}
|
||||
|
||||
//step:start container
|
||||
err = service.MyService.Docker().DockerContainerStart(id)
|
||||
if err != nil {
|
||||
//start container error
|
||||
return
|
||||
}
|
||||
|
||||
portsStr, _ := json.Marshal(appInfo.Ports)
|
||||
envsStr, _ := json.Marshal(appInfo.Envs)
|
||||
volumesStr, _ := json.Marshal(appInfo.Volumes)
|
||||
devicesStr, _ := json.Marshal(appInfo.Devices)
|
||||
//step: 保存数据到数据库
|
||||
md := model2.AppListDBModel{
|
||||
CustomId: id,
|
||||
Title: appInfo.Title,
|
||||
//ScreenshotLink: appInfo.ScreenshotLink,
|
||||
Slogan: appInfo.Tagline,
|
||||
Description: appInfo.Description,
|
||||
//Tags: appInfo.Tags,
|
||||
Icon: appInfo.Icon,
|
||||
Version: dockerImageVersion,
|
||||
ContainerId: containerId,
|
||||
Image: dockerImage,
|
||||
Index: appInfo.Index,
|
||||
PortMap: appInfo.PortMap,
|
||||
Label: appInfo.Title,
|
||||
EnableUPNP: false,
|
||||
Ports: string(portsStr),
|
||||
Envs: string(envsStr),
|
||||
Volumes: string(volumesStr),
|
||||
Position: true,
|
||||
NetModel: appInfo.NetworkModel,
|
||||
Restart: m.Restart,
|
||||
CpuShares: 50,
|
||||
Memory: int64(appInfo.MaxMemory),
|
||||
Devices: string(devicesStr),
|
||||
Origin: m.Origin,
|
||||
CreatedAt: strconv.FormatInt(time.Now().Unix(), 10),
|
||||
UpdatedAt: strconv.FormatInt(time.Now().Unix(), 10),
|
||||
}
|
||||
service.MyService.App().SaveContainer(md)
|
||||
|
||||
checkSystemApp()
|
||||
}
|
||||
|
||||
// check if the system application is installed
|
||||
func checkSystemApp() {
|
||||
list := service.MyService.App().GetSystemAppList()
|
||||
for _, v := range *list {
|
||||
if v.Image == "linuxserver/syncthing" {
|
||||
if v.State != "running" {
|
||||
//step:start container
|
||||
service.MyService.Docker().DockerContainerStart(v.CustomId)
|
||||
}
|
||||
syncIsExistence = true
|
||||
if config.SystemConfigInfo.SyncPort != v.Port {
|
||||
config.SystemConfigInfo.SyncPort = v.Port
|
||||
}
|
||||
var paths []model.PathMap
|
||||
json.Unmarshal([]byte(v.Volumes), &paths)
|
||||
path := ""
|
||||
for _, i := range paths {
|
||||
if i.ContainerPath == "/config" {
|
||||
path = docker.GetDir(v.CustomId, i.Path) + "/config.xml"
|
||||
for i := 0; i < 10; i++ {
|
||||
if file.CheckNotExist(path) {
|
||||
time.Sleep(1 * time.Second)
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
content := file.ReadFullFile(path)
|
||||
syncConfig := &system_app.SyncConfig{}
|
||||
xml.Unmarshal(content, &syncConfig)
|
||||
config.SystemConfigInfo.SyncKey = syncConfig.Key
|
||||
}
|
||||
}
|
||||
if !syncIsExistence {
|
||||
installSyncthing("74")
|
||||
}
|
||||
}
|
||||
func CheckSerialDiskMount() {
|
||||
// check mount point
|
||||
dbList := service.MyService.Disk().GetSerialAll()
|
||||
|
||||
list := service.MyService.Disk().LSBLK()
|
||||
mountPoint := make(map[string]string, len(dbList))
|
||||
//remount
|
||||
for _, v := range dbList {
|
||||
mountPoint[v.Path] = 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.Path]; 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.Serial = v.Serial
|
||||
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")
|
||||
}
|
||||
@@ -1,18 +1,20 @@
|
||||
package route
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/IceWhaleTech/CasaOS/middleware"
|
||||
"github.com/IceWhaleTech/CasaOS/pkg/config"
|
||||
jwt2 "github.com/IceWhaleTech/CasaOS/pkg/utils/jwt"
|
||||
v1 "github.com/IceWhaleTech/CasaOS/route/v1"
|
||||
"github.com/IceWhaleTech/CasaOS/web"
|
||||
"github.com/gin-gonic/gin"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
var swagHandler gin.HandlerFunc
|
||||
var OnlineDemo bool = false
|
||||
|
||||
func InitRouter(swagHandler gin.HandlerFunc) *gin.Engine {
|
||||
func InitRouter() *gin.Engine {
|
||||
|
||||
r := gin.Default()
|
||||
r.Use(middleware.Cors())
|
||||
@@ -26,10 +28,16 @@ func InitRouter(swagHandler gin.HandlerFunc) *gin.Engine {
|
||||
if swagHandler != nil {
|
||||
r.GET("/swagger/*any", swagHandler)
|
||||
}
|
||||
//登录
|
||||
|
||||
r.POST("/v1/user/login", v1.Login)
|
||||
|
||||
r.GET("/debug", v1.GetSystemConfigDebug)
|
||||
r.GET("/v1/guide/check", v1.GetGuideCheck)
|
||||
|
||||
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)
|
||||
|
||||
v1Group := r.Group("/v1")
|
||||
|
||||
@@ -38,8 +46,7 @@ func InitRouter(swagHandler gin.HandlerFunc) *gin.Engine {
|
||||
v1UserGroup := v1Group.Group("/user")
|
||||
v1UserGroup.Use()
|
||||
{
|
||||
//设置用户
|
||||
v1UserGroup.POST("/setusernamepwd", v1.Set_Name_Pwd)
|
||||
|
||||
//chang head
|
||||
v1UserGroup.POST("/changhead", v1.Up_Load_Head)
|
||||
//chang user name
|
||||
@@ -48,8 +55,7 @@ func InitRouter(swagHandler gin.HandlerFunc) *gin.Engine {
|
||||
v1UserGroup.PUT("/changuserpwd", v1.Chang_User_Pwd)
|
||||
//edit user info
|
||||
v1UserGroup.POST("/changuserinfo", v1.Chang_User_Info)
|
||||
//get user info
|
||||
v1UserGroup.GET("/info", v1.UserInfo)
|
||||
|
||||
}
|
||||
|
||||
v1ZiMaGroup := v1Group.Group("/zima")
|
||||
@@ -64,8 +70,7 @@ func InitRouter(swagHandler gin.HandlerFunc) *gin.Engine {
|
||||
|
||||
//获取网络信息
|
||||
v1ZiMaGroup.GET("/getnetinfo", v1.NetInfo)
|
||||
//获取网络信息
|
||||
v1ZiMaGroup.GET("/getinfo", v1.Info)
|
||||
|
||||
//获取系统信息
|
||||
v1ZiMaGroup.GET("/sysinfo", v1.SysInfo)
|
||||
}
|
||||
@@ -135,6 +140,8 @@ func InitRouter(swagHandler gin.HandlerFunc) *gin.Engine {
|
||||
{
|
||||
//获取我的已安装的列表
|
||||
v1AppGroup.GET("/mylist", v1.MyAppList)
|
||||
//
|
||||
v1AppGroup.GET("/usage", v1.AppUsageList)
|
||||
//app详情
|
||||
v1AppGroup.GET("/appinfo/:id", v1.AppInfo)
|
||||
//获取未安装的列表
|
||||
@@ -170,7 +177,7 @@ func InitRouter(swagHandler gin.HandlerFunc) *gin.Engine {
|
||||
v1AppGroup.GET("/rely/:id/info", v1.ContainerRelyInfo)
|
||||
v1AppGroup.GET("/install/config", v1.GetDockerInstallConfig)
|
||||
//v1AppGroup.POST("/custom/install", v1.CustomInstallApp)
|
||||
|
||||
v1AppGroup.POST("/share", v1.ShareAppFile)
|
||||
}
|
||||
|
||||
v1SysGroup := v1Group.Group("/sys")
|
||||
@@ -182,7 +189,14 @@ func InitRouter(swagHandler gin.HandlerFunc) *gin.Engine {
|
||||
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)
|
||||
}
|
||||
v1FileGroup := v1Group.Group("/file")
|
||||
v1FileGroup.Use()
|
||||
@@ -191,27 +205,36 @@ func InitRouter(swagHandler gin.HandlerFunc) *gin.Engine {
|
||||
v1FileGroup.PUT("/rename", v1.RenamePath)
|
||||
v1FileGroup.GET("/read", v1.GetFilerContent)
|
||||
v1FileGroup.POST("/upload", v1.PostFileUpload)
|
||||
v1FileGroup.GET("/dirpath", v1.DirPath)
|
||||
v1FileGroup.GET("/catalog", v1.DirPath)
|
||||
//创建目录
|
||||
v1FileGroup.POST("/mkdir", v1.MkdirAll)
|
||||
v1FileGroup.POST("/create", v1.PostCreateFile)
|
||||
|
||||
v1FileGroup.GET("/download", v1.GetDownloadFile)
|
||||
v1FileGroup.PUT("/move", v1.PutFileMove)
|
||||
//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)
|
||||
@@ -252,6 +275,14 @@ func InitRouter(swagHandler gin.HandlerFunc) *gin.Engine {
|
||||
v1NotifyGroup.GET("/ws", v1.NotifyWS)
|
||||
v1NotifyGroup.PUT("/read/:id", v1.PutNotifyRead)
|
||||
}
|
||||
v1SearchGroup := v1Group.Group("/search")
|
||||
v1SearchGroup.Use()
|
||||
{
|
||||
v1SearchGroup.GET("/search", v1.GetSearchList)
|
||||
}
|
||||
v1Group.GET("/sync/config", v1.GetSyncConfig)
|
||||
v1Group.Any("/syncthing/*url", v1.SyncToSyncthing)
|
||||
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
166
route/v1/app.go
166
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.OAPI().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})
|
||||
}
|
||||
@@ -99,6 +115,18 @@ func MyAppList(c *gin.Context) {
|
||||
c.JSON(http.StatusOK, &model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: list})
|
||||
}
|
||||
|
||||
// @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})
|
||||
}
|
||||
|
||||
// @Summary 应用详情
|
||||
// @Produce application/json
|
||||
// @Accept application/json
|
||||
@@ -110,51 +138,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.OAPI().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.Configures.UdpPorts); i++ {
|
||||
info.Configures.UdpPorts[i].CommendPort, _ = port2.GetAvailablePort("udp")
|
||||
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
|
||||
}
|
||||
}
|
||||
} else {
|
||||
info.PortMap = info.TcpPort
|
||||
}
|
||||
|
||||
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
|
||||
for i := 0; i < len(info.Ports); i++ {
|
||||
if info.Ports[i].Type == 0 {
|
||||
info.PortMap = info.Ports[i].ContainerPort
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
@@ -176,7 +224,31 @@ func CategoryList(c *gin.Context) {
|
||||
}
|
||||
|
||||
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.OAPI().ShareAppFile(str)
|
||||
c.JSON(http.StatusOK, json.RawMessage(content))
|
||||
}
|
||||
|
||||
// @Summary Resource Usage
|
||||
// @Produce application/json
|
||||
// @Accept application/json
|
||||
// @Tags app
|
||||
// @Security ApiKeyAuth
|
||||
// @Success 200 {string} string "ok"
|
||||
// @Router /app/share [post]
|
||||
func AppListResourceUsage() {
|
||||
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
373
route/v1/disk.go
373
route/v1/disk.go
@@ -1,65 +1,134 @@
|
||||
package v1
|
||||
|
||||
import (
|
||||
"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()
|
||||
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 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" {
|
||||
temp := service.MyService.Disk().SmartCTL(list[i].Path)
|
||||
if reflect.DeepEqual(temp, model.SmartctlA{}) {
|
||||
continue
|
||||
}
|
||||
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
|
||||
@@ -76,12 +145,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 +162,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 +238,184 @@ 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 {
|
||||
serial := c.PostForm("serial")
|
||||
format, _ := strconv.ParseBool(c.PostForm("format"))
|
||||
if len(name) == 0 || len(path) == 0 || len(serial) == 0 {
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err.INVALID_PARAMS, Message: oasis_err.GetMsg(oasis_err.INVALID_PARAMS)})
|
||||
return
|
||||
}
|
||||
if _, ok := diskMap[serial]; 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[serial] = "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, serial)
|
||||
return
|
||||
}
|
||||
} else {
|
||||
service.MyService.Disk().AddPartition(path)
|
||||
}
|
||||
|
||||
mountPath := "/DATA/" + name
|
||||
|
||||
service.MyService.Disk().MountDisk(path, mountPath)
|
||||
|
||||
m := model2.SerialDisk{}
|
||||
m.MountPoint = mountPath
|
||||
m.Path = path + "1"
|
||||
m.Serial = serial
|
||||
m.State = 0
|
||||
m.CreatedAt = time.Now().Unix()
|
||||
service.MyService.Disk().SaveMountPoint(m)
|
||||
|
||||
//mount dir
|
||||
service.MyService.Disk().MountDisk(path+"1", mountPath)
|
||||
|
||||
service.MyService.Disk().RemoveLSBLKCache()
|
||||
|
||||
delete(diskMap, serial)
|
||||
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.Serial = 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()
|
||||
|
||||
mapList := make(map[string]string)
|
||||
|
||||
for _, v := range list {
|
||||
mapList[v.Serial] = "1"
|
||||
}
|
||||
|
||||
for _, v := range dbList {
|
||||
if _, ok := mapList[v.Serial]; !ok {
|
||||
//disk undefind
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err.ERROR, Message: oasis_err.GetMsg(oasis_err.ERROR), Data: "disk undefind"})
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
//size*1024*1024/512
|
||||
service.MyService.Disk().AddPartition(path, num, uint64(size*1024*2))
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err.SUCCESS, Message: oasis_err.GetMsg(oasis_err.SUCCESS)})
|
||||
}
|
||||
|
||||
@@ -3,7 +3,14 @@ package v1
|
||||
import (
|
||||
"bytes"
|
||||
json2 "encoding/json"
|
||||
"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"
|
||||
@@ -19,11 +26,8 @@ import (
|
||||
"github.com/gorilla/websocket"
|
||||
"github.com/jinzhu/copier"
|
||||
uuid "github.com/satori/go.uuid"
|
||||
"net/http"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
"github.com/tidwall/gjson"
|
||||
"golang.org/x/crypto/ssh"
|
||||
)
|
||||
|
||||
var upgrader = websocket.Upgrader{
|
||||
@@ -64,19 +68,46 @@ func DockerTerminal(c *gin.Context) {
|
||||
//打开本机的ssh接口
|
||||
func WsSsh(c *gin.Context) {
|
||||
wsConn, _ := upgrader.Upgrade(c.Writer, c.Request, nil)
|
||||
defer wsConn.Close()
|
||||
cols, _ := strconv.Atoi(c.DefaultQuery("cols", "200"))
|
||||
rows, _ := strconv.Atoi(c.DefaultQuery("rows", "32"))
|
||||
client, _ := docker.NewSshClient()
|
||||
defer client.Close()
|
||||
ssConn, _ := docker.NewSshConn(cols, rows, client)
|
||||
defer ssConn.Close()
|
||||
quitChan := make(chan bool, 3)
|
||||
|
||||
var logBuff = new(bytes.Buffer)
|
||||
quitChan := make(chan bool, 3)
|
||||
user := ""
|
||||
password := ""
|
||||
var login int = 1
|
||||
cols, _ := strconv.Atoi(c.DefaultQuery("cols", "200"))
|
||||
rows, _ := strconv.Atoi(c.DefaultQuery("rows", "32"))
|
||||
var client *ssh.Client
|
||||
for login != 0 {
|
||||
|
||||
var err error
|
||||
|
||||
wsConn.WriteMessage(websocket.TextMessage, []byte("login:"))
|
||||
user = docker.ReceiveWsMsgUser(wsConn, logBuff)
|
||||
wsConn.WriteMessage(websocket.TextMessage, []byte("\r\n\x1b[0m"))
|
||||
wsConn.WriteMessage(websocket.TextMessage, []byte("password:"))
|
||||
password = docker.ReceiveWsMsgPassword(wsConn, logBuff)
|
||||
wsConn.WriteMessage(websocket.TextMessage, []byte("\r\n\x1b[0m"))
|
||||
client, err = docker.NewSshClient(user, password)
|
||||
|
||||
if err != nil && client == nil {
|
||||
wsConn.WriteMessage(websocket.TextMessage, []byte(err.Error()))
|
||||
wsConn.WriteMessage(websocket.TextMessage, []byte("\r\n\x1b[0m"))
|
||||
} else {
|
||||
login = 0
|
||||
}
|
||||
|
||||
}
|
||||
if client != nil {
|
||||
defer client.Close()
|
||||
}
|
||||
|
||||
ssConn, _ := docker.NewSshConn(cols, rows, client)
|
||||
defer ssConn.Close()
|
||||
|
||||
go ssConn.ReceiveWsMsg(wsConn, logBuff, quitChan)
|
||||
go ssConn.SendComboOutput(wsConn, quitChan)
|
||||
go ssConn.SessionWait(quitChan)
|
||||
|
||||
<-quitChan
|
||||
|
||||
}
|
||||
@@ -114,6 +145,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)
|
||||
@@ -143,7 +175,7 @@ func InstallApp(c *gin.Context) {
|
||||
dockerImageVersion = "latest"
|
||||
}
|
||||
if m.Origin != "custom" {
|
||||
appInfo = service.MyService.App().GetServerAppInfo(appId)
|
||||
appInfo = service.MyService.OAPI().GetServerAppInfo(appId, "", language)
|
||||
|
||||
} else {
|
||||
|
||||
@@ -187,14 +219,24 @@ 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)})
|
||||
return
|
||||
}
|
||||
|
||||
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)})
|
||||
return
|
||||
}
|
||||
|
||||
} 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 {
|
||||
//
|
||||
@@ -209,10 +251,9 @@ func InstallApp(c *gin.Context) {
|
||||
var relyMap = make(map[string]string)
|
||||
go func() {
|
||||
installLog := model2.AppNotify{}
|
||||
installLog.CustomId = id
|
||||
installLog.State = 0
|
||||
installLog.CustomId = id
|
||||
installLog.Message = "installing rely"
|
||||
installLog.Speed = 10
|
||||
installLog.Type = types.NOTIFY_TYPE_UNIMPORTANT
|
||||
installLog.CreatedAt = strconv.FormatInt(time.Now().Unix(), 10)
|
||||
installLog.UpdatedAt = strconv.FormatInt(time.Now().Unix(), 10)
|
||||
@@ -238,11 +279,11 @@ func InstallApp(c *gin.Context) {
|
||||
rely.ContainerId = mysqlContainerId
|
||||
rely.CustomId = mid
|
||||
rely.ContainerCustomId = id
|
||||
var msqlConfig model2.MysqlConfigs
|
||||
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
|
||||
@@ -250,16 +291,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)
|
||||
|
||||
@@ -267,7 +305,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)
|
||||
@@ -283,36 +320,45 @@ func InstallApp(c *gin.Context) {
|
||||
//}
|
||||
|
||||
//step:创建容器
|
||||
// networkName, err := service.MyService.Docker().GetNetWorkNameByNetWorkID(appInfo.NetworkModel)
|
||||
// if err != nil {
|
||||
// //service.MyService.Redis().Set(id, "{\"id\"\""+id+"\",\"state\":false,\"message\":\""+err.Error()+"\",\"speed\":80}", 100)
|
||||
// installLog.State = 0
|
||||
// installLog.Speed = 75
|
||||
// installLog.Type = types.NOTIFY_TYPE_ERROR
|
||||
// installLog.Message = err.Error()
|
||||
// service.MyService.Notify().UpdateLog(installLog)
|
||||
// return
|
||||
// }
|
||||
containerId, err := service.MyService.Docker().DockerContainerCreate(dockerImage+":"+dockerImageVersion, id, m, appInfo.NetworkModel)
|
||||
installLog.ContainerId = containerId
|
||||
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)
|
||||
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 {
|
||||
@@ -357,13 +403,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)
|
||||
}
|
||||
@@ -375,14 +419,12 @@ func InstallApp(c *gin.Context) {
|
||||
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)
|
||||
}
|
||||
@@ -390,6 +432,12 @@ 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)
|
||||
@@ -429,6 +477,7 @@ func InstallApp(c *gin.Context) {
|
||||
// m.PortMap = m.Port
|
||||
//}
|
||||
service.MyService.App().SaveContainer(md)
|
||||
config.CasaOSGlobalVariables.AppChange = true
|
||||
|
||||
}()
|
||||
|
||||
@@ -643,7 +692,7 @@ func UnInstallApp(c *gin.Context) {
|
||||
}
|
||||
|
||||
//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
|
||||
@@ -658,7 +707,12 @@ func UnInstallApp(c *gin.Context) {
|
||||
if info.Origin != "custom" {
|
||||
|
||||
//step: 删除文件夹
|
||||
service.MyService.App().DelAppConfigDir(appId)
|
||||
vol := gjson.Get(info.Volumes, "#.host")
|
||||
for _, v := range vol.Array() {
|
||||
if strings.Contains(v.String(), appId) {
|
||||
service.MyService.App().DelAppConfigDir(v.String())
|
||||
}
|
||||
}
|
||||
|
||||
//step: 删除install log
|
||||
service.MyService.Notify().DelLog(appId)
|
||||
@@ -700,7 +754,7 @@ func UnInstallApp(c *gin.Context) {
|
||||
// }
|
||||
//}
|
||||
}
|
||||
|
||||
config.CasaOSGlobalVariables.AppChange = true
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS)})
|
||||
|
||||
}
|
||||
@@ -763,7 +817,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})
|
||||
}
|
||||
|
||||
@@ -873,19 +926,24 @@ func UpdateSetting(c *gin.Context) {
|
||||
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 {
|
||||
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
|
||||
|
||||
containerId, err = service.MyService.Docker().DockerContainerCreate(appInfo.Image+":"+appInfo.Version, newUUid, cpd, appInfo.NetModel)
|
||||
// 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)
|
||||
|
||||
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)
|
||||
err = service.MyService.Docker().DockerContainerRemove(id, true)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.ERROR, Message: oasis_err2.GetMsg(oasis_err2.ERROR)})
|
||||
return
|
||||
@@ -980,6 +1038,7 @@ func UpdateSetting(c *gin.Context) {
|
||||
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
|
||||
@@ -1087,16 +1146,20 @@ func ContainerUpdateInfo(c *gin.Context) {
|
||||
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
|
||||
var port model.PortArray
|
||||
json2.Unmarshal([]byte(appInfo.Ports), &port)
|
||||
|
||||
var envs model.EnvArrey
|
||||
var envs model.EnvArray
|
||||
json2.Unmarshal([]byte(appInfo.Envs), &envs)
|
||||
|
||||
var vol model.PathArrey
|
||||
var vol model.PathArray
|
||||
json2.Unmarshal([]byte(appInfo.Volumes), &vol)
|
||||
|
||||
var dir model.PathArrey
|
||||
for i := 0; i < len(vol); i++ {
|
||||
vol[i].Path = strings.ReplaceAll(vol[i].Path, "$AppID", appId)
|
||||
}
|
||||
|
||||
var dir model.PathArray
|
||||
json2.Unmarshal([]byte(appInfo.Devices), &dir)
|
||||
|
||||
//volumesStr, _ := json2.Marshal(m.Volumes)
|
||||
|
||||
@@ -4,16 +4,19 @@ import (
|
||||
"bufio"
|
||||
"encoding/csv"
|
||||
"fmt"
|
||||
"github.com/IceWhaleTech/CasaOS/model"
|
||||
"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"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"time"
|
||||
|
||||
"github.com/IceWhaleTech/CasaOS/model"
|
||||
"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"
|
||||
)
|
||||
|
||||
func downloadReadFile(c *gin.Context) {
|
||||
@@ -218,6 +221,25 @@ func MkdirAll(c *gin.Context) {
|
||||
c.JSON(http.StatusOK, model.Result{Success: code, Message: oasis_err2.GetMsg(code)})
|
||||
}
|
||||
|
||||
// @Summary 创建文件
|
||||
// @Produce application/json
|
||||
// @Accept multipart/form-data
|
||||
// @Tags file
|
||||
// @Security ApiKeyAuth
|
||||
// @Param path formData string false "路径"
|
||||
// @Success 200 {string} string "ok"
|
||||
// @Router /file/create [post]
|
||||
func PostCreateFile(c *gin.Context) {
|
||||
path := c.PostForm("path")
|
||||
var code int
|
||||
if len(path) == 0 {
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.INVALID_PARAMS, Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS)})
|
||||
return
|
||||
}
|
||||
code, _ = service.MyService.ZiMa().CreateFile(path)
|
||||
c.JSON(http.StatusOK, model.Result{Success: code, Message: oasis_err2.GetMsg(code)})
|
||||
}
|
||||
|
||||
// @Summary 上传文件
|
||||
// @Produce application/json
|
||||
// @Accept multipart/form-data
|
||||
@@ -236,3 +258,64 @@ func PostFileUpload(c *gin.Context) {
|
||||
io.Copy(out, file)
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS)})
|
||||
}
|
||||
|
||||
func PutFileMove(c *gin.Context) {
|
||||
from := "/Users/liangjianli/go/CasaOS"
|
||||
to := "/Users/liangjianli/go/CasaOS/test"
|
||||
//t := 1 //是否覆盖
|
||||
|
||||
//方法体
|
||||
stopCh := make(chan int)
|
||||
f, err := os.Stat(from)
|
||||
if err != nil {
|
||||
//未拿到文件信息
|
||||
fmt.Println("stat", err)
|
||||
}
|
||||
//未创建新的文件夹
|
||||
if f.IsDir() {
|
||||
//from 是文件夹,定义to也是文件夹
|
||||
if list, err := ioutil.ReadDir(from); err == nil {
|
||||
for _, v := range list {
|
||||
time.Sleep(time.Second)
|
||||
if err = Copy(stopCh, filepath.Join(from, v.Name()), filepath.Join(to, v.Name())); err != nil {
|
||||
fmt.Printf("copy %s ,err %d", v.Name(), err)
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
p := filepath.Dir(to)
|
||||
if _, err = os.Stat(p); err != nil {
|
||||
if err = os.MkdirAll(p, 0777); err != nil {
|
||||
fmt.Println("mkdir", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
file, err := os.Open(from)
|
||||
|
||||
if err != nil {
|
||||
fmt.Println("open file error ", err)
|
||||
}
|
||||
defer file.Close()
|
||||
out, err := os.Create(to)
|
||||
if err != nil {
|
||||
fmt.Println("create to file err", err)
|
||||
}
|
||||
defer out.Close()
|
||||
io.Copy(out, file)
|
||||
time.Sleep(time.Second * 4)
|
||||
close(stopCh)
|
||||
}
|
||||
func Copy(stop chan int, from, to string) error {
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-stop:
|
||||
return nil
|
||||
default:
|
||||
fmt.Println(from)
|
||||
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
22
route/v1/search.go
Normal file
22
route/v1/search.go
Normal file
@@ -0,0 +1,22 @@
|
||||
package v1
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/IceWhaleTech/CasaOS/model"
|
||||
"github.com/IceWhaleTech/CasaOS/pkg/utils/oasis_err"
|
||||
"github.com/IceWhaleTech/CasaOS/service"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
func GetSearchList(c *gin.Context) {
|
||||
key := c.DefaultQuery("key", "")
|
||||
if len(key) == 0 {
|
||||
return
|
||||
}
|
||||
list, err := service.MyService.Search().SearchList(key)
|
||||
if err != nil {
|
||||
|
||||
}
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err.SUCCESS, Message: oasis_err.GetMsg(oasis_err.SUCCESS), Data: list})
|
||||
}
|
||||
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})
|
||||
}
|
||||
@@ -1,18 +1,26 @@
|
||||
package v1
|
||||
|
||||
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"
|
||||
"github.com/IceWhaleTech/CasaOS/types"
|
||||
"github.com/gin-gonic/gin"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"time"
|
||||
)
|
||||
|
||||
// @Summary 系统信息
|
||||
@@ -26,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)
|
||||
@@ -51,10 +58,8 @@ func CheckVersion(c *gin.Context) {
|
||||
// @Success 200 {string} string "ok"
|
||||
// @Router /sys/update [post]
|
||||
func SystemUpdate(c *gin.Context) {
|
||||
fmt.Println("开始更新")
|
||||
need, version := version.IsNeedUpdate()
|
||||
if need {
|
||||
fmt.Println("进入更新")
|
||||
service.MyService.System().UpdateSystemVersion(version.Version)
|
||||
}
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err.SUCCESS, Message: oasis_err.GetMsg(oasis_err.SUCCESS)})
|
||||
@@ -62,28 +67,40 @@ func SystemUpdate(c *gin.Context) {
|
||||
|
||||
//系统配置
|
||||
func GetSystemConfig(c *gin.Context) {
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err.SUCCESS, Message: oasis_err.GetMsg(oasis_err.SUCCESS), Data: config.SystemConfigInfo})
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err.SUCCESS, Message: oasis_err.GetMsg(oasis_err.SUCCESS), Data: json.RawMessage(config.SystemConfigInfo.ConfigStr)})
|
||||
}
|
||||
|
||||
// @Summary get logs
|
||||
// @Produce application/json
|
||||
// @Accept application/json
|
||||
// @Tags sys
|
||||
// @Security ApiKeyAuth
|
||||
// @Success 200 {string} string "ok"
|
||||
// @Router /sys/error/logs [get]
|
||||
func GetCasaOSErrorLogs(c *gin.Context) {
|
||||
line, _ := strconv.Atoi(c.DefaultQuery("line", "100"))
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err.SUCCESS, Message: oasis_err.GetMsg(oasis_err.SUCCESS), Data: service.MyService.System().GetCasaOSLogs(line)})
|
||||
}
|
||||
|
||||
// @Summary 修改配置文件
|
||||
// @Produce application/json
|
||||
// @Accept multipart/form-data
|
||||
// @Tags user
|
||||
// @Param file formData file true "用户头像"
|
||||
// @Tags sys
|
||||
// @Param config formData string true "config json string"
|
||||
// @Security ApiKeyAuth
|
||||
// @Success 200 {string} string "ok"
|
||||
// @Router /user/changhead [post]
|
||||
// @Router /sys/changhead [post]
|
||||
func PostSetSystemConfig(c *gin.Context) {
|
||||
var systemConfig model.SystemConfig
|
||||
c.BindJSON(&systemConfig)
|
||||
service.MyService.System().UpSystemConfig(systemConfig)
|
||||
buf := make([]byte, 1024)
|
||||
n, _ := c.Request.Body.Read(buf)
|
||||
|
||||
service.MyService.System().UpSystemConfig(string(buf[0:n]), "")
|
||||
c.JSON(http.StatusOK,
|
||||
model.Result{
|
||||
Success: oasis_err.SUCCESS,
|
||||
Message: oasis_err.GetMsg(oasis_err.SUCCESS),
|
||||
Data: config.SystemConfigInfo,
|
||||
Data: json.RawMessage(config.SystemConfigInfo.ConfigStr),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
//系统配置
|
||||
@@ -91,10 +108,235 @@ 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})
|
||||
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})
|
||||
}
|
||||
func Sys(c *gin.Context) {
|
||||
service.DockerPull()
|
||||
}
|
||||
|
||||
//widget配置
|
||||
func GetWidgetConfig(c *gin.Context) {
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err.SUCCESS, Message: oasis_err.GetMsg(oasis_err.SUCCESS), Data: json.RawMessage(config.SystemConfigInfo.WidgetList)})
|
||||
}
|
||||
|
||||
// @Summary 修改组件配置文件
|
||||
// @Produce application/json
|
||||
// @Accept application/json
|
||||
// @Tags sys
|
||||
// @Security ApiKeyAuth
|
||||
// @Success 200 {string} string "ok"
|
||||
// @Router /sys/widget/config [post]
|
||||
func PostSetWidgetConfig(c *gin.Context) {
|
||||
buf := make([]byte, 1024)
|
||||
n, _ := c.Request.Body.Read(buf)
|
||||
fmt.Println("错误", strconv.Itoa(n))
|
||||
service.MyService.System().UpSystemConfig("", string(buf[0:n]))
|
||||
fmt.Println("错误1", string(buf[0:n]))
|
||||
c.JSON(http.StatusOK,
|
||||
model.Result{
|
||||
Success: oasis_err.SUCCESS,
|
||||
Message: oasis_err.GetMsg(oasis_err.SUCCESS),
|
||||
Data: json.RawMessage(config.SystemConfigInfo.WidgetList),
|
||||
})
|
||||
}
|
||||
|
||||
// @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
|
||||
// @Tags sys
|
||||
// @Security ApiKeyAuth
|
||||
// @Success 200 {string} string "ok"
|
||||
// @Router /guide/check [get]
|
||||
func GetGuideCheck(c *gin.Context) {
|
||||
initUser := false
|
||||
if !config.UserInfo.Initialized {
|
||||
initUser = true
|
||||
}
|
||||
data := make(map[string]interface{}, 1)
|
||||
data["need_init_user"] = initUser
|
||||
c.JSON(http.StatusOK,
|
||||
model.Result{
|
||||
Success: oasis_err.SUCCESS,
|
||||
Message: oasis_err.GetMsg(oasis_err.SUCCESS),
|
||||
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 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{}, 5)
|
||||
|
||||
list := service.MyService.Disk().LSBLK()
|
||||
|
||||
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 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" {
|
||||
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
|
||||
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})
|
||||
}
|
||||
|
||||
@@ -2,13 +2,15 @@ package v1
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/IceWhaleTech/CasaOS/model"
|
||||
"github.com/IceWhaleTech/CasaOS/pkg/config"
|
||||
jwt2 "github.com/IceWhaleTech/CasaOS/pkg/utils/jwt"
|
||||
oasis_err2 "github.com/IceWhaleTech/CasaOS/pkg/utils/oasis_err"
|
||||
"github.com/IceWhaleTech/CasaOS/service"
|
||||
"github.com/IceWhaleTech/CasaOS/types"
|
||||
"github.com/gin-gonic/gin"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
var user_service service.UserService
|
||||
@@ -32,7 +34,7 @@ func Set_Name_Pwd(c *gin.Context) {
|
||||
username := c.PostForm("username")
|
||||
pwd := c.PostForm("pwd")
|
||||
//老用户名是否存在即新用户名和密码的验证
|
||||
if len(config.UserInfo.UserName) > 0 || len(username) == 0 || len(pwd) == 0 {
|
||||
if config.UserInfo.Initialized || len(username) == 0 || len(pwd) == 0 {
|
||||
c.JSON(http.StatusOK,
|
||||
model.Result{Success: oasis_err2.ERROR, Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS)})
|
||||
return
|
||||
@@ -69,15 +71,18 @@ func Login(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
//if config.UserInfo.UserName == username && config.UserInfo.PWD == pwd {
|
||||
if username == "admin" && pwd == "admin" {
|
||||
token := jwt2.GetToken(username, pwd)
|
||||
if config.UserInfo.UserName == username && config.UserInfo.PWD == pwd {
|
||||
//if username == "admin" && pwd == "admin" {
|
||||
|
||||
data := make(map[string]string, 2)
|
||||
data["token"] = jwt2.GetToken(username, pwd)
|
||||
data["version"] = types.CURRENTVERSION
|
||||
//user_service.SetUser("", "", token, "", "")
|
||||
c.JSON(http.StatusOK,
|
||||
model.Result{
|
||||
Success: oasis_err2.SUCCESS,
|
||||
Message: oasis_err2.GetMsg(oasis_err2.SUCCESS),
|
||||
Data: token,
|
||||
Data: data,
|
||||
})
|
||||
return
|
||||
}
|
||||
@@ -106,7 +111,6 @@ func Up_Load_Head(c *gin.Context) {
|
||||
Message: oasis_err2.GetMsg(oasis_err2.SUCCESS),
|
||||
Data: config.UserInfo.Head,
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
// @Summary 修改用户名
|
||||
@@ -119,6 +123,10 @@ func Up_Load_Head(c *gin.Context) {
|
||||
// @Success 200 {string} string "ok"
|
||||
// @Router /user/changusername [put]
|
||||
func Chang_User_Name(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 {
|
||||
@@ -127,7 +135,6 @@ func Chang_User_Name(c *gin.Context) {
|
||||
}
|
||||
user_service.SetUser(username, "", "", "", "")
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS)})
|
||||
return
|
||||
}
|
||||
|
||||
// @Summary 修改密码
|
||||
@@ -142,13 +149,20 @@ func Chang_User_Name(c *gin.Context) {
|
||||
func Chang_User_Pwd(c *gin.Context) {
|
||||
oldpwd := c.PostForm("oldpwd")
|
||||
pwd := c.PostForm("pwd")
|
||||
if len(pwd) == 0 || config.UserInfo.PWD != oldpwd {
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.ERROR, Message: oasis_err2.GetMsg(oasis_err2.ERROR)})
|
||||
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, "", "", "")
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS)})
|
||||
return
|
||||
}
|
||||
|
||||
// @Summary 修改用户信息
|
||||
@@ -174,21 +188,23 @@ func Chang_User_Info(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
user_service.SetUser(username, pwd, "", email, description)
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS)})
|
||||
return
|
||||
data := make(map[string]string, 2)
|
||||
|
||||
data["token"] = jwt2.GetToken(username, pwd)
|
||||
data["user_name"] = username
|
||||
data["head"] = config.UserInfo.Head
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: data})
|
||||
}
|
||||
|
||||
// @Summary 获取用户详情
|
||||
// @Produce application/json
|
||||
// @Accept mapplication/json
|
||||
// @Tags user
|
||||
// @Security ApiKeyAuth
|
||||
// @Success 200 {string} string "ok"
|
||||
// @Router /user/info [get]
|
||||
func UserInfo(c *gin.Context) {
|
||||
var u = make(map[string]string, 2)
|
||||
u["user_name"] = config.UserInfo.UserName
|
||||
u["token"] = config.UserInfo.Token
|
||||
u["head"] = config.UserInfo.Head
|
||||
u["email"] = config.UserInfo.Email
|
||||
u["description"] = config.UserInfo.Description
|
||||
@@ -198,5 +214,4 @@ func UserInfo(c *gin.Context) {
|
||||
Message: oasis_err2.GetMsg(oasis_err2.SUCCESS),
|
||||
Data: u,
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
@@ -2,12 +2,13 @@ package v1
|
||||
|
||||
import (
|
||||
json2 "encoding/json"
|
||||
"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"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
// @Summary 登录zerotier获取token
|
||||
@@ -432,11 +433,17 @@ func ZeroTierDeleteNetwork(c *gin.Context) {
|
||||
// @Router /zerotier/join/{id} [post]
|
||||
func ZeroTierJoinNetwork(c *gin.Context) {
|
||||
networkId := c.Param("id")
|
||||
service.MyService.ZeroTier().ZeroTierJoinNetwork(networkId)
|
||||
if len(networkId) == 0 {
|
||||
if len(networkId) != 16 {
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.INVALID_PARAMS, Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS)})
|
||||
return
|
||||
}
|
||||
for _, v := range networkId {
|
||||
if !service.MyService.ZeroTier().NetworkIdFilter(v) {
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.INVALID_PARAMS, Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS)})
|
||||
return
|
||||
}
|
||||
}
|
||||
service.MyService.ZeroTier().ZeroTierJoinNetwork(networkId)
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS)})
|
||||
}
|
||||
|
||||
@@ -450,10 +457,19 @@ func ZeroTierJoinNetwork(c *gin.Context) {
|
||||
// @Router /zerotier/leave/{id} [post]
|
||||
func ZeroTierLeaveNetwork(c *gin.Context) {
|
||||
networkId := c.Param("id")
|
||||
service.MyService.ZeroTier().ZeroTierLeaveNetwork(networkId)
|
||||
if len(networkId) == 0 {
|
||||
|
||||
if len(networkId) != 16 {
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.INVALID_PARAMS, Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS)})
|
||||
return
|
||||
}
|
||||
|
||||
for _, v := range networkId {
|
||||
if !service.MyService.ZeroTier().NetworkIdFilter(v) {
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.INVALID_PARAMS, Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS)})
|
||||
return
|
||||
}
|
||||
}
|
||||
service.MyService.ZeroTier().ZeroTierLeaveNetwork(networkId)
|
||||
|
||||
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信息
|
||||
@@ -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
|
||||
|
||||
234
service/app.go
234
service/app.go
@@ -2,35 +2,40 @@ package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
json2 "encoding/json"
|
||||
"encoding/json"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"runtime"
|
||||
"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"
|
||||
"gorm.io/gorm"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
type AppService interface {
|
||||
GetMyList(index, size int, position bool) *[]model2.MyAppList
|
||||
SaveContainer(m model2.AppListDBModel)
|
||||
GetServerAppInfo(id string) model.ServerAppList
|
||||
GetUninstallInfo(id string) model2.AppListDBModel
|
||||
RemoveContainerById(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() *[]model2.MyAppList
|
||||
GetHardwareUsageSteam()
|
||||
GetHardwareUsage() []model.DockerStatsModel
|
||||
GetAppStats(id string) string
|
||||
}
|
||||
|
||||
type appStruct struct {
|
||||
@@ -41,7 +46,7 @@ type appStruct struct {
|
||||
//获取我的应用列表
|
||||
func (a *appStruct) GetMyList(index, size int, position bool) *[]model2.MyAppList {
|
||||
//获取docker应用
|
||||
cli, err := client2.NewClientWithOpts(client2.FromEnv)
|
||||
cli, err := client2.NewClientWithOpts(client2.FromEnv, client2.WithTimeout(time.Second*5))
|
||||
if err != nil {
|
||||
a.log.Error("初始化client失败", "app.getmylist", "line:36", err)
|
||||
}
|
||||
@@ -52,11 +57,10 @@ func (a *appStruct) GetMyList(index, size int, position bool) *[]model2.MyAppLis
|
||||
if err != nil {
|
||||
a.log.Error("获取docker容器失败", "app.getmylist", "line:42", err)
|
||||
}
|
||||
|
||||
//获取本地数据库应用
|
||||
|
||||
var lm []model2.AppListDBModel
|
||||
a.db.Table(model2.CONTAINERTABLENAME).Select("title,icon,port_map,`index`,container_id,position,label,slogan").Find(&lm)
|
||||
a.db.Table(model2.CONTAINERTABLENAME).Select("title,icon,port_map,`index`,container_id,position,label,slogan,image").Find(&lm)
|
||||
|
||||
list := []model2.MyAppList{}
|
||||
lMap := make(map[string]interface{})
|
||||
@@ -69,11 +73,70 @@ func (a *appStruct) GetMyList(index, size int, position bool) *[]model2.MyAppLis
|
||||
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
|
||||
|
||||
}
|
||||
|
||||
//system application list
|
||||
func (a *appStruct) GetSystemAppList() *[]model2.MyAppList {
|
||||
//获取docker应用
|
||||
cli, err := client2.NewClientWithOpts(client2.FromEnv)
|
||||
if err != nil {
|
||||
a.log.Error("初始化client失败", "app.getmylist", "line:36", err)
|
||||
}
|
||||
defer cli.Close()
|
||||
fts := filters.NewArgs()
|
||||
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.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
|
||||
}
|
||||
for _, container := range containers {
|
||||
|
||||
if lMap[container.ID] != nil {
|
||||
var m model2.AppListDBModel
|
||||
m = lMap[container.ID].(model2.AppListDBModel)
|
||||
m := lMap[container.ID].(model2.AppListDBModel)
|
||||
if len(m.Label) == 0 {
|
||||
m.Label = m.Title
|
||||
}
|
||||
@@ -93,11 +156,12 @@ func (a *appStruct) GetMyList(index, size int, position bool) *[]model2.MyAppLis
|
||||
Port: m.PortMap,
|
||||
Index: m.Index,
|
||||
UpTime: tm,
|
||||
Image: m.Image,
|
||||
Slogan: m.Slogan,
|
||||
Volumes: m.Volumes,
|
||||
//Rely: m.Rely,
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return &list
|
||||
@@ -115,7 +179,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 +199,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 +223,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 +232,125 @@ 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) {
|
||||
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)
|
||||
|
||||
var lm []model2.AppListDBModel
|
||||
a.db.Table(model2.CONTAINERTABLENAME).Select("label,title,icon,container_id").Where("origin != ?", "system").Find(&lm)
|
||||
for i := 0; i < 100; i++ {
|
||||
if config.CasaOSGlobalVariables.AppChange {
|
||||
lm = []model2.AppListDBModel{}
|
||||
config.CasaOSGlobalVariables.AppChange = false
|
||||
a.db.Table(model2.CONTAINERTABLENAME).Select("label,title,icon,container_id").Where("origin != ?", "system").Find(&lm)
|
||||
dataApps := dataStats
|
||||
dataStats.Range(func(key, value interface{}) bool {
|
||||
dataStats.Delete(key)
|
||||
return true
|
||||
})
|
||||
for _, v := range lm {
|
||||
m, _ := dataApps.Load(v.ContainerId)
|
||||
if m != nil {
|
||||
dataStats.Store(v.ContainerId, m)
|
||||
}
|
||||
}
|
||||
}
|
||||
var wg sync.WaitGroup
|
||||
for _, v := range lm {
|
||||
wg.Add(1)
|
||||
go func(v model2.AppListDBModel, i int) {
|
||||
defer wg.Done()
|
||||
stats, err := cli.ContainerStats(ctx, v.ContainerId, 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.ContainerId)
|
||||
dockerStats := model.DockerStatsModel{}
|
||||
if m != nil {
|
||||
dockerStats.Pre = m.(model.DockerStatsModel).Data
|
||||
}
|
||||
dockerStats.Data = data
|
||||
dockerStats.Icon = v.Icon
|
||||
if len(v.Label) > 0 {
|
||||
dockerStats.Title = v.Label
|
||||
} else {
|
||||
dockerStats.Title = v.Title
|
||||
}
|
||||
dataStats.Store(v.ContainerId, 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}
|
||||
}
|
||||
|
||||
128
service/casa.go
Normal file
128
service/casa.go
Normal file
@@ -0,0 +1,128 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
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/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
|
||||
}
|
||||
|
||||
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 NewOasisService() CasaService {
|
||||
return &casaService{}
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
|
||||
182
service/disk.go
182
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
|
||||
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,46 +96,44 @@ 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
|
||||
}
|
||||
|
||||
//获取磁盘信息
|
||||
//get disk details
|
||||
func (d *diskService) LSBLK() []model.LSBLKModel {
|
||||
key := "system_lsblk"
|
||||
var n []model.LSBLKModel
|
||||
|
||||
if result, ok := Cache.Get(key); ok {
|
||||
|
||||
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
|
||||
@@ -102,15 +142,13 @@ func (d *diskService) LSBLK() []model.LSBLKModel {
|
||||
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 +171,7 @@ 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)
|
||||
d.log.Fatal("diskservice_lsblk_fsused", err)
|
||||
}
|
||||
n = append(n, i)
|
||||
health = true
|
||||
@@ -141,15 +179,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 +199,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 +216,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 +224,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 +241,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("serial = ?", m.Serial).Delete(&model2.SerialDisk{})
|
||||
d.db.Create(&m)
|
||||
}
|
||||
|
||||
func (d *diskService) UpdateMountPoint(m model2.SerialDisk) {
|
||||
d.db.Model(&model2.SerialDisk{}).Where("serial = ?", m.Serial).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,27 +7,24 @@ import (
|
||||
"encoding/binary"
|
||||
json2 "encoding/json"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"syscall"
|
||||
|
||||
model2 "github.com/IceWhaleTech/CasaOS/service/model"
|
||||
types2 "github.com/IceWhaleTech/CasaOS/types"
|
||||
"github.com/containerd/containerd"
|
||||
"github.com/containerd/containerd/cio"
|
||||
"github.com/containerd/containerd/namespaces"
|
||||
"github.com/containerd/containerd/oci"
|
||||
"syscall"
|
||||
|
||||
"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"
|
||||
|
||||
//"github.com/containerd/containerd/oci"
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/container"
|
||||
"github.com/docker/docker/api/types/filters"
|
||||
"github.com/docker/docker/api/types/mount"
|
||||
"github.com/docker/docker/api/types/network"
|
||||
client2 "github.com/docker/docker/client"
|
||||
"github.com/docker/go-connections/nat"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
@@ -35,6 +32,14 @@ import (
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/container"
|
||||
"github.com/docker/docker/api/types/filters"
|
||||
"github.com/docker/docker/api/types/mount"
|
||||
"github.com/docker/docker/api/types/network"
|
||||
client2 "github.com/docker/docker/client"
|
||||
"github.com/docker/go-connections/nat"
|
||||
)
|
||||
|
||||
type DockerService interface {
|
||||
@@ -47,7 +52,7 @@ type DockerService interface {
|
||||
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)
|
||||
@@ -55,6 +60,8 @@ type DockerService interface {
|
||||
DockerContainerCommit(name string)
|
||||
DockerNetworkModelList() []types.NetworkResource
|
||||
DockerImageInfo(image string)
|
||||
GetNetWorkNameByNetWorkID(id string) (string, error)
|
||||
ContainerExecShell(container_id string) string
|
||||
}
|
||||
|
||||
type dockerService struct {
|
||||
@@ -62,15 +69,20 @@ type dockerService struct {
|
||||
log loger2.OLog
|
||||
}
|
||||
|
||||
func DockerPs() {
|
||||
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
|
||||
}
|
||||
|
||||
//创建默认网络
|
||||
@@ -79,6 +91,7 @@ func DockerNetwork() {
|
||||
cli, _ := client2.NewClientWithOpts(client2.FromEnv)
|
||||
defer cli.Close()
|
||||
d, _ := cli.NetworkList(context.Background(), types.NetworkListOptions{})
|
||||
|
||||
for _, resource := range d {
|
||||
if resource.Name == docker.NETWORKNAME {
|
||||
return
|
||||
@@ -87,6 +100,19 @@ func DockerNetwork() {
|
||||
cli.NetworkCreate(context.Background(), docker.NETWORKNAME, types.NetworkCreate{})
|
||||
}
|
||||
|
||||
//根据网络id获取网络名
|
||||
func (ds *dockerService) GetNetWorkNameByNetWorkID(id string) (string, error) {
|
||||
cli, _ := client2.NewClientWithOpts(client2.FromEnv)
|
||||
defer cli.Close()
|
||||
filter := filters.NewArgs()
|
||||
filter.Add("id", id)
|
||||
d, err := cli.NetworkList(context.Background(), types.NetworkListOptions{Filters: filter})
|
||||
if err == nil && len(d) > 0 {
|
||||
return d[0].Name, nil
|
||||
}
|
||||
return "", err
|
||||
}
|
||||
|
||||
//拉取镜像
|
||||
func DockerPull() {
|
||||
|
||||
@@ -131,7 +157,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))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -160,7 +186,6 @@ func (ds *dockerService) DockerImageInfo(image string) {
|
||||
if err != nil {
|
||||
fmt.Print(err)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func MsqlExec(container string) error {
|
||||
@@ -239,6 +264,8 @@ func DockerLogs() {
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
defer i.Close()
|
||||
|
||||
hdr := make([]byte, 8)
|
||||
for {
|
||||
_, err := i.Read(hdr)
|
||||
@@ -257,7 +284,6 @@ func DockerLogs() {
|
||||
_, err = i.Read(dat)
|
||||
fmt.Fprint(w, string(dat))
|
||||
}
|
||||
defer i.Close()
|
||||
}
|
||||
|
||||
//正式内容
|
||||
@@ -306,11 +332,13 @@ func (ds *dockerService) DockerPullImage(imageName string, m model2.AppNotify) e
|
||||
}
|
||||
break
|
||||
}
|
||||
m.Type = types2.NOTIFY_TYPE_INSTALL_LOG
|
||||
m.State = 0
|
||||
m.Speed = 70
|
||||
m.Message = string(buf[:n])
|
||||
MyService.Notify().UpdateLog(m)
|
||||
if !reflect.DeepEqual(m, model2.AppNotify{}) {
|
||||
m.Type = types2.NOTIFY_TYPE_INSTALL_LOG
|
||||
m.State = 0
|
||||
m.Message = string(buf[:n])
|
||||
MyService.Notify().UpdateLog(m)
|
||||
}
|
||||
|
||||
}
|
||||
return err
|
||||
}
|
||||
@@ -323,7 +351,7 @@ func (ds *dockerService) DockerPullImage(imageName string, m model2.AppNotify) e
|
||||
//param udp 容器其他udp端口
|
||||
func (ds *dockerService) DockerContainerCreate(imageName string, containerDbId string, m model.CustomizationPostData, net string) (containerId string, err error) {
|
||||
if len(net) == 0 {
|
||||
net = "oasis"
|
||||
net = "bridge"
|
||||
}
|
||||
|
||||
cli, err := client2.NewClientWithOpts(client2.FromEnv)
|
||||
@@ -337,9 +365,13 @@ 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 := ""
|
||||
for _, portMap := range m.Ports {
|
||||
// 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{}{}
|
||||
@@ -379,6 +411,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)
|
||||
@@ -400,22 +436,34 @@ func (ds *dockerService) DockerContainerCreate(imageName string, containerDbId s
|
||||
res.Devices = append(res.Devices, container.DeviceMapping{PathOnHost: p.Path, PathInContainer: p.ContainerPath})
|
||||
}
|
||||
}
|
||||
hostConfingBind := []string{}
|
||||
// volumes bind
|
||||
volumes := []mount.Mount{}
|
||||
for _, v := range m.Volumes {
|
||||
path := v.Path
|
||||
if len(path) == 0 {
|
||||
path = docker.GetDir(containerDbId, v.ContainerPath)
|
||||
path = docker.GetDir(containerDbId, v.Path)
|
||||
if len(path) == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
}
|
||||
path = strings.ReplaceAll(path, "$AppID", containerDbId)
|
||||
//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
|
||||
// }
|
||||
// }
|
||||
|
||||
volumes = append(volumes, mount.Mount{
|
||||
Type: mount.TypeBind,
|
||||
@@ -423,6 +471,7 @@ func (ds *dockerService) DockerContainerCreate(imageName string, containerDbId s
|
||||
Target: v.ContainerPath,
|
||||
})
|
||||
|
||||
hostConfingBind = append(hostConfingBind, v.Path+":"+v.ContainerPath)
|
||||
}
|
||||
|
||||
rp := container.RestartPolicy{}
|
||||
@@ -430,11 +479,22 @@ func (ds *dockerService) DockerContainerCreate(imageName string, containerDbId s
|
||||
if len(m.Restart) > 0 {
|
||||
rp.Name = m.Restart
|
||||
}
|
||||
// healthTest := []string{}
|
||||
// if len(port) > 0 {
|
||||
// healthTest = []string{"CMD-SHELL", "curl -f http://localhost:" + port + m.Index + " || exit 1"}
|
||||
// }
|
||||
|
||||
// health := &container.HealthConfig{
|
||||
// Test: healthTest,
|
||||
// StartPeriod: 0,
|
||||
// Retries: 1000,
|
||||
// }
|
||||
// fmt.Print(health)
|
||||
config := &container.Config{
|
||||
Image: imageName,
|
||||
Labels: map[string]string{"origin": m.Origin, m.Origin: m.Origin},
|
||||
Env: envArr,
|
||||
// Healthcheck: health,
|
||||
}
|
||||
hostConfig := &container.HostConfig{Resources: res, Mounts: volumes, RestartPolicy: rp, NetworkMode: container.NetworkMode(net)}
|
||||
//if net != "host" {
|
||||
@@ -455,7 +515,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
|
||||
@@ -464,9 +524,11 @@ func (ds *dockerService) DockerContainerRemove(name string) error {
|
||||
err = cli.ContainerRemove(context.Background(), name, types.ContainerRemoveOptions{})
|
||||
|
||||
//路径处理
|
||||
path := docker.GetDir(name, "/config")
|
||||
if !file.CheckNotExist(path) {
|
||||
file.RMDir(path)
|
||||
if !update {
|
||||
path := docker.GetDir(name, "/config")
|
||||
if !file.CheckNotExist(path) {
|
||||
file.RMDir(path)
|
||||
}
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
@@ -727,7 +789,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}
|
||||
}
|
||||
|
||||
@@ -771,7 +833,6 @@ func Containerd() {
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
fmt.Println("333")
|
||||
fmt.Println(err)
|
||||
}
|
||||
defer container.Delete(ctx, containerd.WithSnapshotCleanup)
|
||||
@@ -779,7 +840,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)
|
||||
@@ -792,7 +852,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)
|
||||
}
|
||||
|
||||
@@ -802,7 +861,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)
|
||||
}
|
||||
|
||||
@@ -811,7 +869,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"`
|
||||
}
|
||||
|
||||
|
||||
|
||||
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()
|
||||
}
|
||||
@@ -26,14 +26,10 @@ 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"`
|
||||
Devices string `json:"devices"`
|
||||
Envs string `json:"envs"`
|
||||
Ports string `json:"ports"`
|
||||
Volumes string `json:"volumes"`
|
||||
Devices string `json:"devices"`
|
||||
//Envs []model.Env `json:"envs"`
|
||||
//Ports []model.PortMap `gorm:"type:json" json:"ports"`
|
||||
//Volumes []model.PathMap `gorm:"type:json" json:"volumes"`
|
||||
@@ -61,4 +57,6 @@ type MyAppList struct {
|
||||
UpTime string `json:"up_time"`
|
||||
Slogan string `json:"slogan"`
|
||||
Rely model.MapStrings `json:"rely"` //[{"mysql":"id"},{"mysql":"id"}]
|
||||
Image string `json:"image"`
|
||||
Volumes string `json:"volumes"`
|
||||
}
|
||||
|
||||
@@ -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:"-"`
|
||||
@@ -17,8 +17,8 @@ type DDNSUpdataDBModel struct {
|
||||
Secret string `json:"secret" form:"secret"`
|
||||
UserName string `json:"user_name" form:"user_name"`
|
||||
Password string `json:"password" form:"password"`
|
||||
CreatedAt time.Time `gorm:"<-:create" json:"created_at"`
|
||||
UpdatedAt time.Time `gorm:"<-:create;<-:update" json:"updated_at"`
|
||||
CreatedAt time.Time `gorm:"<-:create" json:"created_at"`
|
||||
UpdatedAt time.Time `gorm:"<-:create;<-:update" json:"updated_at"`
|
||||
}
|
||||
|
||||
const DDNSLISTTABLENAME = "o_ddns"
|
||||
@@ -39,9 +39,9 @@ type DDNSList struct {
|
||||
|
||||
//定时任务使用
|
||||
type DDNSCoreList struct {
|
||||
Id uint `gorm:"column:id;primary_key" json:"id"`
|
||||
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"`
|
||||
Serial string `json:"serial"`
|
||||
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"
|
||||
}
|
||||
@@ -1,15 +1,15 @@
|
||||
package model
|
||||
|
||||
type AppNotify struct {
|
||||
CustomId string `gorm:"column:custom_id;primary_key" json:"custom_id"`
|
||||
ContainerId string `json:"container_id,omitempty"`
|
||||
State int `json:"state"` //0:一直在变动的未读消息 1:未读 2:已读
|
||||
Message string `json:"message"`
|
||||
CreatedAt string `gorm:"<-:create;autoCreateTime" json:"created_at"`
|
||||
UpdatedAt string `gorm:"<-:create;<-:update;autoUpdateTime" json:"updated_at"`
|
||||
Speed int `json:"speed"`
|
||||
Id string `gorm:"-" json:"id"`
|
||||
Type int `json:"type"` // 1:显示即为已读 2:必须手动点掉 3:error
|
||||
State int `json:"state"` //0:一直在变动的未读消息 1:未读 2:已读
|
||||
Message string `json:"message"`
|
||||
CreatedAt string `json:"created_at"`
|
||||
UpdatedAt string `json:"updated_at"`
|
||||
Id string `json:"id"`
|
||||
Type int `json:"type"` // 1:显示即为已读 2:info 3:warning 4:error 5:success
|
||||
Icon string `json:"icon"`
|
||||
Name string `json:"name"`
|
||||
CustomId string `gorm:"column:custom_id;primary_key" json:"custom_id"`
|
||||
}
|
||||
|
||||
func (p *AppNotify) TableName() string {
|
||||
|
||||
@@ -1,89 +0,0 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
json2 "encoding/json"
|
||||
"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/tidwall/gjson"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
type OasisService interface {
|
||||
GetServerList(index, size, tp, categoryId, key string) ([]model.ServerAppList, int64)
|
||||
GetServerCategoryList() []model.ServerCategoryList
|
||||
GetTaskList(size int) []model2.TaskDBModel
|
||||
}
|
||||
|
||||
type oasisService struct {
|
||||
}
|
||||
|
||||
func (o *oasisService) GetTaskList(size int) []model2.TaskDBModel {
|
||||
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
|
||||
|
||||
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 *oasisService) GetServerList(index, size, tp, categoryId, key string) ([]model.ServerAppList, int64) {
|
||||
|
||||
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
|
||||
|
||||
listS := httper2.Get(config.ServerInfo.ServerApi+"/v1/app/list?index="+index+"&size="+size+"&type="+tp+"&category_id="+categoryId+"&key="+key, head)
|
||||
|
||||
list := []model.ServerAppList{}
|
||||
|
||||
count := gjson.Get(listS, "data.count").Int()
|
||||
json2.Unmarshal([]byte(gjson.Get(listS, "data.items").String()), &list)
|
||||
|
||||
return list, count
|
||||
}
|
||||
|
||||
func (o *oasisService) GetServerCategoryList() []model.ServerCategoryList {
|
||||
|
||||
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
|
||||
|
||||
listS := httper2.Get(config.ServerInfo.ServerApi+"/v1/app/category", head)
|
||||
|
||||
list := []model.ServerCategoryList{}
|
||||
|
||||
json2.Unmarshal([]byte(gjson.Get(listS, "data").String()), &list)
|
||||
|
||||
return list
|
||||
}
|
||||
|
||||
func NewOasisService() OasisService {
|
||||
return &oasisService{}
|
||||
}
|
||||
57
service/search.go
Normal file
57
service/search.go
Normal file
@@ -0,0 +1,57 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"path"
|
||||
"strings"
|
||||
|
||||
"github.com/IceWhaleTech/CasaOS/model"
|
||||
"github.com/IceWhaleTech/CasaOS/types"
|
||||
)
|
||||
|
||||
type SearchService interface {
|
||||
SearchList(key string) ([]model.SearchFileInfo, error)
|
||||
}
|
||||
|
||||
type searchService struct {
|
||||
}
|
||||
|
||||
func (s *searchService) SearchList(key string) ([]model.SearchFileInfo, error) {
|
||||
pathName := "/Users/liangjianli/go/CasaOSNew/searchTest"
|
||||
resArr := []model.SearchFileInfo{}
|
||||
files, _ := ioutil.ReadDir(pathName)
|
||||
for _, file := range files {
|
||||
if file.IsDir() {
|
||||
tempArr, err := s.SearchList(pathName + "/" + file.Name())
|
||||
if err != nil {
|
||||
resArr = append(resArr, tempArr...)
|
||||
}
|
||||
} else {
|
||||
if strings.Contains(file.Name(), key) {
|
||||
resArr = append(resArr, model.SearchFileInfo{Path: pathName, Name: file.Name(), Type: GetSearchType(path.Ext(file.Name()))})
|
||||
}
|
||||
fmt.Println(pathName + "/" + file.Name())
|
||||
}
|
||||
}
|
||||
return resArr, nil
|
||||
}
|
||||
|
||||
func GetSearchType(ext string) int {
|
||||
var reType int = types.UNKNOWN
|
||||
switch ext {
|
||||
case ".png":
|
||||
reType = types.PICTURE
|
||||
case ".mp4":
|
||||
reType = types.MEDIA
|
||||
case ".mp3":
|
||||
reType = types.MUSIC
|
||||
default:
|
||||
reType = types.UNKNOWN
|
||||
}
|
||||
return reType
|
||||
}
|
||||
|
||||
func NewSearchService() SearchService {
|
||||
return &searchService{}
|
||||
}
|
||||
@@ -2,9 +2,12 @@ package service
|
||||
|
||||
import (
|
||||
loger2 "github.com/IceWhaleTech/CasaOS/pkg/utils/loger"
|
||||
"github.com/patrickmn/go-cache"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
var Cache *cache.Cache
|
||||
|
||||
var MyService Repository
|
||||
|
||||
type Repository interface {
|
||||
@@ -15,7 +18,7 @@ type Repository interface {
|
||||
//Redis() RedisService
|
||||
ZeroTier() ZeroTierService
|
||||
ZiMa() ZiMaService
|
||||
OAPI() OasisService
|
||||
OAPI() CasaService
|
||||
Disk() DiskService
|
||||
Notify() NotifyServer
|
||||
ShareDirectory() ShareDirService
|
||||
@@ -23,25 +26,28 @@ type Repository interface {
|
||||
Rely() RelyService
|
||||
System() SystemService
|
||||
Shortcuts() ShortcutsService
|
||||
Search() SearchService
|
||||
}
|
||||
|
||||
func NewService(db *gorm.DB, log loger2.OLog) Repository {
|
||||
|
||||
return &store{
|
||||
app: NewAppService(db, log),
|
||||
ddns: NewDDNSService(db, log),
|
||||
user: NewUserService(),
|
||||
docker: NewDcokerService(log),
|
||||
docker: NewDockerService(log),
|
||||
//redis: NewRedisService(rp),
|
||||
zerotier: NewZeroTierService(),
|
||||
zima: NewZiMaService(),
|
||||
oapi: NewOasisService(),
|
||||
disk: NewDiskService(log),
|
||||
disk: NewDiskService(log, db),
|
||||
notify: NewNotifyService(db),
|
||||
shareDirectory: NewShareDirService(db, log),
|
||||
task: NewTaskService(db, log),
|
||||
rely: NewRelyService(db, log),
|
||||
system: NewSystemService(log),
|
||||
shortcuts: NewShortcutsService(db),
|
||||
search: NewSearchService(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -53,7 +59,7 @@ type store struct {
|
||||
docker DockerService
|
||||
zerotier ZeroTierService
|
||||
zima ZiMaService
|
||||
oapi OasisService
|
||||
oapi CasaService
|
||||
disk DiskService
|
||||
notify NotifyServer
|
||||
shareDirectory ShareDirService
|
||||
@@ -61,6 +67,7 @@ type store struct {
|
||||
rely RelyService
|
||||
system SystemService
|
||||
shortcuts ShortcutsService
|
||||
search SearchService
|
||||
}
|
||||
|
||||
func (c *store) Rely() RelyService {
|
||||
@@ -99,7 +106,7 @@ func (c *store) ZeroTier() ZeroTierService {
|
||||
func (c *store) ZiMa() ZiMaService {
|
||||
return c.zima
|
||||
}
|
||||
func (c *store) OAPI() OasisService {
|
||||
func (c *store) OAPI() CasaService {
|
||||
return c.oapi
|
||||
}
|
||||
|
||||
@@ -112,3 +119,6 @@ func (c *store) ShareDirectory() ShareDirService {
|
||||
func (c *store) Task() TaskService {
|
||||
return c.task
|
||||
}
|
||||
func (c *store) Search() SearchService {
|
||||
return c.search
|
||||
}
|
||||
|
||||
@@ -1,67 +1,76 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"github.com/IceWhaleTech/CasaOS/model"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
|
||||
"github.com/IceWhaleTech/CasaOS/pkg/config"
|
||||
command2 "github.com/IceWhaleTech/CasaOS/pkg/utils/command"
|
||||
"github.com/IceWhaleTech/CasaOS/pkg/utils/loger"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
type SystemService interface {
|
||||
UpSystemConfig(systemConfig model.SystemConfig)
|
||||
UpSystemConfig(str string, widget string)
|
||||
UpdateSystemVersion(version string)
|
||||
GetSystemConfigDebug() []string
|
||||
GetCasaOSLogs(lineNumber int) string
|
||||
UpdateAssist()
|
||||
UpSystemPort(port string)
|
||||
GetTimeZone() string
|
||||
}
|
||||
type systemService struct {
|
||||
log loger.OLog
|
||||
}
|
||||
|
||||
func (s *systemService) UpdateSystemVersion(version string) {
|
||||
s.log.Error(version)
|
||||
//command2.OnlyExec(config.AppInfo.ProjectPath + "/shell/tool.sh -r " + version)
|
||||
//s.log.Error(config.AppInfo.ProjectPath + "/shell/tool.sh -r " + version)
|
||||
s.log.Error(command2.ExecResultStrArray("source " + config.AppInfo.ProjectPath + "/shell/tools.sh ;update " + version))
|
||||
//s.log.Error(command2.ExecResultStr(config.AppInfo.ProjectPath + "/shell/tool.sh -r " + version))
|
||||
}
|
||||
func (s *systemService) UpdateAssist() {
|
||||
s.log.Error(command2.ExecResultStrArray("source " + config.AppInfo.ProjectPath + "/shell/assist.sh"))
|
||||
}
|
||||
|
||||
func (s *systemService) GetTimeZone() string {
|
||||
return command2.ExecResultStr("source " + config.AppInfo.ProjectPath + "/shell/helper.sh ;GetTimeZone")
|
||||
}
|
||||
|
||||
func (s *systemService) GetSystemConfigDebug() []string {
|
||||
return command2.ExecResultStrArray("source " + config.AppInfo.ProjectPath + "/shell/helper.sh ;GetSysInfo")
|
||||
}
|
||||
func (s *systemService) UpSystemConfig(systemConfig model.SystemConfig) {
|
||||
if systemConfig.AutoUpdate != config.SystemConfigInfo.AutoUpdate {
|
||||
config.Cfg.Section("system").Key("AutoUpdate").SetValue(strconv.FormatBool(systemConfig.AutoUpdate))
|
||||
config.SystemConfigInfo.AutoUpdate = systemConfig.AutoUpdate
|
||||
func (s *systemService) UpSystemConfig(str string, widget string) {
|
||||
if len(str) > 0 && str != config.SystemConfigInfo.ConfigStr {
|
||||
config.Cfg.Section("system").Key("ConfigStr").SetValue(str)
|
||||
config.SystemConfigInfo.ConfigStr = str
|
||||
}
|
||||
if systemConfig.SearchSwitch != config.SystemConfigInfo.SearchSwitch {
|
||||
config.Cfg.Section("system").Key("SearchSwitch").SetValue(strconv.FormatBool(systemConfig.SearchSwitch))
|
||||
config.SystemConfigInfo.SearchSwitch = systemConfig.SearchSwitch
|
||||
if len(widget) > 0 && widget != config.SystemConfigInfo.WidgetList {
|
||||
config.Cfg.Section("system").Key("WidgetList").SetValue(widget)
|
||||
config.SystemConfigInfo.WidgetList = widget
|
||||
}
|
||||
if systemConfig.WidgetsSwitch != config.SystemConfigInfo.WidgetsSwitch {
|
||||
config.Cfg.Section("system").Key("WidgetsSwitch").SetValue(strconv.FormatBool(systemConfig.WidgetsSwitch))
|
||||
config.SystemConfigInfo.WidgetsSwitch = systemConfig.WidgetsSwitch
|
||||
}
|
||||
if systemConfig.ShortcutsSwitch != config.SystemConfigInfo.ShortcutsSwitch {
|
||||
config.Cfg.Section("system").Key("ShortcutsSwitch").SetValue(strconv.FormatBool(systemConfig.ShortcutsSwitch))
|
||||
config.SystemConfigInfo.ShortcutsSwitch = systemConfig.ShortcutsSwitch
|
||||
}
|
||||
if len(systemConfig.SearchEngine) > 0 && systemConfig.SearchEngine != config.SystemConfigInfo.SearchEngine {
|
||||
config.Cfg.Section("system").Key("SearchEngine").SetValue(systemConfig.SearchEngine)
|
||||
config.SystemConfigInfo.SearchEngine = systemConfig.SearchEngine
|
||||
}
|
||||
// if len(systemConfig.Version) > 0 && systemConfig.Version != config.SystemConfigInfo.Version {
|
||||
// config.Cfg.Section("system").Key("Version").SetValue(systemConfig.Version)
|
||||
// config.SystemConfigInfo.Version = systemConfig.Version
|
||||
//}
|
||||
if len(systemConfig.Background) > 0 && systemConfig.Background != config.SystemConfigInfo.Background {
|
||||
config.Cfg.Section("system").Key("Background").SetValue(systemConfig.Background)
|
||||
config.SystemConfigInfo.Background = systemConfig.Background
|
||||
}
|
||||
if len(systemConfig.BackgroundType) > 0 && systemConfig.BackgroundType != config.SystemConfigInfo.BackgroundType {
|
||||
config.Cfg.Section("system").Key("BackgroundType").SetValue(systemConfig.BackgroundType)
|
||||
config.SystemConfigInfo.BackgroundType = systemConfig.BackgroundType
|
||||
}
|
||||
config.Cfg.SaveTo("conf/conf.ini")
|
||||
config.Cfg.SaveTo(config.SystemConfigInfo.ConfigPath)
|
||||
}
|
||||
func (s *systemService) UpSystemPort(port string) {
|
||||
if len(port) > 0 && port != config.ServerInfo.HttpPort {
|
||||
config.Cfg.Section("server").Key("HttpPort").SetValue(port)
|
||||
config.ServerInfo.HttpPort = port
|
||||
}
|
||||
config.Cfg.SaveTo(config.SystemConfigInfo.ConfigPath)
|
||||
}
|
||||
func (s *systemService) GetCasaOSLogs(lineNumber int) string {
|
||||
file, err := os.Open(s.log.Path())
|
||||
if err != nil {
|
||||
return err.Error()
|
||||
}
|
||||
defer file.Close()
|
||||
content, err := ioutil.ReadAll(file)
|
||||
if err != nil {
|
||||
return err.Error()
|
||||
}
|
||||
|
||||
return string(content)
|
||||
}
|
||||
|
||||
func NewSystemService(log loger.OLog) SystemService {
|
||||
return &systemService{log: log}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,8 @@ package service
|
||||
|
||||
import (
|
||||
json2 "encoding/json"
|
||||
"strconv"
|
||||
|
||||
"github.com/IceWhaleTech/CasaOS/pkg/config"
|
||||
httper2 "github.com/IceWhaleTech/CasaOS/pkg/utils/httper"
|
||||
loger2 "github.com/IceWhaleTech/CasaOS/pkg/utils/loger"
|
||||
@@ -9,7 +11,6 @@ import (
|
||||
"github.com/IceWhaleTech/CasaOS/types"
|
||||
"github.com/tidwall/gjson"
|
||||
"gorm.io/gorm"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
type TaskService interface {
|
||||
@@ -80,12 +81,12 @@ func (s *taskService) GetServerTasks() []model.TaskDBModel {
|
||||
list := []model.TaskDBModel{}
|
||||
json2.Unmarshal([]byte(gjson.Get(listS, "data").String()), &list)
|
||||
|
||||
go func(list []model.TaskDBModel) {
|
||||
for _, dbModel := range list {
|
||||
dbModel.Id = 0
|
||||
s.db.Create(&dbModel)
|
||||
}
|
||||
}(list)
|
||||
//go func(list []model.TaskDBModel) {
|
||||
// for _, dbModel := range list {
|
||||
// dbModel.Id = 0
|
||||
// s.db.Create(&dbModel)
|
||||
// }
|
||||
//}(list)
|
||||
return list
|
||||
}
|
||||
func (s *taskService) SyncTaskService() {
|
||||
@@ -133,12 +134,12 @@ func SyncTask(db *gorm.DB) {
|
||||
list := []model.TaskDBModel{}
|
||||
json2.Unmarshal([]byte(gjson.Get(listS, "data").String()), &list)
|
||||
|
||||
//go func(list []model.TaskDBModel) {
|
||||
// for _, dbModel := range list {
|
||||
// dbModel.Id = 0
|
||||
// db.Create(&dbModel)
|
||||
// }
|
||||
//}(list)
|
||||
go func(list []model.TaskDBModel) {
|
||||
for _, dbModel := range list {
|
||||
dbModel.Id = 0
|
||||
db.Create(&dbModel)
|
||||
}
|
||||
}(list)
|
||||
}
|
||||
func NewTaskService(db *gorm.DB, log loger2.OLog) TaskService {
|
||||
return &taskService{db: db, log: log}
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"github.com/IceWhaleTech/CasaOS/pkg/config"
|
||||
"io"
|
||||
"mime/multipart"
|
||||
"os"
|
||||
|
||||
"github.com/IceWhaleTech/CasaOS/pkg/config"
|
||||
)
|
||||
|
||||
type UserService interface {
|
||||
@@ -20,6 +21,8 @@ func (c *user) SetUser(username, pwd, token, email, desc string) error {
|
||||
if len(username) > 0 {
|
||||
config.Cfg.Section("user").Key("UserName").SetValue(username)
|
||||
config.UserInfo.UserName = username
|
||||
config.Cfg.Section("user").Key("Initialized").SetValue("true")
|
||||
config.UserInfo.Initialized = true
|
||||
}
|
||||
if len(pwd) > 0 {
|
||||
config.Cfg.Section("user").Key("PWD").SetValue(pwd)
|
||||
@@ -37,7 +40,7 @@ func (c *user) SetUser(username, pwd, token, email, desc string) error {
|
||||
config.Cfg.Section("user").Key("Description").SetValue(desc)
|
||||
config.UserInfo.Description = desc
|
||||
}
|
||||
config.Cfg.SaveTo("conf/conf.ini")
|
||||
config.Cfg.SaveTo(config.SystemConfigInfo.ConfigPath)
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
@@ -4,18 +4,20 @@ import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/IceWhaleTech/CasaOS/pkg/config"
|
||||
command2 "github.com/IceWhaleTech/CasaOS/pkg/utils/command"
|
||||
httper2 "github.com/IceWhaleTech/CasaOS/pkg/utils/httper"
|
||||
"github.com/IceWhaleTech/CasaOS/pkg/zerotier"
|
||||
"github.com/PuerkitoBio/goquery"
|
||||
"github.com/tidwall/gjson"
|
||||
"io/ioutil"
|
||||
"math/rand"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
"unicode"
|
||||
|
||||
"github.com/IceWhaleTech/CasaOS/pkg/config"
|
||||
command2 "github.com/IceWhaleTech/CasaOS/pkg/utils/command"
|
||||
httper2 "github.com/IceWhaleTech/CasaOS/pkg/utils/httper"
|
||||
"github.com/IceWhaleTech/CasaOS/pkg/zerotier"
|
||||
"github.com/PuerkitoBio/goquery"
|
||||
"github.com/tidwall/gjson"
|
||||
)
|
||||
|
||||
type ZeroTierService interface {
|
||||
@@ -33,21 +35,22 @@ type ZeroTierService interface {
|
||||
DeleteMember(token string, id, mId string) interface{}
|
||||
DeleteNetwork(token, id string) interface{}
|
||||
GetJoinNetworks() string
|
||||
NetworkIdFilter(letter rune) bool
|
||||
}
|
||||
type zerotierstruct struct {
|
||||
type zerotierStruct struct {
|
||||
}
|
||||
|
||||
var client http.Client
|
||||
|
||||
func (c *zerotierstruct) ZeroTierJoinNetwork(networkId string) {
|
||||
func (c *zerotierStruct) ZeroTierJoinNetwork(networkId string) {
|
||||
command2.OnlyExec(`zerotier-cli join ` + networkId)
|
||||
}
|
||||
func (c *zerotierstruct) ZeroTierLeaveNetwork(networkId string) {
|
||||
func (c *zerotierStruct) ZeroTierLeaveNetwork(networkId string) {
|
||||
command2.OnlyExec(`zerotier-cli leave ` + networkId)
|
||||
}
|
||||
|
||||
//登录并获取token
|
||||
func (c *zerotierstruct) GetToken(username, pwd string) string {
|
||||
func (c *zerotierStruct) GetToken(username, pwd string) string {
|
||||
if len(config.ZeroTierInfo.Token) > 0 {
|
||||
return config.ZeroTierInfo.Token
|
||||
} else {
|
||||
@@ -55,7 +58,7 @@ func (c *zerotierstruct) GetToken(username, pwd string) string {
|
||||
}
|
||||
}
|
||||
|
||||
func (c *zerotierstruct) ZeroTierRegister(email, lastName, firstName, password string) string {
|
||||
func (c *zerotierStruct) ZeroTierRegister(email, lastName, firstName, password string) string {
|
||||
|
||||
url := "https://accounts.zerotier.com/auth/realms/zerotier/protocol/openid-connect/registrations?client_id=zt-central&redirect_uri=https%3A%2F%2Fmy.zerotier.com%2Fapi%2F_auth%2Foidc%2Fcallback&response_type=code&scope=openid+profile+email+offline_access&state=state"
|
||||
|
||||
@@ -210,7 +213,7 @@ func ZeroTierGet(url string, cookies []*http.Cookie, t uint8) (action string, c
|
||||
}
|
||||
|
||||
//模拟提交表单
|
||||
func ZeroTierPost(str bytes.Buffer, action string, cookes []*http.Cookie, isLogin bool) (url, errInfo string, err error) {
|
||||
func ZeroTierPost(str bytes.Buffer, action string, cookies []*http.Cookie, isLogin bool) (url, errInfo string, err error) {
|
||||
req, err := http.NewRequest(http.MethodPost, action, strings.NewReader(str.String()))
|
||||
if err != nil {
|
||||
return "", "", errors.New("newrequest error")
|
||||
@@ -219,7 +222,7 @@ func ZeroTierPost(str bytes.Buffer, action string, cookes []*http.Cookie, isLogi
|
||||
req.Header.Set(k, v)
|
||||
}
|
||||
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
|
||||
for _, cookie := range cookes {
|
||||
for _, cookie := range cookies {
|
||||
req.AddCookie(cookie)
|
||||
}
|
||||
res, err := client.Do(req)
|
||||
@@ -273,71 +276,78 @@ func ZeroTierPost(str bytes.Buffer, action string, cookes []*http.Cookie, isLogi
|
||||
}
|
||||
|
||||
//获取zerotile网络列表和本地用户已加入的网络
|
||||
func (c *zerotierstruct) ZeroTierNetworkList(token string) (interface{}, []string) {
|
||||
func (c *zerotierStruct) ZeroTierNetworkList(token string) (interface{}, []string) {
|
||||
url := "https://my.zerotier.com/api/network"
|
||||
return zerotier.GetData(url, token), command2.ExecResultStrArray(`zerotier-cli listnetworks | awk 'NR>1 {print $3} {line=$0}'`)
|
||||
}
|
||||
|
||||
// get network info
|
||||
func (c *zerotierstruct) ZeroTierGetInfo(token, id string) (interface{}, []string) {
|
||||
func (c *zerotierStruct) ZeroTierGetInfo(token, id string) (interface{}, []string) {
|
||||
url := "https://my.zerotier.com/api/network/" + id
|
||||
info := zerotier.GetData(url, token)
|
||||
return info, command2.ExecResultStrArray(`zerotier-cli listnetworks | awk 'NR>1 {print $3} {line=$0}'`)
|
||||
}
|
||||
|
||||
//get status
|
||||
func (c *zerotierstruct) ZeroTierGetStatus(token string) interface{} {
|
||||
func (c *zerotierStruct) ZeroTierGetStatus(token string) interface{} {
|
||||
url := "https://my.zerotier.com/api/v1/status"
|
||||
info := zerotier.GetData(url, token)
|
||||
return info
|
||||
}
|
||||
|
||||
func (c *zerotierstruct) EditNetwork(token string, data string, id string) interface{} {
|
||||
func (c *zerotierStruct) EditNetwork(token string, data string, id string) interface{} {
|
||||
url := "https://my.zerotier.com/api/v1/network/" + id
|
||||
info := zerotier.PostData(url, token, data)
|
||||
return info
|
||||
}
|
||||
|
||||
func (c *zerotierstruct) EditNetworkMember(token string, data string, id, mId string) interface{} {
|
||||
func (c *zerotierStruct) EditNetworkMember(token string, data string, id, mId string) interface{} {
|
||||
url := "https://my.zerotier.com/api/v1/network/" + id + "/member/" + mId
|
||||
info := zerotier.PostData(url, token, data)
|
||||
return info
|
||||
}
|
||||
|
||||
func (c *zerotierstruct) MemberList(token string, id string) interface{} {
|
||||
func (c *zerotierStruct) MemberList(token string, id string) interface{} {
|
||||
url := "https://my.zerotier.com/api/v1/network/" + id + "/member"
|
||||
info := zerotier.GetData(url, token)
|
||||
return info
|
||||
}
|
||||
|
||||
func (c *zerotierstruct) DeleteMember(token string, id, mId string) interface{} {
|
||||
func (c *zerotierStruct) DeleteMember(token string, id, mId string) interface{} {
|
||||
url := "https://my.zerotier.com/api/v1/network/" + id + "/member/" + mId
|
||||
info := zerotier.DeleteMember(url, token)
|
||||
return info
|
||||
}
|
||||
|
||||
func (c *zerotierstruct) DeleteNetwork(token, id string) interface{} {
|
||||
func (c *zerotierStruct) DeleteNetwork(token, id string) interface{} {
|
||||
url := "https://my.zerotier.com/api/v1/network/" + id
|
||||
info := zerotier.DeleteMember(url, token)
|
||||
return info
|
||||
}
|
||||
|
||||
func (c *zerotierstruct) CreateNetwork(token string) interface{} {
|
||||
func (c *zerotierStruct) CreateNetwork(token string) interface{} {
|
||||
url := "https://my.zerotier.com/api/v1/network"
|
||||
info := zerotier.PostData(url, token, "{}")
|
||||
return info
|
||||
}
|
||||
|
||||
func (c *zerotierstruct) GetJoinNetworks() string {
|
||||
func (c *zerotierStruct) GetJoinNetworks() string {
|
||||
json := command2.ExecResultStr("source " + config.AppInfo.ProjectPath + "/shell/helper.sh ;GetLocalJoinNetworks")
|
||||
return json
|
||||
}
|
||||
|
||||
func (c *zerotierStruct) NetworkIdFilter(letter rune) bool {
|
||||
if unicode.IsNumber(letter) || unicode.IsLetter(letter) {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
func NewZeroTierService() ZeroTierService {
|
||||
//初始化client
|
||||
client = http.Client{Timeout: 30 * time.Second, CheckRedirect: func(req *http.Request, via []*http.Request) error {
|
||||
return http.ErrUseLastResponse //禁止重定向
|
||||
},
|
||||
}
|
||||
return &zerotierstruct{}
|
||||
return &zerotierStruct{}
|
||||
}
|
||||
|
||||
@@ -2,20 +2,23 @@ package service
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/IceWhaleTech/CasaOS/model"
|
||||
"github.com/IceWhaleTech/CasaOS/pkg/config"
|
||||
command2 "github.com/IceWhaleTech/CasaOS/pkg/utils/command"
|
||||
"github.com/IceWhaleTech/CasaOS/pkg/utils/file"
|
||||
"github.com/IceWhaleTech/CasaOS/pkg/utils/oasis_err"
|
||||
"github.com/shirou/gopsutil/v3/cpu"
|
||||
"github.com/shirou/gopsutil/v3/disk"
|
||||
"github.com/shirou/gopsutil/v3/host"
|
||||
"github.com/shirou/gopsutil/v3/mem"
|
||||
"github.com/shirou/gopsutil/v3/net"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
//系统信息
|
||||
@@ -30,6 +33,7 @@ type ZiMaService interface {
|
||||
GetSysInfo() host.InfoStat
|
||||
GetDirPath(path string) []model.Path
|
||||
MkdirAll(path string) (int, error)
|
||||
CreateFile(path string) (int, error)
|
||||
RenameFile(oldF, newF string) (int, error)
|
||||
GetCpuInfo() []cpu.InfoStat
|
||||
}
|
||||
@@ -81,17 +85,12 @@ func (c *zima) GetDirPath(path string) []model.Path {
|
||||
ls, _ := ioutil.ReadDir(path)
|
||||
dirs := []model.Path{}
|
||||
|
||||
if strings.Count(path, "/") > 1 {
|
||||
|
||||
if strings.Count(path, "/") > 0 {
|
||||
for _, l := range ls {
|
||||
if !strings.HasPrefix(l.Name(), ".") && l.IsDir() {
|
||||
dirs = append(dirs, model.Path{Name: l.Name(), Path: path + l.Name() + "/"})
|
||||
}
|
||||
dirs = append(dirs, model.Path{Name: l.Name(), Path: path + "/" + l.Name(), IsDir: l.IsDir(), Date: l.ModTime()})
|
||||
}
|
||||
} else {
|
||||
dirs = append(dirs, model.Path{Name: "mnt", Path: "/mnt/"})
|
||||
dirs = append(dirs, model.Path{Name: "media", Path: "/media/"})
|
||||
dirs = append(dirs, model.Path{Name: "home", Path: "/home/"})
|
||||
dirs = append(dirs, model.Path{Name: "DATA", Path: "/DATA/", IsDir: true, Date: time.Now()})
|
||||
}
|
||||
return dirs
|
||||
}
|
||||
@@ -118,7 +117,6 @@ func (c *zima) GetNetState(name string) string {
|
||||
|
||||
//网络信息
|
||||
func (c *zima) GetNetInfo() []net.IOCountersStat {
|
||||
//loger.Error("输出个内容试试")
|
||||
parts, _ := net.IOCounters(true)
|
||||
//fmt.Println(net.ConntrackStatsWithContext(true))
|
||||
return parts
|
||||
@@ -133,6 +131,22 @@ func (c *zima) MkdirAll(path string) (int, error) {
|
||||
if os.IsNotExist(err) {
|
||||
os.MkdirAll(path, os.ModePerm)
|
||||
return oasis_err.SUCCESS, nil
|
||||
} else if strings.Contains(err.Error(), ": not a directory") {
|
||||
return oasis_err.FILE_OR_DIR_EXISTS, err
|
||||
}
|
||||
}
|
||||
return oasis_err.ERROR, err
|
||||
}
|
||||
|
||||
//create
|
||||
func (c *zima) CreateFile(path string) (int, error) {
|
||||
_, err := os.Stat(path)
|
||||
if err == nil {
|
||||
return oasis_err.FILE_OR_DIR_EXISTS, nil
|
||||
} else {
|
||||
if os.IsNotExist(err) {
|
||||
file.CreateFile(path)
|
||||
return oasis_err.SUCCESS, nil
|
||||
}
|
||||
}
|
||||
return oasis_err.ERROR, err
|
||||
|
||||
43
shell/assist.sh
Normal file
43
shell/assist.sh
Normal file
@@ -0,0 +1,43 @@
|
||||
#!/bin/bash
|
||||
|
||||
#add in v0.2.3
|
||||
version_0_2_3() {
|
||||
((EUID)) && sudo_cmd="sudo"
|
||||
$sudo_cmd cp -rf /casaOS/server/shell/11-usb-mount.rules /etc/udev/rules.d/
|
||||
$sudo_cmd chmod +x /casaOS/server/shell/usb-mount.sh
|
||||
$sudo_cmd cp -rf /casaOS/server/shell/usb-mount@.service /etc/systemd/system/
|
||||
|
||||
}
|
||||
|
||||
# add in v0.2.5
|
||||
|
||||
readonly CASA_DEPANDS="curl smartmontools parted fdisk partprobe"
|
||||
|
||||
version_0_2_5() {
|
||||
install_depends "$CASA_DEPANDS"
|
||||
}
|
||||
|
||||
|
||||
#Install Depends
|
||||
install_depends() {
|
||||
((EUID)) && sudo_cmd="sudo"
|
||||
if [[ ! -x "$(command -v '$1')" ]]; then
|
||||
show 2 "Install the necessary dependencies: $1"
|
||||
packagesNeeded=$1
|
||||
if [ -x "$(command -v apk)" ]; then
|
||||
$sudo_cmd apk add --no-cache $packagesNeeded
|
||||
elif [ -x "$(command -v apt-get)" ]; then
|
||||
$sudo_cmd apt-get -y -q install $packagesNeeded
|
||||
elif [ -x "$(command -v dnf)" ]; then
|
||||
$sudo_cmd dnf install $packagesNeeded
|
||||
elif [ -x "$(command -v zypper)" ]; then
|
||||
$sudo_cmd zypper install $packagesNeeded
|
||||
else
|
||||
show 1 "Package manager not found. You must manually install: $packagesNeeded"
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
version_0_2_3
|
||||
|
||||
version_0_2_5
|
||||
206
shell/helper.sh
206
shell/helper.sh
@@ -30,6 +30,11 @@ GetNetCard() {
|
||||
fi
|
||||
}
|
||||
|
||||
|
||||
GetTimeZone(){
|
||||
timedatectl | grep "Time zone" | awk '{print $3}'
|
||||
}
|
||||
|
||||
#查看网卡状态
|
||||
#param 网卡名称
|
||||
CatNetCardState() {
|
||||
@@ -68,10 +73,8 @@ UMountPorintAndRemoveDir() {
|
||||
if [[ -z ${MOUNT_POINT} ]]; then
|
||||
${log} "Warning: ${DEVICE} is not mounted"
|
||||
else
|
||||
umount -l ${DEVICE}
|
||||
${log} "Unmounted ${DEVICE} from ${MOUNT_POINT}"
|
||||
umount -lf ${DEVICE}
|
||||
/bin/rmdir "${MOUNT_POINT}"
|
||||
sed -i.bak "\@${MOUNT_POINT}@d" /var/log/usb-mount.track
|
||||
fi
|
||||
}
|
||||
|
||||
@@ -84,11 +87,11 @@ FormatDisk() {
|
||||
elif [ "$2" == "ntfs" ]; then
|
||||
mkfs.ntfs $1
|
||||
elif [ "$2" == "ext4" ]; then
|
||||
mkfs.ext4 -F $1
|
||||
mkfs.ext4 -m 1 -F $1
|
||||
elif [ "$2" == "exfat" ]; then
|
||||
mkfs.exfat $1
|
||||
else
|
||||
mkfs.ext4 -F $1
|
||||
mkfs.ext4 -m 1 -F $1
|
||||
fi
|
||||
}
|
||||
|
||||
@@ -103,20 +106,20 @@ DelPartition() {
|
||||
EOF
|
||||
}
|
||||
|
||||
#添加分区
|
||||
#添加分区只有一个分区
|
||||
#param 路径 /dev/sdb
|
||||
#param 磁盘号 最大128
|
||||
#param 磁盘大小 字节 512*2048=1024kb=1M
|
||||
#param 要挂载的目录
|
||||
AddPartition() {
|
||||
# fdisk $1 <<EOF
|
||||
# n
|
||||
# $2
|
||||
# $3
|
||||
# $4
|
||||
# wq
|
||||
#EOF
|
||||
|
||||
parted $1 mkpart primary ext4 s3 s4
|
||||
DelPartition $1
|
||||
parted -s $1 mklabel gpt
|
||||
|
||||
parted -s $1 mkpart primary ext4 0 100%
|
||||
|
||||
mkfs.ext4 -m 1 $11
|
||||
|
||||
partprobe $1
|
||||
|
||||
}
|
||||
|
||||
#磁盘类型
|
||||
@@ -141,17 +144,184 @@ GetDiskHealthState() {
|
||||
#result bytes
|
||||
#result sectors
|
||||
GetDiskSizeAndSectors() {
|
||||
fdisk $1 -l | grep "/dev/sda:" | awk -F, 'BEGIN {OFS="\n"}{print $2,$3}' | awk '{print $1}'
|
||||
fdisk $1 -l | grep "$1:" | awk -F, 'BEGIN {OFS="\n"}{print $2,$3}' | awk '{print $1}'
|
||||
}
|
||||
|
||||
#获取磁盘分区数据扇区
|
||||
#param 磁盘路径 /dev/sda
|
||||
#result start,end,sectors
|
||||
GetPartitionSectors() {
|
||||
fdisk $1 -l | grep "/dev/sda[1-9]" | awk 'BEGIN{OFS=","}{print $1,$2,$3,$4}'
|
||||
fdisk $1 -l | grep "$1[1-9]" | awk 'BEGIN{OFS=","}{print $1,$2,$3,$4}'
|
||||
}
|
||||
|
||||
#检查没有使用的挂载点删除文件夹
|
||||
AutoRemoveUnuseDir() {
|
||||
DIRECTORY="/mnt/"
|
||||
dir=$(ls -l $DIRECTORY | awk '/^d/ {print $NF}')
|
||||
for i in $dir; do
|
||||
|
||||
path="$DIRECTORY$i"
|
||||
mountStr=$(mountpoint $path)
|
||||
notMountpoint="is not a mountpoint"
|
||||
if [[ $mountStr =~ $notMountpoint ]]; then
|
||||
if [ "$(ls -A $path)" = "" ]; then
|
||||
rm -fr $path
|
||||
else
|
||||
echo "$path is not empty"
|
||||
fi
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
#重载samba服务
|
||||
ReloadSamba() {
|
||||
/etc/init.d/smbd reload
|
||||
}
|
||||
|
||||
# $1=sda1
|
||||
# $2=volume{1}
|
||||
do_mount() {
|
||||
DEVBASE=$1
|
||||
DEVICE="${DEVBASE}"
|
||||
# See if this drive is already mounted, and if so where
|
||||
MOUNT_POINT=$(mount | grep ${DEVICE} | awk '{ print $3 }')
|
||||
|
||||
if [ -n "${MOUNT_POINT}" ]; then
|
||||
${log} "Warning: ${DEVICE} is already mounted at ${MOUNT_POINT}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Get info for this drive: $ID_FS_LABEL and $ID_FS_TYPE
|
||||
eval $(blkid -o udev ${DEVICE} | grep -i -e "ID_FS_LABEL" -e "ID_FS_TYPE")
|
||||
|
||||
LABEL=$2
|
||||
if grep -q " ${LABEL} " /etc/mtab; then
|
||||
# Already in use, make a unique one
|
||||
LABEL+="-${DEVBASE}"
|
||||
fi
|
||||
DEV_LABEL="${LABEL}"
|
||||
|
||||
# Use the device name in case the drive doesn't have label
|
||||
if [ -z ${DEV_LABEL} ]; then
|
||||
DEV_LABEL="${DEVBASE}"
|
||||
fi
|
||||
|
||||
MOUNT_POINT="${DEV_LABEL}"
|
||||
|
||||
${log} "Mount point: ${MOUNT_POINT}"
|
||||
|
||||
mkdir -p ${MOUNT_POINT}
|
||||
|
||||
case ${ID_FS_TYPE} in
|
||||
vfat)
|
||||
mount -t vfat -o rw,relatime,users,gid=100,umask=000,shortname=mixed,utf8=1,flush ${DEVICE} ${MOUNT_POINT}
|
||||
;;
|
||||
ext[2-4])
|
||||
mount -o noatime ${DEVICE} ${MOUNT_POINT} >/dev/null 2>&1
|
||||
;;
|
||||
exfat)
|
||||
mount -t exfat ${DEVICE} ${MOUNT_POINT} >/dev/null 2>&1
|
||||
;;
|
||||
ntfs)
|
||||
ntfs-3g ${DEVICE} ${MOUNT_POINT}
|
||||
;;
|
||||
iso9660)
|
||||
mount -t iso9660 ${DEVICE} ${MOUNT_POINT}
|
||||
;;
|
||||
*)
|
||||
/bin/rmdir "${MOUNT_POINT}"
|
||||
exit 0
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
# $1=sda1
|
||||
do_umount() {
|
||||
log="logger -t usb-mount.sh -s "
|
||||
DEVBASE=$1
|
||||
DEVICE="${DEVBASE}"
|
||||
MOUNT_POINT=$(mount | grep ${DEVICE} | awk '{ print $3 }')
|
||||
|
||||
if [[ -z ${MOUNT_POINT} ]]; then
|
||||
${log} "Warning: ${DEVICE} is not mounted"
|
||||
else
|
||||
umount -l ${DEVICE}
|
||||
${log} "Unmounted ${DEVICE} from ${MOUNT_POINT}"
|
||||
/bin/rmdir "${MOUNT_POINT}"
|
||||
sed -i.bak "\@${MOUNT_POINT}@d" /var/log/usb-mount.track
|
||||
fi
|
||||
|
||||
}
|
||||
# $1=/mnt/volume1/data.img
|
||||
# $2=100G
|
||||
PackageDocker() {
|
||||
image=$1
|
||||
docker="/mnt/casa_docker"
|
||||
#判断目录docker存在不存在则创建,存在检查是否为空
|
||||
|
||||
if [ ! -d "$docker" ]; then
|
||||
mkdir ${docker}
|
||||
fi
|
||||
|
||||
if [ "$(ls -A $docker)" = "" ]; then
|
||||
echo "$docker count is 0"
|
||||
else
|
||||
mkdir ${docker}_bak
|
||||
mv -r ${docker} ${docker}_bak
|
||||
fi
|
||||
|
||||
daemon="/etc/docker/daemon.json"
|
||||
#1创建img文件在挂载的目录
|
||||
fallocate -l $2 $image
|
||||
#2初始化img文件
|
||||
mkfs -t ext4 $image
|
||||
#3挂载img文件
|
||||
sudo mount -o loop $image $docker
|
||||
#4给移动/var/lib/docker数据到img挂载的目录
|
||||
systemctl stop docker.socket
|
||||
systemctl stop docker
|
||||
cp -r /var/lib/docker/* ${docker}/
|
||||
#5在/etc/docker写入daemon.json(需要检查)
|
||||
if [ -d "$daemon" ]; then
|
||||
mv -r $daemon ${daemon}.bak
|
||||
fi
|
||||
echo "{\"data-root\": \"$docker\"}" >$daemon
|
||||
#删除老数据腾出空间
|
||||
#rm -fr /var/lib/docker
|
||||
systemctl start docker.socket
|
||||
systemctl start docker
|
||||
}
|
||||
|
||||
DockerImgMove() {
|
||||
image=$1
|
||||
systemctl stop docker.socket
|
||||
systemctl stop docker
|
||||
sudo umount -f $image
|
||||
}
|
||||
|
||||
GetDockerDataRoot() {
|
||||
docker info | grep "Docker Root Dir:"
|
||||
}
|
||||
|
||||
SetLink() {
|
||||
ln -s /mnt/casa_sda1/AppData /DATA/AppData
|
||||
#删除所有软链
|
||||
find /DATA -type l -delete
|
||||
}
|
||||
|
||||
#压缩文件夹
|
||||
|
||||
TarFolder() {
|
||||
#压缩
|
||||
tar -zcvf data.tar.gz -C/DATA/ AppDataBak/
|
||||
|
||||
#解压
|
||||
tar zxvf data.tar.gz
|
||||
|
||||
#查看某文件夹下的所有包括子文件夹文件
|
||||
ls /DATA/Media -lR | grep "^-" | wc -l
|
||||
# ls -lR|grep "^d"| wc -l 查看某个文件夹下文件夹的个数,包括子文件夹下的文件夹个数。
|
||||
|
||||
#查看固定文件夹大小
|
||||
du -sh /DATA
|
||||
}
|
||||
|
||||
@@ -60,7 +60,7 @@ show() {
|
||||
}
|
||||
|
||||
run_external_script() {
|
||||
show 0 "run_external_script"
|
||||
assist.sh
|
||||
}
|
||||
|
||||
update() {
|
||||
@@ -99,13 +99,13 @@ update() {
|
||||
target_arch="386"
|
||||
;;
|
||||
*armv5*)
|
||||
target_arch="armv5"
|
||||
target_arch="arm-5"
|
||||
;;
|
||||
*armv6*)
|
||||
target_arch="armv6"
|
||||
target_arch="arm-6"
|
||||
;;
|
||||
*armv7*)
|
||||
target_arch="armv7"
|
||||
target_arch="arm-7"
|
||||
;;
|
||||
*)
|
||||
show 1 "Aborted, unsupported or unknown architecture: $unamem"
|
||||
|
||||
@@ -1,12 +1,10 @@
|
||||
#!/bin/sh
|
||||
#!/bin/bash
|
||||
|
||||
# copy to /oasis/util/shell path
|
||||
# copy to /casaOS/util/shell path
|
||||
# chmod 755
|
||||
|
||||
log="logger -t usb-mount.sh -s "
|
||||
|
||||
${log} "变量:$1 $2"
|
||||
|
||||
ACTION=$1
|
||||
|
||||
DEVBASE=$2
|
||||
@@ -18,10 +16,10 @@ MOUNT_POINT=$(mount | grep ${DEVICE} | awk '{ print $3 }')
|
||||
|
||||
do_mount() {
|
||||
|
||||
if [[ -n ${MOUNT_POINT} ]]; then
|
||||
if [ -n "${MOUNT_POINT}" ]; then
|
||||
${log} "Warning: ${DEVICE} is already mounted at ${MOUNT_POINT}"
|
||||
exit 1
|
||||
fib
|
||||
fi
|
||||
|
||||
# Get info for this drive: $ID_FS_LABEL and $ID_FS_TYPE
|
||||
eval $(blkid -o udev ${DEVICE} | grep -i -e "ID_FS_LABEL" -e "ID_FS_TYPE")
|
||||
@@ -32,23 +30,32 @@ do_mount() {
|
||||
|
||||
# Figure out a mount point to use
|
||||
# LABEL=${ID_FS_LABEL}
|
||||
LABEL=${DEVBASE}
|
||||
if grep -q " /media/${LABEL} " /etc/mtab; then
|
||||
# Already in use, make a unique one
|
||||
LABEL+="-${DEVBASE}"
|
||||
fi
|
||||
DEV_LABEL="${LABEL}"
|
||||
# LABEL=${DEVBASE}
|
||||
# if grep -q " /DATA/USB_${LABEL} " /etc/mtab; then
|
||||
# # Already in use, make a unique one
|
||||
# LABEL+="-${DEVBASE}"
|
||||
# fi
|
||||
# DEV_LABEL="${LABEL}"
|
||||
|
||||
# Use the device name in case the drive doesn't have label
|
||||
if [ -z ${DEV_LABEL} ]; then
|
||||
DEV_LABEL="${DEVBASE}"
|
||||
fi
|
||||
# # Use the device name in case the drive doesn't have label
|
||||
# if [ -z ${DEV_LABEL} ]; then
|
||||
# DEV_LABEL="${DEVBASE}"
|
||||
# fi
|
||||
|
||||
MOUNT_POINT="/media/${DEV_LABEL}"
|
||||
MOUNT_POINT="/DATA/USB_Storage1"
|
||||
arr=("/DATA/USB_Storage1" "/DATA/USB_Storage2" "/DATA/USB_Storage3" "/DATA/USB_Storage4" "/DATA/USB_Storage5" "/DATA/USB_Storage6" "/DATA/USB_Storage7" "/DATA/USB_Storage8" "/DATA/USB_Storage9" "/DATA/USB_Storage10" "/DATA/USB_Storage11" "/DATA/USB_Storage12")
|
||||
for folder in ${arr[@]}; do
|
||||
#如果文件夹不存在,创建文件夹
|
||||
if [ ! -d "$folder" ]; then
|
||||
mkdir -p ${folder}
|
||||
MOUNT_POINT=$folder
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
${log} "Mount point: ${MOUNT_POINT}"
|
||||
|
||||
mkdir -p ${MOUNT_POINT}
|
||||
|
||||
|
||||
# # Global mount options
|
||||
# OPTS="rw,relatime"
|
||||
@@ -86,7 +93,7 @@ do_mount() {
|
||||
mount -t iso9660 ${DEVICE} ${MOUNT_POINT}
|
||||
;;
|
||||
*)
|
||||
/bin/rmdir "${MOUNT_POINT}"
|
||||
/bin/rmdir "${MOUNT_POINT}"
|
||||
exit 0
|
||||
;;
|
||||
esac
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user