Merge branch 'main' into community

This commit is contained in:
LinkLeong 2023-08-18 08:18:36 +01:00
commit 8d6576e5a1
20 changed files with 1001 additions and 185 deletions

View File

@ -33,8 +33,9 @@ jobs:
- name: Get old instance and snapshot name, create new instance name - name: Get old instance and snapshot name, create new instance name
run: | run: |
echo "OLD_INSTANCE_SNAPSHOT_NAME=$(aws lightsail get-instance-snapshots | grep '"name": "updateto_to_0.4.1-1676285322' | sed 's/ //g' | sed 's/"//g' | sed 's/,//g' | sed 's/name://g')" >> $GITHUB_ENV echo "OLD_INSTANCE_SNAPSHOT_NAME=updateto_to_0.4.4-1684926517" >> $GITHUB_ENV
echo "OLD_INSTANCE_NAME=$(aws lightsail get-instances | grep '"name": "CasaOS-Demo-[0-9]' | sed 's/ //g' | sed 's/"//g' | sed 's/,//g' | sed 's/name://g')" >> $GITHUB_ENV echo "OLD_INSTANCE_NAME=$(aws lightsail get-instances | grep '"name": "CasaOS-Demo-[0-9]' | tail -1 | sed 's/ //g' | sed 's/"//g' | sed 's/,//g' | sed 's/name://g')" >> $GITHUB_ENV
# echo "OLD_INSTANCE_NAME=CasaOS-Demo-1687680295" >> $GITHUB_ENV
echo "NEW_INSTANCE_NAME= CasaOS-Demo-$(date +%s)" >> $GITHUB_ENV echo "NEW_INSTANCE_NAME= CasaOS-Demo-$(date +%s)" >> $GITHUB_ENV
- name: Create instances from snapshot - name: Create instances from snapshot
@ -75,5 +76,9 @@ jobs:
run: | run: |
aws lightsail delete-instance \ aws lightsail delete-instance \
--instance-name ${{ env.OLD_INSTANCE_NAME }} --instance-name ${{ env.OLD_INSTANCE_NAME }}
- name: Demo Reset Error Handling
if: ${{ failure() }}
run: |
curl -X POST -H "Content-Type: application/json" -d '{"msg_type":"text","content":{"text":"Demo Reset Error"}}' ${{ secrets.SSH_ROBOT_URL }}

46
.github/workflows/publish_npm.yaml vendored Normal file
View File

@ -0,0 +1,46 @@
name: publish npm
on:
push:
tags:
- v*.*.*
workflow_dispatch:
permissions:
contents: write
jobs:
publish-npm:
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 0
- uses: actions/setup-node@v3
with:
node-version: 16
registry-url: https://registry.npmjs.org/
- run: git tag --sort=-creatordate | head -n 1
- name: Get version
id: get_version
run: echo "VERSION=$(git tag --sort=-creatordate | head -n 1)" >> $GITHUB_OUTPUT
- name: Get commit id
id: get_commit_id
run: echo "COMMIT_ID=$( git rev-parse --short "$GITHUB_SHA" )" >> $GITHUB_OUTPUT
- run: echo "${{ steps.get_version.outputs.VERSION }}-${{ steps.get_commit_id.outputs.COMMIT_ID }}"
- name: Set version
run: |
sudo apt-get install jq
jq '.version="${{ steps.get_version.outputs.VERSION }}-${{ steps.get_commit_id.outputs.COMMIT_ID }}"' package.json > package.json.new
mv package.json.new package.json
- name: Generate SDK
run: |
npm cache clean --force
npm install @openapitools/openapi-generator-cli -g
- run: npm i
- run: npm run start
- run: npm publish --access public
env:
NODE_AUTH_TOKEN: ${{secrets.npm_token}}

View File

@ -2,7 +2,9 @@ name: Auto Publish Website
on: on:
push: push:
branches: branches:
- community - main
workflow_dispatch:
permissions: permissions:
contents: write contents: write
jobs: jobs:
@ -44,7 +46,7 @@ jobs:
with: with:
# either 'goreleaser' (default) or 'goreleaser-pro' # either 'goreleaser' (default) or 'goreleaser-pro'
distribution: goreleaser distribution: goreleaser
version: latest version: 1.14.1
args: release --rm-dist --snapshot args: release --rm-dist --snapshot
env: env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

View File

@ -59,6 +59,22 @@ paths:
$ref: "#/components/responses/GetHealthPortsOK" $ref: "#/components/responses/GetHealthPortsOK"
"500": "500":
$ref: "#/components/responses/ResponseInternalServerError" $ref: "#/components/responses/ResponseInternalServerError"
/health/logs:
get:
tags:
- Health methods
summary: Get log
operationId: getHealthlogs
responses:
"200":
description: OK
content:
application/octet-stream:
schema:
type: string
format: binary
"500":
$ref: "#/components/responses/ResponseInternalServerError"
/health/logs: /health/logs:
get: get:
@ -89,6 +105,52 @@ paths:
$ref: "#/components/responses/ResponseOK" $ref: "#/components/responses/ResponseOK"
"500": "500":
$ref: "#/components/responses/ResponseInternalServerError" $ref: "#/components/responses/ResponseInternalServerError"
/zt/info:
get:
tags:
- Zerotier methods
summary: Get Zerotier info
description: |-
Get Zerotier info.
operationId: getZerotierInfo
responses:
"200":
$ref: "#/components/responses/GetZTInfoOK"
"500":
$ref: "#/components/responses/ResponseInternalServerError"
/zt/{network_id}/status:
put:
tags:
- Zerotier methods
summary: Set Zerotier network status
description: |-
Set Zerotier network status.
operationId: setZerotierNetworkStatus
parameters:
- name: network_id
in: path
description: network id
required: true
schema:
type: string
requestBody:
content:
application/json:
schema:
type: object
properties:
status:
enum:
- online
- offline
type: string
example: "online"
responses:
"200":
$ref: "#/components/responses/GetZTInfoOK"
"500":
$ref: "#/components/responses/ResponseInternalServerError"
components: components:
securitySchemes: securitySchemes:
access_token: access_token:
@ -132,6 +194,13 @@ components:
- properties: - properties:
data: data:
$ref: "#/components/schemas/HealthPorts" $ref: "#/components/schemas/HealthPorts"
GetZTInfoOK:
description: OK
content:
application/json:
schema:
$ref: "#/components/schemas/ZTInfo"
schemas: schemas:
BaseResponse: BaseResponse:
@ -169,3 +238,14 @@ components:
type: integer type: integer
example: 53 example: 53
x-go-name: UDP x-go-name: UDP
ZTInfo:
properties:
id:
type: string
example: "1234567890"
name:
type: string
example: "CasaOS"
status:
type: string
example: "online"

