mirror of
https://github.com/IceWhaleTech/CasaOS.git
synced 2025-12-23 04:54:41 +00:00
Compare commits
110 Commits
v0.3.2.1
...
v0.3.7-alp
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
50d68f3f76 | ||
|
|
d9c6a5c875 | ||
|
|
4bace9b16a | ||
|
|
84dfa7f5bf | ||
|
|
582f85c3ba | ||
|
|
7f4562629a | ||
|
|
4776b76b16 | ||
|
|
9f938f65b1 | ||
|
|
314dbdab57 | ||
|
|
4ccae3f67f | ||
|
|
9f2e8dae6f | ||
|
|
727aca564b | ||
|
|
70ba4d5e3d | ||
|
|
8d088afcc5 | ||
|
|
34f35bbf20 | ||
|
|
b6f413b9e9 | ||
|
|
091be6d12e | ||
|
|
aefa68d8f8 | ||
|
|
9aed323d8d | ||
|
|
eba607fc53 | ||
|
|
d064f20a04 | ||
|
|
079e431d33 | ||
|
|
cee34ec1c2 | ||
|
|
848ee63386 | ||
|
|
c12c6cc940 | ||
|
|
f31fb22039 | ||
|
|
a5133bdbfa | ||
|
|
1902b2d4f2 | ||
|
|
fc5e351f0b | ||
|
|
7f642a7a4c | ||
|
|
c36a046a15 | ||
|
|
8b2c9486da | ||
|
|
ce5ecfcf84 | ||
|
|
bd1a2f5751 | ||
|
|
d2e0695d73 | ||
|
|
8cd18c3218 | ||
|
|
cc0ba82c92 | ||
|
|
ddca242d23 | ||
|
|
eaa07ba95a | ||
|
|
39a4c29680 | ||
|
|
af6900b1c7 | ||
|
|
9ec43a7691 | ||
|
|
bd85cda9fa | ||
|
|
94eaba6ecb | ||
|
|
e207c9c75f | ||
|
|
81d3293991 | ||
|
|
364fbf01f5 | ||
|
|
87e66aae8a | ||
|
|
3a60db3729 | ||
|
|
d3f78b52fa | ||
|
|
7d67a66d6b | ||
|
|
cb9e1b9dd9 | ||
|
|
dc8282acbb | ||
|
|
cf6103a2b5 | ||
|
|
6f98995e7d | ||
|
|
5cc41fa040 | ||
|
|
cb289f5b8a | ||
|
|
1377d55407 | ||
|
|
06eca38022 | ||
|
|
c47c1e548c | ||
|
|
552ec4849d | ||
|
|
7386a9dce3 | ||
|
|
b2b1daf5ab | ||
|
|
bbc0181e23 | ||
|
|
c23bd3f3a3 | ||
|
|
8a1839c02e | ||
|
|
164bf66190 | ||
|
|
a4c2a4b992 | ||
|
|
e7e82e6ca3 | ||
|
|
574295470e | ||
|
|
b1061f19ad | ||
|
|
bdd9eaca9f | ||
|
|
ec4c672924 | ||
|
|
5d4717de4d | ||
|
|
e2de783152 | ||
|
|
09f68f4034 | ||
|
|
cec83fc048 | ||
|
|
33e1d8a806 | ||
|
|
2a8dafae28 | ||
|
|
a426b56306 | ||
|
|
6202d38bdb | ||
|
|
4626ceb048 | ||
|
|
1e7333118c | ||
|
|
9758436a1e | ||
|
|
ed67e977b7 | ||
|
|
b0b1b5e262 | ||
|
|
2796c37bf6 | ||
|
|
d48e24f652 | ||
|
|
3a8cf593d9 | ||
|
|
0ffa2f901a | ||
|
|
bd73141ddf | ||
|
|
346b0f5d97 | ||
|
|
d4b4b75012 | ||
|
|
cb33ffbb46 | ||
|
|
85188d0b05 | ||
|
|
1e60c26920 | ||
|
|
752134942a | ||
|
|
faf683a02c | ||
|
|
f99f49dd7e | ||
|
|
b0dc30277b | ||
|
|
d91fef0a19 | ||
|
|
6bb044ab04 | ||
|
|
78479f9604 | ||
|
|
8fe893847f | ||
|
|
f506d6ce49 | ||
|
|
5d7c5ba120 | ||
|
|
eedffd7c19 | ||
|
|
0885c1386d | ||
|
|
0297fe67af | ||
|
|
3f53e6f33b |
197
.all-contributorsrc
Normal file
197
.all-contributorsrc
Normal file
@@ -0,0 +1,197 @@
|
||||
{
|
||||
"files": [
|
||||
"README.md"
|
||||
],
|
||||
"imageSize": 100,
|
||||
"badgeTemplate": "<a href=\"#credits\"><img alt=\"All Contributors\" src=\"https://img.shields.io/static/v1?label=All%20Contributors&message=<%= contributors.length %>&color=162453&style=flat-square&logo=Handshake&logoColor=fff\" /></a>",
|
||||
"commit": false,
|
||||
"contributors": [
|
||||
{
|
||||
"login": "jerrykuku",
|
||||
"name": "老竭力",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/9485680?v=4",
|
||||
"profile": "https://github.com/jerrykuku",
|
||||
"contributions": [
|
||||
"code",
|
||||
"doc",
|
||||
"ideas",
|
||||
"infra",
|
||||
"maintenance",
|
||||
"platform",
|
||||
"question",
|
||||
"review"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "LinkLeong",
|
||||
"name": "link",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/13556972?v=4",
|
||||
"profile": "https://github.com/LinkLeong",
|
||||
"contributions": [
|
||||
"code",
|
||||
"doc",
|
||||
"ideas",
|
||||
"infra",
|
||||
"maintenance",
|
||||
"question",
|
||||
"review"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "tigerinus",
|
||||
"name": "Tiger Wang (王豫)",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/7172560?v=4",
|
||||
"profile": "https://github.com/tigerinus",
|
||||
"contributions": [
|
||||
"code",
|
||||
"doc",
|
||||
"ideas",
|
||||
"infra",
|
||||
"maintenance",
|
||||
"mentoring",
|
||||
"security",
|
||||
"question",
|
||||
"review"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "Lauren-ED209",
|
||||
"name": "Lauren",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/8243355?v=4",
|
||||
"profile": "https://github.com/Lauren-ED209",
|
||||
"contributions": [
|
||||
"ideas",
|
||||
"fundingFinding",
|
||||
"projectManagement",
|
||||
"question",
|
||||
"test"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "JohnGuan",
|
||||
"name": "John Guan",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/3358477?v=4",
|
||||
"profile": "https://JohnGuan.Cn",
|
||||
"contributions": [
|
||||
"blog",
|
||||
"content",
|
||||
"doc",
|
||||
"ideas",
|
||||
"eventOrganizing",
|
||||
"mentoring",
|
||||
"question",
|
||||
"review"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "dtaivpp",
|
||||
"name": "David Tippett",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/17506770?v=4",
|
||||
"profile": "https://blog.tippybits.com",
|
||||
"contributions": [
|
||||
"doc",
|
||||
"ideas",
|
||||
"question"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "zarevskaya",
|
||||
"name": "Skaya",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/60230221?v=4",
|
||||
"profile": "https://github.com/zarevskaya",
|
||||
"contributions": [
|
||||
"mentoring",
|
||||
"question",
|
||||
"tutorial",
|
||||
"translation"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "AuthorShin",
|
||||
"name": "AuthorShin",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/4959043?v=4",
|
||||
"profile": "https://github.com/AuthorShin",
|
||||
"contributions": [
|
||||
"test",
|
||||
"bug",
|
||||
"question",
|
||||
"ideas"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "baptiste313",
|
||||
"name": "baptiste313",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/93325157?v=4",
|
||||
"profile": "https://github.com/baptiste313",
|
||||
"contributions": [
|
||||
"translation"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "DrMxrcy",
|
||||
"name": "DrMxrcy",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/58747968?v=4",
|
||||
"profile": "https://github.com/DrMxrcy",
|
||||
"contributions": [
|
||||
"test",
|
||||
"ideas",
|
||||
"question"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "Joooost",
|
||||
"name": "Joooost",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/12090673?v=4",
|
||||
"profile": "https://github.com/Joooost",
|
||||
"contributions": [
|
||||
"ideas"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "sio",
|
||||
"name": "Vitaly Potyarkin",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/334908?v=4",
|
||||
"profile": "https://potyarkin.ml",
|
||||
"contributions": [
|
||||
"ideas"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "bearfrieze",
|
||||
"name": "Bjørn Friese",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/1023813?v=4",
|
||||
"profile": "https://github.com/bearfrieze",
|
||||
"contributions": [
|
||||
"ideas"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "Protektor-Desura",
|
||||
"name": "Protektor",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/1195496?v=4",
|
||||
"profile": "https://github.com/Protektor-Desura",
|
||||
"contributions": [
|
||||
"bug",
|
||||
"ideas",
|
||||
"question"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "llwaini",
|
||||
"name": "llwaini",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/59589857?v=4",
|
||||
"profile": "https://github.com/llwaini",
|
||||
"contributions": [
|
||||
"projectManagement",
|
||||
"test",
|
||||
"tutorial"
|
||||
]
|
||||
}
|
||||
],
|
||||
"contributorsPerLine": 7,
|
||||
"projectName": "CasaOS",
|
||||
"projectOwner": "IceWhaleTech",
|
||||
"repoType": "github",
|
||||
"repoHost": "https://github.com",
|
||||
"skipCi": true
|
||||
}
|
||||
26
.github/ISSUE_TEMPLATE/alpha_bug_report.yaml
vendored
Normal file
26
.github/ISSUE_TEMPLATE/alpha_bug_report.yaml
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
name: "[Alpha Only] Bug Report"
|
||||
description: CasaOS Alpha Testing specific bug report form.
|
||||
title: "[Alpha][Bug] "
|
||||
labels: ["alpha", "bug"]
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
Thanks for taking the time to fill out this bug report!
|
||||
> If you haven't joined CasaOS Alpha Team yet.
|
||||
> Please join first on [Discord](https://discord.gg/knqAbbBbeX) to be updated on the Alpha test plan and test scope.
|
||||
- type: textarea
|
||||
id: what-happened
|
||||
attributes:
|
||||
label: What happened?
|
||||
description: Also tell us, what did you expect to happen?
|
||||
placeholder: Tell us what you see!
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: screenshots
|
||||
attributes:
|
||||
label: Screenshots
|
||||
description: If applicable, add screenshots to help explain your problem.
|
||||
placeholder: Screenshots would be very helpful!
|
||||
|
||||
53
.github/ISSUE_TEMPLATE/app_request.yaml
vendored
Normal file
53
.github/ISSUE_TEMPLATE/app_request.yaml
vendored
Normal file
@@ -0,0 +1,53 @@
|
||||
name: "App Request"
|
||||
description: "Request to add an app to the app store."
|
||||
title: "[App Request] AppName"
|
||||
labels: ["App Request"]
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
### ❤ Thanks for taking the time to fill out this app request!
|
||||
> Before proceeding, please make sure that this app is not in App Store and no one has [requested](https://github.com/IceWhaleTech/CasaOS/labels/App%20Request) the same app before.
|
||||
> If you have already requested the app, please ask your friends to help add a 👍 to this issue. Then be patient and wait for the developers to work on it.
|
||||
> If you have any questions, please ask them on [Discord](https://discord.gg/knqAbbBbeX) or [Github Discussions](https://github.com/IceWhaleTech/CasaOS/discussions).
|
||||
|
||||
- type: textarea
|
||||
id: app-info
|
||||
attributes:
|
||||
label: "App Information"
|
||||
description: "The formal information of this app, as detailed as possible."
|
||||
value: |
|
||||
- Name: <!-- eg. Nextcloud -->
|
||||
- Short Description: <!-- eg. Personal cloud and file sharing solution -->
|
||||
- Official Website: <!-- If available. eg. https://nextcloud.com -->
|
||||
- GitHub Repository: <!-- If available. eg. https://github.com/nextcloud/server -->
|
||||
- Docker Image: <!-- If available. eg. nextcloud/server:latest, ghcr.io/nextcloud/server:latest -->
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
id: why
|
||||
attributes:
|
||||
label: "Why do you want this app?"
|
||||
description: "Detailed notes can help developers and others understand the importance of this app."
|
||||
placeholder: |
|
||||
As a [what role], it helps me solve [what problem], and especially [what function] is great!
|
||||
or
|
||||
It solves [what problem] and especially [what feature] works well, which is hard to do with other app.
|
||||
or
|
||||
This is the app that [some device/service] must use and will not work without it.
|
||||
or
|
||||
others
|
||||
|
||||
- type: textarea
|
||||
id: additional-info
|
||||
attributes:
|
||||
label: "Additional information?"
|
||||
description: "Anything else you want to share with the developers and others?"
|
||||
placeholder: |
|
||||
Example:
|
||||
- Noteworthy matters.
|
||||
- Recommended Docker image.
|
||||
- Validated Docker deployment instructions.
|
||||
- Notable Docker setup details.
|
||||
- Recommended config files, user data, accessible directory settings.
|
||||
4
.github/ISSUE_TEMPLATE/bug_report.md
vendored
4
.github/ISSUE_TEMPLATE/bug_report.md
vendored
@@ -1,8 +1,8 @@
|
||||
---
|
||||
name: Bug report
|
||||
about: Create a report to help us improve
|
||||
title: ''
|
||||
labels: ''
|
||||
title: '[Bug] '
|
||||
labels: 'bug'
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
8
.github/ISSUE_TEMPLATE/config.yml
vendored
8
.github/ISSUE_TEMPLATE/config.yml
vendored
@@ -1,5 +1,11 @@
|
||||
blank_issues_enabled: false
|
||||
contact_links:
|
||||
- name: Questions, Ideas, Discussions
|
||||
- name: Feature/Enhancement Ideas
|
||||
url: https://github.com/IceWhaleTech/CasaOS/discussions/164
|
||||
about: Have an idea for a new feature/enhancement?
|
||||
- name: Questions, Discussions
|
||||
url: https://github.com/IceWhaleTech/CasaOS/discussions
|
||||
about: Ask questions, propose ideas, or discuss anything related to CasaOS
|
||||
- name: Discord
|
||||
url: https://discord.gg/knqAbbBbeX
|
||||
about: Get help or share great ideas on Discord!
|
||||
33
.github/workflows/add_issues_to_projects.yml
vendored
Normal file
33
.github/workflows/add_issues_to_projects.yml
vendored
Normal file
@@ -0,0 +1,33 @@
|
||||
name: Add Issues To Projects
|
||||
|
||||
on:
|
||||
issues:
|
||||
types:
|
||||
- opened
|
||||
|
||||
jobs:
|
||||
add-issues:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Generate token
|
||||
id: generate_token
|
||||
uses: tibdex/github-app-token@36464acb844fc53b9b8b2401da68844f6b05ebb0
|
||||
with:
|
||||
app_id: ${{ secrets.ALPHA_BOT_ID }}
|
||||
private_key: ${{ secrets.ALPHA_BOT_PEM }}
|
||||
|
||||
- name: Add Alpha Bug Issue To project
|
||||
uses: actions/add-to-project@v0.3.0
|
||||
with:
|
||||
github-token: ${{ steps.generate_token.outputs.token }}
|
||||
project-url: https://github.com/orgs/IceWhaleTech/projects/5
|
||||
labeled: alpha, bug
|
||||
label-operator: AND
|
||||
|
||||
- name: Add App Request Issue To project
|
||||
uses: actions/add-to-project@v0.3.0
|
||||
with:
|
||||
github-token: ${{ steps.generate_token.outputs.token }}
|
||||
project-url: https://github.com/orgs/IceWhaleTech/projects/8
|
||||
labeled: "App Request"
|
||||
label-operator: AND
|
||||
2
.github/workflows/demo.yml
vendored
2
.github/workflows/demo.yml
vendored
@@ -33,7 +33,7 @@ jobs:
|
||||
|
||||
- name: Get old instance and snapshot name, create new instance name
|
||||
run: |
|
||||
echo "OLD_INSTANCE_SNAPSHOT_NAME=$(aws lightsail get-instance-snapshots | grep '"name": "CasaOS-Demo-Snapshot-1652856810' | sed 's/ //g' | sed 's/"//g' | sed 's/,//g' | sed 's/name://g')" >> $GITHUB_ENV
|
||||
echo "OLD_INSTANCE_SNAPSHOT_NAME=$(aws lightsail get-instance-snapshots | grep '"name": "0.3.3-demo-1658402149' | 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
|
||||
|
||||
|
||||
27
.github/workflows/move_alpha_bug_to_project.yml
vendored
Normal file
27
.github/workflows/move_alpha_bug_to_project.yml
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
# This is a basic workflow to help you get started with Actions
|
||||
|
||||
name: Move alpha bug to project
|
||||
|
||||
on:
|
||||
issues:
|
||||
types:
|
||||
- opened
|
||||
|
||||
jobs:
|
||||
track_issue:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Generate token
|
||||
id: generate_token
|
||||
uses: tibdex/github-app-token@36464acb844fc53b9b8b2401da68844f6b05ebb0
|
||||
with:
|
||||
app_id: ${{ secrets.ALPHA_BOT_ID }}
|
||||
private_key: ${{ secrets.ALPHA_BOT_PEM }}
|
||||
|
||||
- name: Add Issue To GitHub Projects Beta
|
||||
uses: actions/add-to-project@v0.1.0
|
||||
with:
|
||||
project-url: https://github.com/orgs/IceWhaleTech/projects/5
|
||||
github-token: ${{ steps.generate_token.outputs.token }}
|
||||
labeled: alpha, bug
|
||||
label-operator: AND
|
||||
48
.github/workflows/push_events_to_discord.yml
vendored
Normal file
48
.github/workflows/push_events_to_discord.yml
vendored
Normal file
@@ -0,0 +1,48 @@
|
||||
name: Push Events to Discord
|
||||
|
||||
on:
|
||||
issues:
|
||||
types:
|
||||
- opened
|
||||
issue_comment:
|
||||
types:
|
||||
- created
|
||||
discussion:
|
||||
types:
|
||||
- created
|
||||
- transferred
|
||||
- answered
|
||||
discussion_comment:
|
||||
types:
|
||||
- created
|
||||
|
||||
jobs:
|
||||
push-events:
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
|
||||
- name: General Discussions & Comments
|
||||
if: ${{ ( github.event_name == 'discussion' || github.event_name == 'discussion_comment' ) && github.event.discussion.category.name == 'General' }}
|
||||
uses: joseph-montanez/forward-event-action@v3.0.0
|
||||
with:
|
||||
webhook: ${{ secrets.Discord_CasaOS_General_Webhook }}
|
||||
|
||||
- name: App Request Issues & Comments
|
||||
if: ${{ ( github.event_name == 'issues' || github.event_name == 'issue_comment' ) && contains(github.event.issue.labels.*.name, 'App Request') }}
|
||||
uses: joseph-montanez/forward-event-action@v3.0.0
|
||||
with:
|
||||
webhook: ${{ secrets.Discord_CasaOS_App_Request_Webhook }}
|
||||
|
||||
- name: Bug Issues & Comments
|
||||
if: ${{ ( github.event_name == 'issues' || github.event_name == 'issue_comment' ) && contains(github.event.issue.labels.*.name, 'bug') && !contains(github.event.issue.labels.*.name, 'alpha') }}
|
||||
uses: joseph-montanez/forward-event-action@v3.0.0
|
||||
with:
|
||||
webhook: ${{ secrets.Discord_CasaOS_Bug_Webhook }}
|
||||
|
||||
- name: Alpha Issues & Comments
|
||||
if: ${{ ( github.event_name == 'issues' || github.event_name == 'issue_comment' ) && contains(github.event.issue.labels.*.name, 'alpha') }}
|
||||
uses: joseph-montanez/forward-event-action@v3.0.0
|
||||
with:
|
||||
webhook: ${{ secrets.Discord_CasaOS_Alpha_Webhook }}
|
||||
47
.github/workflows/release.yml
vendored
Normal file
47
.github/workflows/release.yml
vendored
Normal file
@@ -0,0 +1,47 @@
|
||||
name: goreleaser
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- v*.*.*
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
|
||||
jobs:
|
||||
goreleaser:
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
-
|
||||
name: Install dependencies for cross-compiling
|
||||
run: |
|
||||
sudo apt update
|
||||
sudo apt-get --no-install-recommends --yes install \
|
||||
libc6-dev-amd64-cross \
|
||||
gcc-aarch64-linux-gnu libc6-dev-arm64-cross \
|
||||
gcc-arm-linux-gnueabihf libc6-dev-armhf-cross
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
fetch-depth: 0
|
||||
-
|
||||
name: Fetch all tags
|
||||
run: git fetch --force --tags
|
||||
-
|
||||
name: Set up Go
|
||||
uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: 1.19
|
||||
-
|
||||
name: Run GoReleaser
|
||||
uses: goreleaser/goreleaser-action@v2
|
||||
with:
|
||||
# either 'goreleaser' (default) or 'goreleaser-pro'
|
||||
distribution: goreleaser
|
||||
version: latest
|
||||
args: release --rm-dist
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
# Your GoReleaser Pro key, if you are using the 'goreleaser-pro' distribution
|
||||
# GORELEASER_KEY: ${{ secrets.GORELEASER_KEY }}
|
||||
8
.gitignore
vendored
8
.gitignore
vendored
@@ -28,10 +28,12 @@ gen
|
||||
/sql/
|
||||
/out/
|
||||
/db/
|
||||
/docs/
|
||||
/web/
|
||||
/conf/conf.ini
|
||||
/conf/conf.conf
|
||||
/conf/conf.json
|
||||
__debug_bin
|
||||
main
|
||||
CasaOS
|
||||
github.com
|
||||
.all-contributorsrc
|
||||
dist
|
||||
CasaOS
|
||||
167
.goreleaser.yaml
Normal file
167
.goreleaser.yaml
Normal file
@@ -0,0 +1,167 @@
|
||||
# This is an example .goreleaser.yml file with some sensible defaults.
|
||||
# Make sure to check the documentation at https://goreleaser.com
|
||||
project_name: casaos
|
||||
before:
|
||||
hooks:
|
||||
# You may remove this if you don't use go modules.
|
||||
- go mod tidy
|
||||
builds:
|
||||
- id: casaos-amd64
|
||||
binary: build/sysroot/usr/bin/casaos
|
||||
env:
|
||||
- CGO_ENABLED=1
|
||||
- CC=x86_64-linux-gnu-gcc
|
||||
ldflags:
|
||||
- -s
|
||||
- -w
|
||||
- -extldflags "-static"
|
||||
tags:
|
||||
- musl
|
||||
- netgo
|
||||
goos:
|
||||
- linux
|
||||
goarch:
|
||||
- amd64
|
||||
hooks:
|
||||
post:
|
||||
- find build/sysroot -type f | xargs -L 1 realpath --relative-to=build/sysroot > build/sysroot.manifest
|
||||
- id: casaos-arm64
|
||||
binary: build/sysroot/usr/bin/casaos
|
||||
env:
|
||||
- CGO_ENABLED=1
|
||||
- CC=aarch64-linux-gnu-gcc
|
||||
ldflags:
|
||||
- -s
|
||||
- -w
|
||||
- -extldflags "-static"
|
||||
tags:
|
||||
- musl
|
||||
- netgo
|
||||
goos:
|
||||
- linux
|
||||
goarch:
|
||||
- arm64
|
||||
hooks:
|
||||
post:
|
||||
- find build/sysroot -type f | xargs -L 1 realpath --relative-to=build/sysroot > build/sysroot.manifest
|
||||
- id: casaos-arm-7
|
||||
binary: build/sysroot/usr/bin/casaos
|
||||
env:
|
||||
- CGO_ENABLED=1
|
||||
- CC=arm-linux-gnueabihf-gcc
|
||||
ldflags:
|
||||
- -s
|
||||
- -w
|
||||
- -extldflags "-static"
|
||||
tags:
|
||||
- musl
|
||||
- netgo
|
||||
goos:
|
||||
- linux
|
||||
goarch:
|
||||
- arm
|
||||
goarm:
|
||||
- "7"
|
||||
hooks:
|
||||
post:
|
||||
- find build/sysroot -type f | xargs -L 1 realpath --relative-to=build/sysroot > build/sysroot.manifest
|
||||
- id: casaos-migration-tool-amd64
|
||||
binary: build/sysroot/usr/bin/casaos-migration-tool
|
||||
main: ./cmd/migration-tool
|
||||
env:
|
||||
- CGO_ENABLED=1
|
||||
- CC=x86_64-linux-gnu-gcc
|
||||
ldflags:
|
||||
- -s
|
||||
- -w
|
||||
- -extldflags "-static"
|
||||
tags:
|
||||
- musl
|
||||
- netgo
|
||||
goos:
|
||||
- linux
|
||||
goarch:
|
||||
- amd64
|
||||
- id: casaos-migration-tool-arm64
|
||||
binary: build/sysroot/usr/bin/casaos-migration-tool
|
||||
main: ./cmd/migration-tool
|
||||
env:
|
||||
- CGO_ENABLED=1
|
||||
- CC=aarch64-linux-gnu-gcc
|
||||
ldflags:
|
||||
- -s
|
||||
- -w
|
||||
- -extldflags "-static"
|
||||
tags:
|
||||
- musl
|
||||
- netgo
|
||||
goos:
|
||||
- linux
|
||||
goarch:
|
||||
- arm64
|
||||
- id: casaos-migration-tool-arm-7
|
||||
binary: build/sysroot/usr/bin/casaos-migration-tool
|
||||
main: ./cmd/migration-tool
|
||||
env:
|
||||
- CGO_ENABLED=1
|
||||
- CC=arm-linux-gnueabihf-gcc
|
||||
ldflags:
|
||||
- -s
|
||||
- -w
|
||||
- -extldflags "-static"
|
||||
tags:
|
||||
- musl
|
||||
- netgo
|
||||
goos:
|
||||
- linux
|
||||
goarch:
|
||||
- arm
|
||||
goarm:
|
||||
- "7"
|
||||
archives:
|
||||
- name_template: "{{ .Os }}-{{ .Arch }}-{{ .ProjectName }}-v{{ .Version }}"
|
||||
id: casaos
|
||||
builds:
|
||||
- casaos-amd64
|
||||
- casaos-arm64
|
||||
- casaos-arm-7
|
||||
replacements:
|
||||
arm: arm-7
|
||||
files:
|
||||
- build/**/*
|
||||
- name_template: "{{ .Os }}-{{ .Arch }}-{{ .ProjectName }}-migration-tool-v{{ .Version }}"
|
||||
id: casaos-migration-tool
|
||||
builds:
|
||||
- casaos-migration-tool-amd64
|
||||
- casaos-migration-tool-arm64
|
||||
- casaos-migration-tool-arm-7
|
||||
replacements:
|
||||
arm: arm-7
|
||||
files:
|
||||
- build/sysroot/etc/**/*
|
||||
checksum:
|
||||
name_template: "checksums.txt"
|
||||
snapshot:
|
||||
name_template: "{{ incpatch .Version }}"
|
||||
changelog:
|
||||
sort: asc
|
||||
filters:
|
||||
exclude:
|
||||
- "^docs:"
|
||||
- "^test:"
|
||||
# release:
|
||||
# github:
|
||||
# owner: IceWhaleTech
|
||||
# name: CasaOS
|
||||
# draft: true
|
||||
# prerelease: auto
|
||||
# mode: replace
|
||||
# name_template: "v{{ .Version }}"
|
||||
release:
|
||||
github:
|
||||
owner: IceWhaleTech
|
||||
name: CasaOS
|
||||
draft: true
|
||||
prerelease: auto
|
||||
mode: replace
|
||||
name_template: "v{{ .Version }}"
|
||||
102
CHANGELOG.md
102
CHANGELOG.md
@@ -18,13 +18,107 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
|
||||
### Fixed
|
||||
|
||||
## [0.3.2.1] - 2022-06-13
|
||||
|
||||
## [0.3.6-alpha.1] - 2022-09-06
|
||||
|
||||
### Added
|
||||
- [System] Added power and temperature info to performance widget (Intel)
|
||||
- [Apps] Custom links can be added to Apps section
|
||||
|
||||
### Fixed
|
||||
- [Apps] Fixed the problem of not being able to modify some App settings ([#510](https://github.com/IceWhaleTech/CasaOS/issues/510))
|
||||
|
||||
### Changed
|
||||
- [System] Architecture optimization. Improved performance.
|
||||
|
||||
## [0.3.5] - 2022-08-23
|
||||
|
||||
### Added
|
||||
|
||||
- [File] Mount the shared samba
|
||||
- [File] File sharing via Samba
|
||||
- [System] You can share casaos on Twitter, facebook, reddit
|
||||
|
||||
### Changed
|
||||
|
||||
- [Disk] Support for mounting existing data disks
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fix the problem of application opening failure on non-80 ports ([#283](https://github.com/IceWhaleTech/CasaOS/issues/283) [#280](https://github.com/IceWhaleTech/CasaOS/issues/280))
|
||||
- Modify port failure problem ([#282](https://github.com/IceWhaleTech/CasaOS/issues/282))
|
||||
- Modify environment variables disappearing problem([#284](https://github.com/IceWhaleTech/CasaOS/issues/284))
|
||||
- [App] fixed uninstalling imported docker container apps results in wiping ALL your config data from them ([#360](https://github.com/IceWhaleTech/CasaOS/issues/360))
|
||||
|
||||
## [0.3.4] - 2022-07-29(UTC)
|
||||
|
||||
### Added
|
||||
|
||||
- SSH adds port-side options and prompts for connection status. ([#286](https://github.com/IceWhaleTech/CasaOS/issues/286))
|
||||
|
||||
### Changed
|
||||
|
||||
- Normalize all routes
|
||||
- Application names now support spaces ([#211](https://github.com/IceWhaleTech/CasaOS/issues/211))
|
||||
|
||||
### Removed
|
||||
|
||||
- Removed casaos connect
|
||||
|
||||
### Security
|
||||
|
||||
- Adjustment of authentication method
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fixed storage format and remove password error issues ([#344](https://github.com/IceWhaleTech/CasaOS/issues/344) [#357](https://github.com/IceWhaleTech/CasaOS/issues/357))
|
||||
|
||||
## [0.3.3] - 2022-07-08(UTC)
|
||||
|
||||
### Added
|
||||
|
||||
- [System]Add interface call log
|
||||
- Adding Developing file ([#311](https://github.com/IceWhaleTech/CasaOS/pull/311))
|
||||
- [App] add new tips for app section.
|
||||
- [System] UI Configurable function modules: support turning off the search bar and recommended apps module in the settings.
|
||||
- [System] Custom wallpapers: two new preset wallpapers, support for custom uploads, support for setting images from Files as wallpapers, Also support right click on dashboard to change wallpaper.
|
||||
|
||||
### Changed
|
||||
|
||||
- [App] Cache app store index and category data
|
||||
- [System] casaos master program adapted to FHS standards
|
||||
- [App] Update casaos icons.
|
||||
- [System] Update translation.
|
||||
|
||||
### Removed
|
||||
|
||||
- [System] Remove upnp function module
|
||||
- [System] Remove ddns function module
|
||||
- [System] Remove search function module
|
||||
- [System] Remove zerotier function module
|
||||
- [System] Remove task function module
|
||||
- [System] Remove file share function module
|
||||
|
||||
### Fixed
|
||||
|
||||
- [Disk] Fixed hard drive won't hibernate problem ([#202](https://github.com/IceWhaleTech/CasaOS/issues/202))
|
||||
- [File] Fixed the backspace key that causes the folder to rewind ([#252](https://github.com/IceWhaleTech/CasaOS/issues/252))
|
||||
- [App] Fixed app logo is not loading when imported. ([#320](https://github.com/IceWhaleTech/CasaOS/issues/320))
|
||||
|
||||
## [0.3.2.1] - 2022-06-16(UTC)
|
||||
|
||||
### Changed
|
||||
|
||||
- [System] Adjusted the display style.
|
||||
|
||||
### Fixed
|
||||
|
||||
- [System] Fixed the issue of widgets displaying wrongly on mobile devices.
|
||||
- [App] Fix the problem of application opening failure on non-80 ports ([#283](https://github.com/IceWhaleTech/CasaOS/issues/283) [#280](https://github.com/IceWhaleTech/CasaOS/issues/280))
|
||||
- [System] Modify port failure problem ([#282](https://github.com/IceWhaleTech/CasaOS/issues/282))
|
||||
- [App]Modify environment variables disappearing problem([#284](https://github.com/IceWhaleTech/CasaOS/issues/284))
|
||||
- [System]Fix no update alert([#278](https://github.com/IceWhaleTech/CasaOS/issues/278))
|
||||
- [System] Fixed some bugs of application cpu usage and memory staging([#272](https://github.com/IceWhaleTech/CasaOS/issues/272))
|
||||
- [App] Fixed plex and HA network mode error issues ([#299](https://github.com/IceWhaleTech/CasaOS/issues/299))
|
||||
- [App] Fix application terminal not working ([#266](https://github.com/IceWhaleTech/CasaOS/issues/266))
|
||||
|
||||
## [0.3.2] - 2022-06-10
|
||||
|
||||
### Added
|
||||
|
||||
33
DEVELOPING.md
Normal file
33
DEVELOPING.md
Normal file
@@ -0,0 +1,33 @@
|
||||
# CasaOS Development
|
||||
Here we will describe the steps required to setup a development environment with CasaOS.
|
||||
|
||||
- [Setting up development environment](#setting-up-development-environment)
|
||||
- [Pre-requisites](#pre-requisites)
|
||||
- [1. Fork the Repo](#1.-fork-the-repo)
|
||||
- [2. Clone the repo down](#2.-clone-the-repo-down)
|
||||
- [3. Install dependencies](#3.-install-dependencies)
|
||||
|
||||
|
||||
## Setting up a development environment
|
||||
In this section we will walk you through the general process of setting up your development environment to get started.
|
||||
|
||||
### Pre-requisites
|
||||
The following must be installed in order to get started. The details of how to install them is outside the scope of this doc, but generally they should be able to be installed with your systems package manager (apt, yum, brew, choco, etc).
|
||||
- Go > v1.17.0
|
||||
- yarn
|
||||
- node.js
|
||||
|
||||
### 1. Fork the Repo
|
||||
[Fork the repo](https://docs.github.com/en/get-started/quickstart/fork-a-repo) onto your own GitHub account for developing.
|
||||
|
||||
### 2. Clone the repo down
|
||||
1. Navigate into your go workspace (check with `go env GOPATH`).
|
||||
2. Navigate to the appropriate path for github. It should look something like this: `<path from GOPATH>/github.com/<GitHub Username>/`. If it doesn't exist create it.
|
||||
3. Clone down the repo with the following: `git clone --recurse-submodules --remote-submodules https://github.com/<your GitHub Username>/CasaOS.git`
|
||||
|
||||
### 3. Install dependencies
|
||||
1. `cd UI`
|
||||
2. `yarn install`
|
||||
3. `yarn build`
|
||||
4. `cd ..`
|
||||
5. `go get`
|
||||
261
README.md
261
README.md
@@ -1,72 +1,150 @@
|
||||
# CasaOS - A simple, easy-to-use, elegant open-source Home Cloud system.
|
||||
# CasaOS - Your Home Cloud OS
|
||||
|
||||

|
||||
|
||||
[](https://github.com/IceWhaleTech/CasaOS)
|
||||
[](https://github.com/IceWhaleTech/CasaOS/pulls)
|
||||
[](https://github.com/IceWhaleTech/CasaOS/issues)
|
||||
[](https://github.com/IceWhaleTech/CasaOS/stargazers)
|
||||
[](https://discord.gg/knqAbbBbeX)
|
||||
<!-- Readme i18n links -->
|
||||
<!-- > English | [中文](#) | [Français](#) -->
|
||||
|
||||
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.
|
||||
<p align="center">
|
||||
<!-- CasaOS Banner -->
|
||||
<picture>
|
||||
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/IceWhaleTech/logo/main/casaos/casaos_banner_dark_night_800px.png">
|
||||
<source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/IceWhaleTech/logo/main/casaos/casaos_banner_twilight_blue_800px.png">
|
||||
<img alt="CasaOS" src="https://raw.githubusercontent.com/IceWhaleTech/logo/main/casaos/casaos_banner_twilight_blue_800px.png">
|
||||
</picture>
|
||||
<br/>
|
||||
<i>Connect with the community developing HOME CLOUD, creating self-sovereign, and defining the future of the distributed cloud.</i>
|
||||
<br/>
|
||||
<br/>
|
||||
<!-- CasaOS Badges -->
|
||||
<a href="https://github.com/IceWhaleTech/CasaOS" target="_blank">
|
||||
<img alt="CasaOS Version" src="https://img.shields.io/github/v/release/IceWhaleTech/CasaOS?color=162453&style=flat-square&label=CasaOS" />
|
||||
</a>
|
||||
<a href="https://github.com/IceWhaleTech/CasaOS/blob/main/LICENSE" target="_blank">
|
||||
<img alt="CasaOS License" src="https://img.shields.io/github/license/IceWhaleTech/CasaOS?color=162453&style=flat-square&label=License" />
|
||||
</a>
|
||||
<a href="https://github.com/IceWhaleTech/CasaOS/pulls" target="_blank">
|
||||
<img alt="CasaOS Pull Requests" src="https://img.shields.io/github/issues-pr/IceWhaleTech/CasaOS?color=162453&style=flat-square&label=PRs" />
|
||||
</a>
|
||||
<a href="https://github.com/IceWhaleTech/CasaOS/issues" target="_blank">
|
||||
<img alt="CasaOS Issues" src="https://img.shields.io/github/issues/IceWhaleTech/CasaOS?color=162453&style=flat-square&label=Issues" />
|
||||
</a>
|
||||
<a href="https://github.com/IceWhaleTech/CasaOS/stargazers" target="_blank">
|
||||
<img alt="CasaOS Stargazers" src="https://img.shields.io/github/stars/IceWhaleTech/CasaOS?color=162453&style=flat-square&label=Stars" />
|
||||
</a>
|
||||
<!-- <a href="https://github.com/IceWhaleTech/CasaOS/releases" target="_blank">
|
||||
<img alt="CasaOS Downloads" src="https://img.shields.io/github/downloads/IceWhaleTech/CasaOS/total?color=162453&style=flat-square" />
|
||||
</a> -->
|
||||
<br/>
|
||||
<!-- CasaOS Community -->
|
||||
<a href="https://discord.gg/knqAbbBbeX" target="_blank">
|
||||
<img alt="IceWhale Discord" src="https://img.shields.io/discord/884667213326463016?color=162453&style=flat-square&label=Discord&logo=discord&logoColor=fff" />
|
||||
</a>
|
||||
<a href="https://github.com/IceWhaleTech/CasaOS/discussions" target="_blank">
|
||||
<img alt="CasaOS GitHub Discussions" src="https://img.shields.io/github/discussions/IceWhaleTech/CasaOS?color=162453&style=flat-square&label=Discussions&logo=github" />
|
||||
</a>
|
||||
<!-- ALL-CONTRIBUTORS-BADGE:START - Do not remove or modify this section -->
|
||||
<a href="#credits"><img alt="All Contributors" src="https://img.shields.io/static/v1?label=All%20Contributors&message=15&color=162453&style=flat-square&logo=Handshake&logoColor=fff" /></a>
|
||||
<!-- ALL-CONTRIBUTORS-BADGE:END -->
|
||||
<br/>
|
||||
<!-- CasaOS Links -->
|
||||
<a href="https://www.casaos.io" target="_blank">Website</a> |
|
||||
<a href="http://demo.casaos.io" target="_blank">Demo</a> |
|
||||
<a href="https://github.com/IceWhaleTech/CasaOS" target="_blank">GitHub</a>
|
||||
<br/>
|
||||
<br/>
|
||||
<!-- CasaOS Snapshots -->
|
||||
<kbd>
|
||||
<picture>
|
||||
<source media="(prefers-color-scheme: dark)" srcset="snapshot-dark.jpg">
|
||||
<source media="(prefers-color-scheme: light)" srcset="snapshot-light.jpg">
|
||||
<img alt="CasaOS Snapshot" src="snapshot-light.jpg">
|
||||
</picture>
|
||||
</kbd>
|
||||
</p>
|
||||
|
||||
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.
|
||||
## Why do we need Home Cloud?
|
||||
|
||||

|
||||

|
||||
Think about it seriously. Is control of our data, smart devices and digital assets now only in the hands of some big company?
|
||||
|
||||
- Is your photo album saved in their cloud service?
|
||||
- Do your thermostats, monitors, lamps need to be used through their cloud services?
|
||||
- Do your personal documents, memos, contacts, passwords, etc. reside in their cloud storage services?
|
||||
- Are you just going to have to accept their decisions when they decide to change prices, review content or even discontinue services?
|
||||
|
||||
It sounds ridiculous, doesn't it? We are losing control of our own data!
|
||||
|
||||
Our ideal home cloud is one where you can manage all your data, devices and data assets very easily. In your own home, you have absolute control.
|
||||
|
||||
> If you think what we are doing is valuable. Please **give us a star ⭐** and **fork it 🤞**!
|
||||
|
||||
## Features
|
||||
|
||||
- Friendly UI designed for home scenarios
|
||||
- No code, no forms, intuitive, design for humanity
|
||||
- Multiple hardware and base system support
|
||||
- ZimaBoard, NUC, RPi, old computers, whatever is available.
|
||||
- Selected apps in the app store, one-click installation
|
||||
- Nextcloud, HomeAssiant, AdGuard, Jellyfin, *arr and more!
|
||||
- Easily install numerous Docker apps
|
||||
- Over 100,000 apps from the Docker ecosystem can be easily installed
|
||||
- Elegant drive and file management
|
||||
- What you see is what you get. No technical background required.
|
||||
- Well-designed system/app widgets
|
||||
- What you care about, at a glance. Resource usage, app status, and more!
|
||||
|
||||
## 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)!
|
||||
CasaOS fully supports ZimaBoard, Intel NUC, and Raspberry Pi. Also, more computers and development boards and fully compatible with Ubuntu, Debian, Raspberry Pi OS, and CentOS with one-liner installation.
|
||||
|
||||
### Hardware Compatibility
|
||||
|
||||
- amd64 / x86-64
|
||||
- arm64
|
||||
- armv7
|
||||
|
||||
### System Compatibility
|
||||
|
||||
Official Support
|
||||
- Debian 11 (✅ Tested, Recommended)
|
||||
- Ubuntu Server 20.04 (✅ Tested)
|
||||
- Raspberry Pi OS (✅ Tested)
|
||||
|
||||
Community Support
|
||||
- Elementary 6.1 (✅ Tested)
|
||||
- Armbian 22.04 (✅ Tested)
|
||||
- Alpine (🚧 Not Fully Tested Yet)
|
||||
- OpenWrt (🚧 Not Fully Tested Yet)
|
||||
|
||||
### Quick Setup CasaOS
|
||||
|
||||
Fresh install a system from the list below and run the this command:
|
||||
Freshly install a system from the list above and run this command:
|
||||
|
||||
```sh
|
||||
wget -qO- https://get.icewhale.io/casaos.sh | bash
|
||||
wget -qO- https://get.casaos.io | bash
|
||||
```
|
||||
|
||||
or
|
||||
|
||||
```sh
|
||||
curl -fsSL https://get.icewhale.io/casaos.sh | bash
|
||||
curl -fsSL https://get.casaos.io | bash
|
||||
```
|
||||
|
||||
### Uninstall CasaOS
|
||||
|
||||
|
||||
v0.3.3 or newer
|
||||
|
||||
```sh
|
||||
casaos-uninstall
|
||||
```
|
||||
|
||||
Before v0.3.3
|
||||
|
||||
```sh
|
||||
curl -fsSL https://get.icewhale.io/casaos-uninstall.sh | bash
|
||||
```
|
||||
|
||||
### System Compatibility
|
||||
|
||||
- Ubuntu Server 20.04 amd64 (✅ Recommend, Tested)
|
||||
- Armbian 22.02 armhf/arm64/amd64 (✅ Recommend, Tested)
|
||||
- Elementary OS 6.1 Jólnir amd64 (✅ Recommend, Tested)
|
||||
- Deepin 20.4 amd64 (⚠️ Not Fully Tested Yet)
|
||||
- Raspberry Pi Lite OS aarch64/arm64 (⚠️ Not Fully Tested Yet)
|
||||
- Debian 11 amd64 (⚠️ Not Fully Tested Yet)
|
||||
- OpenWrt 21.02 amd64 (⚠️ Not Fully Tested Yet)
|
||||
- OpenWrt 21.02 aarch64/arm64 (⚠️ Not Fully Tested Yet)
|
||||
|
||||
|
||||
## Key Features
|
||||
|
||||
- UI designed for home scenarios - simple, elegant, and easy-to-use
|
||||
- Quick Docker app installation with only three steps, plus automatic management
|
||||
- App Store for 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 with us!
|
||||
|
||||
|
||||
## Community
|
||||
## Community
|
||||
|
||||
The word Casa comes from the Spanish word for "home". Project CasaOS originated as a pre-installed system for crowdfunded product [ZimaBoard](https://www.zimaboard.com) on Kickstarter.
|
||||
|
||||
@@ -74,16 +152,97 @@ 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/knqAbbBbeX)!
|
||||
We believes that through community-driven collaborative innovation and open communication with global developers, we can reshape the digital home experience like never before.
|
||||
|
||||
**A warm welcome for you to get help or share great ideas in the [Discord](https://discord.gg/knqAbbBbeX)!**
|
||||
|
||||
[](https://discord.gg/knqAbbBbeX)
|
||||
|
||||
## Contributing
|
||||
|
||||
CasaOS is a community-driven open source project and the people involved are CasaOS users. That means CasaOS will always need contributions from community members just like you!
|
||||
|
||||
## Maintainers
|
||||
- Jerry Liu
|
||||
- Link Liang
|
||||
- Ober Zhang
|
||||
- Zyaire Ann
|
||||
- John Guan
|
||||
- Right here, waiting for YOU!
|
||||
<details>
|
||||
<summary><b>How can I get involved? 🧐</b></summary>
|
||||
<p>
|
||||
|
||||
### Coding 💻 (WIP)
|
||||
|
||||
We are refining documentation that can be used for effective community collaboration. Feel free to start a discussion if you have a good idea.
|
||||
|
||||
### Helping Users 💬
|
||||
|
||||
If you have extensive knowledge of CasaOS and related areas. We highly encourage you to help others as much as you can in Discord and Discussions.
|
||||
|
||||
Discord: [https://discord.gg/knqAbbBbeX](https://discord.gg/knqAbbBbeX)
|
||||
|
||||
GitHub Discussions: [https://github.com/IceWhaleTech/CasaOS/discussions](https://github.com/IceWhaleTech/CasaOS/discussions)
|
||||
|
||||
### Helping with Translations 🌍 (WIP)
|
||||
|
||||
CasaOS officially supports English and Chinese. You are welcome to help make CasaOS available in more languages.
|
||||
|
||||
### Performing Alpha Testing ⚠️
|
||||
|
||||
Alpha testing is quality assurance testing that is engaged and driven by the community. It's a great way to get involved in contributing and experiencing the latest features before a new release.
|
||||
|
||||
The documentation is being refined and you can contact @JohnGuan via [Discord](https://discord.gg/knqAbbBbeX). Ask to join the #casaos-alpha channel.
|
||||
|
||||
### Writing Documentation 📖 (WIP)
|
||||
|
||||
Help make our documentation better by writing new content for the CasaOS Wiki, correcting existing material, or translating content into new languages.
|
||||
|
||||
</p>
|
||||
</details>
|
||||
|
||||
## Credits
|
||||
|
||||
Many thanks to everyone who has helped CasaOS so far!
|
||||
|
||||
Everyone's contribution is greatly appreciated. ([Emoji Key](https://allcontributors.org/docs/en/emoji-key))
|
||||
|
||||
<!-- ALL-CONTRIBUTORS-LIST:START - Do not remove or modify this section -->
|
||||
<!-- prettier-ignore-start -->
|
||||
<!-- markdownlint-disable -->
|
||||
<table>
|
||||
<tr>
|
||||
<td align="center"><a href="https://github.com/jerrykuku"><img src="https://avatars.githubusercontent.com/u/9485680?v=4?s=100" width="100px;" alt=""/><br /><sub><b>老竭力</b></sub></a><br /><a href="https://github.com/IceWhaleTech/CasaOS/commits?author=jerrykuku" title="Code">💻</a> <a href="https://github.com/IceWhaleTech/CasaOS/commits?author=jerrykuku" title="Documentation">📖</a> <a href="#ideas-jerrykuku" title="Ideas, Planning, & Feedback">🤔</a> <a href="#infra-jerrykuku" title="Infrastructure (Hosting, Build-Tools, etc)">🚇</a> <a href="#maintenance-jerrykuku" title="Maintenance">🚧</a> <a href="#platform-jerrykuku" title="Packaging/porting to new platform">📦</a> <a href="#question-jerrykuku" title="Answering Questions">💬</a> <a href="https://github.com/IceWhaleTech/CasaOS/pulls?q=is%3Apr+reviewed-by%3Ajerrykuku" title="Reviewed Pull Requests">👀</a></td>
|
||||
<td align="center"><a href="https://github.com/LinkLeong"><img src="https://avatars.githubusercontent.com/u/13556972?v=4?s=100" width="100px;" alt=""/><br /><sub><b>link</b></sub></a><br /><a href="https://github.com/IceWhaleTech/CasaOS/commits?author=LinkLeong" title="Code">💻</a> <a href="https://github.com/IceWhaleTech/CasaOS/commits?author=LinkLeong" title="Documentation">📖</a> <a href="#ideas-LinkLeong" title="Ideas, Planning, & Feedback">🤔</a> <a href="#infra-LinkLeong" title="Infrastructure (Hosting, Build-Tools, etc)">🚇</a> <a href="#maintenance-LinkLeong" title="Maintenance">🚧</a> <a href="#question-LinkLeong" title="Answering Questions">💬</a> <a href="https://github.com/IceWhaleTech/CasaOS/pulls?q=is%3Apr+reviewed-by%3ALinkLeong" title="Reviewed Pull Requests">👀</a></td>
|
||||
<td align="center"><a href="https://github.com/tigerinus"><img src="https://avatars.githubusercontent.com/u/7172560?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Tiger Wang (王豫)</b></sub></a><br /><a href="https://github.com/IceWhaleTech/CasaOS/commits?author=tigerinus" title="Code">💻</a> <a href="https://github.com/IceWhaleTech/CasaOS/commits?author=tigerinus" title="Documentation">📖</a> <a href="#ideas-tigerinus" title="Ideas, Planning, & Feedback">🤔</a> <a href="#infra-tigerinus" title="Infrastructure (Hosting, Build-Tools, etc)">🚇</a> <a href="#maintenance-tigerinus" title="Maintenance">🚧</a> <a href="#mentoring-tigerinus" title="Mentoring">🧑🏫</a> <a href="#security-tigerinus" title="Security">🛡️</a> <a href="#question-tigerinus" title="Answering Questions">💬</a> <a href="https://github.com/IceWhaleTech/CasaOS/pulls?q=is%3Apr+reviewed-by%3Atigerinus" title="Reviewed Pull Requests">👀</a></td>
|
||||
<td align="center"><a href="https://github.com/Lauren-ED209"><img src="https://avatars.githubusercontent.com/u/8243355?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Lauren</b></sub></a><br /><a href="#ideas-Lauren-ED209" title="Ideas, Planning, & Feedback">🤔</a> <a href="#fundingFinding-Lauren-ED209" title="Funding Finding">🔍</a> <a href="#projectManagement-Lauren-ED209" title="Project Management">📆</a> <a href="#question-Lauren-ED209" title="Answering Questions">💬</a> <a href="https://github.com/IceWhaleTech/CasaOS/commits?author=Lauren-ED209" title="Tests">⚠️</a></td>
|
||||
<td align="center"><a href="https://JohnGuan.Cn"><img src="https://avatars.githubusercontent.com/u/3358477?v=4?s=100" width="100px;" alt=""/><br /><sub><b>John Guan</b></sub></a><br /><a href="#blog-JohnGuan" title="Blogposts">📝</a> <a href="#content-JohnGuan" title="Content">🖋</a> <a href="https://github.com/IceWhaleTech/CasaOS/commits?author=JohnGuan" title="Documentation">📖</a> <a href="#ideas-JohnGuan" title="Ideas, Planning, & Feedback">🤔</a> <a href="#eventOrganizing-JohnGuan" title="Event Organizing">📋</a> <a href="#mentoring-JohnGuan" title="Mentoring">🧑🏫</a> <a href="#question-JohnGuan" title="Answering Questions">💬</a> <a href="https://github.com/IceWhaleTech/CasaOS/pulls?q=is%3Apr+reviewed-by%3AJohnGuan" title="Reviewed Pull Requests">👀</a></td>
|
||||
<td align="center"><a href="https://blog.tippybits.com"><img src="https://avatars.githubusercontent.com/u/17506770?v=4?s=100" width="100px;" alt=""/><br /><sub><b>David Tippett</b></sub></a><br /><a href="https://github.com/IceWhaleTech/CasaOS/commits?author=dtaivpp" title="Documentation">📖</a> <a href="#ideas-dtaivpp" title="Ideas, Planning, & Feedback">🤔</a> <a href="#question-dtaivpp" title="Answering Questions">💬</a></td>
|
||||
<td align="center"><a href="https://github.com/zarevskaya"><img src="https://avatars.githubusercontent.com/u/60230221?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Skaya</b></sub></a><br /><a href="#mentoring-zarevskaya" title="Mentoring">🧑🏫</a> <a href="#question-zarevskaya" title="Answering Questions">💬</a> <a href="#tutorial-zarevskaya" title="Tutorials">✅</a> <a href="#translation-zarevskaya" title="Translation">🌍</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><a href="https://github.com/AuthorShin"><img src="https://avatars.githubusercontent.com/u/4959043?v=4?s=100" width="100px;" alt=""/><br /><sub><b>AuthorShin</b></sub></a><br /><a href="https://github.com/IceWhaleTech/CasaOS/commits?author=AuthorShin" title="Tests">⚠️</a> <a href="https://github.com/IceWhaleTech/CasaOS/issues?q=author%3AAuthorShin" title="Bug reports">🐛</a> <a href="#question-AuthorShin" title="Answering Questions">💬</a> <a href="#ideas-AuthorShin" title="Ideas, Planning, & Feedback">🤔</a></td>
|
||||
<td align="center"><a href="https://github.com/baptiste313"><img src="https://avatars.githubusercontent.com/u/93325157?v=4?s=100" width="100px;" alt=""/><br /><sub><b>baptiste313</b></sub></a><br /><a href="#translation-baptiste313" title="Translation">🌍</a></td>
|
||||
<td align="center"><a href="https://github.com/DrMxrcy"><img src="https://avatars.githubusercontent.com/u/58747968?v=4?s=100" width="100px;" alt=""/><br /><sub><b>DrMxrcy</b></sub></a><br /><a href="https://github.com/IceWhaleTech/CasaOS/commits?author=DrMxrcy" title="Tests">⚠️</a> <a href="#ideas-DrMxrcy" title="Ideas, Planning, & Feedback">🤔</a> <a href="#question-DrMxrcy" title="Answering Questions">💬</a></td>
|
||||
<td align="center"><a href="https://github.com/Joooost"><img src="https://avatars.githubusercontent.com/u/12090673?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Joooost</b></sub></a><br /><a href="#ideas-Joooost" title="Ideas, Planning, & Feedback">🤔</a></td>
|
||||
<td align="center"><a href="https://potyarkin.ml"><img src="https://avatars.githubusercontent.com/u/334908?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Vitaly Potyarkin</b></sub></a><br /><a href="#ideas-sio" title="Ideas, Planning, & Feedback">🤔</a></td>
|
||||
<td align="center"><a href="https://github.com/bearfrieze"><img src="https://avatars.githubusercontent.com/u/1023813?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Bjørn Friese</b></sub></a><br /><a href="#ideas-bearfrieze" title="Ideas, Planning, & Feedback">🤔</a></td>
|
||||
<td align="center"><a href="https://github.com/Protektor-Desura"><img src="https://avatars.githubusercontent.com/u/1195496?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Protektor</b></sub></a><br /><a href="https://github.com/IceWhaleTech/CasaOS/issues?q=author%3AProtektor-Desura" title="Bug reports">🐛</a> <a href="#ideas-Protektor-Desura" title="Ideas, Planning, & Feedback">🤔</a> <a href="#question-Protektor-Desura" title="Answering Questions">💬</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><a href="https://github.com/llwaini"><img src="https://avatars.githubusercontent.com/u/59589857?v=4?s=100" width="100px;" alt=""/><br /><sub><b>llwaini</b></sub></a><br /><a href="#projectManagement-llwaini" title="Project Management">📆</a> <a href="https://github.com/IceWhaleTech/CasaOS/commits?author=llwaini" title="Tests">⚠️</a> <a href="#tutorial-llwaini" title="Tutorials">✅</a></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<!-- markdownlint-restore -->
|
||||
<!-- prettier-ignore-end -->
|
||||
|
||||
<!-- ALL-CONTRIBUTORS-LIST:END -->
|
||||
|
||||
This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome!
|
||||
|
||||
## Changelog
|
||||
|
||||
Detailed changes for each release are documented in the [release notes](https://github.com/IceWhaleTech/CasaOS/releases).
|
||||
|
||||
---
|
||||
|
||||
<p align="center">
|
||||
<a href="https://dashboard.trackgit.com/token/l5q8egi92tfhlxd70l2l">
|
||||
<img src="https://us-central1-trackgit-analytics.cloudfunctions.net/token/ping/l5q8egi92tfhlxd70l2l" alt="trackgit-views" />
|
||||
</a>
|
||||
</p>
|
||||
|
||||
1
UI
1
UI
Submodule UI deleted from 62a6bd44d5
181
build/scripts/migration/script.d/03-migrate-casaos.sh
Normal file
181
build/scripts/migration/script.d/03-migrate-casaos.sh
Normal file
@@ -0,0 +1,181 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
|
||||
# functions
|
||||
__info() {
|
||||
echo -e "🟩 ${1}"
|
||||
}
|
||||
|
||||
__info_done() {
|
||||
echo -e "✅ ${1}"
|
||||
}
|
||||
|
||||
__warning() {
|
||||
echo -e "🟨 ${1}"
|
||||
}
|
||||
|
||||
__error() {
|
||||
echo "🟥 ${1}"
|
||||
exit 1
|
||||
}
|
||||
|
||||
__is_version_gt() {
|
||||
test "$(echo "$@" | tr " " "\n" | sort -V | head -n 1)" != "$1"
|
||||
}
|
||||
__normalize_version() {
|
||||
local version
|
||||
if [ "${1::1}" = "v" ]; then
|
||||
version="${1:1}"
|
||||
else
|
||||
version="${1}"
|
||||
fi
|
||||
|
||||
echo "$version"
|
||||
}
|
||||
|
||||
__is_migration_needed() {
|
||||
local version1
|
||||
local version2
|
||||
|
||||
version1=$(__normalize_version "${1}")
|
||||
version2=$(__normalize_version "${2}")
|
||||
|
||||
if [ "${version1}" = "${version2}" ]; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
if [ "CURRENT_VERSION_NOT_FOUND" = "${version1}" ]; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
if [ "LEGACY_WITHOUT_VERSION" = "${version1}" ]; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
__is_version_gt "${version2}" "${version1}"
|
||||
}
|
||||
|
||||
BUILD_PATH=$(dirname "${BASH_SOURCE[0]}")/../../..
|
||||
SOURCE_ROOT=${BUILD_PATH}/sysroot
|
||||
|
||||
APP_NAME="casaos"
|
||||
APP_NAME_FORMAL="CasaOS"
|
||||
#APP_NAME_FORMAL="casaos-alpha"
|
||||
|
||||
# check if migration is needed
|
||||
SOURCE_BIN_PATH=${SOURCE_ROOT}/usr/bin
|
||||
SOURCE_BIN_FILE=${SOURCE_BIN_PATH}/${APP_NAME}
|
||||
|
||||
CURRENT_BIN_PATH=/usr/bin
|
||||
CURRENT_BIN_PATH_LEGACY=/usr/local/bin
|
||||
CURRENT_BIN_FILE=${CURRENT_BIN_PATH}/${APP_NAME}
|
||||
CURRENT_BIN_FILE_LEGACY=$(realpath -e ${CURRENT_BIN_PATH_LEGACY}/${APP_NAME} || which ${APP_NAME} || echo CURRENT_BIN_FILE_LEGACY_NOT_FOUND)
|
||||
|
||||
SOURCE_VERSION="$(${SOURCE_BIN_FILE} -v)"
|
||||
CURRENT_VERSION="$(${CURRENT_BIN_FILE} -v || ${CURRENT_BIN_FILE_LEGACY} -v || (stat "${CURRENT_BIN_FILE_LEGACY}" > /dev/null && echo LEGACY_WITHOUT_VERSION) || echo CURRENT_VERSION_NOT_FOUND)"
|
||||
|
||||
__info_done "CURRENT_VERSION: ${CURRENT_VERSION}"
|
||||
__info_done "SOURCE_VERSION: ${SOURCE_VERSION}"
|
||||
|
||||
NEED_MIGRATION=$(__is_migration_needed "${CURRENT_VERSION}" "${SOURCE_VERSION}" && echo "true" || echo "false")
|
||||
|
||||
if [ "${NEED_MIGRATION}" = "false" ]; then
|
||||
__info_done "Migration is not needed."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
MIGRATION_SERVICE_DIR=${1}
|
||||
|
||||
if [ -z "${MIGRATION_SERVICE_DIR}" ]; then
|
||||
MIGRATION_SERVICE_DIR=${BUILD_PATH}/scripts/migration/service.d/${APP_NAME}
|
||||
fi
|
||||
MIGRATION_LIST_FILE=${MIGRATION_SERVICE_DIR}/migration.list
|
||||
MIGRATION_PATH=()
|
||||
|
||||
CURRENT_VERSION_FOUND="false"
|
||||
|
||||
# a VERSION_PAIR looks like "v0.3.5 v0.3.6-alpha2"
|
||||
#
|
||||
# - "v0.3.5" is the current version installed on this host
|
||||
# - "v0.3.6-alpha2" is the version of the migration tool from GitHub
|
||||
while read -r VERSION_PAIR; do
|
||||
if [ -z "${VERSION_PAIR}" ]; then
|
||||
continue
|
||||
fi
|
||||
|
||||
# obtain "v0.3.5" from "v0.3.5 v0.3.6-alpha2"
|
||||
VER1=$(echo "${VERSION_PAIR}" | cut -d' ' -f1)
|
||||
|
||||
# obtain "v0.3.6-alpha2" from "v0.3.5 v0.3.6-alpha2"
|
||||
VER2=$(echo "${VERSION_PAIR}" | cut -d' ' -f2)
|
||||
|
||||
if [ "${CURRENT_VERSION}" = "${VER1// /}" ] || [ "${CURRENT_VERSION}" = "LEGACY_WITHOUT_VERSION" ]; then
|
||||
CURRENT_VERSION_FOUND="true"
|
||||
fi
|
||||
|
||||
if [ "${CURRENT_VERSION_FOUND}" = "true" ]; then
|
||||
MIGRATION_PATH+=("${VER2// /}")
|
||||
fi
|
||||
done < "${MIGRATION_LIST_FILE}"
|
||||
|
||||
if [ ${#MIGRATION_PATH[@]} -eq 0 ]; then
|
||||
__warning "No migration path found from ${CURRENT_VERSION} to ${SOURCE_VERSION}"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
ARCH="unknown"
|
||||
|
||||
case $(uname -m) in
|
||||
x86_64)
|
||||
ARCH="amd64"
|
||||
;;
|
||||
aarch64)
|
||||
ARCH="arm64"
|
||||
;;
|
||||
armv7l)
|
||||
ARCH="arm-7"
|
||||
;;
|
||||
*)
|
||||
__error "Unsupported architecture"
|
||||
;;
|
||||
esac
|
||||
|
||||
pushd "${MIGRATION_SERVICE_DIR}"
|
||||
|
||||
{ for VER2 in "${MIGRATION_PATH[@]}"; do
|
||||
|
||||
|
||||
MIGRATION_TOOL_FILE=linux-"${ARCH}"-"${APP_NAME}"-migration-tool-"${VER2}".tar.gz
|
||||
|
||||
if [ -f "${MIGRATION_TOOL_FILE}" ]; then
|
||||
__info "Migration tool ${MIGRATION_TOOL_FILE} exists. Skip downloading."
|
||||
continue
|
||||
fi
|
||||
|
||||
# MIGRATION_TOOL_URL=http://192.168.2.197:8000/v1/package/migration?type=release&name="${APP_NAME_FORMAL}"&version=${VER2}&arch=${ARCH}
|
||||
MIGRATION_TOOL_URL=https://github.com/IceWhaleTech/"${APP_NAME_FORMAL}"/releases/download/"${VER2}"/linux-"${ARCH}"-"${APP_NAME}"-migration-tool-"${VER2}".tar.gz
|
||||
echo "Dowloading ${MIGRATION_TOOL_URL}..."
|
||||
curl -sL -O "${MIGRATION_TOOL_URL}"
|
||||
done
|
||||
} || {
|
||||
popd
|
||||
__error "Failed to download migration tools"
|
||||
}
|
||||
|
||||
{
|
||||
for VER2 in "${MIGRATION_PATH[@]}"; do
|
||||
MIGRATION_TOOL_FILE=linux-"${ARCH}"-"${APP_NAME}"-migration-tool-"${VER2}".tar.gz
|
||||
__info "Extracting ${MIGRATION_TOOL_FILE}..."
|
||||
tar zxvf "${MIGRATION_TOOL_FILE}" || __error "Failed to extract ${MIGRATION_TOOL_FILE}"
|
||||
|
||||
MIGRATION_TOOL_PATH=build/sysroot/usr/bin/${APP_NAME}-migration-tool
|
||||
__info "Running ${MIGRATION_TOOL_PATH}..."
|
||||
${MIGRATION_TOOL_PATH}
|
||||
done
|
||||
} || {
|
||||
popd
|
||||
__error "Failed to extract and run migration tools"
|
||||
}
|
||||
|
||||
popd
|
||||
4
build/scripts/migration/service.d/casaos/migration.list
Normal file
4
build/scripts/migration/service.d/casaos/migration.list
Normal file
@@ -0,0 +1,4 @@
|
||||
LEGACY_WITHOUT_VERSION v0.3.6
|
||||
v0.3.5 v0.3.6
|
||||
v0.3.5.1 v0.3.6
|
||||
v0.3.6 v0.3.7
|
||||
54
build/scripts/setup/script.d/03-setup-casaos.sh
Executable file
54
build/scripts/setup/script.d/03-setup-casaos.sh
Executable file
@@ -0,0 +1,54 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
|
||||
BUILD_PATH=$(dirname "${BASH_SOURCE[0]}")/../../..
|
||||
|
||||
APP_NAME_SHORT=casaos
|
||||
|
||||
__get_setup_script_directory_by_os_release() {
|
||||
pushd "$(dirname "${BASH_SOURCE[0]}")/../service.d/${APP_NAME_SHORT}" >/dev/null
|
||||
|
||||
{
|
||||
# shellcheck source=/dev/null
|
||||
{
|
||||
source /etc/os-release
|
||||
{
|
||||
pushd "${ID}"/"${VERSION_CODENAME}" >/dev/null
|
||||
} || {
|
||||
pushd "${ID}" >/dev/null
|
||||
} || {
|
||||
pushd "${ID_LIKE}" >/dev/null
|
||||
} || {
|
||||
echo "Unsupported OS: ${ID} ${VERSION_CODENAME} (${ID_LIKE})"
|
||||
exit 1
|
||||
}
|
||||
|
||||
pwd
|
||||
|
||||
popd >/dev/null
|
||||
|
||||
} || {
|
||||
echo "Unsupported OS: unknown"
|
||||
exit 1
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
popd >/dev/null
|
||||
}
|
||||
|
||||
SETUP_SCRIPT_DIRECTORY=$(__get_setup_script_directory_by_os_release)
|
||||
SETUP_SCRIPT_FILENAME="setup-${APP_NAME_SHORT}.sh"
|
||||
|
||||
SETUP_SCRIPT_FILEPATH="${SETUP_SCRIPT_DIRECTORY}/${SETUP_SCRIPT_FILENAME}"
|
||||
|
||||
{
|
||||
echo "🟩 Running ${SETUP_SCRIPT_FILENAME}..."
|
||||
$SHELL "${SETUP_SCRIPT_FILEPATH}" "${BUILD_PATH}"
|
||||
} || {
|
||||
echo "🟥 ${SETUP_SCRIPT_FILENAME} failed."
|
||||
exit 1
|
||||
}
|
||||
|
||||
echo "✅ ${SETUP_SCRIPT_FILENAME} finished."
|
||||
@@ -0,0 +1 @@
|
||||
../setup-casaos.sh
|
||||
45
build/scripts/setup/service.d/casaos/debian/setup-casaos.sh
Normal file
45
build/scripts/setup/service.d/casaos/debian/setup-casaos.sh
Normal file
@@ -0,0 +1,45 @@
|
||||
#!/bin/bash
|
||||
###
|
||||
# @Author: LinkLeong link@icewhale.org
|
||||
# @Date: 2022-08-25 11:41:22
|
||||
# @LastEditors: LinkLeong
|
||||
# @LastEditTime: 2022-08-31 17:54:17
|
||||
# @FilePath: /CasaOS/build/scripts/setup/service.d/casaos/debian/setup-casaos.sh
|
||||
# @Description:
|
||||
|
||||
# @Website: https://www.casaos.io
|
||||
# Copyright (c) 2022 by icewhale, All Rights Reserved.
|
||||
###
|
||||
|
||||
set -e
|
||||
|
||||
APP_NAME="casaos"
|
||||
|
||||
# copy config files
|
||||
CONF_PATH=/etc/casaos
|
||||
OLD_CONF_PATH=/etc/casaos.conf
|
||||
CONF_FILE=${CONF_PATH}/${APP_NAME}.conf
|
||||
CONF_FILE_SAMPLE=${CONF_PATH}/${APP_NAME}.conf.sample
|
||||
|
||||
|
||||
if [ -f "${OLD_CONF_PATH}" ]; then
|
||||
echo "copy old conf"
|
||||
cp "${OLD_CONF_PATH}" "${CONF_FILE}"
|
||||
fi
|
||||
if [ ! -f "${CONF_FILE}" ]; then
|
||||
echo "Initializing config file..."
|
||||
cp -v "${CONF_FILE_SAMPLE}" "${CONF_FILE}"
|
||||
fi
|
||||
|
||||
if systemctl is-active "${APP_NAME}.service" &>/dev/null ;then
|
||||
echo "server started"
|
||||
else
|
||||
# enable and start service
|
||||
systemctl daemon-reload
|
||||
|
||||
echo "Enabling service..."
|
||||
systemctl enable --force --no-ask-password "${APP_NAME}.service"
|
||||
|
||||
echo "Starting service..."
|
||||
systemctl start --force --no-ask-password "${APP_NAME}.service"
|
||||
fi
|
||||
@@ -0,0 +1 @@
|
||||
../setup-casaos.sh
|
||||
1
build/scripts/setup/service.d/casaos/ubuntu/setup-casaos.sh
Symbolic link
1
build/scripts/setup/service.d/casaos/ubuntu/setup-casaos.sh
Symbolic link
@@ -0,0 +1 @@
|
||||
../debian/setup-casaos.sh
|
||||
22
build/sysroot/etc/casaos/casaos.conf.sample
Normal file
22
build/sysroot/etc/casaos/casaos.conf.sample
Normal file
@@ -0,0 +1,22 @@
|
||||
[app]
|
||||
PAGE_SIZE = 10
|
||||
RuntimeRootPath = runtime/
|
||||
LogPath = /var/log/casaos/
|
||||
LogSaveName = log
|
||||
LogFileExt = log
|
||||
DateStrFormat = 20060102
|
||||
DateTimeFormat = 2006-01-02 15:04:05
|
||||
TimeFormat = 15:04:05
|
||||
DateFormat = 2006-01-02
|
||||
DBPath = /var/lib/casaos
|
||||
ShellPath = /usr/share/casaos/shell
|
||||
UserDataPath = /var/lib/casaos/conf
|
||||
|
||||
[server]
|
||||
RunMode = release
|
||||
ServerApi = https://api.casaos.io/casaos-api
|
||||
Handshake = socket.casaos.io
|
||||
Token =
|
||||
USBAutoMount =
|
||||
|
||||
[system]
|
||||
12
build/sysroot/usr/lib/systemd/system/casaos.service
Normal file
12
build/sysroot/usr/lib/systemd/system/casaos.service
Normal file
@@ -0,0 +1,12 @@
|
||||
[Unit]
|
||||
After=casaos-gateway.service
|
||||
ConditionFileNotEmpty=/etc/casaos/casaos.conf
|
||||
Description=CasaOS Service
|
||||
|
||||
[Service]
|
||||
ExecStart=/usr/bin/casaos -c /etc/casaos/casaos.conf
|
||||
PIDFile=/var/run/casaos/casaos.pid
|
||||
Restart=always
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
3
build/sysroot/usr/share/casaos/shell/assist.sh
Normal file
3
build/sysroot/usr/share/casaos/shell/assist.sh
Normal file
@@ -0,0 +1,3 @@
|
||||
#!/bin/bash
|
||||
|
||||
|
||||
105
build/sysroot/usr/share/casaos/shell/delete-old-service.sh
Normal file
105
build/sysroot/usr/share/casaos/shell/delete-old-service.sh
Normal file
@@ -0,0 +1,105 @@
|
||||
#!/bin/bash
|
||||
###
|
||||
# @Author: LinkLeong link@icewhale.com
|
||||
# @Date: 2022-06-30 10:08:33
|
||||
# @LastEditors: LinkLeong
|
||||
# @LastEditTime: 2022-07-01 11:17:54
|
||||
# @FilePath: /CasaOS/shell/delete-old-service.sh
|
||||
# @Description:
|
||||
###
|
||||
|
||||
((EUID)) && sudo_cmd="sudo"
|
||||
|
||||
# SYSTEM INFO
|
||||
readonly UNAME_M="$(uname -m)"
|
||||
|
||||
# CasaOS PATHS
|
||||
readonly CASA_REPO=IceWhaleTech/CasaOS
|
||||
readonly CASA_UNZIP_TEMP_FOLDER=/tmp/casaos
|
||||
readonly CASA_BIN=casaos
|
||||
readonly CASA_BIN_PATH=/usr/bin/casaos
|
||||
readonly CASA_CONF_PATH=/etc/casaos.conf
|
||||
readonly CASA_SERVICE_PATH=/etc/systemd/system/casaos.service
|
||||
readonly CASA_HELPER_PATH=/usr/share/casaos/shell/
|
||||
readonly CASA_USER_CONF_PATH=/var/lib/casaos/conf/
|
||||
readonly CASA_DB_PATH=/var/lib/casaos/db/
|
||||
readonly CASA_TEMP_PATH=/var/lib/casaos/temp/
|
||||
readonly CASA_LOGS_PATH=/var/log/casaos/
|
||||
readonly CASA_PACKAGE_EXT=".tar.gz"
|
||||
readonly CASA_RELEASE_API="https://api.github.com/repos/${CASA_REPO}/releases"
|
||||
readonly CASA_OPENWRT_DOCS="https://github.com/IceWhaleTech/CasaOS-OpenWrt"
|
||||
|
||||
readonly COLOUR_RESET='\e[0m'
|
||||
readonly aCOLOUR=(
|
||||
'\e[38;5;154m' # green | Lines, bullets and separators
|
||||
'\e[1m' # Bold white | Main descriptions
|
||||
'\e[90m' # Grey | Credits
|
||||
'\e[91m' # Red | Update notifications Alert
|
||||
'\e[33m' # Yellow | Emphasis
|
||||
)
|
||||
|
||||
Target_Arch=""
|
||||
Target_Distro="debian"
|
||||
Target_OS="linux"
|
||||
Casa_Tag=""
|
||||
|
||||
|
||||
#######################################
|
||||
# Custom printing function
|
||||
# Globals:
|
||||
# None
|
||||
# Arguments:
|
||||
# $1 0:OK 1:FAILED 2:INFO 3:NOTICE
|
||||
# message
|
||||
# Returns:
|
||||
# None
|
||||
#######################################
|
||||
|
||||
Show() {
|
||||
# OK
|
||||
if (($1 == 0)); then
|
||||
echo -e "${aCOLOUR[2]}[$COLOUR_RESET${aCOLOUR[0]} OK $COLOUR_RESET${aCOLOUR[2]}]$COLOUR_RESET $2"
|
||||
# FAILED
|
||||
elif (($1 == 1)); then
|
||||
echo -e "${aCOLOUR[2]}[$COLOUR_RESET${aCOLOUR[3]}FAILED$COLOUR_RESET${aCOLOUR[2]}]$COLOUR_RESET $2"
|
||||
# INFO
|
||||
elif (($1 == 2)); then
|
||||
echo -e "${aCOLOUR[2]}[$COLOUR_RESET${aCOLOUR[0]} INFO $COLOUR_RESET${aCOLOUR[2]}]$COLOUR_RESET $2"
|
||||
# NOTICE
|
||||
elif (($1 == 3)); then
|
||||
echo -e "${aCOLOUR[2]}[$COLOUR_RESET${aCOLOUR[4]}NOTICE$COLOUR_RESET${aCOLOUR[2]}]$COLOUR_RESET $2"
|
||||
fi
|
||||
}
|
||||
|
||||
Warn() {
|
||||
echo -e "${aCOLOUR[3]}$1$COLOUR_RESET"
|
||||
}
|
||||
|
||||
# 0 Check_exist
|
||||
Check_Exist() {
|
||||
#Create Dir
|
||||
Show 2 "Create Folders."
|
||||
${sudo_cmd} mkdir -p ${CASA_HELPER_PATH}
|
||||
${sudo_cmd} mkdir -p ${CASA_LOGS_PATH}
|
||||
${sudo_cmd} mkdir -p ${CASA_USER_CONF_PATH}
|
||||
${sudo_cmd} mkdir -p ${CASA_DB_PATH}
|
||||
${sudo_cmd} mkdir -p ${CASA_TEMP_PATH}
|
||||
|
||||
|
||||
Show 2 "Start cleaning up the old version."
|
||||
|
||||
${sudo_cmd} rm -rf /usr/lib/systemd/system/casaos.service
|
||||
|
||||
${sudo_cmd} rm -rf /lib/systemd/system/casaos.service
|
||||
|
||||
${sudo_cmd} rm -rf /usr/local/bin/${CASA_BIN}
|
||||
|
||||
#Clean
|
||||
if [[ -d "/casaOS" ]]; then
|
||||
${sudo_cmd} rm -rf /casaOS
|
||||
fi
|
||||
Show 0 "Clearance completed."
|
||||
|
||||
$sudo_cmd systemctl restart ${CASA_BIN}
|
||||
}
|
||||
Check_Exist
|
||||
@@ -330,19 +330,59 @@ TarFolder() {
|
||||
du -sh /DATA
|
||||
}
|
||||
|
||||
USB_Move_File() {
|
||||
USB_Start_Auto() {
|
||||
((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/
|
||||
$sudo_cmd systemctl enable devmon@devmon
|
||||
$sudo_cmd systemctl start devmon@devmon
|
||||
}
|
||||
|
||||
USB_Remove_File() {
|
||||
USB_Stop_Auto() {
|
||||
((EUID)) && sudo_cmd="sudo"
|
||||
$sudo_cmd rm -fr /etc/udev/rules.d/11-usb-mount.rules
|
||||
$sudo_cmd rm -fr /etc/systemd/system/usb-mount@.service
|
||||
$sudo_cmd systemctl stop devmon@devmon
|
||||
$sudo_cmd systemctl disable devmon@devmon
|
||||
$sudo_cmd udevil clean
|
||||
}
|
||||
|
||||
GetDeviceTree(){
|
||||
cat /proc/device-tree/model
|
||||
}
|
||||
|
||||
# restart samba service
|
||||
RestartSMBD(){
|
||||
$sudo_cmd systemctl restart smbd
|
||||
}
|
||||
|
||||
# edit user password $1:username
|
||||
EditSmabaUserPassword(){
|
||||
$sudo_cmd smbpasswd $1
|
||||
}
|
||||
|
||||
AddSmabaUser(){
|
||||
$sudo_cmd useradd $1
|
||||
$sudo_cmd smbpasswd -a $1 <<EOF
|
||||
$2
|
||||
$2
|
||||
EOF
|
||||
}
|
||||
|
||||
# $1:username $2:host $3:share $4:port $5:mountpoint $6:password
|
||||
MountCIFS(){
|
||||
$sudo_cmd mount -t cifs -o username=$1,password=$6,port=$4 //$2/$3 $5
|
||||
}
|
||||
|
||||
# $1:service name
|
||||
CheckServiceStatus(){
|
||||
rs="`systemctl status $1 |grep -E 'Active|PID'`"
|
||||
#echo "$rs"
|
||||
run="`echo "$rs" |grep -B 2 'running'`"
|
||||
fai="`echo "$rs" |grep -E -B 2 'failed|inactive|dead'`"
|
||||
if [ "$run" == "" ]
|
||||
then
|
||||
echo "failed"
|
||||
else
|
||||
echo "running"
|
||||
fi
|
||||
}
|
||||
UDEVILUmount(){
|
||||
$sudo_cmd udevil umount -f $1
|
||||
}
|
||||
12
build/sysroot/usr/share/casaos/shell/update.sh
Normal file
12
build/sysroot/usr/share/casaos/shell/update.sh
Normal file
@@ -0,0 +1,12 @@
|
||||
#!/bin/bash
|
||||
###
|
||||
# @Author: LinkLeong link@icewhale.com
|
||||
# @Date: 2022-06-30 10:08:33
|
||||
# @LastEditors: LinkLeong
|
||||
# @LastEditTime: 2022-09-01 22:33:06
|
||||
# @FilePath: /CasaOS/build/sysroot/usr/share/casaos/shell/update.sh
|
||||
# @Description:
|
||||
###
|
||||
|
||||
|
||||
curl -fsSL https://raw.githubusercontent.com/LinkLeong/casaos-alpha/main/new.update.sh | bash
|
||||
37
cmd/migration-tool/log.go
Normal file
37
cmd/migration-tool/log.go
Normal file
@@ -0,0 +1,37 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"log"
|
||||
"os"
|
||||
)
|
||||
|
||||
type Logger struct {
|
||||
DebugMode bool
|
||||
|
||||
_debug *log.Logger
|
||||
_info *log.Logger
|
||||
_error *log.Logger
|
||||
}
|
||||
|
||||
func NewLogger() *Logger {
|
||||
return &Logger{
|
||||
DebugMode: false,
|
||||
_debug: log.New(os.Stdout, "DEBUG: ", 0),
|
||||
_info: log.New(os.Stdout, "", 0),
|
||||
_error: log.New(os.Stderr, "ERROR: ", 0),
|
||||
}
|
||||
}
|
||||
|
||||
func (l *Logger) Debug(format string, v ...interface{}) {
|
||||
if l.DebugMode {
|
||||
l._debug.Printf(format, v...)
|
||||
}
|
||||
}
|
||||
|
||||
func (l *Logger) Info(format string, v ...interface{}) {
|
||||
l._info.Printf(format, v...)
|
||||
}
|
||||
|
||||
func (l *Logger) Error(format string, v ...interface{}) {
|
||||
l._error.Printf(format, v...)
|
||||
}
|
||||
122
cmd/migration-tool/main.go
Normal file
122
cmd/migration-tool/main.go
Normal file
@@ -0,0 +1,122 @@
|
||||
/*
|
||||
* @Author: LinkLeong link@icewhale.org
|
||||
* @Date: 2022-08-23 18:09:11
|
||||
* @LastEditors: LinkLeong
|
||||
* @LastEditTime: 2022-08-31 14:17:51
|
||||
* @FilePath: /CasaOS/cmd/migration-tool/main.go
|
||||
* @Description:
|
||||
* @Website: https://www.casaos.io
|
||||
* Copyright (c) 2022 by icewhale, All Rights Reserved.
|
||||
*/
|
||||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
interfaces "github.com/IceWhaleTech/CasaOS-Common"
|
||||
"github.com/IceWhaleTech/CasaOS-Common/utils/systemctl"
|
||||
"github.com/IceWhaleTech/CasaOS-Gateway/common"
|
||||
"github.com/IceWhaleTech/CasaOS/pkg/config"
|
||||
"github.com/IceWhaleTech/CasaOS/pkg/sqlite"
|
||||
"github.com/IceWhaleTech/CasaOS/service"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
const (
|
||||
casaosServiceName = "casaos.service"
|
||||
)
|
||||
|
||||
var (
|
||||
_logger *Logger
|
||||
sqliteDB *gorm.DB
|
||||
)
|
||||
|
||||
var (
|
||||
configFlag = ""
|
||||
dbFlag = ""
|
||||
)
|
||||
|
||||
func init() {
|
||||
config.InitSetup(configFlag)
|
||||
|
||||
if len(dbFlag) == 0 {
|
||||
dbFlag = config.AppInfo.DBPath + "/db"
|
||||
}
|
||||
|
||||
sqliteDB = sqlite.GetDb(dbFlag)
|
||||
// gredis.GetRedisConn(config.RedisInfo),
|
||||
|
||||
service.MyService = service.NewService(sqliteDB, "")
|
||||
}
|
||||
|
||||
func main() {
|
||||
versionFlag := flag.Bool("v", false, "version")
|
||||
debugFlag := flag.Bool("d", true, "debug")
|
||||
forceFlag := flag.Bool("f", true, "force")
|
||||
flag.Parse()
|
||||
_logger = NewLogger()
|
||||
if *versionFlag {
|
||||
fmt.Println(common.Version)
|
||||
os.Exit(0)
|
||||
}
|
||||
|
||||
if os.Getuid() != 0 {
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
if *debugFlag {
|
||||
_logger.DebugMode = true
|
||||
}
|
||||
|
||||
if !*forceFlag {
|
||||
serviceEnabled, err := systemctl.IsServiceEnabled(casaosServiceName)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
if serviceEnabled {
|
||||
_logger.Info("%s is already enabled. If migration is still needed, try with -f.", casaosServiceName)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
migrationTools := []interfaces.MigrationTool{
|
||||
NewMigrationToolFor_035(),
|
||||
NewMigrationToolFor_036(),
|
||||
}
|
||||
|
||||
var selectedMigrationTool interfaces.MigrationTool
|
||||
|
||||
// look for the right migration tool matching current version
|
||||
for _, tool := range migrationTools {
|
||||
migrationNeeded, err := tool.IsMigrationNeeded()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
if migrationNeeded {
|
||||
selectedMigrationTool = tool
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if selectedMigrationTool == nil {
|
||||
_logger.Error("selectedMigrationTool is null")
|
||||
return
|
||||
}
|
||||
|
||||
if err := selectedMigrationTool.PreMigrate(); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
if err := selectedMigrationTool.Migrate(); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
selectedMigrationTool.PostMigrate()
|
||||
_logger.Info("casaos migration ok")
|
||||
// panic(err)
|
||||
|
||||
}
|
||||
182
cmd/migration-tool/migration-034-035.go
Normal file
182
cmd/migration-tool/migration-034-035.go
Normal file
@@ -0,0 +1,182 @@
|
||||
/*
|
||||
* @Author: LinkLeong link@icewhale.org
|
||||
* @Date: 2022-08-24 17:36:00
|
||||
* @LastEditors: LinkLeong
|
||||
* @LastEditTime: 2022-09-05 11:24:27
|
||||
* @FilePath: /CasaOS/cmd/migration-tool/migration-034-035.go
|
||||
* @Description:
|
||||
* @Website: https://www.casaos.io
|
||||
* Copyright (c) 2022 by icewhale, All Rights Reserved.
|
||||
*/
|
||||
package main
|
||||
|
||||
import (
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path"
|
||||
"strings"
|
||||
|
||||
interfaces "github.com/IceWhaleTech/CasaOS-Common"
|
||||
"github.com/IceWhaleTech/CasaOS-Common/utils/version"
|
||||
"github.com/IceWhaleTech/CasaOS/pkg/config"
|
||||
"github.com/IceWhaleTech/CasaOS/pkg/utils/command"
|
||||
"github.com/IceWhaleTech/CasaOS/pkg/utils/file"
|
||||
"github.com/IceWhaleTech/CasaOS/service"
|
||||
)
|
||||
|
||||
type migrationTool036 struct{}
|
||||
|
||||
func (u *migrationTool036) IsMigrationNeeded() (bool, error) {
|
||||
|
||||
majorVersion, minorVersion, patchVersion, err := version.DetectLegacyVersion()
|
||||
if err != nil {
|
||||
if err == version.ErrLegacyVersionNotFound {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
return false, err
|
||||
}
|
||||
|
||||
if majorVersion > 0 {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
if minorVersion > 3 {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
if minorVersion == 3 && patchVersion > 5 {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
_logger.Info("Migration is needed for a CasaOS version 0.3.5 and older...")
|
||||
return true, nil
|
||||
|
||||
}
|
||||
|
||||
func (u *migrationTool036) PreMigrate() error {
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (u *migrationTool036) Migrate() error {
|
||||
|
||||
if service.MyService.System().GetSysInfo().KernelArch == "aarch64" && config.ServerInfo.USBAutoMount != "True" && strings.Contains(service.MyService.System().GetDeviceTree(), "Raspberry Pi") {
|
||||
service.MyService.System().UpdateUSBAutoMount("False")
|
||||
service.MyService.System().ExecUSBAutoMountShell("False")
|
||||
}
|
||||
newAPIUrl := "https://api.casaos.io/casaos-api"
|
||||
if config.ServerInfo.ServerApi == "https://api.casaos.zimaboard.com" {
|
||||
config.ServerInfo.ServerApi = newAPIUrl
|
||||
config.Cfg.Section("server").Key("ServerApi").SetValue(newAPIUrl)
|
||||
config.Cfg.SaveTo(config.SystemConfigInfo.ConfigPath)
|
||||
}
|
||||
command.OnlyExec("curl -fsSL https://raw.githubusercontent.com/IceWhaleTech/get/main/assist.sh | bash")
|
||||
if !file.CheckNotExist("/casaOS") {
|
||||
command.OnlyExec("source /casaOS/server/shell/update.sh ;")
|
||||
command.OnlyExec("source " + config.AppInfo.ShellPath + "/delete-old-service.sh ;")
|
||||
}
|
||||
|
||||
service.MyService.App().ImportApplications(true)
|
||||
|
||||
src := "/casaOS/server/conf/conf.ini"
|
||||
if file.Exists(src) {
|
||||
dst := "/etc/casaos/casaos.conf"
|
||||
source, err := os.Open(src)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer source.Close()
|
||||
|
||||
destination, err := os.Create(dst)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer destination.Close()
|
||||
_, err = io.Copy(destination, source)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if file.Exists("/casaOS/server/db") {
|
||||
var fds []os.FileInfo
|
||||
var err error
|
||||
to := "/var/lib/casaos/db"
|
||||
file.IsNotExistMkDir(to)
|
||||
from := "/casaOS/server/db"
|
||||
if fds, err = ioutil.ReadDir(from); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, fd := range fds {
|
||||
srcfp := path.Join(from, fd.Name())
|
||||
dstfp := path.Join(to, fd.Name())
|
||||
source, err := os.Open(srcfp)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer source.Close()
|
||||
|
||||
destination, err := os.Create(dstfp)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer destination.Close()
|
||||
_, err = io.Copy(destination, source)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if file.Exists("/casaOS/server/conf") {
|
||||
var fds []os.FileInfo
|
||||
var err error
|
||||
to := "/var/lib/casaos/conf"
|
||||
file.IsNotExistMkDir(to)
|
||||
from := "/casaOS/server/conf"
|
||||
if fds, err = ioutil.ReadDir(from); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, fd := range fds {
|
||||
fExt := path.Ext(fd.Name())
|
||||
if fExt != ".json" {
|
||||
continue
|
||||
}
|
||||
srcfp := path.Join(from, fd.Name())
|
||||
dstfp := path.Join(to, fd.Name())
|
||||
source, err := os.Open(srcfp)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer source.Close()
|
||||
|
||||
destination, err := os.Create(dstfp)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer destination.Close()
|
||||
_, err = io.Copy(destination, source)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
_logger.Info("update done")
|
||||
return nil
|
||||
}
|
||||
|
||||
func (u *migrationTool036) PostMigrate() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func NewMigrationToolFor_035() interfaces.MigrationTool {
|
||||
return &migrationTool{}
|
||||
}
|
||||
74
cmd/migration-tool/migration-036.go
Normal file
74
cmd/migration-tool/migration-036.go
Normal file
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* @Author: LinkLeong link@icewhale.org
|
||||
* @Date: 2022-08-24 17:36:00
|
||||
* @LastEditors: LinkLeong
|
||||
* @LastEditTime: 2022-09-05 11:24:27
|
||||
* @FilePath: /CasaOS/cmd/migration-tool/migration-034-035.go
|
||||
* @Description:
|
||||
* @Website: https://www.casaos.io
|
||||
* Copyright (c) 2022 by icewhale, All Rights Reserved.
|
||||
*/
|
||||
package main
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
interfaces "github.com/IceWhaleTech/CasaOS-Common"
|
||||
"github.com/IceWhaleTech/CasaOS-Common/utils/version"
|
||||
"github.com/IceWhaleTech/CasaOS/pkg/config"
|
||||
"github.com/IceWhaleTech/CasaOS/service"
|
||||
)
|
||||
|
||||
type migrationTool struct{}
|
||||
|
||||
func (u *migrationTool) IsMigrationNeeded() (bool, error) {
|
||||
|
||||
majorVersion, minorVersion, patchVersion, err := version.DetectLegacyVersion()
|
||||
if err != nil {
|
||||
if err == version.ErrLegacyVersionNotFound {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
return false, err
|
||||
}
|
||||
|
||||
if majorVersion > 0 {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
if minorVersion > 3 {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
if minorVersion == 3 && patchVersion > 5 {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
_logger.Info("Migration is needed for a CasaOS version 0.3.5 and older...")
|
||||
return true, nil
|
||||
|
||||
}
|
||||
|
||||
func (u *migrationTool) PreMigrate() error {
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (u *migrationTool) Migrate() error {
|
||||
|
||||
if service.MyService.System().GetSysInfo().KernelArch == "aarch64" && config.ServerInfo.USBAutoMount != "True" && strings.Contains(service.MyService.System().GetDeviceTree(), "Raspberry Pi") {
|
||||
service.MyService.System().UpdateUSBAutoMount("False")
|
||||
service.MyService.System().ExecUSBAutoMountShell("False")
|
||||
}
|
||||
|
||||
_logger.Info("update done")
|
||||
return nil
|
||||
}
|
||||
|
||||
func (u *migrationTool) PostMigrate() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func NewMigrationToolFor_036() interfaces.MigrationTool {
|
||||
return &migrationTool{}
|
||||
}
|
||||
89
common/notify.go
Normal file
89
common/notify.go
Normal file
@@ -0,0 +1,89 @@
|
||||
package common
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const (
|
||||
CasaOSURLFilename = "casaos.url"
|
||||
APICasaOSNotify = "/v1/notify"
|
||||
)
|
||||
|
||||
type NotifyService interface {
|
||||
SendNotify(path string, message map[string]interface{}) error
|
||||
SendSystemStatusNotify(message map[string]interface{}) error
|
||||
}
|
||||
type notifyService struct {
|
||||
address string
|
||||
}
|
||||
|
||||
func (n *notifyService) SendNotify(path string, message map[string]interface{}) error {
|
||||
|
||||
url := strings.TrimSuffix(n.address, "/") + APICasaOSNotify + "/" + path
|
||||
body, err := json.Marshal(message)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
response, err := http.Post(url, "application/json", bytes.NewBuffer(body))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if response.StatusCode != http.StatusOK {
|
||||
return errors.New("failed to send notify (status code: " + fmt.Sprint(response.StatusCode) + ")")
|
||||
}
|
||||
return nil
|
||||
|
||||
}
|
||||
|
||||
// disk: "sys_disk":{"size":56866869248,"avail":5855485952,"health":true,"used":48099700736}
|
||||
// usb: "sys_usb":[{"name": "sdc","size": 7747397632,"model": "DataTraveler_2.0","avail": 7714418688,"children": null}]
|
||||
func (n *notifyService) SendSystemStatusNotify(message map[string]interface{}) error {
|
||||
|
||||
url := strings.TrimSuffix(n.address, "/") + APICasaOSNotify + "/system_status"
|
||||
fmt.Println(url)
|
||||
body, err := json.Marshal(message)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
response, err := http.Post(url, "application/json", bytes.NewBuffer(body))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if response.StatusCode != http.StatusOK {
|
||||
return errors.New("failed to send notify (status code: " + fmt.Sprint(response.StatusCode) + ")")
|
||||
}
|
||||
return nil
|
||||
|
||||
}
|
||||
func NewNotifyService(runtimePath string) (NotifyService, error) {
|
||||
casaosAddressFile := filepath.Join(runtimePath, CasaOSURLFilename)
|
||||
|
||||
buf, err := os.ReadFile(casaosAddressFile)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
address := string(buf)
|
||||
|
||||
response, err := http.Get(address + "/ping")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if response.StatusCode != 200 {
|
||||
return nil, errors.New("failed to ping casaos service")
|
||||
}
|
||||
|
||||
return ¬ifyService{
|
||||
address: address,
|
||||
}, nil
|
||||
}
|
||||
29
common/notify_test.go
Normal file
29
common/notify_test.go
Normal file
@@ -0,0 +1,29 @@
|
||||
package common
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestSendNotify(t *testing.T) {
|
||||
notify, err := NewNotifyService("/var/run/casaos")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
err = notify.SendNotify("test", map[string]interface{}{
|
||||
"test": "test",
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSendSystemStatusNotify(t *testing.T) {
|
||||
notify, err := NewNotifyService("/var/run/casaos")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
err = notify.SendSystemStatusNotify(map[string]interface{}{
|
||||
"sys_usb": `[{"name": "sdc","size": 7747397632,"model": "DataTraveler_2.0","avail": 7714418688,"children": null}]`,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
78
common/share.go
Normal file
78
common/share.go
Normal file
@@ -0,0 +1,78 @@
|
||||
package common
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const (
|
||||
APICasaOSShare = "/v1/samba/shares"
|
||||
)
|
||||
|
||||
type ShareService interface {
|
||||
DeleteShare(id string) error
|
||||
}
|
||||
type shareService struct {
|
||||
address string
|
||||
}
|
||||
|
||||
func (n *shareService) DeleteShare(id string) error {
|
||||
url := strings.TrimSuffix(n.address, "/") + APICasaOSShare + "/" + id
|
||||
fmt.Println(url)
|
||||
message := "{}"
|
||||
body, err := json.Marshal(message)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
client := &http.Client{}
|
||||
|
||||
// Create request
|
||||
req, err := http.NewRequest("DELETE", url, bytes.NewBuffer(body))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Fetch Request
|
||||
response, err := client.Do(req)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer response.Body.Close()
|
||||
|
||||
if response.StatusCode != http.StatusOK {
|
||||
return errors.New("failed to send share (status code: " + fmt.Sprint(response.StatusCode) + ")")
|
||||
}
|
||||
return nil
|
||||
|
||||
}
|
||||
|
||||
func NewShareService(runtimePath string) (ShareService, error) {
|
||||
casaosAddressFile := filepath.Join(runtimePath, CasaOSURLFilename)
|
||||
|
||||
buf, err := os.ReadFile(casaosAddressFile)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
address := string(buf)
|
||||
|
||||
response, err := http.Get(address + "/ping")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if response.StatusCode != 200 {
|
||||
return nil, errors.New("failed to ping casaos service")
|
||||
}
|
||||
|
||||
return &shareService{
|
||||
address: address,
|
||||
}, nil
|
||||
}
|
||||
14
common/share_test.go
Normal file
14
common/share_test.go
Normal file
@@ -0,0 +1,14 @@
|
||||
package common
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestDeleteShare(t *testing.T) {
|
||||
share, err := NewShareService("/var/run/casaos")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
err = share.DeleteShare("1")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
@@ -1,32 +1,25 @@
|
||||
[app]
|
||||
PAGE_SIZE = 10
|
||||
RuntimeRootPath = runtime/
|
||||
LogSavePath = /casaOS/logs/server/
|
||||
LogPath = /var/log/casaos/
|
||||
LogSaveName = log
|
||||
LogFileExt = log
|
||||
DateStrFormat = 20060102
|
||||
DateTimeFormat = 2006-01-02 15:04:05
|
||||
TimeFormat = 15:04:05
|
||||
DateFormat = 2006-01-02
|
||||
ProjectPath = /casaOS/server
|
||||
RootPath = /casaOS
|
||||
|
||||
DBPath = /var/lib/casaos
|
||||
ShellPath = /usr/share/casaos/shell
|
||||
UserDataPath = /var/lib/casaos/conf
|
||||
|
||||
[server]
|
||||
HttpPort = 8089
|
||||
UDPPort =
|
||||
RunMode = release
|
||||
ServerApi = https://api.casaos.io/casaos-api
|
||||
Handshake = socket.casaos.io
|
||||
Token =
|
||||
USBAutoMount =
|
||||
|
||||
|
||||
[system]
|
||||
ConfigStr =
|
||||
WidgetList =
|
||||
|
||||
|
||||
[file]
|
||||
ShareDir =
|
||||
DownloadDir =
|
||||
[common]
|
||||
RuntimePath=/var/run/casaos
|
||||
54
go.mod
54
go.mod
@@ -4,82 +4,52 @@ go 1.16
|
||||
|
||||
require (
|
||||
github.com/Curtis-Milo/nat-type-identifier-go v0.0.0-20220215191915-18d42168c63d
|
||||
github.com/IceWhaleTech/CasaOS-Common v0.0.0-20220901034123-ca130f6b5ce9
|
||||
github.com/IceWhaleTech/CasaOS-Gateway v0.3.6
|
||||
github.com/Microsoft/go-winio v0.5.0 // indirect
|
||||
github.com/Microsoft/hcsshim v0.8.22 // indirect
|
||||
github.com/StackExchange/wmi v0.0.0-20210224194228-fe8f1750fd46 // indirect
|
||||
github.com/ambelovsky/go-structs v1.1.0 // indirect
|
||||
github.com/ambelovsky/gosf v0.0.0-20201109201340-237aea4d6109
|
||||
github.com/ambelovsky/gosf-socketio v0.0.0-20201109193639-add9d32f8b19 // indirect
|
||||
github.com/bits-and-blooms/bitset v1.2.1 // indirect
|
||||
github.com/containerd/containerd v1.5.7
|
||||
github.com/containerd/continuity v0.2.0 // indirect
|
||||
github.com/containerd/containerd v1.5.7 // indirect
|
||||
github.com/disintegration/imaging v1.6.2
|
||||
github.com/docker/distribution v2.8.0+incompatible // indirect
|
||||
github.com/docker/docker v20.10.7+incompatible
|
||||
github.com/docker/go-connections v0.4.0
|
||||
github.com/dsoprea/go-exif/v3 v3.0.0-20210625224831-a6301f85c82b
|
||||
github.com/dsoprea/go-logging v0.0.0-20200710184922-b02d349568dd // indirect
|
||||
github.com/forease/gotld v0.0.0-20190808124948-c50ff635576b
|
||||
github.com/gin-contrib/gzip v0.0.2
|
||||
github.com/gin-gonic/gin v1.7.2
|
||||
github.com/gin-contrib/gzip v0.0.6
|
||||
github.com/gin-gonic/gin v1.8.1
|
||||
github.com/go-ini/ini v1.62.0
|
||||
github.com/go-ole/go-ole v1.2.5 // indirect
|
||||
github.com/go-openapi/spec v0.20.4 // indirect
|
||||
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
|
||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
|
||||
github.com/golang/mock v1.6.0
|
||||
github.com/gomodule/redigo v1.8.5
|
||||
github.com/google/go-github/v36 v36.0.0
|
||||
github.com/google/uuid v1.3.0 // indirect
|
||||
github.com/googollee/go-socket.io v1.6.2
|
||||
github.com/gorilla/mux v1.8.0 // indirect
|
||||
github.com/gorilla/websocket v1.4.2
|
||||
github.com/hirochachacha/go-smb2 v1.1.0
|
||||
github.com/jinzhu/copier v0.3.2
|
||||
github.com/json-iterator/go v1.1.11 // indirect
|
||||
github.com/klauspost/compress v1.13.6 // indirect
|
||||
github.com/leodido/go-urn v1.2.1 // indirect
|
||||
github.com/lucas-clemente/quic-go v0.25.0
|
||||
github.com/mailru/easyjson v0.7.7 // indirect
|
||||
github.com/mattn/go-isatty v0.0.14 // indirect
|
||||
github.com/mattn/go-sqlite3 v1.14.11 // indirect
|
||||
github.com/mholt/archiver/v3 v3.5.1
|
||||
github.com/moby/term v0.0.0-20210619224110-3f7ff695adc6 // indirect
|
||||
github.com/morikuni/aec v1.0.0 // indirect
|
||||
github.com/opencontainers/image-spec v1.0.2 // indirect
|
||||
github.com/opencontainers/selinux v1.8.5 // indirect
|
||||
github.com/patrickmn/go-cache v2.1.0+incompatible
|
||||
github.com/pkg/errors v0.9.1
|
||||
github.com/prestonTao/upnp v0.0.0-20150206124352-f4370df5e109
|
||||
github.com/prometheus/procfs v0.7.3 // indirect
|
||||
github.com/robfig/cron v1.2.0
|
||||
github.com/satori/go.uuid v1.2.0
|
||||
github.com/shirou/gopsutil/v3 v3.21.5
|
||||
github.com/shirou/gopsutil/v3 v3.22.7
|
||||
github.com/sirupsen/logrus v1.8.1
|
||||
github.com/smartystreets/assertions v1.2.0 // indirect
|
||||
github.com/smartystreets/goconvey v1.6.4 // indirect
|
||||
github.com/swaggo/gin-swagger v1.3.0
|
||||
github.com/swaggo/swag v1.7.3
|
||||
github.com/stretchr/testify v1.8.0
|
||||
github.com/tidwall/gjson v1.10.2
|
||||
github.com/tklauser/go-sysconf v0.3.6 // indirect
|
||||
github.com/ugorji/go v1.2.6 // indirect
|
||||
go.opencensus.io v0.23.0 // indirect
|
||||
go.uber.org/zap v1.10.0
|
||||
golang.org/x/crypto v0.0.0-20210817164053-32db794688a5
|
||||
go.uber.org/zap v1.21.0
|
||||
golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4
|
||||
golang.org/x/mod v0.5.0 // 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-20211020174200-9d6173849985 // indirect
|
||||
golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b // indirect
|
||||
golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5
|
||||
golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac // 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
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
|
||||
gopkg.in/ini.v1 v1.62.0 // indirect
|
||||
gopkg.in/natefinch/lumberjack.v2 v2.0.0
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect
|
||||
gorm.io/driver/sqlite v1.2.6
|
||||
gorm.io/gorm v1.22.5
|
||||
)
|
||||
|
||||
18
interfaces/migrationTool.go
Normal file
18
interfaces/migrationTool.go
Normal file
@@ -0,0 +1,18 @@
|
||||
/*
|
||||
* @Author: LinkLeong link@icewhale.org
|
||||
* @Date: 2022-08-24 17:37:36
|
||||
* @LastEditors: LinkLeong
|
||||
* @LastEditTime: 2022-08-24 17:38:48
|
||||
* @FilePath: /CasaOS/interfaces/migrationTool.go
|
||||
* @Description:
|
||||
* @Website: https://www.casaos.io
|
||||
* Copyright (c) 2022 by icewhale, All Rights Reserved.
|
||||
*/
|
||||
package interfaces
|
||||
|
||||
type MigrationTool interface {
|
||||
IsMigrationNeeded() (bool, error)
|
||||
PostMigrate() error
|
||||
Migrate() error
|
||||
PreMigrate() error
|
||||
}
|
||||
136
main.go
136
main.go
@@ -3,54 +3,64 @@ package main
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/http"
|
||||
"path/filepath"
|
||||
"time"
|
||||
|
||||
"github.com/IceWhaleTech/CasaOS-Gateway/common"
|
||||
"github.com/IceWhaleTech/CasaOS/model/notify"
|
||||
"github.com/IceWhaleTech/CasaOS/pkg/cache"
|
||||
"github.com/IceWhaleTech/CasaOS/pkg/config"
|
||||
"github.com/IceWhaleTech/CasaOS/pkg/sqlite"
|
||||
"github.com/IceWhaleTech/CasaOS/pkg/utils/file"
|
||||
"github.com/IceWhaleTech/CasaOS/pkg/utils/loger"
|
||||
"github.com/IceWhaleTech/CasaOS/route"
|
||||
"github.com/IceWhaleTech/CasaOS/service"
|
||||
"github.com/IceWhaleTech/CasaOS/types"
|
||||
"go.uber.org/zap"
|
||||
|
||||
"github.com/robfig/cron"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
const LOCALHOST = "127.0.0.1"
|
||||
|
||||
var sqliteDB *gorm.DB
|
||||
|
||||
var configFlag = flag.String("c", "", "config address")
|
||||
var dbFlag = flag.String("db", "", "db path")
|
||||
var showUserInfo = flag.Bool("show-user-info", false, "show user info")
|
||||
var (
|
||||
configFlag = flag.String("c", "", "config address")
|
||||
dbFlag = flag.String("db", "", "db path")
|
||||
versionFlag = flag.Bool("v", false, "version")
|
||||
)
|
||||
|
||||
func init() {
|
||||
flag.Parse()
|
||||
if *versionFlag {
|
||||
fmt.Println("v" + types.CURRENTVERSION)
|
||||
return
|
||||
}
|
||||
config.InitSetup(*configFlag)
|
||||
config.UpdateSetup()
|
||||
|
||||
loger.LogInit()
|
||||
if len(*dbFlag) == 0 {
|
||||
*dbFlag = config.AppInfo.ProjectPath + "/db"
|
||||
*dbFlag = config.AppInfo.DBPath + "/db"
|
||||
}
|
||||
|
||||
sqliteDB = sqlite.GetDb(*dbFlag)
|
||||
//gredis.GetRedisConn(config.RedisInfo),
|
||||
service.MyService = service.NewService(sqliteDB)
|
||||
// gredis.GetRedisConn(config.RedisInfo),
|
||||
|
||||
service.MyService = service.NewService(sqliteDB, config.CommonInfo.RuntimePath)
|
||||
|
||||
service.Cache = cache.Init()
|
||||
|
||||
go service.UDPService()
|
||||
service.GetToken()
|
||||
|
||||
fmt.Println("t", service.GetToken())
|
||||
service.UDPAddressMap = make(map[string]string)
|
||||
//go service.SocketConnect()
|
||||
service.CancelList = make(map[string]string)
|
||||
service.InternalInspection = make(map[string][]string)
|
||||
service.NewVersionApp = make(map[string]string)
|
||||
route.InitFunction()
|
||||
|
||||
go service.SendIPToServer()
|
||||
// go service.LoopFriend()
|
||||
// go service.MyService.App().CheckNewImage()
|
||||
|
||||
}
|
||||
|
||||
// @title casaOS API
|
||||
@@ -66,41 +76,19 @@ func init() {
|
||||
// @BasePath /v1
|
||||
func main() {
|
||||
service.NotifyMsg = make(chan notify.Message, 10)
|
||||
if *showUserInfo {
|
||||
fmt.Println("CasaOS User Info")
|
||||
fmt.Println("UserName:" + config.UserInfo.UserName)
|
||||
fmt.Println("Password:" + config.UserInfo.PWD)
|
||||
if *versionFlag {
|
||||
return
|
||||
}
|
||||
|
||||
go route.SocketInit(service.NotifyMsg)
|
||||
go func() {
|
||||
for i := 0; i < 1000; i++ {
|
||||
time.Sleep(2 * time.Second)
|
||||
//service.NotifyMsg <- strconv.Itoa(i)
|
||||
}
|
||||
}()
|
||||
// model.Setup()
|
||||
// gredis.Setup()
|
||||
|
||||
//model.Setup()
|
||||
//gredis.Setup()
|
||||
r := route.InitRouter()
|
||||
//service.SyncTask(sqliteDB)
|
||||
// service.SyncTask(sqliteDB)
|
||||
cron2 := cron.New()
|
||||
//every day execution
|
||||
err := cron2.AddFunc("0 0/5 * * * *", func() {
|
||||
//service.PushIpInfo(*&config.ServerInfo.Token)
|
||||
//service.UpdataDDNSList(mysqldb)
|
||||
//service.SyncTask(sqliteDB)
|
||||
// every day execution
|
||||
|
||||
service.SendIPToServer()
|
||||
|
||||
service.LoopFriend()
|
||||
//service.MyService.App().CheckNewImage()
|
||||
})
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
err = cron2.AddFunc("0/5 * * * * *", func() {
|
||||
err := cron2.AddFunc("0/5 * * * * *", func() {
|
||||
if service.ClientCount > 0 {
|
||||
// route.SendNetINfoBySocket()
|
||||
// route.SendCPUBySocket()
|
||||
@@ -114,18 +102,58 @@ func main() {
|
||||
fmt.Println(err)
|
||||
}
|
||||
cron2.Start()
|
||||
|
||||
defer cron2.Stop()
|
||||
s := &http.Server{
|
||||
Addr: fmt.Sprintf(":%v", config.ServerInfo.HttpPort),
|
||||
Handler: r,
|
||||
ReadTimeout: 60 * time.Second,
|
||||
WriteTimeout: 60 * time.Second,
|
||||
MaxHeaderBytes: 1 << 20,
|
||||
|
||||
listener, err := net.Listen("tcp", net.JoinHostPort(LOCALHOST, "0"))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
routers := []string{"sys", "apps", "container", "app-categories", "port", "file", "folder", "batch", "image", "samba", "notify"}
|
||||
for _, v := range routers {
|
||||
err = service.MyService.Gateway().CreateRoute(&common.Route{
|
||||
Path: "/v1/" + v,
|
||||
Target: "http://" + listener.Addr().String(),
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
fmt.Println("err", err)
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
go func() {
|
||||
time.Sleep(time.Second * 2)
|
||||
// v0.3.6
|
||||
if config.ServerInfo.HttpPort != "" {
|
||||
changePort := common.ChangePortRequest{}
|
||||
changePort.Port = config.ServerInfo.HttpPort
|
||||
err := service.MyService.Gateway().ChangePort(&changePort)
|
||||
if err == nil {
|
||||
config.Cfg.Section("server").Key("HttpPort").SetValue("")
|
||||
config.Cfg.SaveTo(config.SystemConfigInfo.ConfigPath)
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
// s := &http.Server{
|
||||
// Addr: listener.Addr().String(), //fmt.Sprintf(":%v", config.ServerInfo.HttpPort),
|
||||
// Handler: r,
|
||||
// ReadTimeout: 60 * time.Second,
|
||||
// WriteTimeout: 60 * time.Second,
|
||||
// MaxHeaderBytes: 1 << 20,
|
||||
// }
|
||||
// s.ListenAndServe()
|
||||
urlFilePath := filepath.Join(config.CommonInfo.RuntimePath, "casaos.url")
|
||||
err = file.CreateFileAndWriteContent(urlFilePath, "http://"+listener.Addr().String())
|
||||
if err != nil {
|
||||
loger.Error("Management service is listening...",
|
||||
zap.Any("address", listener.Addr().String()),
|
||||
zap.Any("filepath", urlFilePath),
|
||||
)
|
||||
}
|
||||
|
||||
s.ListenAndServe()
|
||||
|
||||
// if err := r.Run(fmt.Sprintf(":%v", config.ServerInfo.HttpPort)); err != nil {
|
||||
// fmt.Println("failed run app: ", err)
|
||||
// }
|
||||
err = http.Serve(listener, r)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* @Author: LinkLeong link@icewhale.com
|
||||
* @Date: 2021-10-08 10:29:08
|
||||
* @LastEditors: LinkLeong
|
||||
* @LastEditTime: 2022-05-25 19:17:45
|
||||
* @LastEditTime: 2022-07-22 11:06:07
|
||||
* @FilePath: /CasaOS/middleware/gin.go
|
||||
* @Description:
|
||||
* @Website: https://www.casaos.io
|
||||
@@ -13,8 +13,11 @@ package middleware
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/IceWhaleTech/CasaOS/pkg/utils/loger"
|
||||
"github.com/gin-gonic/gin"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
func Cors() gin.HandlerFunc {
|
||||
@@ -24,14 +27,14 @@ func Cors() gin.HandlerFunc {
|
||||
c.Header("Access-Control-Allow-Origin", "*")
|
||||
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,Language")
|
||||
c.Header("Access-Control-Allow-Headers", "Authorization, Content-Length, X-CSRF-Token, Token,session,Language,Content-Type,Access-Control-Allow-Origin,Access-Control-Allow-Headers,Access-Control-Allow-Methods,Connection,Host,Origin,Referer,User-Agent,X-Requested-With")
|
||||
// 允许浏览器(客户端)可以解析的头部 (重要)
|
||||
c.Header("Access-Control-Expose-Headers", "Content-Length, Access-Control-Allow-Origin, Access-Control-Allow-Headers")
|
||||
//c.Writer.Header().Set("Access-Control-Allow-Headers", "Accept, Authorization, Content-Type, Content-Length, X-CSRF-Token, Token, session, Origin, Host, Connection, Accept-Encoding, Accept-Language, X-Requested-With")
|
||||
//设置缓存时间
|
||||
c.Header("Access-Control-Max-Age", "172800")
|
||||
c.Header("Access-Control-Allow-Credentials", "true")
|
||||
c.Set("content-type", "application/json")
|
||||
c.Set("Content-Type", "application/json")
|
||||
//}
|
||||
|
||||
//允许类型校验
|
||||
@@ -48,3 +51,12 @@ func Cors() gin.HandlerFunc {
|
||||
c.Next()
|
||||
}
|
||||
}
|
||||
func WriteLog() gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
if !strings.Contains(c.Request.URL.String(), "password") {
|
||||
loger.Info("request:", zap.Any("path", c.Request.URL.String()), zap.Any("param", c.Params), zap.Any("query", c.Request.URL.Query()), zap.Any("method", c.Request.Method))
|
||||
c.Next()
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,27 +0,0 @@
|
||||
/*
|
||||
* @Author: LinkLeong link@icewhale.com
|
||||
* @Date: 2022-03-18 11:40:55
|
||||
* @LastEditors: LinkLeong
|
||||
* @LastEditTime: 2022-05-13 14:48:01
|
||||
* @FilePath: /CasaOS/model/app-analyse.go
|
||||
* @Description:
|
||||
* @Website: https://www.casaos.io
|
||||
* Copyright (c) 2022 by icewhale, All Rights Reserved.
|
||||
*/
|
||||
package model
|
||||
|
||||
type AppAnalyse struct {
|
||||
Name string `json:"name"`
|
||||
Type string `json:"type"`
|
||||
UUId string `json:"uuid"`
|
||||
Language string `json:"language"`
|
||||
Version string `json:"version"`
|
||||
}
|
||||
|
||||
type ConnectionStatus struct {
|
||||
From string `json:"from"`
|
||||
To string `json:"to"`
|
||||
Error string `json:"error"`
|
||||
UUId string `json:"uuid"`
|
||||
Event string `json:"event"`
|
||||
}
|
||||
20
model/app.go
20
model/app.go
@@ -6,6 +6,22 @@ import (
|
||||
"time"
|
||||
)
|
||||
|
||||
type ServerAppListCollection struct {
|
||||
List []ServerAppList `json:"list"`
|
||||
Recommend []ServerAppList `json:"recommend"`
|
||||
Community []ServerAppList `json:"community"`
|
||||
Version string `json:"version"`
|
||||
}
|
||||
|
||||
// @tiger - 对于用于出参的数据结构,静态信息(例如 title)和
|
||||
// 动态信息(例如 state、query_count)应该划分到不同的数据结构中
|
||||
//
|
||||
// 这样的好处是
|
||||
// 1 - 多次获取动态信息时可以减少出参复杂度,因为静态信息只获取一次就好
|
||||
// 2 - 在未来的迭代中,可以降低维护成本(所有字段都展开放在一个层级维护成本略高)
|
||||
//
|
||||
// 另外,一些针对性字段,例如 Docker 相关的,可以用 map 来保存。
|
||||
// 这样在未来增加多态 App,例如 Snap,不需要维护多个结构,或者一个结构保存不必要的字段
|
||||
type ServerAppList struct {
|
||||
Id uint `gorm:"column:id;primary_key" json:"id"`
|
||||
Title string `json:"title"`
|
||||
@@ -15,6 +31,7 @@ type ServerAppList struct {
|
||||
Icon string `json:"icon"`
|
||||
ScreenshotLink Strings `gorm:"type:json" json:"screenshot_link"`
|
||||
Category string `json:"category"`
|
||||
CategoryId int `json:"category_id"`
|
||||
CategoryFont string `json:"category_font"`
|
||||
PortMap string `json:"port_map"`
|
||||
ImageVersion string `json:"image_version"`
|
||||
@@ -28,7 +45,7 @@ type ServerAppList struct {
|
||||
Index string `json:"index"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
State string `json:"state"`
|
||||
State int `json:"state"`
|
||||
Author string `json:"author"`
|
||||
MinMemory int `json:"min_memory"`
|
||||
MinDisk int `json:"min_disk"`
|
||||
@@ -38,6 +55,7 @@ type ServerAppList struct {
|
||||
Plugins Strings `json:"plugins"`
|
||||
Origin string `json:"origin"`
|
||||
Type int `json:"type"`
|
||||
QueryCount int `json:"query_count"`
|
||||
Developer string `json:"developer"`
|
||||
HostName string `json:"host_name"`
|
||||
Privileged bool `json:"privileged"`
|
||||
|
||||
@@ -1,24 +1,23 @@
|
||||
/*
|
||||
* @Author: link a624669980@163.com
|
||||
* @Date: 2022-05-16 17:37:08
|
||||
* @LastEditors: link a624669980@163.com
|
||||
* @LastEditTime: 2022-06-07 17:12:30
|
||||
* @FilePath: \CasaOS\model\category.go
|
||||
* @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
|
||||
|
||||
* @LastEditors: LinkLeong
|
||||
* @LastEditTime: 2022-07-13 10:46:38
|
||||
* @FilePath: /CasaOS/model/category.go
|
||||
* @Description:
|
||||
*/
|
||||
package model
|
||||
|
||||
// type ServerCategoryList struct {
|
||||
// Version string `json:"version"`
|
||||
// Item []CategoryList `json:"item"`
|
||||
// }
|
||||
type ServerCategoryList struct {
|
||||
Version string `json:"version"`
|
||||
Item []CategoryList `json:"item"`
|
||||
}
|
||||
type CategoryList struct {
|
||||
Id uint `gorm:"column:id;primary_key" json:"id"`
|
||||
//CreatedAt time.Time `json:"created_at"`
|
||||
//
|
||||
//UpdatedAt time.Time `json:"updated_at"`
|
||||
Font string `json:"font"`
|
||||
Font string `json:"font"` // @tiger - 如果这个和前端有关,应该不属于后端的出参范围,而是前端去界定
|
||||
Name string `json:"name"`
|
||||
Count uint `json:"count"`
|
||||
Count uint `json:"count"` // @tiger - count 属于动态信息,应该单独放在一个出参结构中(原因见另外一个关于 静态/动态 出参的注释)
|
||||
}
|
||||
|
||||
20
model/connections.go
Normal file
20
model/connections.go
Normal file
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* @Author: LinkLeong link@icewhale.org
|
||||
* @Date: 2022-07-27 10:30:43
|
||||
* @LastEditors: LinkLeong
|
||||
* @LastEditTime: 2022-08-04 20:06:04
|
||||
* @FilePath: /CasaOS/model/connections.go
|
||||
* @Description:
|
||||
* @Website: https://www.casaos.io
|
||||
* Copyright (c) 2022 by icewhale, All Rights Reserved.
|
||||
*/
|
||||
package model
|
||||
|
||||
type Connections struct {
|
||||
ID uint `json:"id"`
|
||||
Username string `json:"username"`
|
||||
Password string `json:"password,omitempty"`
|
||||
Host string `json:"host"`
|
||||
Port string `json:"port"`
|
||||
MountPoint string `json:"mount_point"`
|
||||
}
|
||||
@@ -1,76 +0,0 @@
|
||||
package model
|
||||
|
||||
type LSBLKModel struct {
|
||||
Name string `json:"name"`
|
||||
FsType string `json:"fstype"`
|
||||
Size uint64 `json:"size"`
|
||||
FSSize string `json:"fssize"`
|
||||
Path string `json:"path"`
|
||||
Model string `json:"model"` //设备标识符
|
||||
RM bool `json:"rm"` //是否为可移动设备
|
||||
RO bool `json:"ro"` //是否为只读设备
|
||||
State string `json:"state"`
|
||||
PhySec int `json:"phy-sec"` //物理扇区大小
|
||||
Type string `json:"type"`
|
||||
Vendor string `json:"vendor"` //供应商
|
||||
Rev string `json:"rev"` //修订版本
|
||||
FSAvail string `json:"fsavail"` //可用空间
|
||||
FSUse string `json:"fsuse%"` //已用百分比
|
||||
MountPoint string `json:"mountpoint"`
|
||||
Format string `json:"format"`
|
||||
Health string `json:"health"`
|
||||
HotPlug bool `json:"hotplug"`
|
||||
UUID string `json:"uuid"`
|
||||
FSUsed string `json:"fsused"`
|
||||
Temperature int `json:"temperature"`
|
||||
Tran string `json:"tran"`
|
||||
MinIO uint64 `json:"min-io"`
|
||||
UsedPercent float64 `json:"used_percent"`
|
||||
Serial string `json:"serial"`
|
||||
Children []LSBLKModel `json:"children"`
|
||||
SubSystems string `json:"subsystems"`
|
||||
//详情特有
|
||||
StartSector uint64 `json:"start_sector,omitempty"`
|
||||
Rota bool `json:"rota"` //true(hhd) false(ssd)
|
||||
DiskType string `json:"disk_type"`
|
||||
EndSector uint64 `json:"end_sector,omitempty"`
|
||||
}
|
||||
|
||||
type Drive struct {
|
||||
Name string `json:"name"`
|
||||
Size uint64 `json:"size"`
|
||||
Model string `json:"model"`
|
||||
Health string `json:"health"`
|
||||
Temperature int `json:"temperature"`
|
||||
DiskType string `json:"disk_type"`
|
||||
NeedFormat bool `json:"need_format"`
|
||||
Serial string `json:"serial"`
|
||||
Path string `json:"path"`
|
||||
}
|
||||
|
||||
type DriveUSB struct {
|
||||
Name string `json:"name"`
|
||||
Size uint64 `json:"size"`
|
||||
Used uint64 `json:"use"`
|
||||
Model string `json:"model"`
|
||||
Mount bool `json:"mount"` //是否完全挂载
|
||||
Avail uint64 `json:"avail"` //可用空间
|
||||
}
|
||||
|
||||
type Storage struct {
|
||||
Name string `json:"name"`
|
||||
MountPoint string `json:"mountpoint"`
|
||||
Size string `json:"size"`
|
||||
Avail string `json:"avail"` //可用空间
|
||||
Type string `json:"type"`
|
||||
CreatedAt int64 `json:"create_at"`
|
||||
Path string `json:"path"`
|
||||
DriveName string `json:"drive_name"`
|
||||
}
|
||||
|
||||
type Summary struct {
|
||||
Size uint64 `json:"size"`
|
||||
Avail uint64 `json:"avail"` //可用空间
|
||||
Health bool `json:"health"`
|
||||
Used uint64 `json:"used"`
|
||||
}
|
||||
@@ -1,8 +1,22 @@
|
||||
/*
|
||||
* @Author: LinkLeong link@icewhale.com
|
||||
* @Date: 2021-12-08 18:10:25
|
||||
* @LastEditors: LinkLeong
|
||||
* @LastEditTime: 2022-07-13 10:49:16
|
||||
* @FilePath: /CasaOS/model/docker.go
|
||||
* @Description:
|
||||
* @Website: https://www.casaos.io
|
||||
* Copyright (c) 2022 by icewhale, All Rights Reserved.
|
||||
*/
|
||||
package model
|
||||
|
||||
type DockerStatsModel struct {
|
||||
Icon string `json:"icon"`
|
||||
Title string `json:"title"`
|
||||
Data interface{} `json:"data"`
|
||||
Pre interface{} `json:"pre"`
|
||||
Icon string `json:"icon"`
|
||||
Title string `json:"title"`
|
||||
Data interface{} `json:"data"`
|
||||
Previous interface{} `json:"previous"`
|
||||
}
|
||||
|
||||
type DeckerDaemonModel struct {
|
||||
Graph string `json:"graph"`
|
||||
}
|
||||
|
||||
@@ -104,16 +104,17 @@ func (p *PathArray) Scan(input interface{}) error {
|
||||
//}
|
||||
|
||||
type CustomizationPostData struct {
|
||||
CustomId string `json:"custom_id"`
|
||||
Origin string `json:"origin"`
|
||||
NetworkModel string `json:"network_model"`
|
||||
Index string `json:"index"`
|
||||
Icon string `json:"icon"`
|
||||
Image string `json:"image"`
|
||||
Envs EnvArray `json:"envs"`
|
||||
Ports PortArray `json:"ports"`
|
||||
Volumes PathArray `json:"volumes"`
|
||||
Devices PathArray `json:"devices"`
|
||||
ContainerName string `json:"container_name"`
|
||||
CustomId string `json:"custom_id"`
|
||||
Origin string `json:"origin"`
|
||||
NetworkModel string `json:"network_model"`
|
||||
Index string `json:"index"`
|
||||
Icon string `json:"icon"`
|
||||
Image string `json:"image"`
|
||||
Envs 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"`
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
/*
|
||||
* @Author: LinkLeong link@icewhale.com
|
||||
* @Date: 2022-05-27 18:42:42
|
||||
* @LastEditors: LinkLeong
|
||||
* @LastEditTime: 2022-05-27 18:43:08
|
||||
* @FilePath: /CasaOS/model/notify/person.go
|
||||
* @Description:
|
||||
* @Website: https://www.casaos.io
|
||||
* Copyright (c) 2022 by icewhale, All Rights Reserved.
|
||||
*/
|
||||
package notify
|
||||
|
||||
type Person struct {
|
||||
ShareId string `json:"share_id"`
|
||||
Type string `json:"type"`
|
||||
}
|
||||
19
model/notify/storage.go
Normal file
19
model/notify/storage.go
Normal file
@@ -0,0 +1,19 @@
|
||||
/*
|
||||
* @Author: LinkLeong link@icewhale.com
|
||||
* @Date: 2022-07-15 10:43:00
|
||||
* @LastEditors: LinkLeong
|
||||
* @LastEditTime: 2022-07-15 10:56:17
|
||||
* @FilePath: /CasaOS/model/notify/storage.go
|
||||
* @Description:
|
||||
* @Website: https://www.casaos.io
|
||||
* Copyright (c) 2022 by icewhale, All Rights Reserved.
|
||||
*/
|
||||
package notify
|
||||
|
||||
type StorageMessage struct {
|
||||
Type string `json:"type"` //sata,usb
|
||||
Action string `json:"action"` //remove add
|
||||
Path string `json:"path"`
|
||||
Volume string `json:"volume"`
|
||||
Size uint64 `json:"size"`
|
||||
}
|
||||
@@ -1,54 +0,0 @@
|
||||
package model
|
||||
|
||||
import "time"
|
||||
|
||||
type PersionModel struct {
|
||||
Token string `json:"token"`
|
||||
Ips []string `json:"ips"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
}
|
||||
|
||||
//记录链接状态
|
||||
type ConnectState struct {
|
||||
From string `json:"from"`
|
||||
To string `json:"to"`
|
||||
Type string `json:"type"` //current state 1:ready 2:ok
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UUId string `json:"uuid"` //对接标识
|
||||
}
|
||||
type MessageModel struct {
|
||||
Type string `json:"type"`
|
||||
Data interface{} `json:"data"`
|
||||
UUId string `json:"uuid"`
|
||||
From string `json:"from"`
|
||||
To string `json:"to"`
|
||||
}
|
||||
|
||||
type TranFileModel struct {
|
||||
Hash string `json:"hash"` //Verify current fragment integrity
|
||||
Length int `json:"length"`
|
||||
Index int `json:"index"`
|
||||
}
|
||||
|
||||
//需要获取文件详情
|
||||
type FileDetailModel struct {
|
||||
Path string `json:"path"`
|
||||
}
|
||||
|
||||
//返回文件详情
|
||||
type FileSummaryModel struct {
|
||||
Hash string `json:"hash"` //Verify file
|
||||
Name string `json:"name"`
|
||||
BlockSize int `json:"block_size"`
|
||||
Length int `json:"length"`
|
||||
Size int64 `json:"size"`
|
||||
Message string `json:"message"`
|
||||
}
|
||||
|
||||
type FriendsModel struct {
|
||||
Id uint `gorm:"column:id;primary_key" json:"id"`
|
||||
NickName string `json:"nick_name"`
|
||||
Desc string `json:"desc"`
|
||||
ShareId string `json:"share_id"`
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
package receive
|
||||
17
model/share.go
Normal file
17
model/share.go
Normal file
@@ -0,0 +1,17 @@
|
||||
/*
|
||||
* @Author: LinkLeong link@icewhale.org
|
||||
* @Date: 2022-07-26 11:12:12
|
||||
* @LastEditors: LinkLeong
|
||||
* @LastEditTime: 2022-07-27 14:58:55
|
||||
* @FilePath: /CasaOS/model/share.go
|
||||
* @Description:
|
||||
* @Website: https://www.casaos.io
|
||||
* Copyright (c) 2022 by icewhale, All Rights Reserved.
|
||||
*/
|
||||
package model
|
||||
|
||||
type Shares struct {
|
||||
ID uint `json:"id"`
|
||||
Anonymous bool `json:"anonymous"`
|
||||
Path string `json:"path"`
|
||||
}
|
||||
@@ -2,7 +2,7 @@
|
||||
* @Author: LinkLeong link@icewhale.com
|
||||
* @Date: 2022-05-13 18:15:46
|
||||
* @LastEditors: LinkLeong
|
||||
* @LastEditTime: 2022-05-30 16:43:59
|
||||
* @LastEditTime: 2022-09-02 22:12:34
|
||||
* @FilePath: /CasaOS/model/sys_common.go
|
||||
* @Description:
|
||||
* @Website: https://www.casaos.io
|
||||
@@ -12,59 +12,47 @@ package model
|
||||
|
||||
import "time"
|
||||
|
||||
//系统配置
|
||||
// 系统配置
|
||||
type SysInfoModel struct {
|
||||
Name string //系统名称
|
||||
}
|
||||
|
||||
//用户相关
|
||||
type UserModel struct {
|
||||
UserName string
|
||||
PWD string
|
||||
Token string
|
||||
Head string
|
||||
Email string
|
||||
Description string
|
||||
Initialized bool
|
||||
Avatar string
|
||||
NickName string
|
||||
Public string
|
||||
}
|
||||
|
||||
//服务配置
|
||||
// 服务配置
|
||||
type ServerModel struct {
|
||||
HttpPort string
|
||||
RunMode string
|
||||
ServerApi string
|
||||
LockAccount bool
|
||||
Handshake string
|
||||
Token string
|
||||
UDPPort string
|
||||
USBAutoMount string
|
||||
SocketPort string
|
||||
}
|
||||
|
||||
//服务配置
|
||||
// 服务配置
|
||||
type APPModel struct {
|
||||
LogSavePath string
|
||||
LogPath string
|
||||
LogSaveName string
|
||||
LogFileExt string
|
||||
DateStrFormat string
|
||||
DateTimeFormat string
|
||||
UserDataPath string
|
||||
TimeFormat string
|
||||
DateFormat string
|
||||
ProjectPath string
|
||||
RootPath string
|
||||
DBPath string
|
||||
ShellPath string
|
||||
}
|
||||
type CommonModel struct {
|
||||
RuntimePath string
|
||||
}
|
||||
|
||||
//公共返回模型
|
||||
// 公共返回模型
|
||||
type Result struct {
|
||||
Success int `json:"success" example:"200"`
|
||||
Message string `json:"message" example:"ok"`
|
||||
Data interface{} `json:"data" example:"返回结果"`
|
||||
}
|
||||
|
||||
//redis配置文件
|
||||
// redis配置文件
|
||||
type RedisModel struct {
|
||||
Host string
|
||||
Password string
|
||||
@@ -74,12 +62,7 @@ type RedisModel struct {
|
||||
}
|
||||
|
||||
type SystemConfig struct {
|
||||
ConfigStr string `json:"config_str"`
|
||||
WidgetList string `json:"widget_list"`
|
||||
ConfigPath string `json:"config_path"`
|
||||
SyncPort string `json:"sync_port"`
|
||||
SyncKey string `json:"sync_key"`
|
||||
Analyse string `json:"analyse"`
|
||||
}
|
||||
|
||||
type CasaOSGlobalVariables struct {
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
package model
|
||||
17
model/system_model/verify_information.go
Normal file
17
model/system_model/verify_information.go
Normal file
@@ -0,0 +1,17 @@
|
||||
/*
|
||||
* @Author: LinkLeong link@icewhale.com
|
||||
* @Date: 2022-06-15 11:30:47
|
||||
* @LastEditors: LinkLeong
|
||||
* @LastEditTime: 2022-06-23 18:40:40
|
||||
* @FilePath: /CasaOS/model/system_model/verify_information.go
|
||||
* @Description:
|
||||
* @Website: https://www.casaos.io
|
||||
* Copyright (c) 2022 by icewhale, All Rights Reserved.
|
||||
*/
|
||||
package system_model
|
||||
|
||||
type VerifyInformation struct {
|
||||
RefreshToken string `json:"refresh_token"`
|
||||
AccessToken string `json:"access_token"`
|
||||
ExpiresAt int64 `json:"expires_at"`
|
||||
}
|
||||
@@ -1,14 +1,25 @@
|
||||
/*
|
||||
* @Author: LinkLeong link@icewhale.org
|
||||
* @Date: 2022-05-13 18:15:46
|
||||
* @LastEditors: LinkLeong
|
||||
* @LastEditTime: 2022-08-01 18:32:57
|
||||
* @FilePath: /CasaOS/model/zima.go
|
||||
* @Description:
|
||||
* @Website: https://www.casaos.io
|
||||
* Copyright (c) 2022 by icewhale, All Rights Reserved.
|
||||
*/
|
||||
package model
|
||||
|
||||
import "time"
|
||||
|
||||
type Path struct {
|
||||
Name string `json:"name"` //File name or document name
|
||||
Path string `json:"path"` //Full path to file or folder
|
||||
IsDir bool `json:"is_dir"` //Is it a folder
|
||||
Date time.Time `json:"date"`
|
||||
Size int64 `json:"size"` //File Size
|
||||
Type string `json:"type,omitempty"`
|
||||
Label string `json:"label,omitempty"`
|
||||
Write bool `json:"write"`
|
||||
Name string `json:"name"` //File name or document name
|
||||
Path string `json:"path"` //Full path to file or folder
|
||||
IsDir bool `json:"is_dir"` //Is it a folder
|
||||
Date time.Time `json:"date"`
|
||||
Size int64 `json:"size"` //File Size
|
||||
Type string `json:"type,omitempty"`
|
||||
Label string `json:"label,omitempty"`
|
||||
Write bool `json:"write"`
|
||||
Extensions map[string]interface{} `json:"extensions"`
|
||||
}
|
||||
|
||||
@@ -1,5 +1,15 @@
|
||||
/*
|
||||
* @Author: LinkLeong link@icewhale.com
|
||||
* @Date: 2021-09-30 18:18:14
|
||||
* @LastEditors: LinkLeong
|
||||
* @LastEditTime: 2022-08-31 17:04:02
|
||||
* @FilePath: /CasaOS/pkg/config/config.go
|
||||
* @Description:
|
||||
* @Website: https://www.casaos.io
|
||||
* Copyright (c) 2022 by icewhale, All Rights Reserved.
|
||||
*/
|
||||
package config
|
||||
|
||||
const (
|
||||
USERCONFIGURL = "conf/conf.ini"
|
||||
USERCONFIGURL = "/etc/casaos/casaos.conf"
|
||||
)
|
||||
|
||||
@@ -1,3 +1,13 @@
|
||||
/*
|
||||
* @Author: LinkLeong link@icewhale.com
|
||||
* @Date: 2022-05-13 18:15:46
|
||||
* @LastEditors: LinkLeong
|
||||
* @LastEditTime: 2022-09-05 11:58:02
|
||||
* @FilePath: /CasaOS/pkg/config/init.go
|
||||
* @Description:
|
||||
* @Website: https://www.casaos.io
|
||||
* Copyright (c) 2022 by icewhale, All Rights Reserved.
|
||||
*/
|
||||
package config
|
||||
|
||||
import (
|
||||
@@ -13,18 +23,17 @@ import (
|
||||
"github.com/go-ini/ini"
|
||||
)
|
||||
|
||||
//系统配置
|
||||
// 系统配置
|
||||
var SysInfo = &model.SysInfoModel{}
|
||||
|
||||
//用户相关
|
||||
var UserInfo = &model.UserModel{}
|
||||
|
||||
//用户相关
|
||||
// 用户相关
|
||||
var AppInfo = &model.APPModel{}
|
||||
|
||||
var CommonInfo = &model.CommonModel{}
|
||||
|
||||
//var RedisInfo = &model.RedisModel{}
|
||||
|
||||
//server相关
|
||||
// server相关
|
||||
var ServerInfo = &model.ServerModel{}
|
||||
|
||||
var SystemConfigInfo = &model.SystemConfig{}
|
||||
@@ -35,33 +44,57 @@ var FileSettingInfo = &model.FileSetting{}
|
||||
|
||||
var Cfg *ini.File
|
||||
|
||||
//初始化设置,获取系统的部分信息。
|
||||
// 初始化设置,获取系统的部分信息。
|
||||
func InitSetup(config string) {
|
||||
|
||||
var configDir = USERCONFIGURL
|
||||
if len(config) > 0 {
|
||||
configDir = config
|
||||
}
|
||||
if runtime.GOOS == "darwin" {
|
||||
configDir = "./conf/conf.conf"
|
||||
}
|
||||
var err error
|
||||
//读取文件
|
||||
Cfg, err = ini.Load(configDir)
|
||||
if err != nil {
|
||||
fmt.Printf("Fail to read file: %v", err)
|
||||
os.Exit(1)
|
||||
Cfg, err = ini.Load("/etc/casaos.conf")
|
||||
if err != nil {
|
||||
Cfg, err = ini.Load("/casaOS/server/conf/conf.ini")
|
||||
if err != nil {
|
||||
fmt.Printf("Fail to read file: %v", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mapTo("user", UserInfo)
|
||||
mapTo("app", AppInfo)
|
||||
//mapTo("redis", RedisInfo)
|
||||
mapTo("server", ServerInfo)
|
||||
mapTo("system", SystemConfigInfo)
|
||||
mapTo("file", FileSettingInfo)
|
||||
mapTo("common", CommonInfo)
|
||||
SystemConfigInfo.ConfigPath = configDir
|
||||
if len(AppInfo.DBPath) == 0 {
|
||||
AppInfo.DBPath = "/var/lib/casaos"
|
||||
}
|
||||
if len(AppInfo.LogPath) == 0 {
|
||||
AppInfo.LogPath = "/var/log/casaos/"
|
||||
}
|
||||
if len(AppInfo.ShellPath) == 0 {
|
||||
AppInfo.ShellPath = "/usr/share/casaos/shell"
|
||||
}
|
||||
if len(AppInfo.UserDataPath) == 0 {
|
||||
AppInfo.UserDataPath = "/var/lib/casaos/conf"
|
||||
}
|
||||
if len(CommonInfo.RuntimePath) == 0 {
|
||||
CommonInfo.RuntimePath = "/var/run/casaos"
|
||||
}
|
||||
Cfg.SaveTo(configDir)
|
||||
// AppInfo.ProjectPath = getCurrentDirectory() //os.Getwd()
|
||||
|
||||
}
|
||||
|
||||
//映射
|
||||
// 映射
|
||||
func mapTo(section string, v interface{}) {
|
||||
err := Cfg.Section(section).MapTo(v)
|
||||
if err != nil {
|
||||
|
||||
@@ -1,32 +0,0 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"runtime"
|
||||
|
||||
"github.com/IceWhaleTech/CasaOS/pkg/utils/file"
|
||||
)
|
||||
|
||||
//检查目录是否存在
|
||||
func mkdirDATAAll() {
|
||||
sysType := runtime.GOOS
|
||||
var dirArray []string
|
||||
if sysType == "linux" {
|
||||
dirArray = []string{"/DATA/AppData", "/DATA/Documents", "/DATA/Downloads", "/DATA/Gallery", "/DATA/Media/Movies", "/DATA/Media/TV Shows", "/DATA/Media/Music"}
|
||||
}
|
||||
|
||||
if sysType == "windows" {
|
||||
dirArray = []string{"C:\\CasaOS\\DATA\\AppData", "C:\\CasaOS\\DATA\\Documents", "C:\\CasaOS\\DATA\\Downloads", "C:\\CasaOS\\DATA\\Gallery", "C:\\CasaOS\\DATA\\Media/Movies", "C:\\CasaOS\\DATA\\Media\\TV Shows", "C:\\CasaOS\\DATA\\Media\\Music"}
|
||||
}
|
||||
if sysType == "darwin" {
|
||||
dirArray = []string{"./CasaOS/DATA/AppData", "./CasaOS/DATA/Documents", "./CasaOS/DATA/Downloads", "./CasaOS/DATA/Gallery", "./CasaOS/DATA/Media/Movies", "./CasaOS/DATA/Media/TV Shows", "./CasaOS/DATA/Media/Music"}
|
||||
}
|
||||
|
||||
for _, v := range dirArray {
|
||||
file.IsNotExistMkDir(v)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func UpdateSetup() {
|
||||
mkdirDATAAll()
|
||||
}
|
||||
@@ -6,7 +6,6 @@ import (
|
||||
"fmt"
|
||||
"io"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
@@ -15,7 +14,7 @@ import (
|
||||
"golang.org/x/crypto/ssh"
|
||||
)
|
||||
|
||||
func NewSshClient(user, password string) (*ssh.Client, error) {
|
||||
func NewSshClient(user, password string, port string) (*ssh.Client, error) {
|
||||
|
||||
// connet to ssh
|
||||
// addr = fmt.Sprintf("%s:%d", host, port)
|
||||
@@ -32,7 +31,7 @@ func NewSshClient(user, password string) (*ssh.Client, error) {
|
||||
//} else {
|
||||
// config.Auth = []ssh.AuthMethod{publicKeyAuthFunc(h.Key)}
|
||||
//}
|
||||
addr := fmt.Sprintf("%s:%d", "127.0.0.1", 22)
|
||||
addr := fmt.Sprintf("%s:%s", "127.0.0.1", port)
|
||||
c, err := ssh.Dial("tcp", addr, config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -396,7 +395,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"))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
75
pkg/samba/smaba.go
Normal file
75
pkg/samba/smaba.go
Normal file
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* @Author: LinkLeong link@icewhale.org
|
||||
* @Date: 2022-07-27 10:35:29
|
||||
* @LastEditors: LinkLeong
|
||||
* @LastEditTime: 2022-08-01 13:56:44
|
||||
* @FilePath: /CasaOS/pkg/samba/smaba.go
|
||||
* @Description:
|
||||
* @Website: https://www.casaos.io
|
||||
* Copyright (c) 2022 by icewhale, All Rights Reserved.
|
||||
*/
|
||||
package samba
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"net"
|
||||
|
||||
"github.com/hirochachacha/go-smb2"
|
||||
)
|
||||
|
||||
func ConnectSambaService(host, port, username, password, directory string) error {
|
||||
conn, err := net.Dial("tcp", host+":"+port)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer conn.Close()
|
||||
d := &smb2.Dialer{
|
||||
Initiator: &smb2.NTLMInitiator{
|
||||
User: username,
|
||||
Password: password,
|
||||
},
|
||||
}
|
||||
|
||||
s, err := d.Dial(conn)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer s.Logoff()
|
||||
names, err := s.ListSharenames()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, name := range names {
|
||||
if name == directory {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
return errors.New("directory not found")
|
||||
}
|
||||
|
||||
//get share name list
|
||||
func GetSambaSharesList(host, port, username, password string) ([]string, error) {
|
||||
conn, err := net.Dial("tcp", host+":"+port)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer conn.Close()
|
||||
d := &smb2.Dialer{
|
||||
Initiator: &smb2.NTLMInitiator{
|
||||
User: username,
|
||||
Password: password,
|
||||
},
|
||||
}
|
||||
|
||||
s, err := d.Dial(conn)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer s.Logoff()
|
||||
names, err := s.ListSharenames()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return names, err
|
||||
}
|
||||
@@ -1,11 +1,22 @@
|
||||
/*
|
||||
* @Author: LinkLeong link@icewhale.com
|
||||
* @Date: 2022-05-13 18:15:46
|
||||
* @LastEditors: LinkLeong
|
||||
* @LastEditTime: 2022-08-31 13:39:24
|
||||
* @FilePath: /CasaOS/pkg/sqlite/db.go
|
||||
* @Description:
|
||||
* @Website: https://www.casaos.io
|
||||
* Copyright (c) 2022 by icewhale, All Rights Reserved.
|
||||
*/
|
||||
package sqlite
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/IceWhaleTech/CasaOS/pkg/utils/file"
|
||||
"github.com/IceWhaleTech/CasaOS/pkg/utils/loger"
|
||||
model2 "github.com/IceWhaleTech/CasaOS/service/model"
|
||||
"go.uber.org/zap"
|
||||
"gorm.io/driver/sqlite"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
@@ -16,7 +27,7 @@ func GetDb(dbPath string) *gorm.DB {
|
||||
if gdb != nil {
|
||||
return gdb
|
||||
}
|
||||
// 参考 https://github.com/go-sql-driver/mysql#dsn-data-source-name 获取详情
|
||||
// Refer https://github.com/go-sql-driver/mysql#dsn-data-source-name
|
||||
//dsn := fmt.Sprintf("%v:%v@tcp(%v:%v)/%v?charset=utf8mb4&parseTime=True&loc=Local", m.User, m.PWD, m.IP, m.Port, m.DBName)
|
||||
//db, err := gorm.Open(mysql2.Open(dsn), &gorm.Config{})
|
||||
file.IsNotExistMkDir(dbPath)
|
||||
@@ -26,14 +37,19 @@ func GetDb(dbPath string) *gorm.DB {
|
||||
c.SetMaxOpenConns(100)
|
||||
c.SetConnMaxIdleTime(time.Second * 1000)
|
||||
if err != nil {
|
||||
fmt.Println("连接数据失败!")
|
||||
panic("数据库连接失败")
|
||||
loger.Error("sqlite connect error", zap.Any("db connect error", err))
|
||||
panic("sqlite connect error")
|
||||
return nil
|
||||
}
|
||||
gdb = db
|
||||
err = db.AutoMigrate(&model2.TaskDBModel{}, &model2.AppNotify{}, &model2.AppListDBModel{}, &model2.SerialDisk{}, model2.PersonDownloadDBModel{}, model2.FriendModel{}, model2.PersonDownRecordDBModel{}, model2.ApplicationModel{})
|
||||
|
||||
err = db.AutoMigrate(&model2.AppNotify{}, &model2.AppListDBModel{}, model2.SharesDBModel{}, model2.ConnectionsDBModel{})
|
||||
db.Exec("DROP TABLE IF EXISTS o_application")
|
||||
db.Exec("DROP TABLE IF EXISTS o_friend")
|
||||
db.Exec("DROP TABLE IF EXISTS o_person_download")
|
||||
db.Exec("DROP TABLE IF EXISTS o_person_down_record")
|
||||
if err != nil {
|
||||
fmt.Println("检查和创建数据库出错", err)
|
||||
loger.Error("check or create db error", zap.Any("error", err))
|
||||
}
|
||||
return db
|
||||
}
|
||||
|
||||
@@ -1,89 +0,0 @@
|
||||
package upnp
|
||||
|
||||
import (
|
||||
"encoding/xml"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func GetCtrlUrl(host, device string) string {
|
||||
request := ctrlUrlRequest(host, device)
|
||||
response, _ := http.DefaultClient.Do(request)
|
||||
resultBody, _ := ioutil.ReadAll(response.Body)
|
||||
defer response.Body.Close()
|
||||
if response.StatusCode == 200 {
|
||||
return resolve(string(resultBody))
|
||||
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func ctrlUrlRequest(host string, deviceDescUrl string) *http.Request {
|
||||
//请求头
|
||||
header := http.Header{}
|
||||
header.Set("Accept", "text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2")
|
||||
header.Set("User-Agent", "preston")
|
||||
header.Set("Host", host)
|
||||
header.Set("Connection", "keep-alive")
|
||||
request, _ := http.NewRequest("GET", "http://"+host+deviceDescUrl, nil)
|
||||
request.Header = header
|
||||
return request
|
||||
}
|
||||
|
||||
func resolve(resultStr string) string {
|
||||
inputReader := strings.NewReader(resultStr)
|
||||
|
||||
// 从文件读取,如可以如下:
|
||||
// content, err := ioutil.ReadFile("studygolang.xml")
|
||||
// decoder := xml.NewDecoder(bytes.NewBuffer(content))
|
||||
|
||||
lastLabel := ""
|
||||
|
||||
ISUpnpServer := false
|
||||
|
||||
IScontrolURL := false
|
||||
var controlURL string //`controlURL`
|
||||
// var eventSubURL string //`eventSubURL`
|
||||
// var SCPDURL string //`SCPDURL`
|
||||
|
||||
decoder := xml.NewDecoder(inputReader)
|
||||
for t, err := decoder.Token(); err == nil && !IScontrolURL; t, err = decoder.Token() {
|
||||
switch token := t.(type) {
|
||||
// 处理元素开始(标签)
|
||||
case xml.StartElement:
|
||||
if ISUpnpServer {
|
||||
name := token.Name.Local
|
||||
lastLabel = name
|
||||
}
|
||||
|
||||
// 处理元素结束(标签)
|
||||
case xml.EndElement:
|
||||
// log.Println("结束标记:", token.Name.Local)
|
||||
// 处理字符数据(这里就是元素的文本)
|
||||
case xml.CharData:
|
||||
//得到url后其他标记就不处理了
|
||||
content := string([]byte(token))
|
||||
//找到提供端口映射的服务
|
||||
if content == "urn:schemas-upnp-org:service:WANIPConnection:1" {
|
||||
ISUpnpServer = true
|
||||
continue
|
||||
}
|
||||
|
||||
if ISUpnpServer {
|
||||
switch lastLabel {
|
||||
case "controlURL":
|
||||
controlURL = content
|
||||
IScontrolURL = true
|
||||
case "eventSubURL":
|
||||
// eventSubURL = content
|
||||
case "SCPDURL":
|
||||
// SCPDURL = content
|
||||
}
|
||||
}
|
||||
default:
|
||||
// ...
|
||||
}
|
||||
}
|
||||
return controlURL
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
package upnp
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
ip_helper2 "github.com/IceWhaleTech/CasaOS/pkg/utils/ip_helper"
|
||||
)
|
||||
|
||||
func TestGetCtrlUrl(t *testing.T) {
|
||||
upnp, err := Gateway()
|
||||
if err == nil {
|
||||
upnp.CtrlUrl = GetCtrlUrl(upnp.GatewayHost, upnp.DeviceDescUrl)
|
||||
upnp.LocalHost = ip_helper2.GetLoclIp()
|
||||
upnp.AddPortMapping(8090, 8090, "TCP")
|
||||
//upnp.DelPortMapping(9999, "TCP")
|
||||
}
|
||||
}
|
||||
@@ -1,76 +0,0 @@
|
||||
package upnp
|
||||
|
||||
import (
|
||||
ip_helper2 "github.com/IceWhaleTech/CasaOS/pkg/utils/ip_helper"
|
||||
"github.com/pkg/errors"
|
||||
"net"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func Gateway() (*Upnp, error) {
|
||||
result, error := send()
|
||||
if result == "" || error != nil {
|
||||
return nil, error
|
||||
}
|
||||
upnp := resolvesss(result)
|
||||
return upnp, nil
|
||||
}
|
||||
|
||||
func send() (string, error) {
|
||||
var str = "M-SEARCH * HTTP/1.1\r\n" +
|
||||
"HOST: 239.255.255.250:1900\r\n" +
|
||||
"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
|
||||
remoteAddr, err := net.ResolveUDPAddr("udp", "239.255.255.250:1900")
|
||||
if err != nil {
|
||||
return "", errors.New("组播地址格式不正确")
|
||||
}
|
||||
localAddr, err := net.ResolveUDPAddr("udp", ip_helper2.GetLoclIp()+":")
|
||||
|
||||
if err != nil {
|
||||
return "", errors.New("本地ip地址格式不正确")
|
||||
}
|
||||
conn, err = net.ListenUDP("udp", localAddr)
|
||||
defer conn.Close()
|
||||
if err != nil {
|
||||
return "", errors.New("监听udp出错")
|
||||
}
|
||||
_, err = conn.WriteToUDP([]byte(str), remoteAddr)
|
||||
if err != nil {
|
||||
return "", errors.New("发送msg到组播地址出错")
|
||||
}
|
||||
buf := make([]byte, 1024)
|
||||
n, _, err := conn.ReadFromUDP(buf)
|
||||
if err != nil {
|
||||
return "", errors.New("从组播地址接搜消息出错")
|
||||
}
|
||||
result := string(buf[:n])
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func resolvesss(result string) *Upnp {
|
||||
var upnp = &Upnp{}
|
||||
lines := strings.Split(result, "\r\n")
|
||||
for _, line := range lines {
|
||||
//按照第一个冒号分为两个字符串
|
||||
nameValues := strings.SplitAfterN(line, ":", 2)
|
||||
if len(nameValues) < 2 {
|
||||
continue
|
||||
}
|
||||
switch strings.ToUpper(strings.Trim(strings.Split(nameValues[0], ":")[0], " ")) {
|
||||
case "ST":
|
||||
//fmt.Println(nameValues[1])
|
||||
case "CACHE-CONTROL":
|
||||
//fmt.Println(nameValues[1])
|
||||
case "LOCATION":
|
||||
urls := strings.Split(strings.Split(nameValues[1], "//")[1], "/")
|
||||
upnp.GatewayHost = (urls[0])
|
||||
upnp.DeviceDescUrl = ("/" + urls[1])
|
||||
case "SERVER":
|
||||
upnp.GatewayName = (nameValues[1])
|
||||
default:
|
||||
}
|
||||
}
|
||||
return upnp
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
package upnp
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestGateway(t *testing.T) {
|
||||
|
||||
Gateway()
|
||||
}
|
||||
@@ -1,158 +0,0 @@
|
||||
package upnp
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"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() {
|
||||
if errTemp := recover(); errTemp != nil {
|
||||
loger2.NewOLoger().Error("upnp模块报错了", errTemp)
|
||||
}
|
||||
}()
|
||||
|
||||
if isSuccess := addSend(localPort, remotePort, protocol, n.GatewayHost, n.CtrlUrl, n.LocalHost); isSuccess {
|
||||
return nil
|
||||
} else {
|
||||
return errors.New("添加一个端口映射失败")
|
||||
}
|
||||
}
|
||||
|
||||
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))
|
||||
return response.StatusCode == 200
|
||||
}
|
||||
|
||||
type Node struct {
|
||||
Name string
|
||||
Content string
|
||||
Attr map[string]string
|
||||
Child []Node
|
||||
}
|
||||
|
||||
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")
|
||||
header.Set("SOAPAction", `"urn:schemas-upnp-org:service:WANIPConnection:1#AddPortMapping"`)
|
||||
header.Set("Content-Type", "text/xml")
|
||||
header.Set("Connection", "Close")
|
||||
header.Set("Content-Length", "")
|
||||
//请求体
|
||||
body := Node{Name: "SOAP-ENV:Envelope",
|
||||
Attr: map[string]string{"xmlns:SOAP-ENV": `"http://schemas.xmlsoap.org/soap/envelope/"`,
|
||||
"SOAP-ENV:encodingStyle": `"http://schemas.xmlsoap.org/soap/encoding/"`}}
|
||||
childOne := Node{Name: `SOAP-ENV:Body`}
|
||||
childTwo := Node{Name: `m:AddPortMapping`,
|
||||
Attr: map[string]string{"xmlns:m": `"urn:schemas-upnp-org:service:WANIPConnection:1"`}}
|
||||
|
||||
childList1 := Node{Name: "NewExternalPort", Content: strconv.Itoa(remotePort)}
|
||||
childList2 := Node{Name: "NewInternalPort", Content: strconv.Itoa(localPort)}
|
||||
childList3 := Node{Name: "NewProtocol", Content: protocol}
|
||||
childList4 := Node{Name: "NewEnabled", Content: "1"}
|
||||
childList5 := Node{Name: "NewInternalClient", Content: localHost}
|
||||
childList6 := Node{Name: "NewLeaseDuration", Content: "0"}
|
||||
childList7 := Node{Name: "NewPortMappingDescription", Content: "Oasis"}
|
||||
childList8 := Node{Name: "NewRemoteHost"}
|
||||
childTwo.AddChild(childList1)
|
||||
childTwo.AddChild(childList2)
|
||||
childTwo.AddChild(childList3)
|
||||
childTwo.AddChild(childList4)
|
||||
childTwo.AddChild(childList5)
|
||||
childTwo.AddChild(childList6)
|
||||
childTwo.AddChild(childList7)
|
||||
childTwo.AddChild(childList8)
|
||||
|
||||
childOne.AddChild(childTwo)
|
||||
body.AddChild(childOne)
|
||||
bodyStr := body.BuildXML()
|
||||
//请求
|
||||
request, _ := http.NewRequest("POST", "http://"+gatewayHost+ctlUrl,
|
||||
strings.NewReader(bodyStr))
|
||||
request.Header = header
|
||||
request.Header.Set("Content-Length", strconv.Itoa(len([]byte(bodyStr))))
|
||||
return request
|
||||
}
|
||||
|
||||
func (n *Node) AddChild(node Node) {
|
||||
n.Child = append(n.Child, node)
|
||||
}
|
||||
|
||||
func (n *Node) BuildXML() string {
|
||||
buf := bytes.NewBufferString("<")
|
||||
buf.WriteString(n.Name)
|
||||
for key, value := range n.Attr {
|
||||
buf.WriteString(" ")
|
||||
buf.WriteString(key + "=" + value)
|
||||
}
|
||||
buf.WriteString(">" + n.Content)
|
||||
|
||||
for _, node := range n.Child {
|
||||
buf.WriteString(node.BuildXML())
|
||||
}
|
||||
buf.WriteString("</" + n.Name + ">")
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
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()
|
||||
|
||||
return response.StatusCode == 200
|
||||
}
|
||||
|
||||
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")
|
||||
header.Set("SOAPAction", `"urn:schemas-upnp-org:service:WANIPConnection:1#DeletePortMapping"`)
|
||||
header.Set("Content-Type", "text/xml")
|
||||
header.Set("Connection", "Close")
|
||||
header.Set("Content-Length", "")
|
||||
//请求体
|
||||
body := Node{Name: "SOAP-ENV:Envelope",
|
||||
Attr: map[string]string{"xmlns:SOAP-ENV": `"http://schemas.xmlsoap.org/soap/envelope/"`,
|
||||
"SOAP-ENV:encodingStyle": `"http://schemas.xmlsoap.org/soap/encoding/"`}}
|
||||
childOne := Node{Name: `SOAP-ENV:Body`}
|
||||
childTwo := Node{Name: `m:DeletePortMapping`,
|
||||
Attr: map[string]string{"xmlns:m": `"urn:schemas-upnp-org:service:WANIPConnection:1"`}}
|
||||
childList1 := Node{Name: "NewExternalPort", Content: strconv.Itoa(remotePort)}
|
||||
childList2 := Node{Name: "NewProtocol", Content: protocol}
|
||||
childList3 := Node{Name: "NewRemoteHost"}
|
||||
childTwo.AddChild(childList1)
|
||||
childTwo.AddChild(childList2)
|
||||
childTwo.AddChild(childList3)
|
||||
childOne.AddChild(childTwo)
|
||||
body.AddChild(childOne)
|
||||
bodyStr := body.BuildXML()
|
||||
|
||||
//请求
|
||||
request, _ := http.NewRequest("POST", "http://"+host+ctlUrl,
|
||||
strings.NewReader(bodyStr))
|
||||
request.Header = header
|
||||
request.Header.Set("Content-Length", strconv.Itoa(len([]byte(bodyStr))))
|
||||
return request
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
package upnp
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestAddPortMapping(t *testing.T) {
|
||||
//AddPortMapping(6666,6666,"TCP","192.168.2.1:5000",)
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
package upnp
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/prestonTao/upnp"
|
||||
)
|
||||
|
||||
type Upnp struct {
|
||||
LocalHost string `json:"local_host"`
|
||||
GatewayName string `json:"gateway_name"` //网关名称
|
||||
GatewayHost string `json:"gateway_host"` //网关ip和端口
|
||||
DeviceDescUrl string `json:"device_desc_url"` //设备描述url
|
||||
CtrlUrl string `json:"ctrl_url"` //控制请求url
|
||||
}
|
||||
|
||||
func Testaaa() {
|
||||
upnpMan := new(upnp.Upnp)
|
||||
err := upnpMan.SearchGateway()
|
||||
if err != nil {
|
||||
fmt.Println(err.Error())
|
||||
} else {
|
||||
fmt.Println("local ip address: ", upnpMan.LocalHost)
|
||||
fmt.Println("gateway ip address: ", upnpMan.Gateway.Host)
|
||||
}
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
package upnp
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestTestaaa(t *testing.T) {
|
||||
(Testaaa())
|
||||
}
|
||||
123
pkg/utils/common_err/e.go
Normal file
123
pkg/utils/common_err/e.go
Normal file
@@ -0,0 +1,123 @@
|
||||
package common_err
|
||||
|
||||
const (
|
||||
SUCCESS = 200
|
||||
SERVICE_ERROR = 500
|
||||
CLIENT_ERROR = 400
|
||||
ERROR_AUTH_TOKEN = 401
|
||||
|
||||
INVALID_PARAMS = 4000
|
||||
//user
|
||||
PWD_INVALID = 10001
|
||||
PWD_IS_EMPTY = 10002
|
||||
PWD_INVALID_OLD = 10003
|
||||
ACCOUNT_LOCK = 10004
|
||||
PWD_IS_TOO_SIMPLE = 10005
|
||||
USER_NOT_EXIST = 10006
|
||||
USER_EXIST = 10007
|
||||
KEY_NOT_EXIST = 10008
|
||||
NOT_IMAGE = 10009
|
||||
IMAGE_TOO_LARGE = 10010
|
||||
INSUFFICIENT_PERMISSIONS = 10011
|
||||
|
||||
//system
|
||||
DIR_ALREADY_EXISTS = 20001
|
||||
FILE_ALREADY_EXISTS = 20002
|
||||
FILE_OR_DIR_EXISTS = 20003
|
||||
PORT_IS_OCCUPIED = 20004
|
||||
COMMAND_ERROR_INVALID_OPERATION = 20005
|
||||
VERIFICATION_FAILURE = 20006
|
||||
Record_NOT_EXIST = 20007
|
||||
Record_ALREADY_EXIST = 20008
|
||||
SERVICE_NOT_RUNNING = 20009
|
||||
|
||||
//disk
|
||||
NAME_NOT_AVAILABLE = 40001
|
||||
DISK_NEEDS_FORMAT = 40002
|
||||
DISK_BUSYING = 40003
|
||||
REMOVE_MOUNT_POINT_ERROR = 40004
|
||||
FORMAT_ERROR = 40005
|
||||
|
||||
//app
|
||||
UNINSTALL_APP_ERROR = 50001
|
||||
PULL_IMAGE_ERROR = 50002
|
||||
DEVICE_NOT_EXIST = 50003
|
||||
ERROR_APP_NAME_EXIST = 50004
|
||||
|
||||
//file
|
||||
FILE_DOES_NOT_EXIST = 60001
|
||||
FILE_READ_ERROR = 60002
|
||||
FILE_DELETE_ERROR = 60003
|
||||
DIR_NOT_EXISTS = 60004
|
||||
SOURCE_DES_SAME = 60005
|
||||
|
||||
//share
|
||||
SHARE_ALREADY_EXISTS = 70001
|
||||
SHARE_NAME_ALREADY_EXISTS = 70002
|
||||
)
|
||||
|
||||
var MsgFlags = map[int]string{
|
||||
SUCCESS: "ok",
|
||||
SERVICE_ERROR: "Fail",
|
||||
CLIENT_ERROR: "Fail",
|
||||
INVALID_PARAMS: "Parameters Error",
|
||||
ERROR_AUTH_TOKEN: "Error auth token",
|
||||
|
||||
//user
|
||||
PWD_INVALID: "Invalid password",
|
||||
PWD_IS_EMPTY: "Password is empty",
|
||||
PWD_INVALID_OLD: "Invalid old password",
|
||||
ACCOUNT_LOCK: "Account is locked",
|
||||
PWD_IS_TOO_SIMPLE: "Password is too simple",
|
||||
USER_NOT_EXIST: "User does not exist",
|
||||
USER_EXIST: "User already exists",
|
||||
KEY_NOT_EXIST: "Key does not exist",
|
||||
IMAGE_TOO_LARGE: "Image is too large",
|
||||
NOT_IMAGE: "Not an image",
|
||||
INSUFFICIENT_PERMISSIONS: "Insufficient permissions",
|
||||
|
||||
//system
|
||||
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",
|
||||
VERIFICATION_FAILURE: "Verification failure",
|
||||
Record_ALREADY_EXIST: "Record already exists",
|
||||
Record_NOT_EXIST: "Record does not exist",
|
||||
SERVICE_NOT_RUNNING: "Service is not running",
|
||||
|
||||
//app
|
||||
UNINSTALL_APP_ERROR: "Error uninstalling app",
|
||||
PULL_IMAGE_ERROR: "Error pulling image",
|
||||
DEVICE_NOT_EXIST: "Device does not exist",
|
||||
ERROR_APP_NAME_EXIST: "App name already exists",
|
||||
|
||||
//disk
|
||||
NAME_NOT_AVAILABLE: "Name not available",
|
||||
DISK_NEEDS_FORMAT: "Drive needs to be formatted",
|
||||
REMOVE_MOUNT_POINT_ERROR: "Failed to remove mount point",
|
||||
DISK_BUSYING: "Drive is busy",
|
||||
FORMAT_ERROR: "Formatting failed, please check if the directory is occupied",
|
||||
//share
|
||||
SHARE_ALREADY_EXISTS: "Share already exists",
|
||||
SHARE_NAME_ALREADY_EXISTS: "Share name already exists",
|
||||
//
|
||||
SOURCE_DES_SAME: "Source and destination cannot be the same.",
|
||||
FILE_DOES_NOT_EXIST: "File does not exist",
|
||||
|
||||
DIR_NOT_EXISTS: "Directory does not exist",
|
||||
|
||||
FILE_READ_ERROR: "File read error",
|
||||
FILE_DELETE_ERROR: "Delete error",
|
||||
|
||||
COMMAND_ERROR_INVALID_OPERATION: "invalid operation",
|
||||
}
|
||||
|
||||
//获取错误信息
|
||||
func GetMsg(code int) string {
|
||||
msg, ok := MsgFlags[code]
|
||||
if ok {
|
||||
return msg
|
||||
}
|
||||
return MsgFlags[SERVICE_ERROR]
|
||||
}
|
||||
22
pkg/utils/encryption/md5_helper.go
Normal file
22
pkg/utils/encryption/md5_helper.go
Normal file
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
* @Author: LinkLeong link@icewhale.com
|
||||
* @Date: 2022-06-14 14:33:25
|
||||
* @LastEditors: LinkLeong
|
||||
* @LastEditTime: 2022-06-14 14:33:49
|
||||
* @FilePath: /CasaOS/pkg/utils/encryption/md5_helper.go
|
||||
* @Description:
|
||||
* @Website: https://www.casaos.io
|
||||
* Copyright (c) 2022 by icewhale, All Rights Reserved.
|
||||
*/
|
||||
package encryption
|
||||
|
||||
import (
|
||||
"crypto/md5"
|
||||
"encoding/hex"
|
||||
)
|
||||
|
||||
func GetMD5ByStr(str string) string {
|
||||
h := md5.New()
|
||||
h.Write([]byte(str))
|
||||
return hex.EncodeToString(h.Sum(nil))
|
||||
}
|
||||
@@ -225,6 +225,48 @@ func CopyFile(src, dst, style string) error {
|
||||
return os.Chmod(dst, srcinfo.Mode())
|
||||
}
|
||||
|
||||
/**
|
||||
* @description:
|
||||
* @param {*} src
|
||||
* @param {*} dst
|
||||
* @param {string} style
|
||||
* @return {*}
|
||||
* @method:
|
||||
* @router:
|
||||
*/
|
||||
func CopySingleFile(src, dst, style string) error {
|
||||
var err error
|
||||
var srcfd *os.File
|
||||
var dstfd *os.File
|
||||
var srcinfo os.FileInfo
|
||||
|
||||
if Exists(dst) {
|
||||
if style == "skip" {
|
||||
return nil
|
||||
} else {
|
||||
os.Remove(dst)
|
||||
}
|
||||
}
|
||||
|
||||
if srcfd, err = os.Open(src); err != nil {
|
||||
return err
|
||||
}
|
||||
defer srcfd.Close()
|
||||
|
||||
if dstfd, err = os.Create(dst); err != nil {
|
||||
return err
|
||||
}
|
||||
defer dstfd.Close()
|
||||
|
||||
if _, err = io.Copy(dstfd, srcfd); err != nil {
|
||||
return err
|
||||
}
|
||||
if srcinfo, err = os.Stat(src); err != nil {
|
||||
return err
|
||||
}
|
||||
return os.Chmod(dst, srcinfo.Mode())
|
||||
}
|
||||
|
||||
//Check for duplicate file names
|
||||
func GetNoDuplicateFileName(fullPath string) string {
|
||||
path, fileName := filepath.Split(fullPath)
|
||||
@@ -482,3 +524,43 @@ func DirSizeB(path string) (int64, error) {
|
||||
})
|
||||
return size, err
|
||||
}
|
||||
|
||||
func MoveFile(sourcePath, destPath string) error {
|
||||
inputFile, err := os.Open(sourcePath)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Couldn't open source file: %s", err)
|
||||
}
|
||||
outputFile, err := os.Create(destPath)
|
||||
if err != nil {
|
||||
inputFile.Close()
|
||||
return fmt.Errorf("Couldn't open dest file: %s", err)
|
||||
}
|
||||
defer outputFile.Close()
|
||||
_, err = io.Copy(outputFile, inputFile)
|
||||
inputFile.Close()
|
||||
if err != nil {
|
||||
return fmt.Errorf("Writing to output file failed: %s", err)
|
||||
}
|
||||
err = os.Remove(sourcePath)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Failed removing original file: %s", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func ReadLine(lineNumber int, path string) string {
|
||||
file, err := os.Open(path)
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
fileScanner := bufio.NewScanner(file)
|
||||
lineCount := 1
|
||||
for fileScanner.Scan() {
|
||||
if lineCount == lineNumber {
|
||||
return fileScanner.Text()
|
||||
}
|
||||
lineCount++
|
||||
}
|
||||
defer file.Close()
|
||||
return ""
|
||||
}
|
||||
|
||||
@@ -2,9 +2,13 @@ package file
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/disintegration/imaging"
|
||||
"github.com/dsoprea/go-exif/v3"
|
||||
@@ -82,3 +86,176 @@ func GetThumbnailByWebPhoto(path string, width, height int) ([]byte, error) {
|
||||
imaging.Encode(&buf, img, f)
|
||||
return buf.Bytes(), nil
|
||||
}
|
||||
|
||||
func ImageExtArray() []string {
|
||||
|
||||
ext := []string{
|
||||
"ase",
|
||||
"art",
|
||||
"bmp",
|
||||
"blp",
|
||||
"cd5",
|
||||
"cit",
|
||||
"cpt",
|
||||
"cr2",
|
||||
"cut",
|
||||
"dds",
|
||||
"dib",
|
||||
"djvu",
|
||||
"egt",
|
||||
"exif",
|
||||
"gif",
|
||||
"gpl",
|
||||
"grf",
|
||||
"icns",
|
||||
"ico",
|
||||
"iff",
|
||||
"jng",
|
||||
"jpeg",
|
||||
"jpg",
|
||||
"jfif",
|
||||
"jp2",
|
||||
"jps",
|
||||
"lbm",
|
||||
"max",
|
||||
"miff",
|
||||
"mng",
|
||||
"msp",
|
||||
"nitf",
|
||||
"ota",
|
||||
"pbm",
|
||||
"pc1",
|
||||
"pc2",
|
||||
"pc3",
|
||||
"pcf",
|
||||
"pcx",
|
||||
"pdn",
|
||||
"pgm",
|
||||
"PI1",
|
||||
"PI2",
|
||||
"PI3",
|
||||
"pict",
|
||||
"pct",
|
||||
"pnm",
|
||||
"pns",
|
||||
"ppm",
|
||||
"psb",
|
||||
"psd",
|
||||
"pdd",
|
||||
"psp",
|
||||
"px",
|
||||
"pxm",
|
||||
"pxr",
|
||||
"qfx",
|
||||
"raw",
|
||||
"rle",
|
||||
"sct",
|
||||
"sgi",
|
||||
"rgb",
|
||||
"int",
|
||||
"bw",
|
||||
"tga",
|
||||
"tiff",
|
||||
"tif",
|
||||
"vtf",
|
||||
"xbm",
|
||||
"xcf",
|
||||
"xpm",
|
||||
"3dv",
|
||||
"amf",
|
||||
"ai",
|
||||
"awg",
|
||||
"cgm",
|
||||
"cdr",
|
||||
"cmx",
|
||||
"dxf",
|
||||
"e2d",
|
||||
"egt",
|
||||
"eps",
|
||||
"fs",
|
||||
"gbr",
|
||||
"odg",
|
||||
"svg",
|
||||
"stl",
|
||||
"vrml",
|
||||
"x3d",
|
||||
"sxd",
|
||||
"v2d",
|
||||
"vnd",
|
||||
"wmf",
|
||||
"emf",
|
||||
"art",
|
||||
"xar",
|
||||
"png",
|
||||
"webp",
|
||||
"jxr",
|
||||
"hdp",
|
||||
"wdp",
|
||||
"cur",
|
||||
"ecw",
|
||||
"iff",
|
||||
"lbm",
|
||||
"liff",
|
||||
"nrrd",
|
||||
"pam",
|
||||
"pcx",
|
||||
"pgf",
|
||||
"sgi",
|
||||
"rgb",
|
||||
"rgba",
|
||||
"bw",
|
||||
"int",
|
||||
"inta",
|
||||
"sid",
|
||||
"ras",
|
||||
"sun",
|
||||
"tga",
|
||||
}
|
||||
|
||||
return ext
|
||||
}
|
||||
|
||||
/**
|
||||
* @description:get a image's ext
|
||||
* @param {string} path "file path"
|
||||
* @return {string} ext "file ext"
|
||||
* @return {error} err "error info"
|
||||
*/
|
||||
func GetImageExt(p string) (string, error) {
|
||||
file, err := os.Open(p)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
buff := make([]byte, 512)
|
||||
|
||||
_, err = file.Read(buff)
|
||||
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
filetype := http.DetectContentType(buff)
|
||||
|
||||
ext := ImageExtArray()
|
||||
|
||||
for i := 0; i < len(ext); i++ {
|
||||
if strings.Contains(ext[i], filetype[6:]) {
|
||||
return ext[i], nil
|
||||
}
|
||||
}
|
||||
|
||||
return "", errors.New("invalid image type")
|
||||
}
|
||||
|
||||
func GetImageExtByName(p string) (string, error) {
|
||||
|
||||
extArr := ImageExtArray()
|
||||
ext := filepath.Ext(p)
|
||||
for i := 0; i < len(extArr); i++ {
|
||||
if strings.Contains(ext, extArr[i]) {
|
||||
return extArr[i], nil
|
||||
}
|
||||
}
|
||||
return "", errors.New("invalid image type")
|
||||
}
|
||||
|
||||
@@ -1,46 +0,0 @@
|
||||
package jwt
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
jwt "github.com/golang-jwt/jwt"
|
||||
)
|
||||
|
||||
type Claims struct {
|
||||
UserName string `json:"username"`
|
||||
PassWord string `json:"password"`
|
||||
jwt.StandardClaims
|
||||
}
|
||||
|
||||
var jwtSecret []byte
|
||||
|
||||
//创建token
|
||||
func GenerateToken(username, password string) (string, error) {
|
||||
expireTime := time.Now().AddDate(999, 0, 0)
|
||||
clims := Claims{
|
||||
username,
|
||||
password,
|
||||
jwt.StandardClaims{
|
||||
ExpiresAt: expireTime.Unix(),
|
||||
Issuer: "gin-blog",
|
||||
},
|
||||
}
|
||||
|
||||
tokenClaims := jwt.NewWithClaims(jwt.SigningMethodHS256, clims)
|
||||
token, err := tokenClaims.SignedString(jwtSecret)
|
||||
return token, err
|
||||
|
||||
}
|
||||
|
||||
//解析token
|
||||
func ParseToken(token string) (*Claims, error) {
|
||||
tokenClaims, err := jwt.ParseWithClaims(token, &Claims{}, func(token *jwt.Token) (interface{}, error) {
|
||||
return jwtSecret, nil
|
||||
})
|
||||
if tokenClaims != nil {
|
||||
if clims, ok := tokenClaims.Claims.(*Claims); ok && tokenClaims.Valid {
|
||||
return clims, nil
|
||||
}
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
@@ -1,54 +0,0 @@
|
||||
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"
|
||||
)
|
||||
|
||||
func JWT(swagHandler gin.HandlerFunc) gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
var code int
|
||||
code = oasis_err2.SUCCESS
|
||||
token := c.GetHeader("Authorization")
|
||||
if len(token) == 0 {
|
||||
token = c.Query("token")
|
||||
}
|
||||
if token == "" {
|
||||
code = oasis_err2.INVALID_PARAMS
|
||||
}
|
||||
if swagHandler == nil {
|
||||
//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
|
||||
//}
|
||||
}
|
||||
|
||||
if code != oasis_err2.SUCCESS {
|
||||
c.JSON(http.StatusOK, model.Result{Success: code, Message: oasis_err2.GetMsg(code)})
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
c.Next()
|
||||
}
|
||||
}
|
||||
|
||||
//获取token
|
||||
func GetToken(username, pwd string) string {
|
||||
token, err := GenerateToken(username, pwd)
|
||||
if err == nil {
|
||||
return token
|
||||
} else {
|
||||
loger2.NewOLoger().Fatal(fmt.Sprintf("Get Token Fail: %V", err))
|
||||
return ""
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,7 @@
|
||||
* @Author: LinkLeong link@icewhale.com
|
||||
* @Date: 2022-06-02 15:09:38
|
||||
* @LastEditors: LinkLeong
|
||||
* @LastEditTime: 2022-06-02 17:43:38
|
||||
* @LastEditTime: 2022-06-27 15:47:49
|
||||
* @FilePath: /CasaOS/pkg/utils/loger/log.go
|
||||
* @Description:
|
||||
* @Website: https://www.casaos.io
|
||||
@@ -28,11 +28,11 @@ var loggers *zap.Logger
|
||||
func getFileLogWriter() (writeSyncer zapcore.WriteSyncer) {
|
||||
// 使用 lumberjack 实现 log rotate
|
||||
lumberJackLogger := &lumberjack.Logger{
|
||||
Filename: filepath.Join(config.AppInfo.LogSavePath, fmt.Sprintf("%s.%s",
|
||||
Filename: filepath.Join(config.AppInfo.LogPath, fmt.Sprintf("%s.%s",
|
||||
config.AppInfo.LogSaveName,
|
||||
config.AppInfo.LogFileExt,
|
||||
)),
|
||||
MaxSize: 100,
|
||||
MaxSize: 10,
|
||||
MaxBackups: 60,
|
||||
MaxAge: 1,
|
||||
Compress: true,
|
||||
@@ -47,8 +47,8 @@ func LogInit() {
|
||||
encoder := zapcore.NewJSONEncoder(encoderConfig)
|
||||
fileWriteSyncer := getFileLogWriter()
|
||||
core := zapcore.NewTee(
|
||||
zapcore.NewCore(encoder, zapcore.AddSync(os.Stdout), zapcore.DebugLevel),
|
||||
zapcore.NewCore(encoder, fileWriteSyncer, zapcore.DebugLevel),
|
||||
zapcore.NewCore(encoder, zapcore.AddSync(os.Stdout), zapcore.InfoLevel),
|
||||
zapcore.NewCore(encoder, fileWriteSyncer, zapcore.InfoLevel),
|
||||
)
|
||||
loggers = zap.New(core)
|
||||
|
||||
|
||||
@@ -1,109 +0,0 @@
|
||||
package loger
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
|
||||
"github.com/IceWhaleTech/CasaOS/pkg/config"
|
||||
file2 "github.com/IceWhaleTech/CasaOS/pkg/utils/file"
|
||||
)
|
||||
|
||||
//定义一个int的别名
|
||||
type Level int
|
||||
|
||||
type OLog interface {
|
||||
Debug(v ...interface{})
|
||||
Info(v ...interface{})
|
||||
Warn(v ...interface{})
|
||||
Error(v ...interface{})
|
||||
Fatal(v ...interface{})
|
||||
Path() string
|
||||
}
|
||||
|
||||
type oLog struct {
|
||||
}
|
||||
|
||||
var (
|
||||
F *os.File
|
||||
DefaultPrefix = ""
|
||||
DefaultCallerDepth = 2
|
||||
logger *log.Logger
|
||||
logPrefix = ""
|
||||
levelFlags = []string{"DEBUG", "INFO", "WARN", "ERROR", "FATAL"}
|
||||
)
|
||||
|
||||
//iota在const关键字出现时将被重置为0(const内部的第一行之前),const中每新增一行常量声明将使iota计数一次(iota可理解为const语句块中的行索引)。
|
||||
const (
|
||||
DEBUG Level = iota
|
||||
INFO
|
||||
WARN
|
||||
ERROR
|
||||
FATAL
|
||||
)
|
||||
|
||||
//日志初始化
|
||||
func LogSetupOld() {
|
||||
var err error
|
||||
filePath := fmt.Sprintf("%s", config.AppInfo.LogSavePath)
|
||||
fileName := fmt.Sprintf("%s.%s",
|
||||
config.AppInfo.LogSaveName,
|
||||
config.AppInfo.LogFileExt,
|
||||
)
|
||||
F, err = file2.MustOpen(fileName, filePath)
|
||||
if err != nil {
|
||||
log.Fatalf("logging.Setup err: %v", err)
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
func (o *oLog) Info(v ...interface{}) {
|
||||
setPrefix(INFO)
|
||||
logger.Println(v)
|
||||
}
|
||||
|
||||
func (o *oLog) Warn(v ...interface{}) {
|
||||
setPrefix(WARN)
|
||||
logger.Println(v)
|
||||
}
|
||||
|
||||
func (o *oLog) Error(v ...interface{}) {
|
||||
setPrefix(ERROR)
|
||||
logger.Println(v)
|
||||
}
|
||||
|
||||
func (o *oLog) Fatal(v ...interface{}) {
|
||||
setPrefix(FATAL)
|
||||
logger.Println(v)
|
||||
}
|
||||
|
||||
func setPrefix(level Level) {
|
||||
_, file, line, ok := runtime.Caller(DefaultCallerDepth)
|
||||
if ok {
|
||||
logPrefix = fmt.Sprintf("[%s][%s:%d]", levelFlags[level], filepath.Base(file), line)
|
||||
} else {
|
||||
logPrefix = fmt.Sprintf("[%s]", levelFlags[level])
|
||||
}
|
||||
|
||||
logger.SetPrefix(logPrefix)
|
||||
}
|
||||
|
||||
func NewOLoger() OLog {
|
||||
return &oLog{}
|
||||
}
|
||||
@@ -1,117 +0,0 @@
|
||||
package oasis_err
|
||||
|
||||
const (
|
||||
SUCCESS = 200
|
||||
ERROR = 500
|
||||
INVALID_PARAMS = 400
|
||||
ERROR_AUTH_TOKEN = 401
|
||||
|
||||
//user
|
||||
PWD_INVALID = 10001
|
||||
PWD_IS_EMPTY = 10002
|
||||
|
||||
PWD_INVALID_OLD = 10003
|
||||
ACCOUNT_LOCK = 10004
|
||||
//system
|
||||
DIR_ALREADY_EXISTS = 20001
|
||||
FILE_ALREADY_EXISTS = 20002
|
||||
FILE_OR_DIR_EXISTS = 20003
|
||||
PORT_IS_OCCUPIED = 20004
|
||||
COMMAND_ERROR_INVALID_OPERATION = 20005
|
||||
|
||||
//zerotier
|
||||
GET_TOKEN_ERROR = 30001
|
||||
|
||||
//disk
|
||||
NAME_NOT_AVAILABLE = 40001
|
||||
DISK_NEEDS_FORMAT = 40002
|
||||
DISK_BUSYING = 40003
|
||||
REMOVE_MOUNT_POINT_ERROR = 40004
|
||||
FORMAT_ERROR = 40005
|
||||
|
||||
//app
|
||||
UNINSTALL_APP_ERROR = 50001
|
||||
PULL_IMAGE_ERROR = 50002
|
||||
DEVICE_NOT_EXIST = 50003
|
||||
ERROR_APP_NAME_EXIST = 50004
|
||||
|
||||
//file
|
||||
FILE_DOES_NOT_EXIST = 60001
|
||||
FILE_READ_ERROR = 60002
|
||||
FILE_DELETE_ERROR = 60003
|
||||
DIR_NOT_EXISTS = 60004
|
||||
SOURCE_DES_SAME = 60005
|
||||
|
||||
//shortcuts
|
||||
SHORTCUTS_URL_ERROR = 70001
|
||||
|
||||
//person
|
||||
PERSON_REMOTE_ERROR = 80001
|
||||
PERSON_DOWN_NOT_EXIST = 80002
|
||||
PERSON_EXIST_DOWNLOAD = 80003
|
||||
PERSON_NOT_EXIST_USER = 80004
|
||||
PERSON_EXIST_FRIEND = 80005
|
||||
PERSON_MYSELF = 80006
|
||||
)
|
||||
|
||||
var MsgFlags = map[int]string{
|
||||
SUCCESS: "ok",
|
||||
ERROR: "fail",
|
||||
INVALID_PARAMS: "Parameters Error",
|
||||
ERROR_AUTH_TOKEN: "Error auth token",
|
||||
|
||||
//user
|
||||
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: "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: "Error uninstalling app",
|
||||
PULL_IMAGE_ERROR: "Error pulling image",
|
||||
DEVICE_NOT_EXIST: "Device does not exist",
|
||||
ERROR_APP_NAME_EXIST: "App name already exists",
|
||||
|
||||
//disk
|
||||
NAME_NOT_AVAILABLE: "Name not available",
|
||||
DISK_NEEDS_FORMAT: "Drive needs to be formatted",
|
||||
REMOVE_MOUNT_POINT_ERROR: "Failed to remove mount point",
|
||||
DISK_BUSYING: "Drive is busy",
|
||||
FORMAT_ERROR: "Formatting failed, please check if the directory is occupied",
|
||||
|
||||
//
|
||||
SOURCE_DES_SAME: "Source and destination cannot be the same.",
|
||||
FILE_DOES_NOT_EXIST: "File does not exist",
|
||||
|
||||
DIR_NOT_EXISTS: "Directory does not exist",
|
||||
|
||||
FILE_READ_ERROR: "File read error",
|
||||
FILE_DELETE_ERROR: "Delete error",
|
||||
SHORTCUTS_URL_ERROR: "URL error",
|
||||
|
||||
PERSON_REMOTE_ERROR: "Remote connection error",
|
||||
PERSON_DOWN_NOT_EXIST: "Download record does not exist",
|
||||
PERSON_EXIST_DOWNLOAD: "The same download task exists",
|
||||
PERSON_EXIST_FRIEND: "Friend already exist",
|
||||
PERSON_NOT_EXIST_USER: "User does not exist",
|
||||
PERSON_MYSELF: "You can not add yourself",
|
||||
COMMAND_ERROR_INVALID_OPERATION: "invalid operation",
|
||||
}
|
||||
|
||||
//获取错误信息
|
||||
func GetMsg(code int) string {
|
||||
msg, ok := MsgFlags[code]
|
||||
if ok {
|
||||
return msg
|
||||
}
|
||||
return MsgFlags[ERROR]
|
||||
}
|
||||
33
pkg/utils/udev_helper.go
Normal file
33
pkg/utils/udev_helper.go
Normal file
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* @Author: LinkLeong link@icewhale.org
|
||||
* @Date: 2022-08-10 16:06:12
|
||||
* @LastEditors: LinkLeong
|
||||
* @LastEditTime: 2022-08-10 16:11:37
|
||||
* @FilePath: /CasaOS/pkg/utils/udev_helper.go
|
||||
* @Description:
|
||||
* @Website: https://www.casaos.io
|
||||
* Copyright (c) 2022 by icewhale, All Rights Reserved.
|
||||
*/
|
||||
package utils
|
||||
|
||||
// func getOptionnalMatcher() (matcher netlink.Matcher, err error) {
|
||||
// if filePath == nil || *filePath == "" {
|
||||
// return nil, nil
|
||||
// }
|
||||
|
||||
// stream, err := ioutil.ReadFile(*filePath)
|
||||
// if err != nil {
|
||||
// return nil, err
|
||||
// }
|
||||
|
||||
// if stream == nil {
|
||||
// return nil, fmt.Errorf("Empty, no rules provided in \"%s\", err: %w", *filePath, err)
|
||||
// }
|
||||
|
||||
// var rules netlink.RuleDefinitions
|
||||
// if err := json.Unmarshal(stream, &rules); err != nil {
|
||||
// return nil, fmt.Errorf("Wrong rule syntax, err: %w", err)
|
||||
// }
|
||||
|
||||
// return &rules, nil
|
||||
// }
|
||||
@@ -2,7 +2,7 @@
|
||||
* @Author: LinkLeong link@icewhale.com
|
||||
* @Date: 2022-05-13 18:15:46
|
||||
* @LastEditors: LinkLeong
|
||||
* @LastEditTime: 2022-06-02 17:41:47
|
||||
* @LastEditTime: 2022-07-21 15:27:53
|
||||
* @FilePath: /CasaOS/pkg/utils/version/version.go
|
||||
* @Description:
|
||||
* @Website: https://www.casaos.io
|
||||
@@ -11,24 +11,17 @@
|
||||
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"
|
||||
)
|
||||
|
||||
func IsNeedUpdate() (bool, model.Version) {
|
||||
var version model.Version
|
||||
v := httper.OasisGet(config.ServerInfo.ServerApi + "/v1/sys/version")
|
||||
data := gjson.Get(v, "data")
|
||||
json2.Unmarshal([]byte(data.String()), &version)
|
||||
func IsNeedUpdate(version model.Version) (bool, model.Version) {
|
||||
|
||||
v1 := strings.Split(version.Version, ".")
|
||||
|
||||
v2 := strings.Split(types.CURRENTVERSION, ".")
|
||||
|
||||
for len(v1) < len(v2) {
|
||||
@@ -42,29 +35,10 @@ func IsNeedUpdate() (bool, model.Version) {
|
||||
b, _ := strconv.Atoi(v2[i])
|
||||
if a > b {
|
||||
return true, version
|
||||
} else {
|
||||
}
|
||||
if a < b {
|
||||
return false, 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
|
||||
}
|
||||
|
||||
25
route/darwin.go
Normal file
25
route/darwin.go
Normal file
@@ -0,0 +1,25 @@
|
||||
//go:build darwin
|
||||
// +build darwin
|
||||
|
||||
/*
|
||||
* @Author: LinkLeong link@icewhale.org
|
||||
* @Date: 2022-08-12 14:22:28
|
||||
* @LastEditors: LinkLeong
|
||||
* @LastEditTime: 2022-09-05 16:27:55
|
||||
* @FilePath: /CasaOS/route/darwin.go
|
||||
* @Description:
|
||||
* @Website: https://www.casaos.io
|
||||
* Copyright (c) 2022 by icewhale, All Rights Reserved.
|
||||
*/
|
||||
|
||||
package route
|
||||
|
||||
func MonitoryUSB() {
|
||||
|
||||
}
|
||||
func SendAllHardwareStatusBySocket() {
|
||||
|
||||
}
|
||||
func SendUSBBySocket() {
|
||||
|
||||
}
|
||||
15
route/doc.go
15
route/doc.go
@@ -1,15 +0,0 @@
|
||||
//go:build doc
|
||||
// +build doc
|
||||
|
||||
package route
|
||||
|
||||
import (
|
||||
_ "github.com/IceWhaleTech/CasaOS/docs"
|
||||
ginSwagger "github.com/swaggo/gin-swagger"
|
||||
swaggerFiles "github.com/swaggo/gin-swagger/swaggerFiles"
|
||||
)
|
||||
|
||||
func init() {
|
||||
// swagHandler = ginSwagger.WrapHandler(swaggerFiles.Handler)
|
||||
swagHandler = ginSwagger.WrapHandler(swaggerFiles.Handler)
|
||||
}
|
||||
298
route/init.go
298
route/init.go
@@ -1,296 +1,48 @@
|
||||
package route
|
||||
|
||||
import (
|
||||
"encoding/xml"
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/IceWhaleTech/CasaOS/model"
|
||||
"github.com/IceWhaleTech/CasaOS/model/system_app"
|
||||
"github.com/IceWhaleTech/CasaOS/pkg/config"
|
||||
"github.com/IceWhaleTech/CasaOS/pkg/utils/command"
|
||||
"github.com/IceWhaleTech/CasaOS/pkg/utils/env_helper"
|
||||
"github.com/IceWhaleTech/CasaOS/pkg/samba"
|
||||
"github.com/IceWhaleTech/CasaOS/pkg/utils/file"
|
||||
"github.com/IceWhaleTech/CasaOS/pkg/utils/port"
|
||||
"github.com/IceWhaleTech/CasaOS/pkg/utils/loger"
|
||||
"github.com/IceWhaleTech/CasaOS/service"
|
||||
model2 "github.com/IceWhaleTech/CasaOS/service/model"
|
||||
uuid "github.com/satori/go.uuid"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
func InitFunction() {
|
||||
go checkSystemApp()
|
||||
Update2_3()
|
||||
CheckSerialDiskMount()
|
||||
|
||||
CheckToken2_11()
|
||||
ImportApplications()
|
||||
ChangeAPIUrl()
|
||||
InitSystemApplication()
|
||||
|
||||
go InitNetworkMount()
|
||||
}
|
||||
|
||||
var syncIsExistence = false
|
||||
|
||||
func installSyncthing(appId string) {
|
||||
|
||||
var appInfo model.ServerAppList
|
||||
m := model.CustomizationPostData{}
|
||||
var dockerImage string
|
||||
var dockerImageVersion string
|
||||
appInfo = service.MyService.Casa().GetServerAppInfo(appId, "system", "us_en")
|
||||
dockerImage = appInfo.Image
|
||||
dockerImageVersion = appInfo.ImageVersion
|
||||
|
||||
if len(appInfo.ImageVersion) == 0 {
|
||||
dockerImageVersion = "latest"
|
||||
}
|
||||
|
||||
if appInfo.NetworkModel != "host" {
|
||||
for i := 0; i < len(appInfo.Ports); i++ {
|
||||
if p, _ := strconv.Atoi(appInfo.Ports[i].ContainerPort); port.IsPortAvailable(p, appInfo.Ports[i].Protocol) {
|
||||
appInfo.Ports[i].CommendPort = strconv.Itoa(p)
|
||||
} else {
|
||||
if appInfo.Ports[i].Protocol == "tcp" {
|
||||
if p, err := port.GetAvailablePort("tcp"); err == nil {
|
||||
appInfo.Ports[i].CommendPort = strconv.Itoa(p)
|
||||
}
|
||||
} else if appInfo.Ports[i].Protocol == "upd" {
|
||||
if p, err := port.GetAvailablePort("udp"); err == nil {
|
||||
appInfo.Ports[i].CommendPort = strconv.Itoa(p)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if appInfo.Ports[i].Type == 0 {
|
||||
appInfo.PortMap = appInfo.Ports[i].CommendPort
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for i := 0; i < len(appInfo.Devices); i++ {
|
||||
if !file.CheckNotExist(appInfo.Devices[i].ContainerPath) {
|
||||
appInfo.Devices[i].Path = appInfo.Devices[i].ContainerPath
|
||||
}
|
||||
}
|
||||
if len(appInfo.Tip) > 0 {
|
||||
appInfo.Tip = env_helper.ReplaceStringDefaultENV(appInfo.Tip)
|
||||
}
|
||||
|
||||
appInfo.MaxMemory = service.MyService.System().GetMemInfo().Total >> 20
|
||||
|
||||
id := uuid.NewV4().String()
|
||||
|
||||
// step:下载镜像
|
||||
err := service.MyService.Docker().DockerPullImage(dockerImage+":"+dockerImageVersion, "", "")
|
||||
if err != nil {
|
||||
//pull image error
|
||||
fmt.Println("pull image error", err, dockerImage, dockerImageVersion)
|
||||
return
|
||||
}
|
||||
for !service.MyService.Docker().IsExistImage(dockerImage + ":" + dockerImageVersion) {
|
||||
time.Sleep(time.Second)
|
||||
}
|
||||
|
||||
m.CpuShares = 50
|
||||
m.Envs = appInfo.Envs
|
||||
m.Memory = int64(appInfo.MaxMemory)
|
||||
m.Origin = "system"
|
||||
m.PortMap = appInfo.PortMap
|
||||
m.Ports = appInfo.Ports
|
||||
m.Restart = "always"
|
||||
m.Volumes = appInfo.Volumes
|
||||
m.Label = id
|
||||
m.CustomId = id
|
||||
containerId, err := service.MyService.Docker().DockerContainerCreate(dockerImage+":"+dockerImageVersion, m, appInfo.NetworkModel)
|
||||
if err != nil {
|
||||
fmt.Println("container create error", err)
|
||||
// create container error
|
||||
return
|
||||
}
|
||||
|
||||
//step:start container
|
||||
err = service.MyService.Docker().DockerContainerStart(containerId)
|
||||
if err != nil {
|
||||
//start container error
|
||||
return
|
||||
}
|
||||
|
||||
checkSystemApp()
|
||||
}
|
||||
|
||||
// check if the system application is installed
|
||||
func checkSystemApp() {
|
||||
list := service.MyService.App().GetSystemAppList()
|
||||
for _, v := range list {
|
||||
info, err := service.MyService.Docker().DockerContainerInfo(v.ID)
|
||||
func InitNetworkMount() {
|
||||
time.Sleep(time.Second * 10)
|
||||
connections := service.MyService.Connections().GetConnectionsList()
|
||||
for _, v := range connections {
|
||||
connection := service.MyService.Connections().GetConnectionByID(fmt.Sprint(v.ID))
|
||||
directories, err := samba.GetSambaSharesList(connection.Host, connection.Port, connection.Username, connection.Password)
|
||||
if err != nil {
|
||||
service.MyService.Connections().DeleteConnection(fmt.Sprint(connection.ID))
|
||||
loger.Error("mount samba err", zap.Any("err", err), zap.Any("info", connection))
|
||||
continue
|
||||
}
|
||||
if strings.Contains(info.Config.Image, "linuxserver/syncthing") {
|
||||
if v.State != "running" {
|
||||
//step:start container
|
||||
service.MyService.Docker().DockerContainerStart(v.ID)
|
||||
}
|
||||
syncIsExistence = true
|
||||
if config.SystemConfigInfo.SyncPort != v.Labels["web"] {
|
||||
config.SystemConfigInfo.SyncPort = v.Labels["web"]
|
||||
}
|
||||
baseHostPath := "/mnt/" + connection.Host
|
||||
|
||||
path := ""
|
||||
for _, i := range info.Mounts {
|
||||
if i.Destination == "/config" {
|
||||
path = i.Source
|
||||
break
|
||||
}
|
||||
}
|
||||
content := file.ReadFullFile(filepath.Join(path, "config.xml"))
|
||||
syncConfig := &system_app.SyncConfig{}
|
||||
xml.Unmarshal(content, &syncConfig)
|
||||
config.SystemConfigInfo.SyncKey = syncConfig.Key
|
||||
break
|
||||
mountPointList := service.MyService.System().GetDirPath(baseHostPath)
|
||||
for _, v := range mountPointList {
|
||||
service.MyService.Connections().UnmountSmaba(v.Path)
|
||||
}
|
||||
}
|
||||
if !syncIsExistence {
|
||||
installSyncthing("74")
|
||||
}
|
||||
}
|
||||
func CheckSerialDiskMount() {
|
||||
// check mount point
|
||||
dbList := service.MyService.Disk().GetSerialAll()
|
||||
|
||||
list := service.MyService.Disk().LSBLK(true)
|
||||
mountPoint := make(map[string]string, len(dbList))
|
||||
//remount
|
||||
for _, v := range dbList {
|
||||
mountPoint[v.UUID] = v.MountPoint
|
||||
}
|
||||
for _, v := range list {
|
||||
command.ExecEnabledSMART(v.Path)
|
||||
if v.Children != nil {
|
||||
for _, h := range v.Children {
|
||||
if len(h.MountPoint) == 0 && len(v.Children) == 1 && h.FsType == "ext4" {
|
||||
if m, ok := mountPoint[h.UUID]; ok {
|
||||
//mount point check
|
||||
volume := m
|
||||
if !file.CheckNotExist(m) {
|
||||
for i := 0; file.CheckNotExist(volume); i++ {
|
||||
volume = m + strconv.Itoa(i+1)
|
||||
}
|
||||
}
|
||||
service.MyService.Disk().MountDisk(h.Path, volume)
|
||||
if volume != m {
|
||||
ms := model2.SerialDisk{}
|
||||
ms.UUID = v.UUID
|
||||
ms.MountPoint = volume
|
||||
service.MyService.Disk().UpdateMountPoint(ms)
|
||||
}
|
||||
os.RemoveAll(baseHostPath)
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
file.IsNotExistMkDir(baseHostPath)
|
||||
for _, v := range directories {
|
||||
mountPoint := baseHostPath + "/" + v
|
||||
file.IsNotExistMkDir(mountPoint)
|
||||
service.MyService.Connections().MountSmaba(connection.Username, connection.Host, v, connection.Port, mountPoint, connection.Password)
|
||||
}
|
||||
}
|
||||
service.MyService.Disk().RemoveLSBLKCache()
|
||||
command.OnlyExec("source " + config.AppInfo.ProjectPath + "/shell/helper.sh ;AutoRemoveUnuseDir")
|
||||
}
|
||||
func Update2_3() {
|
||||
command.OnlyExec("source " + config.AppInfo.ProjectPath + "/shell/assist.sh")
|
||||
|
||||
}
|
||||
func CheckToken2_11() {
|
||||
if len(config.ServerInfo.Token) == 0 {
|
||||
token := uuid.NewV4().String
|
||||
config.ServerInfo.Token = token()
|
||||
config.Cfg.Section("server").Key("Token").SetValue(token())
|
||||
config.Cfg.SaveTo(config.SystemConfigInfo.ConfigPath)
|
||||
}
|
||||
if len(config.AppInfo.RootPath) == 0 {
|
||||
config.Cfg.Section("app").Key("RootPath").SetValue("/casaOS")
|
||||
config.AppInfo.RootPath = "/casaOS"
|
||||
config.Cfg.SaveTo(config.SystemConfigInfo.ConfigPath)
|
||||
}
|
||||
// if len(config.ServerInfo.Handshake) == 0 {
|
||||
// config.Cfg.Section("app").Key("RootPath").SetValue("/casaOS")
|
||||
// config.AppInfo.RootPath = "/casaOS"
|
||||
// config.Cfg.SaveTo(config.SystemConfigInfo.ConfigPath)
|
||||
// }
|
||||
sysType := runtime.GOOS
|
||||
if len(config.FileSettingInfo.DownloadDir) == 0 {
|
||||
downloadPath := "/DATA/Downloads"
|
||||
if sysType == "windows" {
|
||||
downloadPath = "C:\\CasaOS\\DATA\\Downloads"
|
||||
}
|
||||
if sysType == "darwin" {
|
||||
downloadPath = "./CasaOS/DATA/Downloads"
|
||||
}
|
||||
config.Cfg.Section("file").Key("DownloadDir").SetValue(downloadPath)
|
||||
config.FileSettingInfo.DownloadDir = downloadPath
|
||||
file.IsNotExistMkDir(config.FileSettingInfo.DownloadDir)
|
||||
config.Cfg.SaveTo(config.SystemConfigInfo.ConfigPath)
|
||||
}
|
||||
|
||||
if len(config.UserInfo.Description) == 0 {
|
||||
config.Cfg.Section("user").Key("Description").SetValue("nothing")
|
||||
config.UserInfo.Description = "nothing"
|
||||
config.Cfg.SaveTo(config.SystemConfigInfo.ConfigPath)
|
||||
}
|
||||
if len(config.ServerInfo.Handshake) == 0 {
|
||||
config.Cfg.Section("server").Key("Handshake").SetValue("socket.casaos.io")
|
||||
config.ServerInfo.Handshake = "socket.casaos.io"
|
||||
config.Cfg.SaveTo(config.SystemConfigInfo.ConfigPath)
|
||||
}
|
||||
|
||||
if service.MyService.ZiMa().GetSysInfo().KernelArch == "aarch64" && config.ServerInfo.USBAutoMount != "True" && strings.Contains(service.MyService.ZiMa().GetDeviceTree(), "Raspberry Pi") {
|
||||
service.MyService.System().UpdateUSBAutoMount("False")
|
||||
service.MyService.System().ExecUSBAutoMountShell("False")
|
||||
}
|
||||
|
||||
// str := []string{}
|
||||
// str = append(str, "ddd")
|
||||
// str = append(str, "aaa")
|
||||
// ddd := strings.Join(str, "|")
|
||||
// config.Cfg.Section("file").Key("ShareDir").SetValue(ddd)
|
||||
|
||||
// config.Cfg.SaveTo(config.SystemConfigInfo.ConfigPath)
|
||||
|
||||
}
|
||||
|
||||
func ImportApplications() {
|
||||
service.MyService.App().ImportApplications(true)
|
||||
}
|
||||
|
||||
// 0.3.1
|
||||
func ChangeAPIUrl() {
|
||||
|
||||
newAPIUrl := "https://api.casaos.io/casaos-api"
|
||||
if config.ServerInfo.ServerApi == "https://api.casaos.zimaboard.com" {
|
||||
config.ServerInfo.ServerApi = newAPIUrl
|
||||
config.Cfg.Section("server").Key("ServerApi").SetValue(newAPIUrl)
|
||||
config.Cfg.SaveTo(config.SystemConfigInfo.ConfigPath)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// 0.3.1
|
||||
func InitSystemApplication() {
|
||||
list := service.MyService.App().GetApplicationList()
|
||||
if len(list) != 2 {
|
||||
application := model2.ApplicationModel{}
|
||||
application.Name = "Files"
|
||||
application.Icon = "/ui/img/Files.svg"
|
||||
application.Type = "system"
|
||||
application.Order = 0
|
||||
service.MyService.App().CreateApplication(application)
|
||||
|
||||
application.Name = "CasaConnect"
|
||||
application.Icon = "/ui/img/CasaConnect.svg"
|
||||
application.Type = "system"
|
||||
application.Order = 0
|
||||
|
||||
service.MyService.App().CreateApplication(application)
|
||||
connection.Directories = strings.Join(directories, ",")
|
||||
service.MyService.Connections().UpdateConnection(&connection)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
//go:build !darwin
|
||||
// +build !darwin
|
||||
|
||||
/*
|
||||
* @Author: LinkLeong link@icewhale.com
|
||||
* @Date: 2022-05-27 15:55:36
|
||||
* @Date: 2022-07-01 15:11:36
|
||||
* @LastEditors: LinkLeong
|
||||
* @LastEditTime: 2022-06-10 12:17:59
|
||||
* @LastEditTime: 2022-09-05 16:28:46
|
||||
* @FilePath: /CasaOS/route/periodical.go
|
||||
* @Description:
|
||||
* @Website: https://www.casaos.io
|
||||
@@ -11,8 +14,6 @@
|
||||
package route
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
"unsafe"
|
||||
@@ -29,7 +30,7 @@ func SendNetINfoBySocket() {
|
||||
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.State = strings.TrimSpace(service.MyService.System().GetNetState(n.Name))
|
||||
item.Time = time.Now().Unix()
|
||||
newNet = append(newNet, item)
|
||||
break
|
||||
@@ -52,108 +53,6 @@ func SendMemBySocket() {
|
||||
service.MyService.Notify().SendMemInfoBySocket(service.MyService.System().GetMemInfo())
|
||||
}
|
||||
|
||||
func SendDiskBySocket() {
|
||||
list := service.MyService.Disk().LSBLK(true)
|
||||
|
||||
summary := model.Summary{}
|
||||
healthy := true
|
||||
findSystem := 0
|
||||
|
||||
for i := 0; i < len(list); i++ {
|
||||
if len(list[i].Children) > 0 && findSystem == 0 {
|
||||
|
||||
for j := 0; j < len(list[i].Children); j++ {
|
||||
|
||||
if len(list[i].Children[j].Children) > 0 {
|
||||
for _, v := range list[i].Children[j].Children {
|
||||
if v.MountPoint == "/" {
|
||||
s, _ := strconv.ParseUint(v.FSSize, 10, 64)
|
||||
a, _ := strconv.ParseUint(v.FSAvail, 10, 64)
|
||||
u, _ := strconv.ParseUint(v.FSUsed, 10, 64)
|
||||
summary.Size += s
|
||||
summary.Avail += a
|
||||
summary.Used += u
|
||||
findSystem = 1
|
||||
break
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if list[i].Children[j].MountPoint == "/" {
|
||||
s, _ := strconv.ParseUint(list[i].Children[j].FSSize, 10, 64)
|
||||
a, _ := strconv.ParseUint(list[i].Children[j].FSAvail, 10, 64)
|
||||
u, _ := strconv.ParseUint(list[i].Children[j].FSUsed, 10, 64)
|
||||
summary.Size += s
|
||||
summary.Avail += a
|
||||
summary.Used += u
|
||||
findSystem = 1
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
if findSystem == 1 {
|
||||
findSystem += 1
|
||||
continue
|
||||
}
|
||||
if list[i].Tran == "sata" || list[i].Tran == "nvme" || list[i].Tran == "spi" || list[i].Tran == "sas" {
|
||||
temp := service.MyService.Disk().SmartCTL(list[i].Path)
|
||||
if reflect.DeepEqual(temp, model.SmartctlA{}) {
|
||||
continue
|
||||
}
|
||||
|
||||
//list[i].Temperature = temp.Temperature.Current
|
||||
if !temp.SmartStatus.Passed {
|
||||
healthy = false
|
||||
}
|
||||
if len(list[i].Children) > 0 {
|
||||
for _, v := range list[i].Children {
|
||||
s, _ := strconv.ParseUint(v.FSSize, 10, 64)
|
||||
a, _ := strconv.ParseUint(v.FSAvail, 10, 64)
|
||||
u, _ := strconv.ParseUint(v.FSUsed, 10, 64)
|
||||
summary.Size += s
|
||||
summary.Avail += a
|
||||
summary.Used += u
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
summary.Health = healthy
|
||||
service.MyService.Notify().SendDiskInfoBySocket(summary)
|
||||
}
|
||||
|
||||
func SendUSBBySocket() {
|
||||
usbList := service.MyService.Disk().LSBLK(false)
|
||||
usb := []model.DriveUSB{}
|
||||
for _, v := range usbList {
|
||||
if v.Tran == "usb" {
|
||||
temp := model.DriveUSB{}
|
||||
temp.Model = v.Model
|
||||
temp.Name = v.Name
|
||||
temp.Size = v.Size
|
||||
mountTemp := true
|
||||
if len(v.Children) == 0 {
|
||||
mountTemp = false
|
||||
}
|
||||
for _, child := range v.Children {
|
||||
if len(child.MountPoint) > 0 {
|
||||
avail, _ := strconv.ParseUint(child.FSAvail, 10, 64)
|
||||
temp.Avail += avail
|
||||
used, _ := strconv.ParseUint(child.FSUsed, 10, 64)
|
||||
temp.Used += used
|
||||
} else {
|
||||
mountTemp = false
|
||||
}
|
||||
}
|
||||
temp.Mount = mountTemp
|
||||
usb = append(usb, temp)
|
||||
}
|
||||
}
|
||||
service.MyService.Notify().SendUSBInfoBySocket(usb)
|
||||
}
|
||||
|
||||
func SendAllHardwareStatusBySocket() {
|
||||
|
||||
netList := service.MyService.System().GetNetInfo()
|
||||
@@ -163,123 +62,59 @@ func SendAllHardwareStatusBySocket() {
|
||||
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.State = strings.TrimSpace(service.MyService.System().GetNetState(n.Name))
|
||||
item.Time = time.Now().Unix()
|
||||
newNet = append(newNet, item)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cpu := service.MyService.System().GetCpuPercent()
|
||||
num := service.MyService.System().GetCpuCoreNum()
|
||||
cpuData := make(map[string]interface{})
|
||||
cpuData["percent"] = cpu
|
||||
cpuData["num"] = num
|
||||
cpuData["temperature"] = service.MyService.System().GetCPUTemperature()
|
||||
cpuData["power"] = service.MyService.System().GetCPUPower()
|
||||
|
||||
list := service.MyService.Disk().LSBLK(true)
|
||||
|
||||
summary := model.Summary{}
|
||||
healthy := true
|
||||
findSystem := 0
|
||||
|
||||
for i := 0; i < len(list); i++ {
|
||||
if len(list[i].Children) > 0 && findSystem == 0 {
|
||||
|
||||
for j := 0; j < len(list[i].Children); j++ {
|
||||
|
||||
if len(list[i].Children[j].Children) > 0 {
|
||||
for _, v := range list[i].Children[j].Children {
|
||||
if v.MountPoint == "/" {
|
||||
s, _ := strconv.ParseUint(v.FSSize, 10, 64)
|
||||
a, _ := strconv.ParseUint(v.FSAvail, 10, 64)
|
||||
u, _ := strconv.ParseUint(v.FSUsed, 10, 64)
|
||||
summary.Size += s
|
||||
summary.Avail += a
|
||||
summary.Used += u
|
||||
findSystem = 1
|
||||
break
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if list[i].Children[j].MountPoint == "/" {
|
||||
s, _ := strconv.ParseUint(list[i].Children[j].FSSize, 10, 64)
|
||||
a, _ := strconv.ParseUint(list[i].Children[j].FSAvail, 10, 64)
|
||||
u, _ := strconv.ParseUint(list[i].Children[j].FSUsed, 10, 64)
|
||||
summary.Size += s
|
||||
summary.Avail += a
|
||||
summary.Used += u
|
||||
findSystem = 1
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
if findSystem == 1 {
|
||||
findSystem += 1
|
||||
continue
|
||||
}
|
||||
if list[i].Tran == "sata" || list[i].Tran == "nvme" || list[i].Tran == "spi" || list[i].Tran == "sas" {
|
||||
temp := service.MyService.Disk().SmartCTL(list[i].Path)
|
||||
if reflect.DeepEqual(temp, model.SmartctlA{}) {
|
||||
continue
|
||||
}
|
||||
|
||||
//list[i].Temperature = temp.Temperature.Current
|
||||
if !temp.SmartStatus.Passed {
|
||||
healthy = false
|
||||
}
|
||||
if len(list[i].Children) > 0 {
|
||||
for _, v := range list[i].Children {
|
||||
s, _ := strconv.ParseUint(v.FSSize, 10, 64)
|
||||
a, _ := strconv.ParseUint(v.FSAvail, 10, 64)
|
||||
u, _ := strconv.ParseUint(v.FSUsed, 10, 64)
|
||||
summary.Size += s
|
||||
summary.Avail += a
|
||||
summary.Used += u
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
summary.Health = healthy
|
||||
|
||||
usbList := service.MyService.Disk().LSBLK(false)
|
||||
usb := []model.DriveUSB{}
|
||||
for _, v := range usbList {
|
||||
if v.Tran == "usb" {
|
||||
temp := model.DriveUSB{}
|
||||
temp.Model = v.Model
|
||||
temp.Name = v.Name
|
||||
temp.Size = v.Size
|
||||
mountTemp := true
|
||||
if len(v.Children) == 0 {
|
||||
mountTemp = false
|
||||
}
|
||||
for _, child := range v.Children {
|
||||
if len(child.MountPoint) > 0 {
|
||||
avail, _ := strconv.ParseUint(child.FSAvail, 10, 64)
|
||||
temp.Avail += avail
|
||||
used, _ := strconv.ParseUint(child.FSUsed, 10, 64)
|
||||
temp.Used += used
|
||||
} else {
|
||||
mountTemp = false
|
||||
}
|
||||
}
|
||||
temp.Mount = mountTemp
|
||||
usb = append(usb, temp)
|
||||
}
|
||||
}
|
||||
memInfo := service.MyService.System().GetMemInfo()
|
||||
memData := make(map[string]interface{})
|
||||
memData["total"] = memInfo.Total
|
||||
memData["available"] = memInfo.Available
|
||||
memData["used"] = memInfo.Used
|
||||
memData["free"] = memInfo.Free
|
||||
memData["usedPercent"] = memInfo.UsedPercent
|
||||
|
||||
service.MyService.Notify().SendAllHardwareStatusBySocket(summary, usb, memData, cpuData, newNet)
|
||||
service.MyService.Notify().SendAllHardwareStatusBySocket(memInfo, cpuData, newNet)
|
||||
|
||||
}
|
||||
|
||||
// func MonitoryUSB() {
|
||||
// var matcher netlink.Matcher
|
||||
|
||||
// conn := new(netlink.UEventConn)
|
||||
// if err := conn.Connect(netlink.UdevEvent); err != nil {
|
||||
// loger.Error("udev err", zap.Any("Unable to connect to Netlink Kobject UEvent socket", err))
|
||||
// }
|
||||
// defer conn.Close()
|
||||
|
||||
// queue := make(chan netlink.UEvent)
|
||||
// errors := make(chan error)
|
||||
// quit := conn.Monitor(queue, errors, matcher)
|
||||
|
||||
// signals := make(chan os.Signal, 1)
|
||||
// signal.Notify(signals, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT)
|
||||
// go func() {
|
||||
// <-signals
|
||||
// close(quit)
|
||||
// os.Exit(0)
|
||||
// }()
|
||||
|
||||
// for {
|
||||
// select {
|
||||
// case uevent := <-queue:
|
||||
// if uevent.Env["DEVTYPE"] == "disk" {
|
||||
// time.Sleep(time.Microsecond * 500)
|
||||
// SendUSBBySocket()
|
||||
// continue
|
||||
// }
|
||||
// case err := <-errors:
|
||||
// loger.Error("udev err", zap.Any("err", err))
|
||||
// }
|
||||
// }
|
||||
|
||||
// }
|
||||
|
||||
345
route/route.go
345
route/route.go
@@ -1,244 +1,219 @@
|
||||
package route
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/IceWhaleTech/CasaOS-Common/utils/jwt"
|
||||
"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-contrib/gzip"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
var swagHandler gin.HandlerFunc
|
||||
var OnlineDemo bool = false
|
||||
|
||||
func InitRouter() *gin.Engine {
|
||||
|
||||
r := gin.Default()
|
||||
|
||||
r.Use(middleware.Cors())
|
||||
r.Use(middleware.WriteLog())
|
||||
r.Use(gzip.Gzip(gzip.DefaultCompression))
|
||||
gin.SetMode(config.ServerInfo.RunMode)
|
||||
|
||||
r.StaticFS("/ui", http.FS(web.Static))
|
||||
r.GET("/", WebUIHome)
|
||||
// r.StaticFS("/ui", http.FS(web.Static))
|
||||
// r.GET("/", WebUIHome)
|
||||
// r.StaticFS("/assets", http.Dir("./static/assets"))
|
||||
// r.StaticFile("/favicon.ico", "./static/favicon.ico")
|
||||
//r.GET("/", func(c *gin.Context) {
|
||||
// c.Redirect(http.StatusMovedPermanently, "ui/")
|
||||
//})
|
||||
if swagHandler != nil {
|
||||
r.GET("/swagger/*any", swagHandler)
|
||||
}
|
||||
r.POST("/v1/user/login", v1.Login)
|
||||
|
||||
r.GET("/v1/guide/check", v1.GetGuideCheck)
|
||||
// r.POST("/v1/users/register", v1.PostUserRegister)
|
||||
// r.POST("/v1/users/login", v1.PostUserLogin)
|
||||
// r.GET("/v1/users/name", v1.GetUserAllUsername) //all/name
|
||||
// r.POST("/v1/users/refresh", v1.PostUserRefreshToken)
|
||||
// // No short-term modifications
|
||||
// r.GET("/v1/users/image", v1.GetUserImage)
|
||||
|
||||
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.GetUserInfo)
|
||||
//get user info
|
||||
r.GET("/v1/person/shareid", v1.GetPersonShareId)
|
||||
r.GET("/v1/sys/socket/port", v1.GetSystemSocketPort)
|
||||
// r.GET("/v1/users/status", v1.GetUserStatus) //init/check
|
||||
//r.GET("/v1/guide/check", v1.GetGuideCheck) // /v1/sys/guide_check
|
||||
r.GET("/v1/sys/debug", v1.GetSystemConfigDebug) // //debug
|
||||
|
||||
r.GET("/v1/sys/socket-port", v1.GetSystemSocketPort) //sys/socket_port
|
||||
r.GET("/v1/sys/version/check", v1.GetSystemCheckVersion)
|
||||
r.GET("/ping", func(ctx *gin.Context) {
|
||||
ctx.String(200, "pong")
|
||||
})
|
||||
v1Group := r.Group("/v1")
|
||||
|
||||
v1Group.Use(jwt2.JWT(swagHandler))
|
||||
v1Group.Use(jwt.ExceptLocalhost())
|
||||
{
|
||||
v1UserGroup := v1Group.Group("/user")
|
||||
v1UserGroup.Use()
|
||||
// v1UsersGroup := v1Group.Group("/users")
|
||||
// v1UsersGroup.Use()
|
||||
// {
|
||||
// v1UsersGroup.GET("/current", v1.GetUserInfo)
|
||||
// v1UsersGroup.PUT("/current", v1.PutUserInfo)
|
||||
// v1UsersGroup.PUT("/current/password", v1.PutUserPassword)
|
||||
|
||||
// v1UsersGroup.GET("/current/custom/:key", v1.GetUserCustomConf)
|
||||
// v1UsersGroup.POST("/current/custom/:key", v1.PostUserCustomConf)
|
||||
// v1UsersGroup.DELETE("/current/custom/:key", v1.DeleteUserCustomConf)
|
||||
|
||||
// v1UsersGroup.POST("/current/image/:key", v1.PostUserUploadImage)
|
||||
// v1UsersGroup.PUT("/current/image/:key", v1.PutUserImage)
|
||||
// //v1UserGroup.POST("/file/image/:key", v1.PostUserFileImage)
|
||||
// v1UsersGroup.DELETE("/current/image", v1.DeleteUserImage)
|
||||
|
||||
// //v1UserGroup.PUT("/avatar", v1.PutUserAvatar)
|
||||
// //v1UserGroup.GET("/avatar", v1.GetUserAvatar)
|
||||
// v1UsersGroup.DELETE("/:id", v1.DeleteUser)
|
||||
// v1UsersGroup.GET("/:username", v1.GetUserInfoByUsername)
|
||||
// v1UsersGroup.DELETE("", v1.DeleteUserAll)
|
||||
// }
|
||||
|
||||
v1AppsGroup := v1Group.Group("/apps")
|
||||
v1AppsGroup.Use()
|
||||
{
|
||||
v1AppsGroup.GET("", v1.AppList) //list
|
||||
v1AppsGroup.GET("/:id", v1.AppInfo)
|
||||
}
|
||||
v1ContainerGroup := v1Group.Group("/container")
|
||||
v1ContainerGroup.Use()
|
||||
{
|
||||
|
||||
//chang head
|
||||
v1UserGroup.POST("/head", v1.PostUserHead)
|
||||
//chang user name
|
||||
v1UserGroup.PUT("/username", v1.PutUserName)
|
||||
//chang pwd
|
||||
v1UserGroup.PUT("/password", v1.PutUserPwd)
|
||||
//edit user info
|
||||
v1UserGroup.POST("/info", v1.PostUserChangeInfo)
|
||||
v1UserGroup.PUT("/nick", v1.PutUserChangeNick)
|
||||
v1UserGroup.PUT("/desc", v1.PutUserChangeDesc)
|
||||
v1UserGroup.POST("/person/info", v1.PostUserPersonInfo)
|
||||
v1ContainerGroup.GET("", v1.MyAppList) ///my/list
|
||||
v1ContainerGroup.GET("/usage", v1.AppUsageList)
|
||||
v1ContainerGroup.GET("/:id", v1.ContainerUpdateInfo) ///update/:id/info
|
||||
v1ContainerGroup.GET("/:id/logs", v1.ContainerLog) // /app/logs/:id
|
||||
v1ContainerGroup.GET("/networks", v1.GetDockerNetworks) //app/install/config
|
||||
|
||||
v1UserGroup.GET("/shareid", v1.GetUserShareID)
|
||||
// v1UserGroup.GET("/custom/:name")
|
||||
// v1UserGroup.POST("/custom/:name")
|
||||
v1ContainerGroup.GET("/:id/state", v1.GetContainerState) //app/state/:id ?state=install_progress
|
||||
// there are problems, temporarily do not deal with
|
||||
v1ContainerGroup.GET("/:id/terminal", v1.DockerTerminal) //app/terminal/:id
|
||||
v1ContainerGroup.POST("", v1.InstallApp) //app/install
|
||||
//v1ContainerGroup.GET("/:id", v1.ContainerInfo) // /app/info/:id
|
||||
|
||||
v1ContainerGroup.PUT("/:id", v1.UpdateSetting) ///update/:id/setting
|
||||
|
||||
v1ContainerGroup.PUT("/:id/state", v1.ChangAppState) // /app/state/:id
|
||||
v1ContainerGroup.DELETE("/:id", v1.UnInstallApp) //app/uninstall/:id
|
||||
//Not used
|
||||
v1ContainerGroup.PUT("/:id/latest", v1.PutAppUpdate)
|
||||
//Not used
|
||||
v1ContainerGroup.POST("/share", v1.ShareAppFile)
|
||||
v1ContainerGroup.GET("/info", v1.GetcontainerInfo)
|
||||
v1ContainerGroup.PUT("/info", v1.PutcontainerInfo)
|
||||
|
||||
}
|
||||
v1AppGroup := v1Group.Group("/app")
|
||||
v1AppGroup.Use()
|
||||
v1AppCategoriesGroup := v1Group.Group("/app-categories")
|
||||
v1AppCategoriesGroup.Use()
|
||||
{
|
||||
//获取我的已安装的列表
|
||||
v1AppGroup.GET("/my/list", v1.MyAppList)
|
||||
//
|
||||
v1AppGroup.GET("/usage", v1.AppUsageList)
|
||||
//app详情
|
||||
v1AppGroup.GET("/appinfo/:id", v1.AppInfo)
|
||||
//获取未安装的列表
|
||||
v1AppGroup.GET("/list", v1.AppList)
|
||||
//获取端口
|
||||
v1AppGroup.GET("/port", v1.GetPort)
|
||||
//检查端口
|
||||
v1AppGroup.GET("/check/:port", v1.PortCheck)
|
||||
//分类
|
||||
v1AppGroup.GET("/category", v1.CategoryList)
|
||||
//容器相关
|
||||
v1AppGroup.GET("/terminal/:id", v1.DockerTerminal)
|
||||
v1AppGroup.GET("/order", v1.GetAppOrder)
|
||||
v1AppGroup.POST("/order", v1.PostAppOrder)
|
||||
//app容器详情
|
||||
v1AppGroup.GET("/info/:id", v1.ContainerInfo)
|
||||
//app容器日志
|
||||
v1AppGroup.GET("/logs/:id", v1.ContainerLog)
|
||||
//暂停或启动容器
|
||||
v1AppGroup.PUT("/state/:id", v1.ChangAppState)
|
||||
//安装app
|
||||
v1AppGroup.POST("/install", v1.InstallApp)
|
||||
//卸载app
|
||||
v1AppGroup.DELETE("/uninstall/:id", v1.UnInstallApp)
|
||||
//获取进度
|
||||
v1AppGroup.GET("/state/:id", v1.GetContainerState)
|
||||
//更新容器配置
|
||||
v1AppGroup.PUT("/update/:id/setting", v1.UpdateSetting)
|
||||
//获取可能新数据
|
||||
v1AppGroup.GET("/update/:id/info", v1.ContainerUpdateInfo)
|
||||
v1AppGroup.GET("/rely/:id/info", v1.ContainerRelyInfo)
|
||||
v1AppGroup.GET("/install/config", v1.GetDockerInstallConfig)
|
||||
v1AppGroup.PUT("/update/:id", v1.PutAppUpdate)
|
||||
v1AppGroup.POST("/share", v1.ShareAppFile)
|
||||
v1AppCategoriesGroup.GET("", v1.CategoryList)
|
||||
}
|
||||
|
||||
v1SysGroup := v1Group.Group("/sys")
|
||||
v1SysGroup.Use()
|
||||
{
|
||||
v1SysGroup.GET("/version/check", v1.GetSystemCheckVersion)
|
||||
v1SysGroup.GET("/hardware/info", v1.GetSystemHardwareInfo)
|
||||
v1SysGroup.POST("/update", v1.SystemUpdate)
|
||||
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("/stop", v1.PostKillCasaOS)
|
||||
v1SysGroup.GET("/utilization", v1.GetSystemUtilization)
|
||||
v1SysGroup.PUT("/usb/:status", v1.PutSystemUSBAutoMount)
|
||||
v1SysGroup.GET("/usb/status", v1.GetSystemUSBAutoMount)
|
||||
v1SysGroup.GET("/cpu", v1.GetSystemCupInfo)
|
||||
v1SysGroup.GET("/mem", v1.GetSystemMemInfo)
|
||||
v1SysGroup.GET("/disk", v1.GetSystemDiskInfo)
|
||||
v1SysGroup.GET("/network", v1.GetSystemNetInfo)
|
||||
v1SysGroup.GET("/version", v1.GetSystemCheckVersion) //version/check
|
||||
|
||||
v1SysGroup.POST("/update", v1.SystemUpdate)
|
||||
|
||||
v1SysGroup.GET("/hardware", v1.GetSystemHardwareInfo) //hardware/info
|
||||
|
||||
v1SysGroup.GET("/wsssh", v1.WsSsh)
|
||||
v1SysGroup.POST("/ssh-login", v1.PostSshLogin)
|
||||
//v1SysGroup.GET("/config", v1.GetSystemConfig) //delete
|
||||
//v1SysGroup.POST("/config", v1.PostSetSystemConfig)
|
||||
v1SysGroup.GET("/logs", v1.GetCasaOSErrorLogs) //error/logs
|
||||
//v1SysGroup.GET("/widget/config", v1.GetWidgetConfig)//delete
|
||||
//v1SysGroup.POST("/widget/config", v1.PostSetWidgetConfig)//delete
|
||||
|
||||
v1SysGroup.POST("/stop", v1.PostKillCasaOS)
|
||||
|
||||
v1SysGroup.GET("/utilization", v1.GetSystemUtilization)
|
||||
// v1SysGroup.GET("/cpu", v1.GetSystemCupInfo)
|
||||
// v1SysGroup.GET("/mem", v1.GetSystemMemInfo)
|
||||
// v1SysGroup.GET("/disk", v1.GetSystemDiskInfo)
|
||||
// v1SysGroup.GET("/network", v1.GetSystemNetInfo)
|
||||
|
||||
v1SysGroup.PUT("/usb-auto-mount", v1.PutSystemUSBAutoMount) ///sys/usb/:status
|
||||
v1SysGroup.GET("/usb-auto-mount", v1.GetSystemUSBAutoMount) ///sys/usb/status
|
||||
|
||||
v1SysGroup.GET("/server-info", nil)
|
||||
v1SysGroup.PUT("/server-info", nil)
|
||||
v1SysGroup.GET("/apps-state", v1.GetSystemAppsStatus)
|
||||
//v1SysGroup.GET("/port", v1.GetCasaOSPort)
|
||||
//v1SysGroup.PUT("/port", v1.PutCasaOSPort)
|
||||
v1SysGroup.GET("/proxy", v1.GetSystemProxy)
|
||||
}
|
||||
v1PortGroup := v1Group.Group("/port")
|
||||
v1PortGroup.Use()
|
||||
{
|
||||
v1PortGroup.GET("/", v1.GetPort) //app/port
|
||||
v1PortGroup.GET("/state/:port", v1.PortCheck) //app/check/:port
|
||||
}
|
||||
|
||||
v1FileGroup := v1Group.Group("/file")
|
||||
v1FileGroup.Use()
|
||||
{
|
||||
v1FileGroup.PUT("/rename", v1.RenamePath)
|
||||
v1FileGroup.GET("/read", v1.GetFilerContent)
|
||||
v1FileGroup.GET("", v1.GetDownloadSingleFile) //download/:path
|
||||
v1FileGroup.POST("", v1.PostCreateFile)
|
||||
v1FileGroup.PUT("", v1.PutFileContent)
|
||||
v1FileGroup.PUT("/name", v1.RenamePath)
|
||||
//file/rename
|
||||
v1FileGroup.GET("/content", v1.GetFilerContent) //file/read
|
||||
|
||||
//File uploads need to be handled separately, and will not be modified here
|
||||
v1FileGroup.POST("/upload", v1.PostFileUpload)
|
||||
v1FileGroup.GET("/upload", v1.GetFileUpload)
|
||||
v1FileGroup.GET("/dirpath", v1.DirPath)
|
||||
//create folder
|
||||
v1FileGroup.POST("/mkdir", v1.MkdirAll)
|
||||
v1FileGroup.POST("/create", v1.PostCreateFile)
|
||||
|
||||
v1FileGroup.GET("/download", v1.GetDownloadFile)
|
||||
v1FileGroup.GET("/download/*path", v1.GetDownloadSingleFile)
|
||||
v1FileGroup.POST("/operate", v1.PostOperateFileOrDir)
|
||||
v1FileGroup.DELETE("/delete", v1.DeleteFile)
|
||||
v1FileGroup.PUT("/update", v1.PutFileContent)
|
||||
v1FileGroup.GET("/image", v1.GetFileImage)
|
||||
v1FileGroup.DELETE("/operate/:id", v1.DeleteOperateFileOrDir)
|
||||
|
||||
//v1FileGroup.GET("/download", v1.UserFileDownloadCommonService)
|
||||
}
|
||||
v1DiskGroup := v1Group.Group("/disk")
|
||||
v1DiskGroup.Use()
|
||||
v1FolderGroup := v1Group.Group("/folder")
|
||||
v1FolderGroup.Use()
|
||||
{
|
||||
v1DiskGroup.GET("/check", v1.GetDiskCheck)
|
||||
|
||||
v1DiskGroup.GET("/list", v1.GetDiskList)
|
||||
|
||||
//获取磁盘详情
|
||||
v1DiskGroup.GET("/info", v1.GetDiskInfo)
|
||||
|
||||
//format storage
|
||||
v1DiskGroup.POST("/format", v1.FormatDisk)
|
||||
|
||||
// add storage
|
||||
v1DiskGroup.POST("/storage", v1.AddPartition)
|
||||
|
||||
//mount SATA disk
|
||||
v1DiskGroup.POST("/mount", v1.PostMountDisk)
|
||||
|
||||
//umount sata disk
|
||||
v1DiskGroup.POST("/umount", v1.PostDiskUmount)
|
||||
|
||||
//获取可以格式化的内容
|
||||
v1DiskGroup.GET("/type", v1.FormatDiskType)
|
||||
|
||||
//删除分区
|
||||
v1DiskGroup.DELETE("/delpart", v1.RemovePartition)
|
||||
v1DiskGroup.GET("/usb", v1.GetUSBList)
|
||||
|
||||
v1FolderGroup.PUT("/name", v1.RenamePath)
|
||||
v1FolderGroup.GET("", v1.DirPath) ///file/dirpath
|
||||
v1FolderGroup.POST("", v1.MkdirAll) ///file/mkdir
|
||||
}
|
||||
v1ShareGroup := v1Group.Group("/share")
|
||||
v1ShareGroup.Use()
|
||||
v1BatchGroup := v1Group.Group("/batch")
|
||||
v1BatchGroup.Use()
|
||||
{
|
||||
v1ShareGroup.POST("/add", v1.PostShareDirAdd)
|
||||
v1ShareGroup.DELETE("/del/:id", v1.DeleteShareDirDel)
|
||||
v1ShareGroup.GET("/list", v1.GetShareDirList)
|
||||
v1ShareGroup.GET("/info/:id", v1.GetShareDirInfo)
|
||||
v1ShareGroup.PUT("/update/:id", v1.PutShareDirEdit)
|
||||
|
||||
v1BatchGroup.DELETE("", v1.DeleteFile) //file/delete
|
||||
v1BatchGroup.DELETE("/:id/task", v1.DeleteOperateFileOrDir)
|
||||
v1BatchGroup.POST("/task", v1.PostOperateFileOrDir) //file/operate
|
||||
v1BatchGroup.GET("", v1.GetDownloadFile)
|
||||
}
|
||||
v1TaskGroup := v1Group.Group("/task")
|
||||
v1TaskGroup.Use()
|
||||
v1ImageGroup := v1Group.Group("/image")
|
||||
v1ImageGroup.Use()
|
||||
{
|
||||
v1TaskGroup.GET("/list", v1.GetTaskList)
|
||||
v1TaskGroup.PUT("/update", v1.PutTaskUpdate)
|
||||
v1TaskGroup.POST("/add", v1.PostTaskAdd)
|
||||
v1TaskGroup.PUT("/completion/:id", v1.PutTaskMarkerCompletion)
|
||||
v1ImageGroup.GET("", v1.GetFileImage)
|
||||
}
|
||||
|
||||
v1PersonGroup := v1Group.Group("/person")
|
||||
v1PersonGroup.Use()
|
||||
v1SambaGroup := v1Group.Group("/samba")
|
||||
v1SambaGroup.Use()
|
||||
{
|
||||
v1PersonGroup.GET("/detection", v1.GetPersonDetection)
|
||||
v1PersonGroup.GET("/users", v1.GetPersonFriend)
|
||||
v1PersonGroup.POST("/user/:shareids", v1.PostAddPersonFriend)
|
||||
v1PersonGroup.DELETE("/user/:shareid", v1.DeletePersonFriend)
|
||||
v1PersonGroup.GET("/directory", v1.GetPersonDirectory)
|
||||
v1PersonGroup.GET("/file", v1.GetPersonFile)
|
||||
v1PersonGroup.GET("/refile/:uuid", v1.GetPersonReFile)
|
||||
v1PersonGroup.PUT("/remarks/:shareid", v1.PutPersonRemarks)
|
||||
v1PersonGroup.GET("/list", v1.GetPersonDownloadList)
|
||||
v1PersonGroup.DELETE("/file/:uuid", v1.DeletePersonDownloadFile)
|
||||
|
||||
v1PersonGroup.POST("/share", v1.PostPersonShare)
|
||||
v1PersonGroup.POST("/file/:shareid", v1.PostPersonFile)
|
||||
v1PersonGroup.GET("/share", v1.GetPersonShare)
|
||||
v1PersonGroup.POST("/down/dir", v1.PostPersonDownDir)
|
||||
v1PersonGroup.GET("/down/dir", v1.GetPersonDownDir)
|
||||
v1PersonGroup.PUT("/block/:shareid", v1.PutPersonBlock)
|
||||
v1PersonGroup.GET("/public", v1.GetPersonPublic)
|
||||
v1PersonGroup.PUT("/friend/:shareid", v1.PutPersonAgreeFriend)
|
||||
v1PersonGroup.PUT("/write/:shareid", v1.PutPersonWrite)
|
||||
v1PersonGroup.GET("/image/thumbnail/:shareid", v1.GetPersonImageThumbnail)
|
||||
|
||||
v1ConnectionsGroup := v1SambaGroup.Group("/connections")
|
||||
v1ConnectionsGroup.Use()
|
||||
{
|
||||
v1ConnectionsGroup.GET("", v1.GetSambaConnectionsList)
|
||||
v1ConnectionsGroup.POST("", v1.PostSambaConnectionsCreate)
|
||||
v1ConnectionsGroup.DELETE("/:id", v1.DeleteSambaConnections)
|
||||
}
|
||||
v1SharesGroup := v1SambaGroup.Group("/shares")
|
||||
v1SharesGroup.Use()
|
||||
{
|
||||
v1SharesGroup.GET("", v1.GetSambaSharesList)
|
||||
v1SharesGroup.POST("", v1.PostSambaSharesCreate)
|
||||
v1SharesGroup.DELETE("/:id", v1.DeleteSambaShares)
|
||||
v1SharesGroup.GET("/status", v1.GetSambaStatus)
|
||||
}
|
||||
}
|
||||
v1AnalyseGroup := v1Group.Group("/analyse")
|
||||
v1AnalyseGroup.Use()
|
||||
v1NotifyGroup := v1Group.Group("/notify")
|
||||
v1NotifyGroup.Use()
|
||||
{
|
||||
v1AnalyseGroup.POST("/app", v1.PostAppAnalyse)
|
||||
v1NotifyGroup.POST("/:path", v1.PostNotifyMessage)
|
||||
//merge to system
|
||||
v1NotifyGroup.POST("/system_status", v1.PostSystemStatusNotify)
|
||||
}
|
||||
v1Group.GET("/sync/config", v1.GetSyncConfig)
|
||||
v1Group.Any("/syncthing/*url", v1.SyncToSyncthing)
|
||||
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
14
route/ui.go
14
route/ui.go
@@ -1,14 +0,0 @@
|
||||
package route
|
||||
|
||||
import (
|
||||
"github.com/IceWhaleTech/CasaOS/web"
|
||||
"github.com/gin-gonic/gin"
|
||||
"html/template"
|
||||
)
|
||||
|
||||
func WebUIHome(c *gin.Context) {
|
||||
c.Writer.Header().Set("Content-Type", "text/html; charset=utf-8")
|
||||
index, _ := template.ParseFS(web.Static, "index.html")
|
||||
index.Execute(c.Writer, nil)
|
||||
return
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
package v1
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/IceWhaleTech/CasaOS/model"
|
||||
"github.com/IceWhaleTech/CasaOS/pkg/config"
|
||||
oasis_err2 "github.com/IceWhaleTech/CasaOS/pkg/utils/oasis_err"
|
||||
"github.com/IceWhaleTech/CasaOS/service"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
// @Summary post app analyse
|
||||
// @Produce application/json
|
||||
// @Accept multipart/form-data
|
||||
// @Tags analyse
|
||||
// @Param name formData string true "app name"
|
||||
// @Param type formData string true "action" Enums(open,delete)
|
||||
// @Security ApiKeyAuth
|
||||
// @Success 200 {string} string "ok"
|
||||
// @Router /analyse/app [post]
|
||||
func PostAppAnalyse(c *gin.Context) {
|
||||
if config.SystemConfigInfo.Analyse == "False" {
|
||||
c.JSON(http.StatusOK, &model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS)})
|
||||
return
|
||||
}
|
||||
name := c.PostForm("name")
|
||||
t := c.PostForm("type")
|
||||
language := c.GetHeader("Language")
|
||||
|
||||
if len(name) == 0 || len(t) == 0 {
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.INVALID_PARAMS, Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS)})
|
||||
return
|
||||
}
|
||||
|
||||
service.MyService.Casa().PushAppAnalyse(config.ServerInfo.Token, t, name, language)
|
||||
c.JSON(http.StatusOK, &model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS)})
|
||||
}
|
||||
117
route/v1/app.go
117
route/v1/app.go
@@ -2,13 +2,15 @@ package v1
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"strconv"
|
||||
|
||||
"github.com/IceWhaleTech/CasaOS/model"
|
||||
"github.com/IceWhaleTech/CasaOS/pkg/utils/command"
|
||||
"github.com/IceWhaleTech/CasaOS/pkg/utils/common_err"
|
||||
"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/service"
|
||||
"github.com/gin-gonic/gin"
|
||||
@@ -35,8 +37,15 @@ func AppList(c *gin.Context) {
|
||||
t := c.DefaultQuery("type", "rank")
|
||||
categoryId := c.DefaultQuery("category_id", "0")
|
||||
key := c.DefaultQuery("key", "")
|
||||
language := c.GetHeader("Language")
|
||||
recommend, list, community := service.MyService.Casa().GetServerList(index, size, t, categoryId, key, language)
|
||||
if len(index) == 0 || len(size) == 0 || len(t) == 0 || len(categoryId) == 0 {
|
||||
c.JSON(common_err.CLIENT_ERROR, &model.Result{Success: common_err.INVALID_PARAMS, Message: common_err.GetMsg(common_err.INVALID_PARAMS)})
|
||||
return
|
||||
}
|
||||
collection, err := service.MyService.Casa().GetServerList(index, size, t, categoryId, key)
|
||||
if err != nil {
|
||||
c.JSON(common_err.SERVICE_ERROR, &model.Result{Success: common_err.SERVICE_ERROR, Message: common_err.GetMsg(common_err.SERVICE_ERROR), Data: err.Error()})
|
||||
return
|
||||
}
|
||||
// for i := 0; i < len(recommend); i++ {
|
||||
// ct, _ := service.MyService.Docker().DockerListByImage(recommend[i].Image, recommend[i].ImageVersion)
|
||||
// if ct != nil {
|
||||
@@ -56,11 +65,11 @@ func AppList(c *gin.Context) {
|
||||
// }
|
||||
// }
|
||||
data := make(map[string]interface{}, 3)
|
||||
data["recommend"] = recommend
|
||||
data["list"] = list
|
||||
data["community"] = community
|
||||
data["recommend"] = collection.Recommend
|
||||
data["list"] = collection.List
|
||||
data["community"] = collection.Community
|
||||
|
||||
c.JSON(http.StatusOK, &model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: data})
|
||||
c.JSON(common_err.SUCCESS, &model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: data})
|
||||
}
|
||||
|
||||
// @Summary 获取一个可用端口
|
||||
@@ -79,7 +88,8 @@ func GetPort(c *gin.Context) {
|
||||
p, _ = port2.GetAvailablePort(t)
|
||||
ok = !port2.IsPortAvailable(p, t)
|
||||
}
|
||||
c.JSON(http.StatusOK, &model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: p})
|
||||
// @tiger 这里最好封装成 {'port': ...} 的形式,来体现出参的上下文
|
||||
c.JSON(common_err.SUCCESS, &model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: p})
|
||||
}
|
||||
|
||||
// @Summary 检查端口是否可用
|
||||
@@ -94,7 +104,7 @@ func GetPort(c *gin.Context) {
|
||||
func PortCheck(c *gin.Context) {
|
||||
p, _ := strconv.Atoi(c.Param("port"))
|
||||
t := c.DefaultQuery("type", "tcp")
|
||||
c.JSON(http.StatusOK, &model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: port2.IsPortAvailable(p, t)})
|
||||
c.JSON(common_err.SUCCESS, &model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: port2.IsPortAvailable(p, t)})
|
||||
}
|
||||
|
||||
// @Summary 我的应用列表
|
||||
@@ -112,12 +122,11 @@ func MyAppList(c *gin.Context) {
|
||||
size, _ := strconv.Atoi(c.DefaultQuery("size", "0"))
|
||||
position, _ := strconv.ParseBool(c.DefaultQuery("position", "true"))
|
||||
list, unTranslation := service.MyService.App().GetMyList(index, size, position)
|
||||
|
||||
data := make(map[string]interface{}, 2)
|
||||
data["list"] = list
|
||||
data["local"] = unTranslation
|
||||
data["casaos_apps"] = list
|
||||
data["local_apps"] = unTranslation
|
||||
|
||||
c.JSON(http.StatusOK, &model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: data})
|
||||
c.JSON(common_err.SUCCESS, &model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: data})
|
||||
}
|
||||
|
||||
// @Summary my app hardware usage list
|
||||
@@ -129,7 +138,8 @@ func MyAppList(c *gin.Context) {
|
||||
// @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})
|
||||
c.JSON(common_err.SUCCESS, &model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: list})
|
||||
//c.JSON(common_err.SUCCESS, &model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: nil})
|
||||
}
|
||||
|
||||
// @Summary 应用详情
|
||||
@@ -144,7 +154,11 @@ func AppInfo(c *gin.Context) {
|
||||
|
||||
id := c.Param("id")
|
||||
language := c.GetHeader("Language")
|
||||
info := service.MyService.Casa().GetServerAppInfo(id, "", language)
|
||||
info, err := service.MyService.Casa().GetServerAppInfo(id, "", language)
|
||||
if err != nil {
|
||||
c.JSON(common_err.SERVICE_ERROR, &model.Result{Success: common_err.SERVICE_ERROR, Message: common_err.GetMsg(common_err.SERVICE_ERROR), Data: err.Error()})
|
||||
return
|
||||
}
|
||||
if info.NetworkModel != "host" {
|
||||
for i := 0; i < len(info.Ports); i++ {
|
||||
if p, _ := strconv.Atoi(info.Ports[i].ContainerPort); port2.IsPortAvailable(p, info.Ports[i].Protocol) {
|
||||
@@ -208,10 +222,10 @@ func AppInfo(c *gin.Context) {
|
||||
// sort.EnvSort(envOrder).Sort(info.Envs)
|
||||
// sort.VolSort(volOrder).Sort(info.Volumes.([]model.PathMap))
|
||||
// sort.DevSort(devOrder).Sort(info.Devices)
|
||||
info.Image += ":" + info.ImageVersion
|
||||
info.MaxMemory = (service.MyService.System().GetMemInfo()["total"]).(uint64) >> 20
|
||||
|
||||
info.MaxMemory = service.MyService.System().GetMemInfo().Total >> 20
|
||||
|
||||
c.JSON(http.StatusOK, &model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: info})
|
||||
c.JSON(common_err.SUCCESS, &model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: info})
|
||||
}
|
||||
|
||||
// @Summary 获取远程分类列表
|
||||
@@ -222,16 +236,20 @@ func AppInfo(c *gin.Context) {
|
||||
// @Success 200 {string} string "ok"
|
||||
// @Router /app/category [get]
|
||||
func CategoryList(c *gin.Context) {
|
||||
list := service.MyService.Casa().GetServerCategoryList()
|
||||
list, err := service.MyService.Casa().GetServerCategoryList()
|
||||
if err != nil {
|
||||
c.JSON(common_err.SERVICE_ERROR, &model.Result{Success: common_err.SERVICE_ERROR, Message: common_err.GetMsg(common_err.SERVICE_ERROR), Data: err.Error()})
|
||||
return
|
||||
}
|
||||
var count uint = 0
|
||||
for _, category := range list {
|
||||
count += category.Count
|
||||
}
|
||||
|
||||
rear := append([]model.ServerCategoryList{}, list[0:]...)
|
||||
list = append(list[:0], model.ServerCategoryList{Count: count, Name: "All", Font: "apps"})
|
||||
rear := append([]model.CategoryList{}, list[0:]...)
|
||||
list = append(list[:0], model.CategoryList{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})
|
||||
c.JSON(common_err.SUCCESS, &model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: list})
|
||||
}
|
||||
|
||||
// @Summary 分享该应用配置
|
||||
@@ -244,5 +262,56 @@ func CategoryList(c *gin.Context) {
|
||||
func ShareAppFile(c *gin.Context) {
|
||||
str, _ := ioutil.ReadAll(c.Request.Body)
|
||||
content := service.MyService.Casa().ShareAppFile(str)
|
||||
c.JSON(http.StatusOK, json.RawMessage(content))
|
||||
c.JSON(common_err.SUCCESS, json.RawMessage(content))
|
||||
}
|
||||
|
||||
func GetcontainerInfo(c *gin.Context) {
|
||||
// info, err := service.MyService.Docker().GetDockerInfo()
|
||||
// if err != nil {
|
||||
// c.JSON(common_err.SERVICE_ERROR, &model.Result{Success: common_err.SERVICE_ERROR, Message: common_err.GetMsg(common_err.SERVICE_ERROR), Data: err.Error()})
|
||||
// return
|
||||
// }
|
||||
daemon := model.DeckerDaemonModel{}
|
||||
data := make(map[string]interface{}, 1)
|
||||
data["docker_root_dir"] = ""
|
||||
if file.Exists("/etc/docker/daemon.json") {
|
||||
byteResult := file.ReadFullFile("/etc/docker/daemon.json")
|
||||
err := json.Unmarshal(byteResult, &daemon)
|
||||
if err != nil {
|
||||
c.JSON(common_err.CLIENT_ERROR, &model.Result{Success: common_err.CLIENT_ERROR, Message: common_err.GetMsg(common_err.INVALID_PARAMS), Data: err.Error()})
|
||||
return
|
||||
}
|
||||
data["docker_root_dir"] = daemon.Graph
|
||||
}
|
||||
c.JSON(common_err.SUCCESS, &model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: data})
|
||||
}
|
||||
func PutcontainerInfo(c *gin.Context) {
|
||||
js := make(map[string]interface{})
|
||||
err := c.BindJSON(&js)
|
||||
if err != nil {
|
||||
c.JSON(common_err.CLIENT_ERROR, &model.Result{Success: common_err.CLIENT_ERROR, Message: common_err.GetMsg(common_err.INVALID_PARAMS), Data: err.Error()})
|
||||
return
|
||||
}
|
||||
dockerRootDir := js["docker_root_dir"].(string)
|
||||
daemon := model.DeckerDaemonModel{}
|
||||
if file.Exists("/etc/docker/daemon.json") {
|
||||
byteResult := file.ReadFullFile("/etc/docker/daemon.json")
|
||||
err := json.Unmarshal(byteResult, &daemon)
|
||||
if err != nil {
|
||||
c.JSON(common_err.CLIENT_ERROR, &model.Result{Success: common_err.CLIENT_ERROR, Message: common_err.GetMsg(common_err.INVALID_PARAMS), Data: err.Error()})
|
||||
return
|
||||
}
|
||||
}
|
||||
if !file.Exists(dockerRootDir) {
|
||||
c.JSON(common_err.CLIENT_ERROR, &model.Result{Success: common_err.CLIENT_ERROR, Message: common_err.GetMsg(common_err.DIR_NOT_EXISTS), Data: common_err.GetMsg(common_err.DIR_NOT_EXISTS)})
|
||||
return
|
||||
}
|
||||
daemon.Graph = dockerRootDir
|
||||
byteMode, _ := json.Marshal(daemon)
|
||||
file.WriteToPath(byteMode, "/etc/docker", "daemon.json")
|
||||
|
||||
fmt.Println(command.ExecResultStr("systemctl daemon-reload"))
|
||||
fmt.Println(command.ExecResultStr("systemctl restart docker"))
|
||||
|
||||
c.JSON(common_err.SUCCESS, &model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: js})
|
||||
}
|
||||
|
||||
174
route/v1/ddns.go
174
route/v1/ddns.go
@@ -1,174 +0,0 @@
|
||||
package v1
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/IceWhaleTech/CasaOS/model"
|
||||
ip_helper2 "github.com/IceWhaleTech/CasaOS/pkg/utils/ip_helper"
|
||||
oasis_err2 "github.com/IceWhaleTech/CasaOS/pkg/utils/oasis_err"
|
||||
"github.com/IceWhaleTech/CasaOS/service"
|
||||
model2 "github.com/IceWhaleTech/CasaOS/service/model"
|
||||
"github.com/forease/gotld"
|
||||
"github.com/gin-gonic/gin"
|
||||
"net/http"
|
||||
"os/exec"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// @Summary 获取可以设置的ddns列表
|
||||
// @Produce application/json
|
||||
// @Accept application/json
|
||||
// @Tags ddns
|
||||
// @Security ApiKeyAuth
|
||||
// @Success 200 {string} string "ok"
|
||||
// @Router /ddns/getlist [get]
|
||||
func DDNSGetDomainList(c *gin.Context) {
|
||||
|
||||
host, domain, tld := gotld.GetSubdomain("bbb.aaa.liru-05.com.cn", 3)
|
||||
fmt.Println(strings.Replace(host, "."+domain, "", 1))
|
||||
fmt.Println(domain)
|
||||
fmt.Println(tld)
|
||||
|
||||
data := make(map[string]interface{}, 2)
|
||||
t, api := service.MyService.DDNS().GetType("godaddy")
|
||||
data["godaddy"] = &model.GoDaddyModel{Type: t, ApiHost: api}
|
||||
c.JSON(http.StatusOK,
|
||||
model.Result{
|
||||
Success: oasis_err2.SUCCESS,
|
||||
Message: oasis_err2.GetMsg(oasis_err2.SUCCESS),
|
||||
Data: data,
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
// @Summary 添加新的ddns(按给定模型返回内容)
|
||||
// @Produce application/json
|
||||
// @Accept multipart/form-data
|
||||
// @Tags ddns
|
||||
// @Param type formData string true "类型"
|
||||
// @Param host formData string true "host"
|
||||
// @Security ApiKeyAuth
|
||||
// @Success 200 {string} string "ok"
|
||||
// @Router /ddns/set [post]
|
||||
func DDNSAddConfig(c *gin.Context) {
|
||||
t, _ := strconv.Atoi(c.PostForm("type"))
|
||||
host := c.PostForm("host")
|
||||
_, domain, _ := gotld.GetSubdomain("host", 3)
|
||||
sub := strings.ReplaceAll(host, "."+domain, "")
|
||||
|
||||
if service.MyService.DDNS().IsExis(t, domain, sub) {
|
||||
c.JSON(http.StatusOK,
|
||||
model.Result{
|
||||
Success: oasis_err2.ERROR,
|
||||
Message: "Repeat add",
|
||||
})
|
||||
return
|
||||
}
|
||||
var m model2.DDNSUpdateDBModel
|
||||
c.Bind(&m)
|
||||
if err := service.MyService.DDNS().SaveConfig(m); err != nil {
|
||||
c.JSON(http.StatusOK,
|
||||
model.Result{
|
||||
Success: oasis_err2.ERROR,
|
||||
Message: oasis_err2.GetMsg(oasis_err2.ERROR),
|
||||
Data: err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
c.JSON(http.StatusOK,
|
||||
model.Result{
|
||||
Success: oasis_err2.SUCCESS,
|
||||
Message: oasis_err2.GetMsg(oasis_err2.SUCCESS),
|
||||
})
|
||||
}
|
||||
|
||||
// @Summary 获取ip,仅做展示使用
|
||||
// @Produce application/json
|
||||
// @Accept application/json
|
||||
// @Tags ddns
|
||||
// @Security ApiKeyAuth
|
||||
// @Success 200 {string} string "ok"
|
||||
// @Router /ddns/ip [get]
|
||||
func DDNSGetIP(c *gin.Context) {
|
||||
ipv4, ipv6 := service.MyService.DDNS().GetExternalIP()
|
||||
var ipjson = make(map[string]string, 2)
|
||||
ipjson["ipv4"] = ipv4
|
||||
ipjson["ipv6"] = ipv6
|
||||
c.JSON(http.StatusOK, &model.Result{
|
||||
Success: oasis_err2.SUCCESS,
|
||||
Message: oasis_err2.GetMsg(oasis_err2.SUCCESS),
|
||||
Data: ipjson,
|
||||
})
|
||||
}
|
||||
|
||||
// @Summary 测试网址是否可以ping通
|
||||
// @Produce application/json
|
||||
// @Accept application/json
|
||||
// @Tags ddns
|
||||
// @Param api_host path int true "api地址"
|
||||
// @Security ApiKeyAuth
|
||||
// @Success 200 {string} string "ok"
|
||||
// @Router /ddns/ping/{api_host} [get]
|
||||
func DDNSPing(c *gin.Context) {
|
||||
url := c.Param("api_host")
|
||||
url = strings.ReplaceAll(url, "https://", "")
|
||||
url = strings.ReplaceAll(url, "http://", "")
|
||||
cmd := exec.Command("ping", url, "-c", "1", "-W", "5")
|
||||
err := cmd.Run()
|
||||
if err != nil {
|
||||
c.JSON(http.StatusOK, &model.Result{
|
||||
Success: oasis_err2.ERROR,
|
||||
Message: err.Error(),
|
||||
Data: false,
|
||||
})
|
||||
} else {
|
||||
c.JSON(http.StatusOK, &model.Result{
|
||||
Success: oasis_err2.SUCCESS,
|
||||
Message: oasis_err2.GetMsg(oasis_err2.SUCCESS),
|
||||
Data: true,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// @Summary 获取已设置的列表
|
||||
// @Produce application/json
|
||||
// @Accept application/json
|
||||
// @Tags ddns
|
||||
// @Security ApiKeyAuth
|
||||
// @Success 200 {string} string "ok"
|
||||
// @Router /ddns/list [get]
|
||||
func DDNSConfigList(c *gin.Context) {
|
||||
j := service.MyService.DDNS().GetConfigList()
|
||||
ip4 := ip_helper2.GetExternalIPV4()
|
||||
ip6 := ip_helper2.GetExternalIPV6()
|
||||
for i := 0; i < len(*j); i++ {
|
||||
(*j)[i].IPV6 = ip6
|
||||
(*j)[i].IPV4 = ip4
|
||||
cmd := exec.Command("ping", (*j)[i].Host+"."+(*j)[i].Domain, "-c", "1", "-W", "3")
|
||||
err := cmd.Run()
|
||||
if err != nil {
|
||||
(*j)[i].State = false
|
||||
} else {
|
||||
(*j)[i].State = true
|
||||
}
|
||||
}
|
||||
c.JSON(http.StatusOK, &model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: j})
|
||||
}
|
||||
|
||||
// @Summary 删除ddns
|
||||
// @Produce application/json
|
||||
// @Accept application/json
|
||||
// @Tags ddns
|
||||
// @Param id path int true "ID"
|
||||
// @Security ApiKeyAuth
|
||||
// @Success 200 {string} string "ok"
|
||||
// @Router /ddns/delete/{id} [delete]
|
||||
func DDNSDelete(c *gin.Context) {
|
||||
id, err := strconv.ParseUint(c.Param("id"), 10, 32)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusOK, &model.Result{Success: oasis_err2.ERROR, Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS)})
|
||||
return
|
||||
}
|
||||
isok := service.MyService.DDNS().DeleteConfig(uint(id))
|
||||
c.JSON(http.StatusOK, &model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: isok})
|
||||
}
|
||||
497
route/v1/disk.go
497
route/v1/disk.go
@@ -1,497 +0,0 @@
|
||||
package v1
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/IceWhaleTech/CasaOS/model"
|
||||
"github.com/IceWhaleTech/CasaOS/pkg/config"
|
||||
"github.com/IceWhaleTech/CasaOS/pkg/utils/file"
|
||||
"github.com/IceWhaleTech/CasaOS/pkg/utils/oasis_err"
|
||||
"github.com/IceWhaleTech/CasaOS/service"
|
||||
model2 "github.com/IceWhaleTech/CasaOS/service/model"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/shirou/gopsutil/v3/disk"
|
||||
)
|
||||
|
||||
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 GetDiskList(c *gin.Context) {
|
||||
list := service.MyService.Disk().LSBLK(false)
|
||||
dbList := service.MyService.Disk().GetSerialAll()
|
||||
part := make(map[string]int64, len(dbList))
|
||||
for _, v := range dbList {
|
||||
part[v.MountPoint] = v.CreatedAt
|
||||
}
|
||||
findSystem := 0
|
||||
|
||||
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
|
||||
|
||||
if len(list[i].Children) > 0 && findSystem == 0 {
|
||||
for j := 0; j < len(list[i].Children); j++ {
|
||||
if len(list[i].Children[j].Children) > 0 {
|
||||
for _, v := range list[i].Children[j].Children {
|
||||
if v.MountPoint == "/" {
|
||||
stor := model.Storage{}
|
||||
stor.Name = "System"
|
||||
stor.MountPoint = v.MountPoint
|
||||
stor.Size = v.FSSize
|
||||
stor.Avail = v.FSAvail
|
||||
stor.Path = v.Path
|
||||
stor.Type = v.FsType
|
||||
stor.DriveName = "System"
|
||||
disk.Model = "System"
|
||||
if strings.Contains(v.SubSystems, "mmc") {
|
||||
disk.DiskType = "MMC"
|
||||
} else if strings.Contains(v.SubSystems, "usb") {
|
||||
disk.DiskType = "USB"
|
||||
}
|
||||
disk.Health = "true"
|
||||
|
||||
disks = append(disks, disk)
|
||||
storage = append(storage, stor)
|
||||
findSystem = 1
|
||||
break
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if list[i].Children[j].MountPoint == "/" {
|
||||
stor := model.Storage{}
|
||||
stor.Name = "System"
|
||||
stor.MountPoint = list[i].Children[j].MountPoint
|
||||
stor.Size = list[i].Children[j].FSSize
|
||||
stor.Avail = list[i].Children[j].FSAvail
|
||||
stor.Path = list[i].Children[j].Path
|
||||
stor.Type = list[i].Children[j].FsType
|
||||
stor.DriveName = "System"
|
||||
disk.Model = "System"
|
||||
if strings.Contains(list[i].Children[j].SubSystems, "mmc") {
|
||||
disk.DiskType = "MMC"
|
||||
} else if strings.Contains(list[i].Children[j].SubSystems, "usb") {
|
||||
disk.DiskType = "USB"
|
||||
}
|
||||
disk.Health = "true"
|
||||
|
||||
disks = append(disks, disk)
|
||||
storage = append(storage, stor)
|
||||
findSystem = 1
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
if findSystem == 1 {
|
||||
findSystem += 1
|
||||
continue
|
||||
}
|
||||
|
||||
if list[i].Tran == "sata" || list[i].Tran == "nvme" || list[i].Tran == "spi" || list[i].Tran == "sas" {
|
||||
temp := service.MyService.Disk().SmartCTL(list[i].Path)
|
||||
if reflect.DeepEqual(temp, model.SmartctlA{}) {
|
||||
temp.SmartStatus.Passed = true
|
||||
}
|
||||
if len(list[i].Children) == 1 && len(list[i].Children[0].MountPoint) > 0 {
|
||||
stor := model.Storage{}
|
||||
stor.MountPoint = list[i].Children[0].MountPoint
|
||||
stor.Size = list[i].Children[0].FSSize
|
||||
stor.Avail = list[i].Children[0].FSAvail
|
||||
stor.Path = list[i].Children[0].Path
|
||||
stor.Type = list[i].Children[0].FsType
|
||||
stor.DriveName = list[i].Name
|
||||
pathArr := strings.Split(list[i].Children[0].MountPoint, "/")
|
||||
if len(pathArr) == 3 {
|
||||
stor.Name = pathArr[2]
|
||||
}
|
||||
if t, ok := part[list[i].Children[0].MountPoint]; ok {
|
||||
stor.CreatedAt = t
|
||||
}
|
||||
storage = append(storage, stor)
|
||||
} else {
|
||||
//todo 长度有问题
|
||||
if len(list[i].Children) == 1 && list[i].Children[0].FsType == "ext4" {
|
||||
disk.NeedFormat = false
|
||||
avail = append(avail, disk)
|
||||
} else {
|
||||
disk.NeedFormat = true
|
||||
avail = append(avail, disk)
|
||||
}
|
||||
}
|
||||
|
||||
disk.Temperature = temp.Temperature.Current
|
||||
disk.Health = strconv.FormatBool(temp.SmartStatus.Passed)
|
||||
|
||||
disks = append(disks, disk)
|
||||
}
|
||||
}
|
||||
data := make(map[string]interface{}, 3)
|
||||
data["drive"] = disks
|
||||
data["storage"] = storage
|
||||
data["avail"] = avail
|
||||
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err.SUCCESS, Message: oasis_err.GetMsg(oasis_err.SUCCESS), Data: data})
|
||||
}
|
||||
|
||||
// @Summary get disk list
|
||||
// @Produce application/json
|
||||
// @Accept application/json
|
||||
// @Tags disk
|
||||
// @Security ApiKeyAuth
|
||||
// @Success 200 {string} string "ok"
|
||||
// @Router /disk/lists [get]
|
||||
func GetPlugInDisks(c *gin.Context) {
|
||||
|
||||
list := service.MyService.Disk().LSBLK(true)
|
||||
var result []*disk.UsageStat
|
||||
for _, item := range list {
|
||||
result = append(result, service.MyService.Disk().GetDiskInfoByPath(item.Path))
|
||||
}
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err.SUCCESS, Message: oasis_err.GetMsg(oasis_err.SUCCESS), Data: result})
|
||||
}
|
||||
|
||||
// @Summary disk detail
|
||||
// @Produce application/json
|
||||
// @Accept application/json
|
||||
// @Tags disk
|
||||
// @Security ApiKeyAuth
|
||||
// @Param path query string true "for example /dev/sda"
|
||||
// @Success 200 {string} string "ok"
|
||||
// @Router /disk/info [get]
|
||||
func GetDiskInfo(c *gin.Context) {
|
||||
path := c.Query("path")
|
||||
if len(path) == 0 {
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err.INVALID_PARAMS, Message: oasis_err.GetMsg(oasis_err.INVALID_PARAMS)})
|
||||
}
|
||||
m := service.MyService.Disk().GetDiskInfo(path)
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err.SUCCESS, Message: oasis_err.GetMsg(oasis_err.SUCCESS), Data: m})
|
||||
}
|
||||
|
||||
// @Summary format storage
|
||||
// @Produce application/json
|
||||
// @Accept multipart/form-data
|
||||
// @Tags disk
|
||||
// @Security ApiKeyAuth
|
||||
// @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")
|
||||
|
||||
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)
|
||||
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)})
|
||||
}
|
||||
|
||||
// @Summary 获取支持的格式
|
||||
// @Produce application/json
|
||||
// @Accept application/json
|
||||
// @Tags disk
|
||||
// @Security ApiKeyAuth
|
||||
// @Success 200 {string} string "ok"
|
||||
// @Router /disk/type [get]
|
||||
func FormatDiskType(c *gin.Context) {
|
||||
var strArr = [4]string{"fat32", "ntfs", "ext4", "exfat"}
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err.SUCCESS, Message: oasis_err.GetMsg(oasis_err.SUCCESS), Data: strArr})
|
||||
|
||||
}
|
||||
|
||||
// @Summary 删除分区
|
||||
// @Produce application/json
|
||||
// @Accept multipart/form-data
|
||||
// @Tags disk
|
||||
// @Security ApiKeyAuth
|
||||
// @Param path formData string true "磁盘路径 例如/dev/sda1"
|
||||
// @Success 200 {string} string "ok"
|
||||
// @Router /disk/delpart [delete]
|
||||
func RemovePartition(c *gin.Context) {
|
||||
path := c.PostForm("path")
|
||||
|
||||
if len(path) == 0 {
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err.INVALID_PARAMS, Message: oasis_err.GetMsg(oasis_err.INVALID_PARAMS)})
|
||||
}
|
||||
var p = path[:len(path)-1]
|
||||
var n = path[len(path)-1:]
|
||||
service.MyService.Disk().DelPartition(p, n)
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err.SUCCESS, Message: oasis_err.GetMsg(oasis_err.SUCCESS)})
|
||||
}
|
||||
|
||||
// @Summary add storage
|
||||
// @Produce application/json
|
||||
// @Accept multipart/form-data
|
||||
// @Tags disk
|
||||
// @Security ApiKeyAuth
|
||||
// @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/storage [post]
|
||||
func AddPartition(c *gin.Context) {
|
||||
name := c.PostForm("name")
|
||||
path := c.PostForm("path")
|
||||
format, _ := strconv.ParseBool(c.PostForm("format"))
|
||||
if len(name) == 0 || len(path) == 0 {
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err.INVALID_PARAMS, Message: oasis_err.GetMsg(oasis_err.INVALID_PARAMS)})
|
||||
return
|
||||
}
|
||||
if _, ok := diskMap[path]; ok {
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err.DISK_BUSYING, Message: oasis_err.GetMsg(oasis_err.DISK_BUSYING)})
|
||||
return
|
||||
}
|
||||
if !file.CheckNotExist("/DATA/" + name) {
|
||||
// /mnt/name exist
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err.NAME_NOT_AVAILABLE, Message: oasis_err.GetMsg(oasis_err.NAME_NOT_AVAILABLE)})
|
||||
return
|
||||
}
|
||||
diskMap[path] = "busying"
|
||||
currentDisk := service.MyService.Disk().GetDiskInfo(path)
|
||||
if !format {
|
||||
if len(currentDisk.Children) != 1 || !(len(currentDisk.Children) > 0 && currentDisk.Children[0].FsType == "ext4") {
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err.DISK_NEEDS_FORMAT, Message: oasis_err.GetMsg(oasis_err.DISK_NEEDS_FORMAT)})
|
||||
delete(diskMap, path)
|
||||
return
|
||||
}
|
||||
} else {
|
||||
service.MyService.Disk().AddPartition(path)
|
||||
}
|
||||
|
||||
formatBool := true
|
||||
for formatBool {
|
||||
currentDisk = service.MyService.Disk().GetDiskInfo(path)
|
||||
fmt.Println(currentDisk.Children)
|
||||
if len(currentDisk.Children) > 0 {
|
||||
formatBool = false
|
||||
break
|
||||
}
|
||||
time.Sleep(time.Second)
|
||||
}
|
||||
currentDisk = service.MyService.Disk().GetDiskInfo(path)
|
||||
if len(currentDisk.Children) != 1 {
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err.DISK_NEEDS_FORMAT, Message: oasis_err.GetMsg(oasis_err.DISK_NEEDS_FORMAT)})
|
||||
return
|
||||
}
|
||||
|
||||
mountPath := "/DATA/" + name
|
||||
m := model2.SerialDisk{}
|
||||
m.MountPoint = mountPath
|
||||
m.Path = currentDisk.Children[0].Path
|
||||
m.UUID = currentDisk.Children[0].UUID
|
||||
m.State = 0
|
||||
m.CreatedAt = time.Now().Unix()
|
||||
service.MyService.Disk().SaveMountPoint(m)
|
||||
|
||||
//mount dir
|
||||
service.MyService.Disk().MountDisk(currentDisk.Children[0].Path, mountPath)
|
||||
|
||||
service.MyService.Disk().RemoveLSBLKCache()
|
||||
|
||||
delete(diskMap, path)
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err.SUCCESS, Message: oasis_err.GetMsg(oasis_err.SUCCESS)})
|
||||
}
|
||||
|
||||
// @Summary add mount point
|
||||
// @Produce application/json
|
||||
// @Accept multipart/form-data
|
||||
// @Tags disk
|
||||
// @Security ApiKeyAuth
|
||||
// @Param path formData string true "for example: /dev/sda1"
|
||||
// @Param serial formData string true "disk id"
|
||||
// @Success 200 {string} string "ok"
|
||||
// @Router /disk/mount [post]
|
||||
func PostMountDisk(c *gin.Context) {
|
||||
// for example: path=/dev/sda1
|
||||
path := c.PostForm("path")
|
||||
serial := c.PostForm("serial")
|
||||
|
||||
mountPath := "/DATA/volume"
|
||||
var list = service.MyService.Disk().GetSerialAll()
|
||||
var pathMapList = make(map[string]string, len(list))
|
||||
for _, v := range list {
|
||||
pathMapList[v.MountPoint] = "1"
|
||||
}
|
||||
|
||||
for i := 0; i < len(list)+1; i++ {
|
||||
if _, ok := pathMapList[mountPath+strconv.Itoa(i)]; !ok {
|
||||
mountPath = mountPath + strconv.Itoa(i)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
//mount dir
|
||||
service.MyService.Disk().MountDisk(path, mountPath)
|
||||
|
||||
m := model2.SerialDisk{}
|
||||
m.MountPoint = mountPath
|
||||
m.Path = path
|
||||
m.UUID = serial
|
||||
m.State = 0
|
||||
//service.MyService.Disk().SaveMountPoint(m)
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err.SUCCESS, Message: oasis_err.GetMsg(oasis_err.SUCCESS)})
|
||||
}
|
||||
|
||||
// @Summary remove mount point
|
||||
// @Produce application/json
|
||||
// @Accept multipart/form-data
|
||||
// @Tags disk
|
||||
// @Security ApiKeyAuth
|
||||
// @Param path formData string true "e.g. /dev/sda1"
|
||||
// @Param mount_point formData string true "e.g. /mnt/volume1"
|
||||
// @Param pwd formData string true "user password"
|
||||
// @Success 200 {string} string "ok"
|
||||
// @Router /disk/umount [post]
|
||||
func PostDiskUmount(c *gin.Context) {
|
||||
|
||||
path := c.PostForm("path")
|
||||
mountPoint := c.PostForm("volume")
|
||||
pwd := c.PostForm("pwd")
|
||||
|
||||
if len(path) == 0 || len(mountPoint) == 0 {
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err.INVALID_PARAMS, Message: oasis_err.GetMsg(oasis_err.INVALID_PARAMS)})
|
||||
return
|
||||
}
|
||||
if pwd != config.UserInfo.PWD {
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err.PWD_INVALID, Message: oasis_err.GetMsg(oasis_err.PWD_INVALID)})
|
||||
return
|
||||
}
|
||||
|
||||
if _, ok := diskMap[path]; ok {
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err.DISK_BUSYING, Message: oasis_err.GetMsg(oasis_err.DISK_BUSYING)})
|
||||
return
|
||||
}
|
||||
|
||||
service.MyService.Disk().UmountPointAndRemoveDir(path)
|
||||
//delete data
|
||||
service.MyService.Disk().DeleteMountPoint(path, mountPoint)
|
||||
service.MyService.Disk().RemoveLSBLKCache()
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err.SUCCESS, Message: oasis_err.GetMsg(oasis_err.SUCCESS)})
|
||||
}
|
||||
|
||||
// @Summary confirm delete disk
|
||||
// @Produce application/json
|
||||
// @Accept application/json
|
||||
// @Tags disk
|
||||
// @Security ApiKeyAuth
|
||||
// @Param id path string true "id"
|
||||
// @Success 200 {string} string "ok"
|
||||
// @Router /disk/remove/{id} [delete]
|
||||
func DeleteDisk(c *gin.Context) {
|
||||
id := c.Param("id")
|
||||
service.MyService.Disk().DeleteMount(id)
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err.SUCCESS, Message: oasis_err.GetMsg(oasis_err.SUCCESS)})
|
||||
}
|
||||
|
||||
// @Summary check mount point
|
||||
// @Produce application/json
|
||||
// @Accept application/json
|
||||
// @Tags disk
|
||||
// @Security ApiKeyAuth
|
||||
// @Success 200 {string} string "ok"
|
||||
// @Router /disk/init [get]
|
||||
func GetDiskCheck(c *gin.Context) {
|
||||
|
||||
dbList := service.MyService.Disk().GetSerialAll()
|
||||
list := service.MyService.Disk().LSBLK(true)
|
||||
|
||||
mapList := make(map[string]string)
|
||||
|
||||
for _, v := range list {
|
||||
mapList[v.Serial] = "1"
|
||||
}
|
||||
|
||||
for _, v := range dbList {
|
||||
if _, ok := mapList[v.UUID]; !ok {
|
||||
//disk undefind
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err.ERROR, Message: oasis_err.GetMsg(oasis_err.ERROR), Data: "disk undefind"})
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err.SUCCESS, Message: oasis_err.GetMsg(oasis_err.SUCCESS)})
|
||||
}
|
||||
|
||||
// @Summary check mount point
|
||||
// @Produce application/json
|
||||
// @Accept application/json
|
||||
// @Tags disk
|
||||
// @Security ApiKeyAuth
|
||||
// @Success 200 {string} string "ok"
|
||||
// @Router /disk/usb [get]
|
||||
func GetUSBList(c *gin.Context) {
|
||||
list := service.MyService.Disk().LSBLK(false)
|
||||
data := []model.DriveUSB{}
|
||||
for _, v := range list {
|
||||
if v.Tran == "usb" {
|
||||
temp := model.DriveUSB{}
|
||||
temp.Model = v.Model
|
||||
temp.Name = v.Name
|
||||
temp.Size = v.Size
|
||||
mountTemp := true
|
||||
if len(v.Children) == 0 {
|
||||
mountTemp = false
|
||||
}
|
||||
for _, child := range v.Children {
|
||||
if len(child.MountPoint) > 0 {
|
||||
avail, _ := strconv.ParseUint(child.FSAvail, 10, 64)
|
||||
temp.Avail += avail
|
||||
} else {
|
||||
mountTemp = false
|
||||
}
|
||||
}
|
||||
temp.Mount = mountTemp
|
||||
data = append(data, temp)
|
||||
}
|
||||
}
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err.SUCCESS, Message: oasis_err.GetMsg(oasis_err.SUCCESS), Data: data})
|
||||
}
|
||||
@@ -2,9 +2,9 @@ package v1
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
json2 "encoding/json"
|
||||
"net/http"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
@@ -14,11 +14,9 @@ import (
|
||||
"github.com/IceWhaleTech/CasaOS/model/notify"
|
||||
"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/common_err"
|
||||
"github.com/IceWhaleTech/CasaOS/pkg/utils/file"
|
||||
ip_helper2 "github.com/IceWhaleTech/CasaOS/pkg/utils/ip_helper"
|
||||
"github.com/IceWhaleTech/CasaOS/pkg/utils/oasis_err"
|
||||
oasis_err2 "github.com/IceWhaleTech/CasaOS/pkg/utils/oasis_err"
|
||||
"github.com/IceWhaleTech/CasaOS/pkg/utils/loger"
|
||||
port2 "github.com/IceWhaleTech/CasaOS/pkg/utils/port"
|
||||
"github.com/IceWhaleTech/CasaOS/pkg/utils/random"
|
||||
"github.com/IceWhaleTech/CasaOS/service"
|
||||
@@ -29,6 +27,7 @@ import (
|
||||
"github.com/gorilla/websocket"
|
||||
"github.com/jinzhu/copier"
|
||||
uuid "github.com/satori/go.uuid"
|
||||
"go.uber.org/zap"
|
||||
"golang.org/x/crypto/ssh"
|
||||
)
|
||||
|
||||
@@ -39,20 +38,20 @@ var upgrader = websocket.Upgrader{
|
||||
HandshakeTimeout: time.Duration(time.Second * 5),
|
||||
}
|
||||
|
||||
//打开docker的terminal
|
||||
// 打开docker的terminal
|
||||
func DockerTerminal(c *gin.Context) {
|
||||
col := c.DefaultQuery("cols", "100")
|
||||
row := c.DefaultQuery("rows", "30")
|
||||
conn, err := upgrader.Upgrade(c.Writer, c.Request, nil)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.ERROR, Message: oasis_err2.GetMsg(oasis_err2.ERROR), Data: err.Error()})
|
||||
c.JSON(common_err.SERVICE_ERROR, model.Result{Success: common_err.SERVICE_ERROR, Message: common_err.GetMsg(common_err.SERVICE_ERROR), Data: err.Error()})
|
||||
return
|
||||
}
|
||||
defer conn.Close()
|
||||
container := c.Param("id")
|
||||
hr, err := service.Exec(container, row, col)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.ERROR, Message: oasis_err2.GetMsg(oasis_err2.ERROR), Data: err.Error()})
|
||||
c.JSON(common_err.SERVICE_ERROR, model.Result{Success: common_err.SERVICE_ERROR, Message: common_err.GetMsg(common_err.SERVICE_ERROR), Data: err.Error()})
|
||||
return
|
||||
}
|
||||
// 关闭I/O流
|
||||
@@ -67,14 +66,41 @@ func DockerTerminal(c *gin.Context) {
|
||||
docker.WsReaderCopy(conn, hr.Conn)
|
||||
}
|
||||
|
||||
//打开本机的ssh接口
|
||||
func WsSsh(c *gin.Context) {
|
||||
wsConn, _ := upgrader.Upgrade(c.Writer, c.Request, nil)
|
||||
func PostSshLogin(c *gin.Context) {
|
||||
j := make(map[string]string)
|
||||
c.ShouldBind(&j)
|
||||
userName := j["username"]
|
||||
password := j["password"]
|
||||
port := j["port"]
|
||||
if userName == "" || password == "" || port == "" {
|
||||
c.JSON(common_err.CLIENT_ERROR, model.Result{Success: common_err.INVALID_PARAMS, Message: common_err.GetMsg(common_err.INVALID_PARAMS), Data: "Username or password or port is empty"})
|
||||
return
|
||||
}
|
||||
_, err := docker.NewSshClient(userName, password, port)
|
||||
if err != nil {
|
||||
c.JSON(common_err.CLIENT_ERROR, model.Result{Success: common_err.CLIENT_ERROR, Message: common_err.GetMsg(common_err.CLIENT_ERROR), Data: "Please check if the username and port are correct, and make sure that ssh server is installed."})
|
||||
loger.Error("connect ssh error", zap.Any("error", err))
|
||||
return
|
||||
}
|
||||
c.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS)})
|
||||
}
|
||||
|
||||
func WsSsh(c *gin.Context) {
|
||||
_, e := exec.LookPath("ssh")
|
||||
if e != nil {
|
||||
c.JSON(common_err.SERVICE_ERROR, model.Result{Success: common_err.SERVICE_ERROR, Message: common_err.GetMsg(common_err.SERVICE_ERROR), Data: "ssh server not found"})
|
||||
return
|
||||
}
|
||||
|
||||
userName := c.Query("username")
|
||||
password := c.Query("password")
|
||||
port := c.Query("port")
|
||||
wsConn, _ := upgrader.Upgrade(c.Writer, c.Request, nil)
|
||||
var logBuff = new(bytes.Buffer)
|
||||
|
||||
quitChan := make(chan bool, 3)
|
||||
user := ""
|
||||
password := ""
|
||||
// user := ""
|
||||
// password := ""
|
||||
var login int = 1
|
||||
cols, _ := strconv.Atoi(c.DefaultQuery("cols", "200"))
|
||||
rows, _ := strconv.Atoi(c.DefaultQuery("rows", "32"))
|
||||
@@ -82,14 +108,16 @@ func WsSsh(c *gin.Context) {
|
||||
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 userName == "" || password == "" || port == "" {
|
||||
wsConn.WriteMessage(websocket.TextMessage, []byte("username or password or port is empty"))
|
||||
}
|
||||
// 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(userName, password, port)
|
||||
|
||||
if err != nil && client == nil {
|
||||
wsConn.WriteMessage(websocket.TextMessage, []byte(err.Error()))
|
||||
@@ -114,25 +142,6 @@ func WsSsh(c *gin.Context) {
|
||||
|
||||
}
|
||||
|
||||
//安装进度推送
|
||||
func SpeedPush(c *gin.Context) {
|
||||
//token := c.Query("token")
|
||||
//if len(token) == 0 || token != config.UserInfo.Token {
|
||||
// c.JSON(http.StatusOK, model.Result{Success: oasis_err2.ERROR_AUTH_TOKEN, Message: oasis_err2.GetMsg(oasis_err2.ERROR_AUTH_TOKEN)})
|
||||
// return
|
||||
//}
|
||||
|
||||
//ws, _ := upgrader.Upgrade(c.Writer, c.Request, nil)
|
||||
//defer ws.Close()
|
||||
//
|
||||
//for {
|
||||
// select {
|
||||
// case msg := <-WSMSG:
|
||||
// ws.WriteMessage(websocket.TextMessage, []byte(fmt.Sprintln(msg)))
|
||||
// }
|
||||
//}
|
||||
}
|
||||
|
||||
// @Summary 安装app(该接口需要post json数据)
|
||||
// @Produce application/json
|
||||
// @Accept application/json
|
||||
@@ -148,7 +157,7 @@ func SpeedPush(c *gin.Context) {
|
||||
func InstallApp(c *gin.Context) {
|
||||
var appInfo model.ServerAppList
|
||||
m := model.CustomizationPostData{}
|
||||
c.BindJSON(&m)
|
||||
c.ShouldBind(&m)
|
||||
|
||||
const CUSTOM = "custom"
|
||||
var dockerImage string
|
||||
@@ -158,19 +167,22 @@ func InstallApp(c *gin.Context) {
|
||||
if len(m.Protocol) == 0 {
|
||||
m.Protocol = "http"
|
||||
}
|
||||
if m.Origin != "custom" {
|
||||
oldName := m.Label
|
||||
m.ContainerName = strings.Replace(m.Label, " ", "_", -1)
|
||||
if m.Origin != CUSTOM {
|
||||
oldName := m.ContainerName
|
||||
oldLabel := m.Label
|
||||
for i := 0; true; i++ {
|
||||
if i != 0 {
|
||||
m.Label = oldName + "-" + strconv.Itoa(i)
|
||||
m.ContainerName = oldName + "-" + strconv.Itoa(i)
|
||||
m.Label = oldLabel + "-" + strconv.Itoa(i)
|
||||
}
|
||||
if _, err := service.MyService.Docker().DockerListByName(m.Label); err != nil {
|
||||
if _, err := service.MyService.Docker().DockerListByName(m.ContainerName); err != nil {
|
||||
break
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if _, err := service.MyService.Docker().DockerListByName(m.Label); err == nil {
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.ERROR_APP_NAME_EXIST, Message: oasis_err2.GetMsg(oasis_err2.ERROR_APP_NAME_EXIST)})
|
||||
if _, err := service.MyService.Docker().DockerListByName(m.ContainerName); err == nil {
|
||||
c.JSON(common_err.SERVICE_ERROR, model.Result{Success: common_err.ERROR_APP_NAME_EXIST, Message: common_err.GetMsg(common_err.ERROR_APP_NAME_EXIST)})
|
||||
return
|
||||
}
|
||||
|
||||
@@ -178,10 +190,10 @@ func InstallApp(c *gin.Context) {
|
||||
|
||||
//check port
|
||||
if len(m.PortMap) > 0 && m.PortMap != "0" {
|
||||
//c.JSON(http.StatusOK, model.Result{Success: oasis_err2.INVALID_PARAMS, Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS)})
|
||||
//c.JSON(http.StatusOK, model.Result{Success: common_err.INVALID_PARAMS, Message: common_err.GetMsg(common_err.INVALID_PARAMS)})
|
||||
portMap, _ := strconv.Atoi(m.PortMap)
|
||||
if !port2.IsPortAvailable(portMap, "tcp") {
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.ERROR, Message: "Duplicate port:" + m.PortMap})
|
||||
c.JSON(common_err.SERVICE_ERROR, model.Result{Success: common_err.SERVICE_ERROR, Message: "Duplicate port:" + m.PortMap})
|
||||
return
|
||||
}
|
||||
}
|
||||
@@ -197,40 +209,39 @@ func InstallApp(c *gin.Context) {
|
||||
dockerImage = m.Image
|
||||
dockerImageVersion = "latest"
|
||||
}
|
||||
|
||||
m.Image = dockerImage + ":" + dockerImageVersion
|
||||
for _, u := range m.Ports {
|
||||
|
||||
if u.Protocol == "udp" {
|
||||
t, _ := strconv.Atoi(u.CommendPort)
|
||||
if !port2.IsPortAvailable(t, "udp") {
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.ERROR, Message: "Duplicate port:" + u.CommendPort})
|
||||
c.JSON(common_err.SERVICE_ERROR, model.Result{Success: common_err.SERVICE_ERROR, Message: "Duplicate port:" + u.CommendPort})
|
||||
return
|
||||
}
|
||||
} else if u.Protocol == "tcp" {
|
||||
|
||||
te, _ := strconv.Atoi(u.CommendPort)
|
||||
if !port2.IsPortAvailable(te, "tcp") {
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.ERROR, Message: "Duplicate port:" + u.CommendPort})
|
||||
c.JSON(common_err.SERVICE_ERROR, model.Result{Success: common_err.SERVICE_ERROR, Message: "Duplicate port:" + u.CommendPort})
|
||||
return
|
||||
}
|
||||
} else if u.Protocol == "both" {
|
||||
t, _ := strconv.Atoi(u.CommendPort)
|
||||
if !port2.IsPortAvailable(t, "udp") {
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.ERROR, Message: "Duplicate port:" + u.CommendPort})
|
||||
c.JSON(common_err.SERVICE_ERROR, model.Result{Success: common_err.SERVICE_ERROR, Message: "Duplicate port:" + u.CommendPort})
|
||||
return
|
||||
}
|
||||
te, _ := strconv.Atoi(u.CommendPort)
|
||||
if !port2.IsPortAvailable(te, "tcp") {
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.ERROR, Message: "Duplicate port:" + u.CommendPort})
|
||||
c.JSON(common_err.SERVICE_ERROR, model.Result{Success: common_err.SERVICE_ERROR, Message: "Duplicate port:" + u.CommendPort})
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
if m.Origin == "custom" {
|
||||
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)})
|
||||
c.JSON(common_err.SERVICE_ERROR, model.Result{Success: common_err.DEVICE_NOT_EXIST, Message: device.Path + "," + common_err.GetMsg(common_err.DEVICE_NOT_EXIST)})
|
||||
return
|
||||
}
|
||||
|
||||
@@ -268,7 +279,7 @@ func InstallApp(c *gin.Context) {
|
||||
// installLog.UpdatedAt = strconv.FormatInt(time.Now().Unix(), 10)
|
||||
// installLog.Id = uuid.NewV4().String()
|
||||
// service.MyService.Notify().AddLog(installLog)
|
||||
if m.Origin != "custom" {
|
||||
if m.Origin != CUSTOM {
|
||||
for _, plugin := range appInfo.Plugins {
|
||||
if plugin == "mysql" {
|
||||
mid := uuid.NewV4().String()
|
||||
@@ -323,11 +334,11 @@ func InstallApp(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
for !service.MyService.Docker().IsExistImage(dockerImage + ":" + dockerImageVersion) {
|
||||
for !service.MyService.Docker().IsExistImage(m.Image) {
|
||||
time.Sleep(time.Second)
|
||||
}
|
||||
|
||||
_, err = service.MyService.Docker().DockerContainerCreate(dockerImage+":"+dockerImageVersion, m, appInfo.NetworkModel)
|
||||
_, err = service.MyService.Docker().DockerContainerCreate(m, "")
|
||||
if err != nil {
|
||||
//service.MyService.Redis().Set(id, "{\"id\"\""+id+"\",\"state\":false,\"message\":\""+err.Error()+"\",\"speed\":80}", 100)
|
||||
notify := notify.Application{}
|
||||
@@ -354,7 +365,7 @@ func InstallApp(c *gin.Context) {
|
||||
// echo -e "hellow\nworld" >>
|
||||
|
||||
//step:启动容器
|
||||
err = service.MyService.Docker().DockerContainerStart(m.Label)
|
||||
err = service.MyService.Docker().DockerContainerStart(m.ContainerName)
|
||||
if err != nil {
|
||||
//service.MyService.Redis().Set(id, "{\"id\"\""+id+"\",\"state\":false,\"message\":\""+err.Error()+"\",\"speed\":90}", 100)
|
||||
notify := notify.Application{}
|
||||
@@ -376,55 +387,8 @@ func InstallApp(c *gin.Context) {
|
||||
// service.MyService.Notify().UpdateLog(installLog)
|
||||
}
|
||||
|
||||
if m.Origin != CUSTOM {
|
||||
//step:enable upnp
|
||||
if m.EnableUPNP {
|
||||
upnp, err := upnp2.Gateway()
|
||||
if err == nil {
|
||||
for _, p := range m.Ports {
|
||||
if p.Protocol == "udp" {
|
||||
upnp.CtrlUrl = upnp2.GetCtrlUrl(upnp.GatewayHost, upnp.DeviceDescUrl)
|
||||
upnp.LocalHost = ip_helper2.GetLoclIp()
|
||||
tComment, _ := strconv.Atoi(p.CommendPort)
|
||||
upnp.AddPortMapping(tComment, tComment, "UDP")
|
||||
time.Sleep(time.Millisecond * 200)
|
||||
} else if p.Protocol == "tcp" {
|
||||
upnp.CtrlUrl = upnp2.GetCtrlUrl(upnp.GatewayHost, upnp.DeviceDescUrl)
|
||||
upnp.LocalHost = ip_helper2.GetLoclIp()
|
||||
tComment, _ := strconv.Atoi(p.CommendPort)
|
||||
upnp.AddPortMapping(tComment, tComment, "TCP")
|
||||
time.Sleep(time.Millisecond * 200)
|
||||
} else if p.Protocol == "both" {
|
||||
|
||||
upnp.CtrlUrl = upnp2.GetCtrlUrl(upnp.GatewayHost, upnp.DeviceDescUrl)
|
||||
upnp.LocalHost = ip_helper2.GetLoclIp()
|
||||
tComment, _ := strconv.Atoi(p.CommendPort)
|
||||
upnp.AddPortMapping(tComment, tComment, "UDP")
|
||||
time.Sleep(time.Millisecond * 200)
|
||||
|
||||
upnp.AddPortMapping(tComment, tComment, "TCP")
|
||||
time.Sleep(time.Millisecond * 200)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
// if err != nil {
|
||||
// //service.MyService.Redis().Set(id, "{\"id\"\""+id+"\",\"state\":false,\"message\":\""+err.Error()+"\",\"speed\":95}", 100)
|
||||
// installLog.State = 0
|
||||
// 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.Message = "checking"
|
||||
// service.MyService.Notify().UpdateLog(installLog)
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
//step: 启动成功 检查容器状态确认启动成功
|
||||
container, err := service.MyService.Docker().DockerContainerInfo(m.Label)
|
||||
container, err := service.MyService.Docker().DockerContainerInfo(m.ContainerName)
|
||||
if err != nil && container.ContainerJSONBase.State.Running {
|
||||
notify := notify.Application{}
|
||||
notify.Icon = m.Icon
|
||||
@@ -457,7 +421,7 @@ func InstallApp(c *gin.Context) {
|
||||
|
||||
}()
|
||||
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: m.Label})
|
||||
c.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: m.Label})
|
||||
|
||||
}
|
||||
|
||||
@@ -478,10 +442,10 @@ func InstallApp(c *gin.Context) {
|
||||
// // appInfo := service.MyService.App().GetServerAppInfo(appId)
|
||||
//
|
||||
// m := model.CustomizationPostData{}
|
||||
// c.BindJSON(&m)
|
||||
// c.ShouldBind(&m)
|
||||
// //检查端口
|
||||
// if len(m.PortMap) == 0 || m.PortMap == "0" {
|
||||
// c.JSON(http.StatusOK, model.Result{Success: oasis_err2.INVALID_PARAMS, Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS)})
|
||||
// c.JSON(http.StatusOK, model.Result{Success: common_err.INVALID_PARAMS, Message: common_err.GetMsg(common_err.INVALID_PARAMS)})
|
||||
// return
|
||||
// }
|
||||
// if len(m.Port) == 0 || m.Port == "0" {
|
||||
@@ -490,14 +454,14 @@ func InstallApp(c *gin.Context) {
|
||||
//
|
||||
// portMap, _ := strconv.Atoi(m.PortMap)
|
||||
// if !port2.IsPortAvailable(portMap, "tcp") {
|
||||
// c.JSON(http.StatusOK, model.Result{Success: oasis_err2.ERROR, Message: "Duplicate port:" + m.PortMap})
|
||||
// c.JSON(http.StatusOK, model.Result{Success: common_err.ERROR, Message: "Duplicate port:" + m.PortMap})
|
||||
// return
|
||||
// }
|
||||
//
|
||||
// for _, u := range m.Udp {
|
||||
// t, _ := strconv.Atoi(u.CommendPort)
|
||||
// if !port2.IsPortAvailable(t, "udp") {
|
||||
// c.JSON(http.StatusOK, model.Result{Success: oasis_err2.ERROR, Message: "Duplicate port:" + u.CommendPort})
|
||||
// c.JSON(http.StatusOK, model.Result{Success: common_err.ERROR, Message: "Duplicate port:" + u.CommendPort})
|
||||
// return
|
||||
// }
|
||||
// }
|
||||
@@ -505,7 +469,7 @@ func InstallApp(c *gin.Context) {
|
||||
// for _, t := range m.Tcp {
|
||||
// te, _ := strconv.Atoi(t.CommendPort)
|
||||
// if !port2.IsPortAvailable(te, "tcp") {
|
||||
// c.JSON(http.StatusOK, model.Result{Success: oasis_err2.ERROR, Message: "Duplicate port:" + t.CommendPort})
|
||||
// c.JSON(http.StatusOK, model.Result{Success: common_err.ERROR, Message: "Duplicate port:" + t.CommendPort})
|
||||
// return
|
||||
// }
|
||||
// }
|
||||
@@ -522,7 +486,7 @@ func InstallApp(c *gin.Context) {
|
||||
//
|
||||
// err := service.MyService.Docker().DockerPullImage(m.Image)
|
||||
// if err != nil {
|
||||
// c.JSON(http.StatusOK, model.Result{Success: oasis_err2.PULL_IMAGE_ERROR, Message: oasis_err2.GetMsg(oasis_err2.PULL_IMAGE_ERROR)})
|
||||
// c.JSON(http.StatusOK, model.Result{Success: common_err.PULL_IMAGE_ERROR, Message: common_err.GetMsg(common_err.PULL_IMAGE_ERROR)})
|
||||
// }
|
||||
//
|
||||
// id := uuid.NewV4().String()
|
||||
@@ -639,7 +603,7 @@ func InstallApp(c *gin.Context) {
|
||||
//
|
||||
// }()
|
||||
//
|
||||
// c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: id})
|
||||
// c.JSON(http.StatusOK, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: id})
|
||||
//
|
||||
//}
|
||||
|
||||
@@ -655,27 +619,27 @@ func UnInstallApp(c *gin.Context) {
|
||||
appId := c.Param("id")
|
||||
|
||||
if len(appId) == 0 {
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.INVALID_PARAMS, Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS)})
|
||||
c.JSON(common_err.CLIENT_ERROR, model.Result{Success: common_err.INVALID_PARAMS, Message: common_err.GetMsg(common_err.INVALID_PARAMS)})
|
||||
return
|
||||
}
|
||||
//info := service.MyService.App().GetUninstallInfo(appId)
|
||||
|
||||
info, err := service.MyService.Docker().DockerContainerInfo(appId)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.ERROR, Message: oasis_err2.GetMsg(oasis_err2.ERROR), Data: err.Error()})
|
||||
c.JSON(common_err.SERVICE_ERROR, model.Result{Success: common_err.SERVICE_ERROR, Message: common_err.GetMsg(common_err.SERVICE_ERROR), Data: err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
//step:停止容器
|
||||
err = service.MyService.Docker().DockerContainerStop(appId)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.UNINSTALL_APP_ERROR, Message: oasis_err2.GetMsg(oasis_err2.UNINSTALL_APP_ERROR), Data: err.Error()})
|
||||
c.JSON(common_err.SERVICE_ERROR, model.Result{Success: common_err.UNINSTALL_APP_ERROR, Message: common_err.GetMsg(common_err.UNINSTALL_APP_ERROR), Data: err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
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()})
|
||||
c.JSON(common_err.SERVICE_ERROR, model.Result{Success: common_err.UNINSTALL_APP_ERROR, Message: common_err.GetMsg(common_err.UNINSTALL_APP_ERROR), Data: err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
@@ -740,7 +704,7 @@ func UnInstallApp(c *gin.Context) {
|
||||
notify.Success = true
|
||||
notify.Finished = true
|
||||
service.MyService.Notify().SendUninstallAppBySocket(notify)
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS)})
|
||||
c.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS)})
|
||||
|
||||
}
|
||||
|
||||
@@ -755,26 +719,35 @@ func UnInstallApp(c *gin.Context) {
|
||||
// @Router /app/state/{id} [put]
|
||||
func ChangAppState(c *gin.Context) {
|
||||
appId := c.Param("id")
|
||||
state := c.DefaultPostForm("state", "stop")
|
||||
js := make(map[string]string)
|
||||
c.ShouldBind(&js)
|
||||
state := js["state"]
|
||||
if len(appId) == 0 || len(state) == 0 {
|
||||
c.JSON(common_err.CLIENT_ERROR, model.Result{Success: common_err.INVALID_PARAMS, Message: common_err.GetMsg(common_err.INVALID_PARAMS)})
|
||||
return
|
||||
}
|
||||
var err error
|
||||
if state == "stop" {
|
||||
err = service.MyService.Docker().DockerContainerStop(appId)
|
||||
} else if state == "start" {
|
||||
if state == "start" {
|
||||
err = service.MyService.Docker().DockerContainerStart(appId)
|
||||
} else if state == "restart" {
|
||||
service.MyService.Docker().DockerContainerStop(appId)
|
||||
err = service.MyService.Docker().DockerContainerStart(appId)
|
||||
} else {
|
||||
err = service.MyService.Docker().DockerContainerStop(appId)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.ERROR, Message: oasis_err2.GetMsg(oasis_err2.ERROR), Data: err.Error()})
|
||||
c.JSON(common_err.SERVICE_ERROR, model.Result{Success: common_err.SERVICE_ERROR, Message: common_err.GetMsg(common_err.SERVICE_ERROR), Data: err.Error()})
|
||||
return
|
||||
}
|
||||
info, err := service.MyService.App().GetContainerInfo(appId)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.ERROR, Message: oasis_err2.GetMsg(oasis_err2.ERROR), Data: err.Error()})
|
||||
c.JSON(common_err.SERVICE_ERROR, model.Result{Success: common_err.SERVICE_ERROR, Message: common_err.GetMsg(common_err.SERVICE_ERROR), Data: err.Error()})
|
||||
return
|
||||
}
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: info.State})
|
||||
|
||||
// @tiger - 用 {'state': ...} 来体现出参上下文
|
||||
c.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: info.State})
|
||||
}
|
||||
|
||||
// @Summary 查看容器日志
|
||||
@@ -788,7 +761,7 @@ func ChangAppState(c *gin.Context) {
|
||||
func ContainerLog(c *gin.Context) {
|
||||
appId := c.Param("id")
|
||||
log, _ := service.MyService.Docker().DockerContainerLog(appId)
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: log})
|
||||
c.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: string(log)})
|
||||
}
|
||||
|
||||
// @Summary 获取容器状态
|
||||
@@ -802,10 +775,10 @@ func ContainerLog(c *gin.Context) {
|
||||
// @Router /app/state/{id} [get]
|
||||
func GetContainerState(c *gin.Context) {
|
||||
id := c.Param("id")
|
||||
t := c.DefaultQuery("type", "0")
|
||||
//t := c.DefaultQuery("type", "0")
|
||||
containerInfo, e := service.MyService.App().GetSimpleContainerInfo(id)
|
||||
if e != nil {
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.ERROR, Message: e.Error()})
|
||||
c.JSON(common_err.SERVICE_ERROR, model.Result{Success: common_err.SERVICE_ERROR, Message: e.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
@@ -813,12 +786,12 @@ func GetContainerState(c *gin.Context) {
|
||||
|
||||
data["state"] = containerInfo.State
|
||||
|
||||
if t == "1" {
|
||||
appInfo := service.MyService.App().GetAppDBInfo(id)
|
||||
data["app"] = appInfo
|
||||
}
|
||||
// if t == "1" {
|
||||
// appInfo := service.MyService.App().GetAppDBInfo(id)
|
||||
// data["app"] = appInfo
|
||||
// }
|
||||
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: data})
|
||||
c.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: data})
|
||||
}
|
||||
|
||||
// @Summary 更新设置
|
||||
@@ -838,10 +811,10 @@ func UpdateSetting(c *gin.Context) {
|
||||
id := c.Param("id")
|
||||
const CUSTOM = "custom"
|
||||
m := model.CustomizationPostData{}
|
||||
c.BindJSON(&m)
|
||||
c.ShouldBind(&m)
|
||||
|
||||
if len(id) == 0 {
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.INVALID_PARAMS, Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS)})
|
||||
c.JSON(common_err.CLIENT_ERROR, model.Result{Success: common_err.INVALID_PARAMS, Message: common_err.GetMsg(common_err.INVALID_PARAMS)})
|
||||
return
|
||||
}
|
||||
//var cpd model.CustomizationPostData
|
||||
@@ -853,15 +826,14 @@ func UpdateSetting(c *gin.Context) {
|
||||
|
||||
// //check app name is exist
|
||||
// if _, err := service.MyService.Docker().DockerListByName(m.Label); err == nil {
|
||||
// c.JSON(http.StatusOK, model.Result{Success: oasis_err2.ERROR_APP_NAME_EXIST, Message: oasis_err2.GetMsg(oasis_err2.ERROR_APP_NAME_EXIST)})
|
||||
// c.JSON(http.StatusOK, model.Result{Success: common_err.ERROR_APP_NAME_EXIST, Message: common_err.GetMsg(common_err.ERROR_APP_NAME_EXIST)})
|
||||
// return
|
||||
// }
|
||||
|
||||
service.MyService.Docker().DockerContainerStop(id)
|
||||
portMap, _ := strconv.Atoi(m.PortMap)
|
||||
if !port2.IsPortAvailable(portMap, "tcp") {
|
||||
service.MyService.Docker().DockerContainerStart(id)
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.ERROR, Message: "Duplicate port:" + m.PortMap})
|
||||
c.JSON(common_err.SERVICE_ERROR, model.Result{Success: common_err.SERVICE_ERROR, Message: "Duplicate port:" + m.PortMap})
|
||||
return
|
||||
}
|
||||
|
||||
@@ -871,28 +843,28 @@ func UpdateSetting(c *gin.Context) {
|
||||
t, _ := strconv.Atoi(u.CommendPort)
|
||||
if !port2.IsPortAvailable(t, "udp") {
|
||||
service.MyService.Docker().DockerContainerStart(id)
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.ERROR, Message: "Duplicate port:" + u.CommendPort})
|
||||
c.JSON(common_err.SERVICE_ERROR, model.Result{Success: common_err.SERVICE_ERROR, Message: "Duplicate port:" + u.CommendPort})
|
||||
return
|
||||
}
|
||||
} else if u.Protocol == "tcp" {
|
||||
te, _ := strconv.Atoi(u.CommendPort)
|
||||
if !port2.IsPortAvailable(te, "tcp") {
|
||||
service.MyService.Docker().DockerContainerStart(id)
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.ERROR, Message: "Duplicate port:" + u.CommendPort})
|
||||
c.JSON(common_err.SERVICE_ERROR, model.Result{Success: common_err.SERVICE_ERROR, Message: "Duplicate port:" + u.CommendPort})
|
||||
return
|
||||
}
|
||||
} else if u.Protocol == "both" {
|
||||
t, _ := strconv.Atoi(u.CommendPort)
|
||||
if !port2.IsPortAvailable(t, "udp") {
|
||||
service.MyService.Docker().DockerContainerStart(id)
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.ERROR, Message: "Duplicate port:" + u.CommendPort})
|
||||
c.JSON(common_err.SERVICE_ERROR, model.Result{Success: common_err.SERVICE_ERROR, Message: "Duplicate port:" + u.CommendPort})
|
||||
return
|
||||
}
|
||||
|
||||
te, _ := strconv.Atoi(u.CommendPort)
|
||||
if !port2.IsPortAvailable(te, "tcp") {
|
||||
service.MyService.Docker().DockerContainerStart(id)
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.ERROR, Message: "Duplicate port:" + u.CommendPort})
|
||||
c.JSON(common_err.SERVICE_ERROR, model.Result{Success: common_err.SERVICE_ERROR, Message: "Duplicate port:" + u.CommendPort})
|
||||
return
|
||||
}
|
||||
}
|
||||
@@ -901,11 +873,11 @@ func UpdateSetting(c *gin.Context) {
|
||||
service.MyService.Docker().DockerContainerUpdateName(id, id)
|
||||
//service.MyService.Docker().DockerContainerRemove(id, true)
|
||||
|
||||
containerId, err := service.MyService.Docker().DockerContainerCreate(m.Image, m, m.NetworkModel)
|
||||
containerId, err := service.MyService.Docker().DockerContainerCreate(m, id)
|
||||
if err != nil {
|
||||
service.MyService.Docker().DockerContainerUpdateName(m.Label, id)
|
||||
service.MyService.Docker().DockerContainerUpdateName(m.ContainerName, id)
|
||||
service.MyService.Docker().DockerContainerStart(id)
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.ERROR, Message: oasis_err2.GetMsg(oasis_err2.ERROR)})
|
||||
c.JSON(common_err.SERVICE_ERROR, model.Result{Success: common_err.SERVICE_ERROR, Message: common_err.GetMsg(common_err.SERVICE_ERROR), Data: err.Error()})
|
||||
return
|
||||
}
|
||||
// echo -e "hellow\nworld" >>
|
||||
@@ -914,7 +886,7 @@ func UpdateSetting(c *gin.Context) {
|
||||
err = service.MyService.Docker().DockerContainerStart(containerId)
|
||||
|
||||
if err != nil {
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.ERROR, Message: oasis_err2.GetMsg(oasis_err2.ERROR)})
|
||||
c.JSON(common_err.SERVICE_ERROR, model.Result{Success: common_err.SERVICE_ERROR, Message: common_err.GetMsg(common_err.SERVICE_ERROR)})
|
||||
return
|
||||
}
|
||||
service.MyService.Docker().DockerContainerRemove(id, true)
|
||||
@@ -985,7 +957,7 @@ func UpdateSetting(c *gin.Context) {
|
||||
|
||||
//service.MyService.App().UpdateApp(appInfo)
|
||||
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS)})
|
||||
c.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS)})
|
||||
}
|
||||
|
||||
// @Summary update app version
|
||||
@@ -1000,20 +972,20 @@ func PutAppUpdate(c *gin.Context) {
|
||||
id := c.Param("id")
|
||||
|
||||
if len(id) == 0 {
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.INVALID_PARAMS, Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS)})
|
||||
c.JSON(common_err.CLIENT_ERROR, model.Result{Success: common_err.INVALID_PARAMS, Message: common_err.GetMsg(common_err.INVALID_PARAMS)})
|
||||
return
|
||||
}
|
||||
|
||||
inspect, err := service.MyService.Docker().DockerContainerInfo(id)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.ERROR, Message: oasis_err2.GetMsg(oasis_err2.ERROR), Data: err.Error()})
|
||||
c.JSON(common_err.SERVICE_ERROR, model.Result{Success: common_err.SERVICE_ERROR, Message: common_err.GetMsg(common_err.SERVICE_ERROR), Data: err.Error()})
|
||||
return
|
||||
|
||||
}
|
||||
imageLatest := strings.Split(inspect.Config.Image, ":")[0] + ":latest"
|
||||
err = service.MyService.Docker().DockerPullImage(imageLatest, "", "")
|
||||
if err != nil {
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.ERROR, Message: oasis_err2.GetMsg(oasis_err2.ERROR), Data: err.Error()})
|
||||
c.JSON(common_err.SERVICE_ERROR, model.Result{Success: common_err.SERVICE_ERROR, Message: common_err.GetMsg(common_err.SERVICE_ERROR), Data: err.Error()})
|
||||
return
|
||||
|
||||
}
|
||||
@@ -1026,7 +998,7 @@ func PutAppUpdate(c *gin.Context) {
|
||||
if err != nil {
|
||||
service.MyService.Docker().DockerContainerUpdateName(inspect.Name, id)
|
||||
service.MyService.Docker().DockerContainerStart(id)
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.ERROR, Message: oasis_err2.GetMsg(oasis_err2.ERROR)})
|
||||
c.JSON(common_err.SERVICE_ERROR, model.Result{Success: common_err.SERVICE_ERROR, Message: common_err.GetMsg(common_err.SERVICE_ERROR)})
|
||||
return
|
||||
}
|
||||
|
||||
@@ -1034,43 +1006,13 @@ func PutAppUpdate(c *gin.Context) {
|
||||
err = service.MyService.Docker().DockerContainerStart(containerId)
|
||||
|
||||
if err != nil {
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.ERROR, Message: oasis_err2.GetMsg(oasis_err2.ERROR)})
|
||||
c.JSON(common_err.SERVICE_ERROR, model.Result{Success: common_err.SERVICE_ERROR, Message: common_err.GetMsg(common_err.SERVICE_ERROR)})
|
||||
return
|
||||
}
|
||||
service.MyService.Docker().DockerContainerRemove(id, true)
|
||||
delete(service.NewVersionApp, id)
|
||||
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS)})
|
||||
}
|
||||
|
||||
// @Summary get app index
|
||||
// @Produce application/json
|
||||
// @Accept application/json
|
||||
// @Tags app
|
||||
// @Security ApiKeyAuth
|
||||
// @Success 200 {string} string "ok"
|
||||
// @Router /app/order [get]
|
||||
func GetAppOrder(c *gin.Context) {
|
||||
data := service.MyService.System().GetAppOrderFile()
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err.SUCCESS, Message: oasis_err.GetMsg(oasis_err.SUCCESS), Data: json.RawMessage(data)})
|
||||
}
|
||||
|
||||
// @Summary update app index
|
||||
// @Produce application/json
|
||||
// @Accept application/json
|
||||
// @Tags app
|
||||
// @Security ApiKeyAuth
|
||||
// @Success 200 {string} string "ok"
|
||||
// @Router /app/order [post]
|
||||
func PostAppOrder(c *gin.Context) {
|
||||
data := c.PostForm("data")
|
||||
service.MyService.System().UpAppOrderFile(data)
|
||||
c.JSON(http.StatusOK,
|
||||
model.Result{
|
||||
Success: oasis_err.SUCCESS,
|
||||
Message: oasis_err.GetMsg(oasis_err.SUCCESS),
|
||||
Data: json.RawMessage(data),
|
||||
})
|
||||
c.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS)})
|
||||
}
|
||||
|
||||
// @Summary 获取容器详情
|
||||
@@ -1083,10 +1025,12 @@ func PostAppOrder(c *gin.Context) {
|
||||
// @Router /app/info/{id} [get]
|
||||
func ContainerInfo(c *gin.Context) {
|
||||
appId := c.Param("id")
|
||||
|
||||
// @tiger - 作为最佳实践,不应该直接把数据库的信息返回,来避免未来数据库结构上的迭代带来的新字段
|
||||
appInfo := service.MyService.App().GetAppDBInfo(appId)
|
||||
containerInfo, _ := service.MyService.Docker().DockerContainerStats(appId)
|
||||
var cpuModel = "arm"
|
||||
if cpu := service.MyService.ZiMa().GetCpuInfo(); len(cpu) > 0 {
|
||||
if cpu := service.MyService.System().GetCpuInfo(); len(cpu) > 0 {
|
||||
if strings.Count(strings.ToLower(strings.TrimSpace(cpu[0].ModelName)), "intel") > 0 {
|
||||
cpuModel = "intel"
|
||||
} else if strings.Count(strings.ToLower(strings.TrimSpace(cpu[0].ModelName)), "amd") > 0 {
|
||||
@@ -1097,44 +1041,34 @@ func ContainerInfo(c *gin.Context) {
|
||||
info, err := service.MyService.Docker().DockerContainerInfo(appId)
|
||||
if err != nil {
|
||||
//todo 需要自定义错误
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: err.Error()})
|
||||
c.JSON(common_err.SERVICE_ERROR, model.Result{Success: common_err.SERVICE_ERROR, Message: common_err.GetMsg(common_err.SERVICE_ERROR), Data: err.Error()})
|
||||
return
|
||||
}
|
||||
con := struct {
|
||||
Status string `json:"status"`
|
||||
StartedAt string `json:"started_at"`
|
||||
CPUShares int64 `json:"cpu_shares"`
|
||||
Memory int64 `json:"memory"`
|
||||
Restart string `json:"restart"`
|
||||
Memory int64 `json:"total_memory"` // @tiger - 改成 total_memory,方便以后增加 free_memory 之类的字段
|
||||
Restart string `json:"restart_policy"` // @tiger - 改成 restart_policy?
|
||||
}{Status: info.State.Status, StartedAt: info.State.StartedAt, CPUShares: info.HostConfig.CPUShares, Memory: info.HostConfig.Memory >> 20, Restart: info.HostConfig.RestartPolicy.Name}
|
||||
data := make(map[string]interface{}, 5)
|
||||
data["app"] = appInfo
|
||||
data["cpu"] = cpuModel
|
||||
data["memory"] = service.MyService.System().GetMemInfo().Total
|
||||
data["app"] = appInfo // @tiget - 最佳实践是,返回 appid,然后具体的 app 信息由前端另行获取
|
||||
data["cpu"] = cpuModel // @tiger - 改成 arch
|
||||
data["memory"] = service.MyService.System().GetMemInfo()["total"] // @tiger - 改成 total_memory,方便以后增加 free_memory 之类的字段
|
||||
data["container"] = json2.RawMessage(containerInfo)
|
||||
data["info"] = con
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: data})
|
||||
c.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: data})
|
||||
}
|
||||
|
||||
// @Summary 获取安装所需要的数据
|
||||
// @Produce application/json
|
||||
// @Accept application/json
|
||||
// @Tags app
|
||||
// @Security ApiKeyAuth
|
||||
// @Success 200 {string} string "ok"
|
||||
// @Router /app/install/config [get]
|
||||
func GetDockerInstallConfig(c *gin.Context) {
|
||||
func GetDockerNetworks(c *gin.Context) {
|
||||
networks := service.MyService.Docker().DockerNetworkModelList()
|
||||
data := make(map[string]interface{}, 2)
|
||||
list := []map[string]string{}
|
||||
for _, network := range networks {
|
||||
if network.Driver != "null" {
|
||||
list = append(list, map[string]string{"name": network.Name, "driver": network.Driver, "id": network.ID})
|
||||
}
|
||||
}
|
||||
data["networks"] = list
|
||||
data["memory"] = service.MyService.System().GetMemInfo()
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: data})
|
||||
c.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: list})
|
||||
}
|
||||
|
||||
// @Summary 获取依赖数据
|
||||
@@ -1148,10 +1082,9 @@ func GetDockerInstallConfig(c *gin.Context) {
|
||||
func ContainerRelyInfo(c *gin.Context) {
|
||||
id := c.Param("id")
|
||||
appInfo := service.MyService.Rely().GetInfo(id)
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: appInfo})
|
||||
c.JSON(http.StatusOK, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: appInfo})
|
||||
}
|
||||
|
||||
// @Summary 获取可更新数据
|
||||
// @Produce application/json
|
||||
// @Accept application/json
|
||||
// @Tags app
|
||||
@@ -1165,7 +1098,7 @@ func ContainerUpdateInfo(c *gin.Context) {
|
||||
info, err := service.MyService.Docker().DockerContainerInfo(appId)
|
||||
if err != nil {
|
||||
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: err.Error()})
|
||||
c.JSON(common_err.SERVICE_ERROR, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: err.Error()})
|
||||
return
|
||||
}
|
||||
var port model.PortArray
|
||||
@@ -1187,13 +1120,13 @@ func ContainerUpdateInfo(c *gin.Context) {
|
||||
showENV := info.Config.Labels["show_env"]
|
||||
showENVList := strings.Split(showENV, ",")
|
||||
showENVMap := make(map[string]string)
|
||||
if len(showENVList) > 1 {
|
||||
if len(showENVList) > 0 && showENVList[0] != "" {
|
||||
for _, name := range showENVList {
|
||||
showENVMap[name] = "1"
|
||||
}
|
||||
}
|
||||
for _, v := range info.Config.Env {
|
||||
if len(showENVList) > 1 {
|
||||
if len(showENVList) > 0 {
|
||||
if _, ok := showENVMap[strings.Split(v, "=")[0]]; ok {
|
||||
temp := model.Env{
|
||||
Name: strings.Split(v, "=")[0],
|
||||
@@ -1243,7 +1176,7 @@ func ContainerUpdateInfo(c *gin.Context) {
|
||||
}
|
||||
m.NetworkModel = string(info.HostConfig.NetworkMode)
|
||||
m.Description = info.Config.Labels["desc"]
|
||||
m.Label = strings.ReplaceAll(info.Name, "/", "")
|
||||
m.ContainerName = strings.ReplaceAll(info.Name, "/", "")
|
||||
m.PortMap = info.Config.Labels["web"]
|
||||
m.Devices = driver
|
||||
m.Envs = envs
|
||||
@@ -1263,13 +1196,18 @@ func ContainerUpdateInfo(c *gin.Context) {
|
||||
m.Cmd = info.Config.Cmd
|
||||
m.HostName = info.Config.Hostname
|
||||
m.Privileged = info.HostConfig.Privileged
|
||||
name := info.Config.Labels["name"]
|
||||
if len(name) == 0 {
|
||||
name = strings.ReplaceAll(info.Name, "/", "")
|
||||
}
|
||||
m.Label = name
|
||||
|
||||
m.Protocol = info.Config.Labels["protocol"]
|
||||
if m.Protocol == "" {
|
||||
m.Protocol = "http"
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: m})
|
||||
c.JSON(http.StatusOK, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: m})
|
||||
}
|
||||
|
||||
////准备安装(暂时不需要)
|
||||
@@ -1320,5 +1258,5 @@ func ContainerUpdateInfo(c *gin.Context) {
|
||||
// }
|
||||
// data["udp"] = inarr
|
||||
// }
|
||||
// c.JSON(http.StatusOK, model.Result{Success: oasis_err.SUCCESS, Message: oasis_err.GetMsg(oasis_err.SUCCESS), Data: data})
|
||||
// c.JSON(http.StatusOK, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: data})
|
||||
//}
|
||||
|
||||
253
route/v1/file.go
253
route/v1/file.go
@@ -1,8 +1,6 @@
|
||||
package v1
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"encoding/csv"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
@@ -18,41 +16,13 @@ import (
|
||||
"sync"
|
||||
|
||||
"github.com/IceWhaleTech/CasaOS/model"
|
||||
"github.com/IceWhaleTech/CasaOS/pkg/config"
|
||||
"github.com/IceWhaleTech/CasaOS/pkg/utils/common_err"
|
||||
"github.com/IceWhaleTech/CasaOS/pkg/utils/file"
|
||||
"github.com/IceWhaleTech/CasaOS/pkg/utils/oasis_err"
|
||||
oasis_err2 "github.com/IceWhaleTech/CasaOS/pkg/utils/oasis_err"
|
||||
"github.com/IceWhaleTech/CasaOS/service"
|
||||
"github.com/gin-gonic/gin"
|
||||
uuid "github.com/satori/go.uuid"
|
||||
)
|
||||
|
||||
func downloadReadFile(c *gin.Context) {
|
||||
//http下载地址 csv
|
||||
csvFileUrl := c.PostForm("file_name")
|
||||
res, err := http.Get(csvFileUrl)
|
||||
if err != nil {
|
||||
c.String(400, err.Error())
|
||||
return
|
||||
}
|
||||
defer res.Body.Close()
|
||||
//读取csv
|
||||
reader := csv.NewReader(bufio.NewReader(res.Body))
|
||||
for {
|
||||
line, err := reader.Read()
|
||||
if err == io.EOF {
|
||||
break
|
||||
} else if err != nil {
|
||||
c.String(400, err.Error())
|
||||
return
|
||||
}
|
||||
//line 就是每一行的内容
|
||||
fmt.Println(line)
|
||||
//line[0] 就是第几列
|
||||
fmt.Println(line[0])
|
||||
}
|
||||
}
|
||||
|
||||
// @Summary 读取文件
|
||||
// @Produce application/json
|
||||
// @Accept application/json
|
||||
@@ -64,35 +34,34 @@ func downloadReadFile(c *gin.Context) {
|
||||
func GetFilerContent(c *gin.Context) {
|
||||
filePath := c.Query("path")
|
||||
if len(filePath) == 0 {
|
||||
c.JSON(http.StatusOK, model.Result{
|
||||
Success: oasis_err2.INVALID_PARAMS,
|
||||
Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS),
|
||||
c.JSON(common_err.CLIENT_ERROR, model.Result{
|
||||
Success: common_err.INVALID_PARAMS,
|
||||
Message: common_err.GetMsg(common_err.INVALID_PARAMS),
|
||||
})
|
||||
return
|
||||
}
|
||||
if !file.Exists(filePath) {
|
||||
c.JSON(http.StatusOK, model.Result{
|
||||
Success: oasis_err2.FILE_DOES_NOT_EXIST,
|
||||
Message: oasis_err2.GetMsg(oasis_err2.FILE_DOES_NOT_EXIST),
|
||||
c.JSON(common_err.SERVICE_ERROR, model.Result{
|
||||
Success: common_err.FILE_DOES_NOT_EXIST,
|
||||
Message: common_err.GetMsg(common_err.FILE_DOES_NOT_EXIST),
|
||||
})
|
||||
return
|
||||
}
|
||||
//文件读取任务是将文件内容读取到内存中。
|
||||
info, err := ioutil.ReadFile(filePath)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusOK, model.Result{
|
||||
Success: oasis_err2.FILE_READ_ERROR,
|
||||
Message: oasis_err2.GetMsg(oasis_err2.FILE_READ_ERROR),
|
||||
c.JSON(common_err.SERVICE_ERROR, model.Result{
|
||||
Success: common_err.FILE_READ_ERROR,
|
||||
Message: common_err.GetMsg(common_err.FILE_READ_ERROR),
|
||||
Data: err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
result := string(info)
|
||||
|
||||
//返回结果
|
||||
c.JSON(http.StatusOK, model.Result{
|
||||
Success: oasis_err2.SUCCESS,
|
||||
Message: oasis_err2.GetMsg(oasis_err2.SUCCESS),
|
||||
c.JSON(common_err.SUCCESS, model.Result{
|
||||
Success: common_err.SUCCESS,
|
||||
Message: common_err.GetMsg(common_err.SUCCESS),
|
||||
Data: result,
|
||||
})
|
||||
}
|
||||
@@ -101,15 +70,15 @@ func GetLocalFile(c *gin.Context) {
|
||||
path := c.Query("path")
|
||||
if len(path) == 0 {
|
||||
c.JSON(http.StatusOK, model.Result{
|
||||
Success: oasis_err2.INVALID_PARAMS,
|
||||
Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS),
|
||||
Success: common_err.INVALID_PARAMS,
|
||||
Message: common_err.GetMsg(common_err.INVALID_PARAMS),
|
||||
})
|
||||
return
|
||||
}
|
||||
if !file.Exists(path) {
|
||||
c.JSON(http.StatusOK, model.Result{
|
||||
Success: oasis_err2.FILE_DOES_NOT_EXIST,
|
||||
Message: oasis_err2.GetMsg(oasis_err2.FILE_DOES_NOT_EXIST),
|
||||
Success: common_err.FILE_DOES_NOT_EXIST,
|
||||
Message: common_err.GetMsg(common_err.FILE_DOES_NOT_EXIST),
|
||||
})
|
||||
return
|
||||
}
|
||||
@@ -122,29 +91,29 @@ func GetLocalFile(c *gin.Context) {
|
||||
// @Accept application/json
|
||||
// @Tags file
|
||||
// @Security ApiKeyAuth
|
||||
// @Param t query string false "Compression format" Enums(zip,tar,targz)
|
||||
// @Param format query string false "Compression format" Enums(zip,tar,targz)
|
||||
// @Param files query string true "file list eg: filename1,filename2,filename3 "
|
||||
// @Success 200 {string} string "ok"
|
||||
// @Router /file/download [get]
|
||||
func GetDownloadFile(c *gin.Context) {
|
||||
|
||||
t := c.Query("t")
|
||||
t := c.Query("format")
|
||||
|
||||
files := c.Query("files")
|
||||
|
||||
if len(files) == 0 {
|
||||
c.JSON(http.StatusOK, model.Result{
|
||||
Success: oasis_err2.INVALID_PARAMS,
|
||||
Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS),
|
||||
c.JSON(common_err.CLIENT_ERROR, model.Result{
|
||||
Success: common_err.INVALID_PARAMS,
|
||||
Message: common_err.GetMsg(common_err.INVALID_PARAMS),
|
||||
})
|
||||
return
|
||||
}
|
||||
list := strings.Split(files, ",")
|
||||
for _, v := range list {
|
||||
if !file.Exists(v) {
|
||||
c.JSON(http.StatusOK, model.Result{
|
||||
Success: oasis_err2.FILE_DOES_NOT_EXIST,
|
||||
Message: oasis_err2.GetMsg(oasis_err2.FILE_DOES_NOT_EXIST),
|
||||
c.JSON(common_err.SERVICE_ERROR, model.Result{
|
||||
Success: common_err.FILE_DOES_NOT_EXIST,
|
||||
Message: common_err.GetMsg(common_err.FILE_DOES_NOT_EXIST),
|
||||
})
|
||||
return
|
||||
}
|
||||
@@ -159,8 +128,8 @@ func GetDownloadFile(c *gin.Context) {
|
||||
info, err := os.Stat(filePath)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusOK, model.Result{
|
||||
Success: oasis_err2.FILE_DOES_NOT_EXIST,
|
||||
Message: oasis_err2.GetMsg(oasis_err2.FILE_DOES_NOT_EXIST),
|
||||
Success: common_err.FILE_DOES_NOT_EXIST,
|
||||
Message: common_err.GetMsg(common_err.FILE_DOES_NOT_EXIST),
|
||||
})
|
||||
return
|
||||
}
|
||||
@@ -180,18 +149,18 @@ func GetDownloadFile(c *gin.Context) {
|
||||
|
||||
extension, ar, err := file.GetCompressionAlgorithm(t)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusOK, model.Result{
|
||||
Success: oasis_err2.INVALID_PARAMS,
|
||||
Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS),
|
||||
c.JSON(common_err.CLIENT_ERROR, model.Result{
|
||||
Success: common_err.INVALID_PARAMS,
|
||||
Message: common_err.GetMsg(common_err.INVALID_PARAMS),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
err = ar.Create(c.Writer)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusOK, model.Result{
|
||||
Success: oasis_err.ERROR,
|
||||
Message: oasis_err2.GetMsg(oasis_err2.ERROR),
|
||||
c.JSON(common_err.SERVICE_ERROR, model.Result{
|
||||
Success: common_err.SERVICE_ERROR,
|
||||
Message: common_err.GetMsg(common_err.SERVICE_ERROR),
|
||||
Data: err.Error(),
|
||||
})
|
||||
return
|
||||
@@ -214,8 +183,22 @@ func GetDownloadFile(c *gin.Context) {
|
||||
}
|
||||
|
||||
func GetDownloadSingleFile(c *gin.Context) {
|
||||
filePath := c.Param("path")
|
||||
fileTmp, _ := os.Open(filePath)
|
||||
filePath := c.Query("path")
|
||||
if len(filePath) == 0 {
|
||||
c.JSON(service.ClientCount, model.Result{
|
||||
Success: common_err.INVALID_PARAMS,
|
||||
Message: common_err.GetMsg(common_err.INVALID_PARAMS),
|
||||
})
|
||||
return
|
||||
}
|
||||
fileTmp, err := os.Open(filePath)
|
||||
if err != nil {
|
||||
c.JSON(common_err.SERVICE_ERROR, model.Result{
|
||||
Success: common_err.FILE_DOES_NOT_EXIST,
|
||||
Message: common_err.GetMsg(common_err.FILE_DOES_NOT_EXIST),
|
||||
})
|
||||
return
|
||||
}
|
||||
defer fileTmp.Close()
|
||||
|
||||
fileName := path.Base(filePath)
|
||||
@@ -234,7 +217,12 @@ func GetDownloadSingleFile(c *gin.Context) {
|
||||
// @Router /file/dirpath [get]
|
||||
func DirPath(c *gin.Context) {
|
||||
path := c.DefaultQuery("path", "")
|
||||
info := service.MyService.ZiMa().GetDirPath(path)
|
||||
info := service.MyService.System().GetDirPath(path)
|
||||
shares := service.MyService.Shares().GetSharesList()
|
||||
sharesMap := make(map[string]string)
|
||||
for _, v := range shares {
|
||||
sharesMap[v.Path] = fmt.Sprint(v.ID)
|
||||
}
|
||||
if path == "/DATA/AppData" {
|
||||
list := service.MyService.Docker().DockerContainerList()
|
||||
apps := make(map[string]string, len(list))
|
||||
@@ -247,34 +235,19 @@ func DirPath(c *gin.Context) {
|
||||
info[i].Type = "application"
|
||||
}
|
||||
}
|
||||
} else if path == "/DATA" {
|
||||
disk := make(map[string]string)
|
||||
lsblk := service.MyService.Disk().LSBLK(true)
|
||||
for _, v := range lsblk {
|
||||
if len(v.Children) > 0 {
|
||||
t := v.Tran
|
||||
for _, c := range v.Children {
|
||||
if len(c.Children) > 0 {
|
||||
for _, gc := range c.Children {
|
||||
if len(gc.MountPoint) > 0 {
|
||||
disk[gc.MountPoint] = t
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(c.MountPoint) > 0 {
|
||||
disk[c.MountPoint] = t
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
for i := 0; i < len(info); i++ {
|
||||
if v, ok := disk[info[i].Path]; ok {
|
||||
info[i].Type = v
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for i := 0; i < len(info); i++ {
|
||||
if v, ok := sharesMap[info[i].Path]; ok {
|
||||
ex := make(map[string]interface{})
|
||||
|
||||
shareEx := make(map[string]string)
|
||||
shareEx["shared"] = "true"
|
||||
shareEx["id"] = v
|
||||
ex["share"] = shareEx
|
||||
info[i].Extensions = ex
|
||||
}
|
||||
}
|
||||
//Hide the files or folders in operation
|
||||
fileQueue := make(map[string]string)
|
||||
if len(service.OpStrArr) > 0 {
|
||||
@@ -293,12 +266,15 @@ func DirPath(c *gin.Context) {
|
||||
|
||||
pathList := []model.Path{}
|
||||
for i := 0; i < len(info); i++ {
|
||||
if info[i].Name == ".temp" && info[i].IsDir {
|
||||
continue
|
||||
}
|
||||
if _, ok := fileQueue[info[i].Path]; !ok {
|
||||
pathList = append(pathList, info[i])
|
||||
}
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: pathList})
|
||||
c.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: pathList})
|
||||
}
|
||||
|
||||
// @Summary rename file or dir
|
||||
@@ -312,15 +288,15 @@ func DirPath(c *gin.Context) {
|
||||
// @Router /file/rename [put]
|
||||
func RenamePath(c *gin.Context) {
|
||||
json := make(map[string]string)
|
||||
c.BindJSON(&json)
|
||||
op := json["oldpath"]
|
||||
np := json["newpath"]
|
||||
c.ShouldBind(&json)
|
||||
op := json["old_path"]
|
||||
np := json["new_path"]
|
||||
if len(op) == 0 || len(np) == 0 {
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.INVALID_PARAMS, Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS)})
|
||||
c.JSON(common_err.CLIENT_ERROR, model.Result{Success: common_err.INVALID_PARAMS, Message: common_err.GetMsg(common_err.INVALID_PARAMS)})
|
||||
return
|
||||
}
|
||||
success, err := service.MyService.ZiMa().RenameFile(op, np)
|
||||
c.JSON(http.StatusOK, model.Result{Success: success, Message: oasis_err2.GetMsg(success), Data: err})
|
||||
success, err := service.MyService.System().RenameFile(op, np)
|
||||
c.JSON(common_err.SUCCESS, model.Result{Success: success, Message: common_err.GetMsg(success), Data: err})
|
||||
}
|
||||
|
||||
// @Summary create folder
|
||||
@@ -333,20 +309,20 @@ func RenamePath(c *gin.Context) {
|
||||
// @Router /file/mkdir [post]
|
||||
func MkdirAll(c *gin.Context) {
|
||||
json := make(map[string]string)
|
||||
c.BindJSON(&json)
|
||||
c.ShouldBind(&json)
|
||||
path := json["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)})
|
||||
c.JSON(common_err.CLIENT_ERROR, model.Result{Success: common_err.INVALID_PARAMS, Message: common_err.GetMsg(common_err.INVALID_PARAMS)})
|
||||
return
|
||||
}
|
||||
// decodedPath, err := url.QueryUnescape(path)
|
||||
// if err != nil {
|
||||
// c.JSON(http.StatusOK, model.Result{Success: oasis_err2.INVALID_PARAMS, Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS)})
|
||||
// c.JSON(http.StatusOK, model.Result{Success: common_err.INVALID_PARAMS, Message: common_err.GetMsg(common_err.INVALID_PARAMS)})
|
||||
// return
|
||||
// }
|
||||
code, _ = service.MyService.ZiMa().MkdirAll(path)
|
||||
c.JSON(http.StatusOK, model.Result{Success: code, Message: oasis_err2.GetMsg(code)})
|
||||
code, _ = service.MyService.System().MkdirAll(path)
|
||||
c.JSON(common_err.SUCCESS, model.Result{Success: code, Message: common_err.GetMsg(code)})
|
||||
}
|
||||
|
||||
// @Summary create file
|
||||
@@ -359,20 +335,20 @@ func MkdirAll(c *gin.Context) {
|
||||
// @Router /file/create [post]
|
||||
func PostCreateFile(c *gin.Context) {
|
||||
json := make(map[string]string)
|
||||
c.BindJSON(&json)
|
||||
c.ShouldBind(&json)
|
||||
path := json["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)})
|
||||
c.JSON(common_err.CLIENT_ERROR, model.Result{Success: common_err.INVALID_PARAMS, Message: common_err.GetMsg(common_err.INVALID_PARAMS)})
|
||||
return
|
||||
}
|
||||
// decodedPath, err := url.QueryUnescape(path)
|
||||
// if err != nil {
|
||||
// c.JSON(http.StatusOK, model.Result{Success: oasis_err2.INVALID_PARAMS, Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS)})
|
||||
// c.JSON(http.StatusOK, model.Result{Success: common_err.INVALID_PARAMS, Message: common_err.GetMsg(common_err.INVALID_PARAMS)})
|
||||
// return
|
||||
// }
|
||||
code, _ = service.MyService.ZiMa().CreateFile(path)
|
||||
c.JSON(http.StatusOK, model.Result{Success: code, Message: oasis_err2.GetMsg(code)})
|
||||
code, _ = service.MyService.System().CreateFile(path)
|
||||
c.JSON(common_err.SUCCESS, model.Result{Success: code, Message: common_err.GetMsg(code)})
|
||||
}
|
||||
|
||||
// @Summary upload file
|
||||
@@ -393,7 +369,7 @@ func GetFileUpload(c *gin.Context) {
|
||||
path := c.Query("path")
|
||||
dirPath := ""
|
||||
hash := file.GetHashByContent([]byte(fileName))
|
||||
tempDir := config.AppInfo.RootPath + "/temp/" + hash + strconv.Itoa(totalChunks) + "/"
|
||||
tempDir := filepath.Join(path, ".temp", hash+strconv.Itoa(totalChunks)) + "/"
|
||||
if fileName != relative {
|
||||
dirPath = strings.TrimSuffix(relative, fileName)
|
||||
tempDir += dirPath
|
||||
@@ -401,11 +377,11 @@ func GetFileUpload(c *gin.Context) {
|
||||
}
|
||||
tempDir += chunkNumber
|
||||
if !file.CheckNotExist(tempDir) {
|
||||
c.JSON(200, model.Result{Success: 200, Message: oasis_err2.GetMsg(oasis_err2.FILE_ALREADY_EXISTS)})
|
||||
c.JSON(200, model.Result{Success: 200, Message: common_err.GetMsg(common_err.FILE_ALREADY_EXISTS)})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(204, model.Result{Success: 204, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS)})
|
||||
c.JSON(204, model.Result{Success: 204, Message: common_err.GetMsg(common_err.SUCCESS)})
|
||||
}
|
||||
|
||||
// @Summary upload file
|
||||
@@ -429,10 +405,10 @@ func PostFileUpload(c *gin.Context) {
|
||||
hash := file.GetHashByContent([]byte(fileName))
|
||||
|
||||
if len(path) == 0 {
|
||||
c.JSON(oasis_err2.INVALID_PARAMS, model.Result{Success: oasis_err2.INVALID_PARAMS, Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS)})
|
||||
c.JSON(common_err.INVALID_PARAMS, model.Result{Success: common_err.INVALID_PARAMS, Message: common_err.GetMsg(common_err.INVALID_PARAMS)})
|
||||
return
|
||||
}
|
||||
tempDir := config.AppInfo.RootPath + "/temp/" + hash + strconv.Itoa(totalChunks) + "/"
|
||||
tempDir := filepath.Join(path, ".temp", hash+strconv.Itoa(totalChunks)) + "/"
|
||||
|
||||
if fileName != relative {
|
||||
dirPath = strings.TrimSuffix(relative, fileName)
|
||||
@@ -453,7 +429,7 @@ func PostFileUpload(c *gin.Context) {
|
||||
defer out.Close()
|
||||
_, err := io.Copy(out, f)
|
||||
if err != nil {
|
||||
c.JSON(oasis_err2.ERROR, model.Result{Success: oasis_err2.ERROR, Message: oasis_err2.GetMsg(oasis_err2.ERROR), Data: err.Error()})
|
||||
c.JSON(common_err.SERVICE_ERROR, model.Result{Success: common_err.SERVICE_ERROR, Message: common_err.GetMsg(common_err.SERVICE_ERROR), Data: err.Error()})
|
||||
return
|
||||
}
|
||||
} else {
|
||||
@@ -461,15 +437,15 @@ func PostFileUpload(c *gin.Context) {
|
||||
defer out.Close()
|
||||
_, err := io.Copy(out, f)
|
||||
if err != nil {
|
||||
c.JSON(oasis_err2.ERROR, model.Result{Success: oasis_err2.ERROR, Message: oasis_err2.GetMsg(oasis_err2.ERROR), Data: err.Error()})
|
||||
c.JSON(common_err.SERVICE_ERROR, model.Result{Success: common_err.SERVICE_ERROR, Message: common_err.GetMsg(common_err.SERVICE_ERROR), Data: err.Error()})
|
||||
return
|
||||
}
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS)})
|
||||
c.JSON(http.StatusOK, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS)})
|
||||
return
|
||||
}
|
||||
fileNum, err := ioutil.ReadDir(tempDir)
|
||||
if err != nil {
|
||||
c.JSON(oasis_err2.ERROR, model.Result{Success: oasis_err2.ERROR, Message: oasis_err2.GetMsg(oasis_err2.ERROR), Data: err.Error()})
|
||||
c.JSON(common_err.SERVICE_ERROR, model.Result{Success: common_err.SERVICE_ERROR, Message: common_err.GetMsg(common_err.SERVICE_ERROR), Data: err.Error()})
|
||||
return
|
||||
}
|
||||
if totalChunks == len(fileNum) {
|
||||
@@ -477,7 +453,7 @@ func PostFileUpload(c *gin.Context) {
|
||||
file.RMDir(tempDir)
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS)})
|
||||
c.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS)})
|
||||
}
|
||||
|
||||
// @Summary copy or move file
|
||||
@@ -491,14 +467,14 @@ func PostFileUpload(c *gin.Context) {
|
||||
func PostOperateFileOrDir(c *gin.Context) {
|
||||
|
||||
list := model.FileOperate{}
|
||||
c.BindJSON(&list)
|
||||
c.ShouldBind(&list)
|
||||
|
||||
if len(list.Item) == 0 {
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.INVALID_PARAMS, Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS)})
|
||||
c.JSON(common_err.CLIENT_ERROR, model.Result{Success: common_err.INVALID_PARAMS, Message: common_err.GetMsg(common_err.INVALID_PARAMS)})
|
||||
return
|
||||
}
|
||||
if list.To == list.Item[0].From[:strings.LastIndex(list.Item[0].From, "/")] {
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SOURCE_DES_SAME, Message: oasis_err2.GetMsg(oasis_err2.SOURCE_DES_SAME)})
|
||||
c.JSON(common_err.SERVICE_ERROR, model.Result{Success: common_err.SOURCE_DES_SAME, Message: common_err.GetMsg(common_err.SOURCE_DES_SAME)})
|
||||
return
|
||||
}
|
||||
|
||||
@@ -519,7 +495,6 @@ func PostOperateFileOrDir(c *gin.Context) {
|
||||
uid := uuid.NewV4().String()
|
||||
service.FileQueue.Store(uid, list)
|
||||
service.OpStrArr = append(service.OpStrArr, uid)
|
||||
|
||||
if len(service.OpStrArr) == 1 {
|
||||
go service.ExecOpFile()
|
||||
go service.CheckFileStatus()
|
||||
@@ -528,7 +503,7 @@ func PostOperateFileOrDir(c *gin.Context) {
|
||||
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS)})
|
||||
c.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS)})
|
||||
}
|
||||
|
||||
// @Summary delete file
|
||||
@@ -542,9 +517,9 @@ func PostOperateFileOrDir(c *gin.Context) {
|
||||
func DeleteFile(c *gin.Context) {
|
||||
|
||||
paths := []string{}
|
||||
c.BindJSON(&paths)
|
||||
c.ShouldBind(&paths)
|
||||
if len(paths) == 0 {
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.INVALID_PARAMS, Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS)})
|
||||
c.JSON(common_err.CLIENT_ERROR, model.Result{Success: common_err.INVALID_PARAMS, Message: common_err.GetMsg(common_err.INVALID_PARAMS)})
|
||||
return
|
||||
}
|
||||
// path := c.Query("path")
|
||||
@@ -554,12 +529,12 @@ func DeleteFile(c *gin.Context) {
|
||||
for _, v := range paths {
|
||||
err := os.RemoveAll(v)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.FILE_DELETE_ERROR, Message: oasis_err2.GetMsg(oasis_err2.FILE_DELETE_ERROR), Data: err})
|
||||
c.JSON(common_err.SERVICE_ERROR, model.Result{Success: common_err.FILE_DELETE_ERROR, Message: common_err.GetMsg(common_err.FILE_DELETE_ERROR), Data: err})
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS)})
|
||||
c.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS)})
|
||||
}
|
||||
|
||||
// @Summary update file
|
||||
@@ -574,26 +549,26 @@ func DeleteFile(c *gin.Context) {
|
||||
func PutFileContent(c *gin.Context) {
|
||||
|
||||
fi := model.FileUpdate{}
|
||||
c.BindJSON(&fi)
|
||||
c.ShouldBind(&fi)
|
||||
|
||||
// path := c.PostForm("path")
|
||||
// content := c.PostForm("content")
|
||||
if !file.Exists(fi.FilePath) {
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.FILE_ALREADY_EXISTS, Message: oasis_err2.GetMsg(oasis_err2.FILE_ALREADY_EXISTS)})
|
||||
c.JSON(common_err.SERVICE_ERROR, model.Result{Success: common_err.FILE_ALREADY_EXISTS, Message: common_err.GetMsg(common_err.FILE_ALREADY_EXISTS)})
|
||||
return
|
||||
}
|
||||
//err := os.Remove(path)
|
||||
err := os.RemoveAll(fi.FilePath)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.FILE_DELETE_ERROR, Message: oasis_err2.GetMsg(oasis_err2.FILE_DELETE_ERROR), Data: err})
|
||||
c.JSON(common_err.SERVICE_ERROR, model.Result{Success: common_err.FILE_DELETE_ERROR, Message: common_err.GetMsg(common_err.FILE_DELETE_ERROR), Data: err})
|
||||
return
|
||||
}
|
||||
err = file.CreateFileAndWriteContent(fi.FilePath, fi.FileContent)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.ERROR, Message: oasis_err2.GetMsg(oasis_err2.ERROR), Data: err})
|
||||
c.JSON(common_err.SERVICE_ERROR, model.Result{Success: common_err.SERVICE_ERROR, Message: common_err.GetMsg(common_err.SERVICE_ERROR), Data: err.Error()})
|
||||
return
|
||||
}
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS)})
|
||||
c.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS)})
|
||||
}
|
||||
|
||||
// @Summary image thumbnail/original image
|
||||
@@ -609,13 +584,13 @@ func GetFileImage(c *gin.Context) {
|
||||
t := c.Query("type")
|
||||
path := c.Query("path")
|
||||
if !file.Exists(path) {
|
||||
c.JSON(http.StatusInternalServerError, model.Result{Success: oasis_err2.FILE_ALREADY_EXISTS, Message: oasis_err2.GetMsg(oasis_err2.FILE_ALREADY_EXISTS)})
|
||||
c.JSON(common_err.SERVICE_ERROR, model.Result{Success: common_err.FILE_ALREADY_EXISTS, Message: common_err.GetMsg(common_err.FILE_ALREADY_EXISTS)})
|
||||
return
|
||||
}
|
||||
if t == "thumbnail" {
|
||||
f, err := file.GetImage(path, 100, 0)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, model.Result{Success: oasis_err2.ERROR, Message: oasis_err2.GetMsg(oasis_err2.ERROR), Data: err.Error()})
|
||||
c.JSON(common_err.SERVICE_ERROR, model.Result{Success: common_err.SERVICE_ERROR, Message: common_err.GetMsg(common_err.SERVICE_ERROR), Data: err.Error()})
|
||||
return
|
||||
}
|
||||
c.Writer.WriteString(string(f))
|
||||
@@ -623,13 +598,13 @@ func GetFileImage(c *gin.Context) {
|
||||
}
|
||||
f, err := os.Open(path)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, model.Result{Success: oasis_err2.ERROR, Message: oasis_err2.GetMsg(oasis_err2.ERROR), Data: err.Error()})
|
||||
c.JSON(common_err.SERVICE_ERROR, model.Result{Success: common_err.SERVICE_ERROR, Message: common_err.GetMsg(common_err.SERVICE_ERROR), Data: err.Error()})
|
||||
return
|
||||
}
|
||||
defer f.Close()
|
||||
data, err := ioutil.ReadAll(f)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, model.Result{Success: oasis_err2.ERROR, Message: oasis_err2.GetMsg(oasis_err2.ERROR), Data: err.Error()})
|
||||
c.JSON(common_err.SERVICE_ERROR, model.Result{Success: common_err.SERVICE_ERROR, Message: common_err.GetMsg(common_err.SERVICE_ERROR), Data: err.Error()})
|
||||
return
|
||||
}
|
||||
c.Writer.WriteString(string(data))
|
||||
@@ -654,5 +629,5 @@ func DeleteOperateFileOrDir(c *gin.Context) {
|
||||
}
|
||||
|
||||
go service.MyService.Notify().SendFileOperateNotify(true)
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS)})
|
||||
c.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS)})
|
||||
}
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
package v1
|
||||
|
||||
func aaa() {
|
||||
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user