2023-01-30 22:01:47 +00:00
//go:generate bash -c "mkdir -p codegen && go run github.com/deepmap/oapi-codegen/cmd/oapi-codegen@v1.12.4 -generate types,server,spec -package codegen api/casaos/openapi.yaml > codegen/casaos_api.go"
2023-02-06 07:47:29 +00:00
//go:generate bash -c "mkdir -p codegen/message_bus && go run github.com/deepmap/oapi-codegen/cmd/oapi-codegen@v1.12.4 -generate types,client -package message_bus https://raw.githubusercontent.com/IceWhaleTech/CasaOS-MessageBus/main/api/message_bus/openapi.yaml > codegen/message_bus/api.go"
2021-09-26 02:35:02 +00:00
package main
import (
2023-02-06 07:47:29 +00:00
"context"
2023-01-30 22:01:47 +00:00
_ "embed"
2023-05-15 03:01:21 +00:00
"encoding/base64"
"encoding/json"
2021-09-26 02:35:02 +00:00
"flag"
"fmt"
2022-09-06 06:28:49 +00:00
"net"
2021-10-15 03:43:41 +00:00
"net/http"
2022-10-20 06:25:26 +00:00
"path/filepath"
2023-05-15 03:01:21 +00:00
"strconv"
2021-10-15 03:43:41 +00:00
"time"
2022-10-28 21:34:18 +00:00
"github.com/IceWhaleTech/CasaOS-Common/model"
2022-12-15 23:31:06 +00:00
"github.com/IceWhaleTech/CasaOS-Common/utils/constants"
2022-11-29 17:17:14 +00:00
"github.com/IceWhaleTech/CasaOS-Common/utils/logger"
2023-05-15 03:01:21 +00:00
"github.com/tidwall/gjson"
"golang.org/x/net/websocket"
2023-01-30 22:01:47 +00:00
util_http "github.com/IceWhaleTech/CasaOS-Common/utils/http"
2023-02-06 07:47:29 +00:00
"github.com/IceWhaleTech/CasaOS/codegen/message_bus"
"github.com/IceWhaleTech/CasaOS/common"
2023-05-15 03:01:21 +00:00
model2 "github.com/IceWhaleTech/CasaOS/model"
2021-10-29 10:37:27 +00:00
"github.com/IceWhaleTech/CasaOS/pkg/cache"
2021-09-27 06:17:36 +00:00
"github.com/IceWhaleTech/CasaOS/pkg/config"
"github.com/IceWhaleTech/CasaOS/pkg/sqlite"
2022-12-15 23:31:06 +00:00
"github.com/IceWhaleTech/CasaOS/pkg/utils/command"
2022-10-20 06:25:26 +00:00
"github.com/IceWhaleTech/CasaOS/pkg/utils/file"
2021-09-27 06:17:36 +00:00
"github.com/IceWhaleTech/CasaOS/route"
"github.com/IceWhaleTech/CasaOS/service"
2022-10-20 06:25:26 +00:00
"github.com/coreos/go-systemd/daemon"
"go.uber.org/zap"
2021-10-29 10:37:27 +00:00
2023-03-19 00:55:51 +00:00
"github.com/robfig/cron/v3"
2021-09-26 02:35:02 +00:00
"gorm.io/gorm"
)
2022-09-06 06:28:49 +00:00
const LOCALHOST = "127.0.0.1"
2021-09-26 02:35:02 +00:00
var sqliteDB * gorm . DB
2022-10-20 06:25:26 +00:00
var (
2022-12-29 23:24:36 +00:00
commit = "private build"
date = "private build"
2023-01-30 22:01:47 +00:00
//go:embed api/index.html
_docHTML string
//go:embed api/casaos/openapi.yaml
_docYAML string
2022-10-20 06:25:26 +00:00
configFlag = flag . String ( "c" , "" , "config address" )
dbFlag = flag . String ( "db" , "" , "db path" )
versionFlag = flag . Bool ( "v" , false , "version" )
)
2021-10-22 08:49:09 +00:00
2021-09-26 02:35:02 +00:00
func init ( ) {
flag . Parse ( )
2022-09-06 06:28:49 +00:00
if * versionFlag {
2023-02-06 07:47:29 +00:00
fmt . Println ( "v" + common . VERSION )
2022-08-15 03:37:21 +00:00
return
}
2022-12-29 23:24:36 +00:00
println ( "git commit:" , commit )
println ( "build date:" , date )
2021-09-26 02:35:02 +00:00
config . InitSetup ( * configFlag )
2022-08-15 03:37:21 +00:00
2022-11-29 17:17:14 +00:00
logger . LogInit ( config . AppInfo . LogPath , config . AppInfo . LogSaveName , config . AppInfo . LogFileExt )
2022-05-05 05:46:55 +00:00
if len ( * dbFlag ) == 0 {
2022-06-29 03:09:58 +00:00
* dbFlag = config . AppInfo . DBPath + "/db"
2022-04-06 04:10:51 +00:00
}
2022-08-15 03:37:21 +00:00
2022-05-05 05:46:55 +00:00
sqliteDB = sqlite . GetDb ( * dbFlag )
2022-10-20 06:25:26 +00:00
// gredis.GetRedisConn(config.RedisInfo),
2022-08-15 03:37:21 +00:00
2023-02-06 07:47:29 +00:00
service . MyService = service . NewService ( sqliteDB , config . CommonInfo . RuntimePath )
2022-08-15 03:37:21 +00:00
2021-10-29 10:37:27 +00:00
service . Cache = cache . Init ( )
2022-03-16 07:41:14 +00:00
2022-11-16 09:30:19 +00:00
service . GetCPUThermalZone ( )
2023-03-06 08:10:19 +00:00
2021-11-09 10:57:50 +00:00
route . InitFunction ( )
2023-05-15 03:01:21 +00:00
go SendToSocket ( service . MyService . System ( ) . GetDeviceInfo ( ) )
service . MyService . System ( ) . GenreateSystemEntry ( )
2023-03-17 07:37:28 +00:00
///
2023-04-12 05:53:27 +00:00
//service.MountLists = make(map[string]*mountlib.MountPoint)
//configfile.Install()
2021-09-26 02:35:02 +00:00
}
2021-10-22 08:49:09 +00:00
// @title casaOS API
2021-09-26 02:35:02 +00:00
// @version 1.0.0
// @contact.name lauren.pan
// @contact.url https://www.zimaboard.com
// @contact.email lauren.pan@icewhale.org
2021-10-22 08:49:09 +00:00
// @description casaOS v1版本api
// @host 192.168.2.217:8089
2021-09-26 02:35:02 +00:00
// @securityDefinitions.apikey ApiKeyAuth
// @in header
// @name Authorization
// @BasePath /v1
func main ( ) {
2022-09-06 06:28:49 +00:00
if * versionFlag {
2022-06-29 03:09:58 +00:00
return
}
2023-05-15 03:01:21 +00:00
go Special ( service . MyService )
2023-01-30 22:01:47 +00:00
v1Router := route . InitV1Router ( )
2023-02-02 15:59:33 +00:00
2023-01-30 22:01:47 +00:00
v2Router := route . InitV2Router ( )
v2DocRouter := route . InitV2DocRouter ( _docHTML , _docYAML )
2023-02-08 10:11:46 +00:00
v3file := route . InitFile ( )
v4dir := route . InitDir ( )
2023-01-30 22:01:47 +00:00
mux := & util_http . HandlerMultiplexer {
HandlerMap : map [ string ] http . Handler {
"v1" : v1Router ,
"v2" : v2Router ,
"doc" : v2DocRouter ,
2023-02-08 10:11:46 +00:00
"v3" : v3file ,
"v4" : v4dir ,
2023-01-30 22:01:47 +00:00
} ,
}
2023-03-19 00:55:51 +00:00
crontab := cron . New ( cron . WithSeconds ( ) )
if _ , err := crontab . AddFunc ( "@every 5s" , route . SendAllHardwareStatusBySocket ) ; err != nil {
logger . Error ( "add crontab error" , zap . Error ( err ) )
2022-05-05 05:46:55 +00:00
}
2022-02-17 10:43:25 +00:00
2023-03-19 00:55:51 +00:00
crontab . Start ( )
defer crontab . Stop ( )
2021-09-26 02:35:02 +00:00
2022-09-06 06:28:49 +00:00
listener , err := net . Listen ( "tcp" , net . JoinHostPort ( LOCALHOST , "0" ) )
if err != nil {
panic ( err )
}
2023-02-02 03:51:41 +00:00
routers := [ ] string {
2023-01-30 22:01:47 +00:00
"/v1/sys" ,
"/v1/port" ,
"/v1/file" ,
"/v1/folder" ,
"/v1/batch" ,
"/v1/image" ,
"/v1/samba" ,
"/v1/notify" ,
2023-03-17 07:37:28 +00:00
"/v1/driver" ,
"/v1/cloud" ,
"/v1/recover" ,
2023-02-16 08:55:51 +00:00
"/v1/other" ,
2023-01-30 22:01:47 +00:00
route . V2APIPath ,
route . V2DocPath ,
2023-02-08 10:11:46 +00:00
route . V3FilePath ,
2023-01-30 22:01:47 +00:00
}
2023-02-02 03:51:41 +00:00
for _ , apiPath := range routers {
2022-10-28 21:34:18 +00:00
err = service . MyService . Gateway ( ) . CreateRoute ( & model . Route {
2023-01-30 22:01:47 +00:00
Path : apiPath ,
2022-09-06 06:28:49 +00:00
Target : "http://" + listener . Addr ( ) . String ( ) ,
} )
if err != nil {
fmt . Println ( "err" , err )
panic ( err )
}
}
2023-02-06 07:47:29 +00:00
var events [ ] message_bus . EventType
events = append ( events , message_bus . EventType { Name : "casaos:system:utilization" , SourceID : common . SERVICENAME , PropertyTypeList : [ ] message_bus . PropertyType { } } )
2023-03-17 07:37:28 +00:00
events = append ( events , message_bus . EventType { Name : "casaos:file:recover" , SourceID : common . SERVICENAME , PropertyTypeList : [ ] message_bus . PropertyType { } } )
2023-02-06 07:47:29 +00:00
events = append ( events , message_bus . EventType { Name : "casaos:file:operate" , SourceID : common . SERVICENAME , PropertyTypeList : [ ] message_bus . PropertyType { } } )
// register at message bus
2023-02-17 10:40:19 +00:00
for i := 0 ; i < 10 ; i ++ {
response , err := service . MyService . MessageBus ( ) . RegisterEventTypesWithResponse ( context . Background ( ) , events )
if err != nil {
logger . Error ( "error when trying to register one or more event types - some event type will not be discoverable" , zap . Error ( err ) )
}
if response != nil && response . StatusCode ( ) != http . StatusOK {
logger . Error ( "error when trying to register one or more event types - some event type will not be discoverable" , zap . String ( "status" , response . Status ( ) ) , zap . String ( "body" , string ( response . Body ) ) )
}
if response . StatusCode ( ) == http . StatusOK {
break
}
time . Sleep ( time . Second )
2023-02-06 07:47:29 +00:00
}
2022-09-06 06:28:49 +00:00
go func ( ) {
time . Sleep ( time . Second * 2 )
2022-10-20 06:25:26 +00:00
// v0.3.6
2022-09-06 06:28:49 +00:00
if config . ServerInfo . HttpPort != "" {
2022-10-28 21:34:18 +00:00
changePort := model . ChangePortRequest { }
2022-09-06 06:28:49 +00:00
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 )
}
}
} ( )
2022-10-20 06:25:26 +00:00
urlFilePath := filepath . Join ( config . CommonInfo . RuntimePath , "casaos.url" )
2022-11-29 17:17:14 +00:00
if err := file . CreateFileAndWriteContent ( urlFilePath , "http://" + listener . Addr ( ) . String ( ) ) ; err != nil {
logger . Error ( "error when creating address file" , zap . Error ( err ) ,
2022-10-20 06:25:26 +00:00
zap . Any ( "address" , listener . Addr ( ) . String ( ) ) ,
zap . Any ( "filepath" , urlFilePath ) ,
)
}
2022-12-15 23:31:06 +00:00
// run any script that needs to be executed
scriptDirectory := filepath . Join ( constants . DefaultConfigPath , "start.d" )
command . ExecuteScripts ( scriptDirectory )
2022-10-20 06:25:26 +00:00
if supported , err := daemon . SdNotify ( false , daemon . SdNotifyReady ) ; err != nil {
2022-11-29 17:17:14 +00:00
logger . Error ( "Failed to notify systemd that casaos main service is ready" , zap . Any ( "error" , err ) )
2022-10-20 06:25:26 +00:00
} else if supported {
2022-11-29 17:17:14 +00:00
logger . Info ( "Notified systemd that casaos main service is ready" )
2022-10-20 06:25:26 +00:00
} else {
2022-11-29 17:17:14 +00:00
logger . Info ( "This process is not running as a systemd service." )
2022-10-20 06:25:26 +00:00
}
2023-02-08 10:11:46 +00:00
// http.HandleFunc("/v1/file/test", func(w http.ResponseWriter, r *http.Request) {
// //http.ServeFile(w, r, r.URL.Path[1:])
// http.ServeFile(w, r, "/DATA/test.img")
// })
// go http.ListenAndServe(":8081", nil)
2022-10-20 06:25:26 +00:00
s := & http . Server {
2023-01-30 22:01:47 +00:00
Handler : mux ,
2022-10-20 06:25:26 +00:00
ReadHeaderTimeout : 5 * time . Second , // fix G112: Potential slowloris attack (see https://github.com/securego/gosec)
}
2022-11-29 17:17:14 +00:00
logger . Info ( "CasaOS main service is listening..." , zap . Any ( "address" , listener . Addr ( ) . String ( ) ) )
2023-03-19 00:55:51 +00:00
// defer service.MyService.Storage().UnmountAllStorage()
2022-10-20 06:25:26 +00:00
err = s . Serve ( listener ) // not using http.serve() to fix G114: Use of net/http serve function that has no support for setting timeouts (see https://github.com/securego/gosec)
2022-09-06 06:28:49 +00:00
if err != nil {
panic ( err )
}
2021-09-26 02:35:02 +00:00
}
2023-05-15 03:01:21 +00:00
func Special ( myservice service . Repository ) {
http . HandleFunc ( "/" , func ( w http . ResponseWriter , r * http . Request ) {
w . Header ( ) . Set ( "Access-Control-Allow-Origin" , "*" )
m := myservice . System ( ) . GetDeviceInfo ( )
jsonData , err := json . Marshal ( m )
if err != nil {
fmt . Println ( "Error:" , err )
http . Error ( w , "Internal Server Error" , http . StatusInternalServerError )
return
}
w . Header ( ) . Set ( "Content-Type" , "application/json" )
fmt . Fprintln ( w , string ( jsonData ) )
} )
if err := http . ListenAndServe ( ":9527" , nil ) ; err != nil {
fmt . Println ( "Error:" , err )
}
}
func SendToSocket ( m model2 . DeviceInfo ) {
if len ( m . DeviceSN ) == 0 {
//TODO:需要更换socket地址,需要放开sn的判断
//return
}
by , _ := json . Marshal ( m )
base64Str := base64 . StdEncoding . EncodeToString ( by )
var count int = 1
for i := 0 ; i < 10 ; i ++ {
wsURL := fmt . Sprintf ( "ws://%s/server/zima%s" , "52.193.63.104:3060" , "?device=" + base64Str )
ws , err := websocket . Dial ( wsURL , "" , "http://localhost" )
if err != nil {
logger . Error ( "connect websocket err" + strconv . Itoa ( i ) , zap . Any ( "error" , err ) )
time . Sleep ( time . Second * 1 )
continue
}
defer ws . Close ( )
logger . Info ( "subscribed to" , zap . Any ( "url" , wsURL ) )
for {
msg := make ( [ ] byte , 1024 )
n , err := ws . Read ( msg )
if err != nil {
logger . Error ( "err" , zap . Any ( "err" , err . Error ( ) ) )
break
}
message := msg [ : n ]
t := gjson . GetBytes ( message , "type" )
if t . Str == "ping" {
ws . Write ( [ ] byte ( ` { "type":"pong"} ` ) )
count ++
}
if count > 600 {
return
}
}
}
logger . Error ( "error when try to connect to message bus" )
}