View File

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

View File

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

View File

@ -8,10 +8,12 @@ import (
"compress/gzip" "compress/gzip"
"encoding/base64" "encoding/base64"
"fmt" "fmt"
"net/http"
"net/url" "net/url"
"path" "path"
"strings" "strings"
"github.com/deepmap/oapi-codegen/pkg/runtime"
"github.com/getkin/kin-openapi/openapi3" "github.com/getkin/kin-openapi/openapi3"
"github.com/labstack/echo/v4" "github.com/labstack/echo/v4"
) )
@ -20,6 +22,12 @@ const (
Access_tokenScopes = "access_token.Scopes" Access_tokenScopes = "access_token.Scopes"
) )
// Defines values for SetZerotierNetworkStatusJSONBodyStatus.
const (
Offline SetZerotierNetworkStatusJSONBodyStatus = "offline"
Online SetZerotierNetworkStatusJSONBodyStatus = "online"
)
// BaseResponse defines model for BaseResponse. // BaseResponse defines model for BaseResponse.
type BaseResponse struct { type BaseResponse struct {
// Message message returned by server side if there is any // Message message returned by server side if there is any
@ -38,6 +46,13 @@ type HealthServices struct {
Running *[]string `json:"running,omitempty"` Running *[]string `json:"running,omitempty"`
} }
// ZTInfo defines model for ZTInfo.
type ZTInfo struct {
Id *string `json:"id,omitempty"`
Name *string `json:"name,omitempty"`
Status *string `json:"status,omitempty"`
}
// GetHealthPortsOK defines model for GetHealthPortsOK. // GetHealthPortsOK defines model for GetHealthPortsOK.
type GetHealthPortsOK struct { type GetHealthPortsOK struct {
Data *HealthPorts `json:"data,omitempty"` Data *HealthPorts `json:"data,omitempty"`
@ -54,12 +69,26 @@ type GetHealthServicesOK struct {
Message *string `json:"message,omitempty"` Message *string `json:"message,omitempty"`
} }
// GetZTInfoOK defines model for GetZTInfoOK.
type GetZTInfoOK = ZTInfo
// ResponseInternalServerError defines model for ResponseInternalServerError. // ResponseInternalServerError defines model for ResponseInternalServerError.
type ResponseInternalServerError = BaseResponse type ResponseInternalServerError = BaseResponse
// ResponseOK defines model for ResponseOK. // ResponseOK defines model for ResponseOK.
type ResponseOK = BaseResponse type ResponseOK = BaseResponse
// SetZerotierNetworkStatusJSONBody defines parameters for SetZerotierNetworkStatus.
type SetZerotierNetworkStatusJSONBody struct {
Status *SetZerotierNetworkStatusJSONBodyStatus `json:"status,omitempty"`
}
// SetZerotierNetworkStatusJSONBodyStatus defines parameters for SetZerotierNetworkStatus.
type SetZerotierNetworkStatusJSONBodyStatus string
// SetZerotierNetworkStatusJSONRequestBody defines body for SetZerotierNetworkStatus for application/json ContentType.
type SetZerotierNetworkStatusJSONRequestBody SetZerotierNetworkStatusJSONBody
// ServerInterface represents all server handlers. // ServerInterface represents all server handlers.
type ServerInterface interface { type ServerInterface interface {
// Test file methods // Test file methods
@ -74,6 +103,12 @@ type ServerInterface interface {
// Get service status // Get service status
// (GET /health/services) // (GET /health/services)
GetHealthServices(ctx echo.Context) error GetHealthServices(ctx echo.Context) error
// Get Zerotier info
// (GET /zt/info)
GetZerotierInfo(ctx echo.Context) error
// Set Zerotier network status
// (PUT /zt/{network_id}/status)
SetZerotierNetworkStatus(ctx echo.Context, networkId string) error
} }
// ServerInterfaceWrapper converts echo contexts to parameters. // ServerInterfaceWrapper converts echo contexts to parameters.
@ -125,6 +160,35 @@ func (w *ServerInterfaceWrapper) GetHealthServices(ctx echo.Context) error {
return err return err
} }
// GetZerotierInfo converts echo context to params.
func (w *ServerInterfaceWrapper) GetZerotierInfo(ctx echo.Context) error {
var err error
ctx.Set(Access_tokenScopes, []string{""})
// Invoke the callback with all the unmarshalled arguments
err = w.Handler.GetZerotierInfo(ctx)
return err
}
// SetZerotierNetworkStatus converts echo context to params.
func (w *ServerInterfaceWrapper) SetZerotierNetworkStatus(ctx echo.Context) error {
var err error
// ------------- Path parameter "network_id" -------------
var networkId string
err = runtime.BindStyledParameterWithLocation("simple", false, "network_id", runtime.ParamLocationPath, ctx.Param("network_id"), &networkId)
if err != nil {
return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter network_id: %s", err))
}
ctx.Set(Access_tokenScopes, []string{""})
// Invoke the callback with all the unmarshalled arguments
err = w.Handler.SetZerotierNetworkStatus(ctx, networkId)
return err
}
// This is a simple interface which specifies echo.Route addition functions which // This is a simple interface which specifies echo.Route addition functions which
// are present on both echo.Echo and echo.Group, since we want to allow using // are present on both echo.Echo and echo.Group, since we want to allow using
// either of them for path registration // either of them for path registration
@ -157,31 +221,36 @@ func RegisterHandlersWithBaseURL(router EchoRouter, si ServerInterface, baseURL
router.GET(baseURL+"/health/logs", wrapper.GetHealthlogs) router.GET(baseURL+"/health/logs", wrapper.GetHealthlogs)
router.GET(baseURL+"/health/ports", wrapper.GetHealthPorts) router.GET(baseURL+"/health/ports", wrapper.GetHealthPorts)
router.GET(baseURL+"/health/services", wrapper.GetHealthServices) router.GET(baseURL+"/health/services", wrapper.GetHealthServices)
router.GET(baseURL+"/zt/info", wrapper.GetZerotierInfo)
router.PUT(baseURL+"/zt/:network_id/status", wrapper.SetZerotierNetworkStatus)
} }
// Base64 encoded, gzipped, json marshaled Swagger object // Base64 encoded, gzipped, json marshaled Swagger object
var swaggerSpec = []string{ var swaggerSpec = []string{
"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",
"DgAA", "vBc9jixrJDqqLMe3dLk2wJcWzyc6qcOVESurHplOuhXa79oZ2BbsZCXYHz70ZDFXpUJVAANSc3NdL7LI",
"qxMZeBfnzo+Vh1vhbebgU6URksXtYrXBbW5nYx8MxC9tMn/QNWzdBnfMqqkKJ+7SqtrZrPk3Du5jZJcj",
"dvoRYm6t7be2qm6Z8zvWV8enN9O87tDPxm5K/EXSL4MKcxnJ8GKv9WXSBbQFNhfJk9Oj10c7q0Wx0fV1",
"cNcHa2exK3S1yyo9QFuVvl4b9/vWKb61wYzrfwMAAP//9tkexLESAAA=",
} }
// GetSwagger returns the content of the embedded swagger specification file // GetSwagger returns the content of the embedded swagger specification file

View File

@ -73,4 +73,5 @@ type BaseInfo struct {
Hash string `json:"i"` Hash string `json:"i"`
Version string `json:"v"` Version string `json:"v"`
Channel string `json:"c,omitempty"` Channel string `json:"c,omitempty"`
DriveModel string `json:"m,omitempty"`
} }

View File

@ -23,3 +23,14 @@ type Path struct {
Write bool `json:"write"` Write bool `json:"write"`
Extensions map[string]interface{} `json:"extensions"` Extensions map[string]interface{} `json:"extensions"`
} }
type DeviceInfo struct {
LanIpv4 []string `json:"lan_ipv4"`
Port int `json:"port"`
DeviceName string `json:"device_name"`
DeviceModel string `json:"device_model"`
DeviceSN string `json:"device_sn"`
Initialized bool `json:"initialized"`
OS_Version string `json:"os_version"`
Hash string `json:"hash"`
}

View File

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

View File

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

View File

@ -0,0 +1,78 @@
package httper
import (
"fmt"
"io/ioutil"
"net/http"
"strings"
)
func ZTGet(url string) ([]byte, error) {
port, err := ioutil.ReadFile("/var/lib/zerotier-one/zerotier-one.port")
if err != nil {
return nil, err
}
// Build the target URL
targetURL := fmt.Sprintf("http://localhost:%s%s", strings.TrimSpace(string(port)), url)
// Create a new request
req, err := http.NewRequest("GET", targetURL, nil)
if err != nil {
return nil, err
}
// Add the X-ZT1-AUTH header
authToken, err := ioutil.ReadFile("/var/lib/zerotier-one/authtoken.secret")
if err != nil {
return nil, err
}
req.Header.Set("X-ZT1-AUTH", strings.TrimSpace(string(authToken)))
client := http.Client{}
resp, err := client.Do(req)
if err != nil {
return nil, err
}
defer resp.Body.Close()
respBody, err := ioutil.ReadAll(resp.Body)
if err != nil {
return nil, err
}
return respBody, nil
}
func ZTPost(url string, body string) ([]byte, error) {
port, err := ioutil.ReadFile("/var/lib/zerotier-one/zerotier-one.port")
if err != nil {
return nil, err
}
// Build the target URL
targetURL := fmt.Sprintf("http://localhost:%s%s", strings.TrimSpace(string(port)), url)
// Create a new request
req, err := http.NewRequest("POST", targetURL, strings.NewReader(body))
if err != nil {
return nil, err
}
// Add the X-ZT1-AUTH header
authToken, err := ioutil.ReadFile("/var/lib/zerotier-one/authtoken.secret")
if err != nil {
return nil, err
}
req.Header.Set("X-ZT1-AUTH", strings.TrimSpace(string(authToken)))
client := http.Client{}
resp, err := client.Do(req)
if err != nil {
return nil, err
}
defer resp.Body.Close()
respBody, err := ioutil.ReadAll(resp.Body)
if err != nil {
return nil, err
}
return respBody, nil
}

View File

@ -1,6 +1,7 @@
package ip_helper package ip_helper
import ( import (
"fmt"
"net" "net"
"strings" "strings"
@ -56,7 +57,30 @@ func GetDeviceAllIP(port string) []string {
} }
return address return address
} }
func GetDeviceAllIPv4() map[string]string {
address := make(map[string]string)
addrs, err := net.Interfaces()
if err != nil {
return address
}
for _, a := range addrs {
if a.Flags&net.FlagLoopback != 0 || a.Flags&net.FlagUp == 0 {
continue
}
addrs, err := a.Addrs()
if err != nil {
fmt.Println("Error:", err)
continue
}
for _, addr := range addrs {
if ipnet, ok := addr.(*net.IPNet); ok && !ipnet.IP.IsLoopback() && ipnet.IP.To4() != nil {
address[a.Name] = ipnet.IP.String()
}
}
}
return address
}
func HasLocalIP(ip net.IP) bool { func HasLocalIP(ip net.IP) bool {
if ip.IsLoopback() { if ip.IsLoopback() {
return true return true

View File

@ -17,6 +17,7 @@ import (
"strings" "strings"
"time" "time"
file1 "github.com/IceWhaleTech/CasaOS-Common/utils/file"
"github.com/IceWhaleTech/CasaOS-Common/utils/logger" "github.com/IceWhaleTech/CasaOS-Common/utils/logger"
"github.com/IceWhaleTech/CasaOS/common" "github.com/IceWhaleTech/CasaOS/common"
"github.com/IceWhaleTech/CasaOS/model" "github.com/IceWhaleTech/CasaOS/model"
@ -24,6 +25,7 @@ import (
"github.com/IceWhaleTech/CasaOS/pkg/samba" "github.com/IceWhaleTech/CasaOS/pkg/samba"
"github.com/IceWhaleTech/CasaOS/pkg/utils/encryption" "github.com/IceWhaleTech/CasaOS/pkg/utils/encryption"
"github.com/IceWhaleTech/CasaOS/pkg/utils/file" "github.com/IceWhaleTech/CasaOS/pkg/utils/file"
v1 "github.com/IceWhaleTech/CasaOS/route/v1"
"github.com/IceWhaleTech/CasaOS/service" "github.com/IceWhaleTech/CasaOS/service"
"go.uber.org/zap" "go.uber.org/zap"
) )
@ -31,6 +33,7 @@ import (
func InitFunction() { func InitFunction() {
go InitNetworkMount() go InitNetworkMount()
go InitInfo() go InitInfo()
go InitZerotier()
} }
func InitInfo() { func InitInfo() {
@ -51,6 +54,12 @@ func InitInfo() {
} }
mb.Hash = encryption.GetMD5ByStr(mac) mb.Hash = encryption.GetMD5ByStr(mac)
mb.Version = common.VERSION mb.Version = common.VERSION
osRelease, _ := file1.ReadOSRelease()
mb.DriveModel = osRelease["MODEL"]
if len(mb.DriveModel) == 0 {
mb.DriveModel = "Casa"
}
os.Remove(config.AppInfo.DBPath + "/baseinfo.conf") os.Remove(config.AppInfo.DBPath + "/baseinfo.conf")
by, err := json.Marshal(mb) by, err := json.Marshal(mb)
if err != nil { if err != nil {
@ -98,3 +107,6 @@ func InitNetworkMount() {
logger.Error("mount storage err", zap.Any("err", err)) logger.Error("mount storage err", zap.Any("err", err))
} }
} }
func InitZerotier() {
v1.CheckNetwork()
}

View File

@ -7,6 +7,7 @@ import (
"github.com/IceWhaleTech/CasaOS-Common/external" "github.com/IceWhaleTech/CasaOS-Common/external"
"github.com/IceWhaleTech/CasaOS-Common/middleware" "github.com/IceWhaleTech/CasaOS-Common/middleware"
"github.com/IceWhaleTech/CasaOS-Common/utils/jwt" "github.com/IceWhaleTech/CasaOS-Common/utils/jwt"
"github.com/IceWhaleTech/CasaOS/common"
"github.com/IceWhaleTech/CasaOS/pkg/config" "github.com/IceWhaleTech/CasaOS/pkg/config"
v1 "github.com/IceWhaleTech/CasaOS/route/v1" v1 "github.com/IceWhaleTech/CasaOS/route/v1"
@ -35,17 +36,16 @@ func InitV1Router() *gin.Engine {
r.GET("/v1/sys/debug", v1.GetSystemConfigDebug) // //debug r.GET("/v1/sys/debug", v1.GetSystemConfigDebug) // //debug
r.GET("/v1/sys/version/check", v1.GetSystemCheckVersion) r.GET("/v1/sys/version/check", v1.GetSystemCheckVersion)
r.GET("/v1/sys/version/current", func(ctx *gin.Context) {
ctx.String(200, common.VERSION)
})
r.GET("/ping", func(ctx *gin.Context) { r.GET("/ping", func(ctx *gin.Context) {
ctx.String(200, "pong") ctx.String(200, "pong")
}) })
r.GET("/v1/recover/:type", v1.GetRecoverStorage) r.GET("/v1/recover/:type", v1.GetRecoverStorage)
v1Group := r.Group("/v1") v1Group := r.Group("/v1")
// r.Any("/v1/test", v1.CheckNetwork)
v1Group.Use(jwt.ExceptLocalhost( v1Group.Use(jwt.ExceptLocalhost(func() (*ecdsa.PublicKey, error) { return external.GetPublicKey(config.CommonInfo.RuntimePath) }))
func() (*ecdsa.PublicKey, error) {
return external.GetPublicKey(config.CommonInfo.RuntimePath)
},
))
{ {
v1SysGroup := v1Group.Group("/sys") v1SysGroup := v1Group.Group("/sys")
@ -79,6 +79,7 @@ func InitV1Router() *gin.Engine {
// v1SysGroup.PUT("/port", v1.PutCasaOSPort) // v1SysGroup.PUT("/port", v1.PutCasaOSPort)
v1SysGroup.GET("/proxy", v1.GetSystemProxy) v1SysGroup.GET("/proxy", v1.GetSystemProxy)
v1SysGroup.PUT("/state/:state", v1.PutSystemState) v1SysGroup.PUT("/state/:state", v1.PutSystemState)
v1SysGroup.GET("/entry", v1.GetSystemEntry)
} }
v1PortGroup := v1Group.Group("/port") v1PortGroup := v1Group.Group("/port")
v1PortGroup.Use() v1PortGroup.Use()
@ -86,79 +87,78 @@ func InitV1Router() *gin.Engine {
v1PortGroup.GET("/", v1.GetPort) // app/port v1PortGroup.GET("/", v1.GetPort) // app/port
v1PortGroup.GET("/state/:port", v1.PortCheck) // app/check/:port v1PortGroup.GET("/state/:port", v1.PortCheck) // app/check/:port
} }
// v1FileGroup := v1Group.Group("/file")
// v1FileGroup.Use()
// {
// 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
v1FileGroup := v1Group.Group("/file") // // File uploads need to be handled separately, and will not be modified here
v1FileGroup.Use() // //v1FileGroup.POST("/upload", v1.PostFileUpload)
{ // v1FileGroup.POST("/upload", v1.PostFileUpload)
v1FileGroup.GET("", v1.GetDownloadSingleFile) // download/:path // v1FileGroup.GET("/upload", v1.GetFileUpload)
v1FileGroup.POST("", v1.PostCreateFile) // // v1FileGroup.GET("/download", v1.UserFileDownloadCommonService)
v1FileGroup.PUT("", v1.PutFileContent) // v1FileGroup.GET("/ws", v1.ConnectWebSocket)
v1FileGroup.PUT("/name", v1.RenamePath) // v1FileGroup.GET("/peers", v1.GetPeers)
// file/rename // }
v1FileGroup.GET("/content", v1.GetFilerContent) // file/read // v1CloudGroup := v1Group.Group("/cloud")
// v1CloudGroup.Use()
// {
// v1CloudGroup.GET("", v1.ListStorages)
// v1CloudGroup.DELETE("", v1.UmountStorage)
// }
// v1DriverGroup := v1Group.Group("/driver")
// v1DriverGroup.Use()
// {
// v1DriverGroup.GET("", v1.ListDriverInfo)
// }
// File uploads need to be handled separately, and will not be modified here // v1FolderGroup := v1Group.Group("/folder")
//v1FileGroup.POST("/upload", v1.PostFileUpload) // v1FolderGroup.Use()
v1FileGroup.POST("/upload", v1.PostFileUpload) // {
v1FileGroup.GET("/upload", v1.GetFileUpload) // v1FolderGroup.PUT("/name", v1.RenamePath)
// v1FileGroup.GET("/download", v1.UserFileDownloadCommonService) // v1FolderGroup.GET("", v1.DirPath) ///file/dirpath
v1FileGroup.GET("/ws", v1.ConnectWebSocket) // v1FolderGroup.POST("", v1.MkdirAll) ///file/mkdir
v1FileGroup.GET("/peers", v1.GetPeers) // v1FolderGroup.GET("/size", v1.GetSize)
} // v1FolderGroup.GET("/count", v1.GetFileCount)
v1CloudGroup := v1Group.Group("/cloud") // }
v1CloudGroup.Use() // v1BatchGroup := v1Group.Group("/batch")
{ // v1BatchGroup.Use()
v1CloudGroup.GET("", v1.ListStorages) // {
v1CloudGroup.DELETE("", v1.UmountStorage)
}
v1DriverGroup := v1Group.Group("/driver")
v1DriverGroup.Use()
{
v1DriverGroup.GET("", v1.ListDriverInfo)
}
v1FolderGroup := v1Group.Group("/folder") // v1BatchGroup.DELETE("", v1.DeleteFile) // file/delete
v1FolderGroup.Use() // v1BatchGroup.DELETE("/:id/task", v1.DeleteOperateFileOrDir)
{ // v1BatchGroup.POST("/task", v1.PostOperateFileOrDir) // file/operate
v1FolderGroup.PUT("/name", v1.RenamePath) // v1BatchGroup.GET("", v1.GetDownloadFile)
v1FolderGroup.GET("", v1.DirPath) ///file/dirpath // }
v1FolderGroup.POST("", v1.MkdirAll) ///file/mkdir
v1FolderGroup.GET("/size", v1.GetSize)
v1FolderGroup.GET("/count", v1.GetFileCount)
}
v1BatchGroup := v1Group.Group("/batch")
v1BatchGroup.Use()
{
v1BatchGroup.DELETE("", v1.DeleteFile) // file/delete
v1BatchGroup.DELETE("/:id/task", v1.DeleteOperateFileOrDir)
v1BatchGroup.POST("/task", v1.PostOperateFileOrDir) // file/operate
v1BatchGroup.GET("", v1.GetDownloadFile)
}
v1ImageGroup := v1Group.Group("/image") v1ImageGroup := v1Group.Group("/image")
v1ImageGroup.Use() v1ImageGroup.Use()
{ {
v1ImageGroup.GET("", v1.GetFileImage) v1ImageGroup.GET("", v1.GetFileImage)
} }
v1SambaGroup := v1Group.Group("/samba") // v1SambaGroup := v1Group.Group("/samba")
v1SambaGroup.Use() // v1SambaGroup.Use()
{ // {
v1ConnectionsGroup := v1SambaGroup.Group("/connections") // v1ConnectionsGroup := v1SambaGroup.Group("/connections")
v1ConnectionsGroup.Use() // v1ConnectionsGroup.Use()
{ // {
v1ConnectionsGroup.GET("", v1.GetSambaConnectionsList) // v1ConnectionsGroup.GET("", v1.GetSambaConnectionsList)
v1ConnectionsGroup.POST("", v1.PostSambaConnectionsCreate) // v1ConnectionsGroup.POST("", v1.PostSambaConnectionsCreate)
v1ConnectionsGroup.DELETE("/:id", v1.DeleteSambaConnections) // v1ConnectionsGroup.DELETE("/:id", v1.DeleteSambaConnections)
} // }
v1SharesGroup := v1SambaGroup.Group("/shares") // v1SharesGroup := v1SambaGroup.Group("/shares")
v1SharesGroup.Use() // v1SharesGroup.Use()
{ // {
v1SharesGroup.GET("", v1.GetSambaSharesList) // v1SharesGroup.GET("", v1.GetSambaSharesList)
v1SharesGroup.POST("", v1.PostSambaSharesCreate) // v1SharesGroup.POST("", v1.PostSambaSharesCreate)
v1SharesGroup.DELETE("/:id", v1.DeleteSambaShares) // v1SharesGroup.DELETE("/:id", v1.DeleteSambaShares)
v1SharesGroup.GET("/status", v1.GetSambaStatus) // v1SharesGroup.GET("/status", v1.GetSambaStatus)
} // }
} // }
v1NotifyGroup := v1Group.Group("/notify") v1NotifyGroup := v1Group.Group("/notify")
v1NotifyGroup.Use() v1NotifyGroup.Use()
{ {
@ -173,6 +173,11 @@ func InitV1Router() *gin.Engine {
v1OtherGroup.GET("/search", v1.GetSearchResult) v1OtherGroup.GET("/search", v1.GetSearchResult)
} }
v1ZerotierGroup := v1Group.Group("/zt")
v1ZerotierGroup.Use()
{
v1ZerotierGroup.Any("/*url", v1.ZerotierProxy)
}
} }
return r return r

View File

@ -2,6 +2,7 @@ package v1
import ( import (
"bytes" "bytes"
"encoding/json"
"fmt" "fmt"
"io" "io"
"io/ioutil" "io/ioutil"
@ -24,6 +25,7 @@ import (
model2 "github.com/IceWhaleTech/CasaOS/service/model" model2 "github.com/IceWhaleTech/CasaOS/service/model"
"github.com/IceWhaleTech/CasaOS/types" "github.com/IceWhaleTech/CasaOS/types"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"github.com/tidwall/gjson"
) )
// @Summary check version // @Summary check version
@ -371,3 +373,13 @@ func PortCheck(c *gin.Context) {
t := c.DefaultQuery("type", "tcp") t := c.DefaultQuery("type", "tcp")
c.JSON(common_err.SUCCESS, &model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: port.IsPortAvailable(p, t)}) c.JSON(common_err.SUCCESS, &model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: port.IsPortAvailable(p, t)})
} }
func GetSystemEntry(c *gin.Context) {
entry := service.MyService.System().GetSystemEntry()
str := json.RawMessage(entry)
if !gjson.ValidBytes(str) {
c.JSON(http.StatusInternalServerError, model.Result{Success: common_err.SERVICE_ERROR, Message: entry, Data: json.RawMessage("[]")})
return
}
c.JSON(http.StatusOK, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: str})
}

313
route/v1/zerotier.go Normal file
View File

@ -0,0 +1,313 @@
package v1
import (
"fmt"
"io/ioutil"
"math/rand"
"net"
"net/http"
"strings"
"time"
"github.com/IceWhaleTech/CasaOS-Common/utils/logger"
"github.com/IceWhaleTech/CasaOS/common"
"github.com/IceWhaleTech/CasaOS/pkg/utils/httper"
"github.com/gin-gonic/gin"
"github.com/tidwall/gjson"
"go.uber.org/zap"
)
func ZerotierProxy(c *gin.Context) {
// Read the port number from the file
w := c.Writer
r := c.Request
port, err := ioutil.ReadFile("/var/lib/zerotier-one/zerotier-one.port")
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
// Get the request path and remove "/zt"
path := strings.TrimPrefix(r.URL.Path, "/v1/zt")
fmt.Println(path)
// Build the target URL
targetURL := fmt.Sprintf("http://localhost:%s%s", strings.TrimSpace(string(port)), path)
// Create a new request
req, err := http.NewRequest(r.Method, targetURL, r.Body)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
// Add the X-ZT1-AUTH header
authToken, err := ioutil.ReadFile("/var/lib/zerotier-one/authtoken.secret")
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
req.Header.Set("X-ZT1-AUTH", strings.TrimSpace(string(authToken)))
copyHeaders(req.Header, r.Header)
client := http.Client{}
resp, err := client.Do(req)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
defer resp.Body.Close()
copyHeaders(w.Header(), resp.Header)
respBody, err := ioutil.ReadAll(resp.Body)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
// Return the response to the client
w.WriteHeader(resp.StatusCode)
w.Write(respBody)
}
func copyHeaders(destination, source http.Header) {
for key, values := range source {
for _, value := range values {
destination.Add(key, value)
}
}
}
func CheckNetwork() {
logger.Info("start check network")
respBody, err := httper.ZTGet("/controller/network")
if err != nil {
logger.Error("get network error", zap.Error(err))
return
}
networkId := ""
address := ""
networkNames := gjson.ParseBytes(respBody).Array()
routers := ""
for _, v := range networkNames {
res, err := httper.ZTGet("/controller/network/" + v.Str)
if err != nil {
logger.Error("get network error", zap.Error(err))
return
}
name := gjson.GetBytes(res, "name").Str
if name == common.RANW_NAME {
networkId = gjson.GetBytes(res, "id").Str
routers = gjson.GetBytes(res, "routes.0.target").Str
break
}
}
ip, s, e, c := getZTIP(routers)
logger.Info("ip", zap.Any("ip", ip))
if len(networkId) == 0 {
if len(address) == 0 {
address = GetAddress()
}
networkId = CreateNet(address, s, e, c)
}
res, err := httper.ZTGet("/network")
if err != nil {
logger.Error("get network error", zap.Error(err))
return
}
joined := false
networks := gjson.GetBytes(res, "#.id").Array()
for _, v := range networks {
if v.Str == networkId {
joined = true
break
}
}
logger.Info("joined", zap.Any("joined", joined))
if !joined {
JoinAndUpdateNet(address, networkId, ip)
}
}
func GetAddress() string {
nodeRes, err := httper.ZTGet("/status")
if err != nil {
logger.Error("get status error", zap.Error(err))
return ""
}
return gjson.GetBytes(nodeRes, "address").String()
}
func JoinAndUpdateNet(address, networkId, ip string) {
logger.Info("start join network", zap.Any("ip", ip))
_, err := httper.ZTPost("/network/"+networkId, "")
if err != nil {
logger.Error(" get network error", zap.Error(err))
return
}
if len(address) == 0 {
address = GetAddress()
}
b := `{
"authorized": true,
"activeBridge": true,
"ipAssignments": [
"` + ip + `"
]
}`
_, err = httper.ZTPost("/controller/network/"+networkId+"/member/"+address, b)
if err != nil {
logger.Error("join network error", zap.Error(err))
return
}
}
func CreateNet(address, s, e, c string) string {
body := `{
"name": "` + common.RANW_NAME + `",
"private": false,
"v4AssignMode": {
"zt": true
},
"ipAssignmentPools": [
{
"ipRangeStart": "` + s + `",
"ipRangeEnd": "` + e + `"
}
],
"routes": [
{
"target": "` + c + `"
}
],
"rules": [
{
"etherType": 2048,
"not": true,
"or": false,
"type": "MATCH_ETHERTYPE"
},
{
"etherType": 2054,
"not": true,
"or": false,
"type": "MATCH_ETHERTYPE"
},
{
"etherType": 34525,
"not": true,
"or": false,
"type": "MATCH_ETHERTYPE"
},
{
"type": "ACTION_DROP"
},
{
"type": "ACTION_ACCEPT"
}
],
"v6AssignMode": {
"rfc4193": true
}
}`
createRes, err := httper.ZTPost("/controller/network/"+address+"______", body)
if err != nil {
logger.Error("post network error", zap.Error(err))
return ""
}
return gjson.GetBytes(createRes, "id").Str
}
func GetZTIPs() []gjson.Result {
res, err := httper.ZTGet("/network")
if err != nil {
logger.Error("get network error", zap.Error(err))
return []gjson.Result{}
}
a := gjson.GetBytes(res, "#.routes.0.target")
return a.Array()
}
func getZTIP(routes string) (ip, start, end, cidr string) {
excluded := GetZTIPs()
cidrs := []string{
"10.147.11.0/24",
"10.147.12.0/24",
"10.147.13.0/24",
"10.147.14.0/24",
"10.147.15.0/24",
"10.147.16.0/24",
"10.147.17.0/24",
"10.147.18.0/24",
"10.147.19.0/24",
"10.147.20.0/24",
"10.240.0.0/16",
"10.241.0.0/16",
"10.242.0.0/16",
"10.243.0.0/16",
"10.244.0.0/16",
"10.245.0.0/16",
"10.246.0.0/16",
"10.247.0.0/16",
"10.248.0.0/16",
"10.249.0.0/16",
"172.21.0.0/16",
"172.22.0.0/16",
"172.23.0.0/16",
"172.24.0.0/16",
"172.25.0.0/16",
"172.26.0.0/16",
"172.27.0.0/16",
"172.28.0.0/16",
"172.29.0.0/16",
"172.30.0.0/16",
}
filteredCidrs := make([]string, 0)
if len(routes) > 0 {
filteredCidrs = append(filteredCidrs, routes)
} else {
for _, cidr := range cidrs {
isExcluded := false
for _, excludedIP := range excluded {
if cidr == excludedIP.Str {
isExcluded = true
break
}
}
if !isExcluded {
filteredCidrs = append(filteredCidrs, cidr)
}
}
}
rnd := rand.New(rand.NewSource(time.Now().UnixNano()))
ip = ""
if len(filteredCidrs) > 0 {
randomIndex := rnd.Intn(len(filteredCidrs))
selectedCIDR := filteredCidrs[randomIndex]
_, ipNet, err := net.ParseCIDR(selectedCIDR)
if err != nil {
logger.Error("ParseCIDR error", zap.Error(err))
return
}
cidr = selectedCIDR
startIP := ipNet.IP
endIP := make(net.IP, len(startIP))
copy(endIP, startIP)
for i := range startIP {
endIP[i] |= ^ipNet.Mask[i]
}
startIP[3] = 1
start = startIP.String()
endIP[3] = 254
end = endIP.String()
ipt := ipNet
ipt.IP[3] = 1
ip = ipt.IP.String()
return
} else {
logger.Error("No available CIDR found")
}
return
}

View File

@ -29,8 +29,6 @@ var (
V2APIPath string V2APIPath string
V2DocPath string V2DocPath string
V3FilePath string
V4DirPath string
) )
func init() { func init() {
@ -48,8 +46,6 @@ func init() {
V2APIPath = strings.TrimRight(u.Path, "/") V2APIPath = strings.TrimRight(u.Path, "/")
V2DocPath = "/doc" + V2APIPath V2DocPath = "/doc" + V2APIPath
V3FilePath = "/v3/file"
V4DirPath = "/v4/dir"
} }
func InitV2Router() http.Handler { func InitV2Router() http.Handler {
@ -73,13 +69,10 @@ func InitV2Router() http.Handler {
e.Use(echo_middleware.JWTWithConfig(echo_middleware.JWTConfig{ e.Use(echo_middleware.JWTWithConfig(echo_middleware.JWTConfig{
Skipper: func(c echo.Context) bool { Skipper: func(c echo.Context) bool {
return c.RealIP() == "::1" || c.RealIP() == "127.0.0.1" return c.RealIP() == "::1" || c.RealIP() == "127.0.0.1"
// return true //return true
}, },
ParseTokenFunc: func(token string, c echo.Context) (interface{}, error) { ParseTokenFunc: func(token string, c echo.Context) (interface{}, error) {
// claims, code := jwt.Validate(token) // TODO - needs JWT validation
// if code != common_err.SUCCESS {
// return nil, echo.ErrUnauthorized
// }
valid, claims, err := jwt.Validate(token, func() (*ecdsa.PublicKey, error) { return external.GetPublicKey(config.CommonInfo.RuntimePath) }) valid, claims, err := jwt.Validate(token, func() (*ecdsa.PublicKey, error) { return external.GetPublicKey(config.CommonInfo.RuntimePath) })
if err != nil || !valid { if err != nil || !valid {
return nil, echo.ErrUnauthorized return nil, echo.ErrUnauthorized

74
route/v2/zerotier.go Normal file
View File

@ -0,0 +1,74 @@
package v2
import (
"fmt"
"net/http"
"github.com/IceWhaleTech/CasaOS-Common/utils"
"github.com/IceWhaleTech/CasaOS/codegen"
"github.com/IceWhaleTech/CasaOS/common"
"github.com/IceWhaleTech/CasaOS/pkg/utils/httper"
"github.com/labstack/echo/v4"
"github.com/tidwall/gjson"
)
func (s *CasaOS) SetZerotierNetworkStatus(ctx echo.Context, networkId string) error {
ip := `,"via":"10.147.19.0"`
m := make(map[string]string)
ctx.Bind(&m)
status := m["status"]
if status == "online" {
ip = ``
}
body := `{
"routes": [
{
"target": "10.147.20.0/24"` + ip + `
}
]
}`
res, err := httper.ZTPost("/controller/network/"+networkId, body)
if err != nil {
fmt.Println(err)
return ctx.JSON(http.StatusInternalServerError, codegen.BaseResponse{Message: utils.Ptr(err.Error())})
}
info := codegen.GetZTInfoOK{}
via := gjson.GetBytes(res, "routes.0.via").Str
info.Id = utils.Ptr(gjson.GetBytes(res, "id").Str)
info.Name = utils.Ptr(gjson.GetBytes(res, "name").Str)
if len(via) == 0 {
info.Status = utils.Ptr("online")
} else {
info.Status = utils.Ptr("offline")
}
return ctx.JSON(http.StatusOK, info)
}
func (s *CasaOS) GetZerotierInfo(ctx echo.Context) error {
info := codegen.GetZTInfoOK{}
respBody, err := httper.ZTGet("/controller/network")
if err != nil {
return ctx.JSON(http.StatusInternalServerError, codegen.BaseResponse{Message: utils.Ptr(err.Error())})
}
networkNames := gjson.ParseBytes(respBody).Array()
for _, v := range networkNames {
res, err := httper.ZTGet("/controller/network/" + v.Str)
if err != nil {
fmt.Println(err)
return ctx.JSON(http.StatusInternalServerError, codegen.BaseResponse{Message: utils.Ptr(err.Error())})
}
name := gjson.GetBytes(res, "name").Str
if name == common.RANW_NAME {
via := gjson.GetBytes(res, "routes.0.via").Str
info.Id = utils.Ptr(gjson.GetBytes(res, "id").Str)
info.Name = &name
if len(via) == 0 {
info.Status = utils.Ptr("online")
} else {
info.Status = utils.Ptr("offline")
}
break
}
}
return ctx.JSON(http.StatusOK, info)
}

View File

@ -1,6 +1,7 @@
package service package service
import ( import (
"encoding/json"
"errors" "errors"
"fmt" "fmt"
"io/ioutil" "io/ioutil"
@ -15,10 +16,14 @@ import (
"github.com/IceWhaleTech/CasaOS-Common/utils/file" "github.com/IceWhaleTech/CasaOS-Common/utils/file"
"github.com/IceWhaleTech/CasaOS-Common/utils/logger" "github.com/IceWhaleTech/CasaOS-Common/utils/logger"
"github.com/IceWhaleTech/CasaOS/common"
"github.com/IceWhaleTech/CasaOS/model" "github.com/IceWhaleTech/CasaOS/model"
"github.com/IceWhaleTech/CasaOS/pkg/config" "github.com/IceWhaleTech/CasaOS/pkg/config"
command2 "github.com/IceWhaleTech/CasaOS/pkg/utils/command" command2 "github.com/IceWhaleTech/CasaOS/pkg/utils/command"
"github.com/IceWhaleTech/CasaOS/pkg/utils/common_err" "github.com/IceWhaleTech/CasaOS/pkg/utils/common_err"
"github.com/IceWhaleTech/CasaOS/pkg/utils/httper"
"github.com/IceWhaleTech/CasaOS/pkg/utils/ip_helper"
"github.com/tidwall/gjson"
"go.uber.org/zap" "go.uber.org/zap"
"github.com/shirou/gopsutil/v3/cpu" "github.com/shirou/gopsutil/v3/cpu"
@ -49,6 +54,7 @@ type SystemService interface {
GetDiskInfo() *disk.UsageStat GetDiskInfo() *disk.UsageStat
GetSysInfo() host.InfoStat GetSysInfo() host.InfoStat
GetDeviceTree() string GetDeviceTree() string
GetDeviceInfo() model.DeviceInfo
CreateFile(path string) (int, error) CreateFile(path string) (int, error)
RenameFile(oldF, newF string) (int, error) RenameFile(oldF, newF string) (int, error)
MkdirAll(path string) (int, error) MkdirAll(path string) (int, error)
@ -57,9 +63,117 @@ type SystemService interface {
GetMacAddress() (string, error) GetMacAddress() (string, error)
SystemReboot() error SystemReboot() error
SystemShutdown() error SystemShutdown() error
GetSystemEntry() string
GenreateSystemEntry()
} }
type systemService struct{} type systemService struct{}
func (c *systemService) GetDeviceInfo() model.DeviceInfo {
m := model.DeviceInfo{}
m.OS_Version = common.VERSION
err, portStr := MyService.Gateway().GetPort()
if err != nil {
m.Port = 80
} else {
port := gjson.Get(portStr, "data")
if len(port.Raw) == 0 {
m.Port = 80
} else {
p, err := strconv.Atoi(port.Raw)
if err != nil {
m.Port = 80
} else {
m.Port = p
}
}
}
allIpv4 := ip_helper.GetDeviceAllIPv4()
ip := []string{}
nets := MyService.System().GetNet(true)
for _, n := range nets {
if v, ok := allIpv4[n]; ok {
{
ip = append(ip, v)
}
}
}
m.LanIpv4 = ip
h, err := host.Info() /* */
if err == nil {
m.DeviceName = h.Hostname
}
mb := model.BaseInfo{}
err = json.Unmarshal(file.ReadFullFile(config.AppInfo.DBPath+"/baseinfo.conf"), &mb)
if err == nil {
m.Hash = mb.Hash
}
osRelease, _ := file.ReadOSRelease()
m.DeviceModel = osRelease["MODEL"]
m.DeviceSN = osRelease["SN"]
res := httper.Get("http://127.0.0.1:"+strconv.Itoa(m.Port)+"/v1/users/status", nil)
init := gjson.Get(res, "data.initialized")
m.Initialized, _ = strconv.ParseBool(init.Raw)
return m
}
func (c *systemService) GenreateSystemEntry() {
modelsPath := "/var/lib/casaos/www/modules"
entryFileName := "entry.json"
entryFilePath := filepath.Join(config.AppInfo.DBPath, "db", entryFileName)
file.IsNotExistCreateFile(entryFilePath)
dir, err := os.ReadDir(modelsPath)
if err != nil {
logger.Error("read dir error", zap.Error(err))
return
}
json := "["
for _, v := range dir {
data, err := os.ReadFile(filepath.Join(modelsPath, v.Name(), entryFileName))
if err != nil {
logger.Error("read entry file error", zap.Error(err))
continue
}
json += string(data) + ","
}
json = strings.TrimRight(json, ",")
json += "]"
err = os.WriteFile(entryFilePath, []byte(json), 0666)
if err != nil {
logger.Error("write entry file error", zap.Error(err))
return
}
}
func (c *systemService) GetSystemEntry() string {
modelsPath := "/var/lib/casaos/www/modules"
entryFileName := "entry.json"
dir, err := os.ReadDir(modelsPath)
if err != nil {
logger.Error("read dir error", zap.Error(err))
return ""
}
json := "["
for _, v := range dir {
data, err := os.ReadFile(filepath.Join(modelsPath, v.Name(), entryFileName))
if err != nil {
logger.Error("read entry file error", zap.Error(err))
continue
}
json += string(data) + ","
}
json = strings.TrimRight(json, ",")
json += "]"
if err != nil {
logger.Error("write entry file error", zap.Error(err))
return ""
}
return json
}
func (c *systemService) GetMacAddress() (string, error) { func (c *systemService) GetMacAddress() (string, error) {
interfaces, err := net.Interfaces() interfaces, err := net.Interfaces()
if err != nil { if err != nil {