main.go 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298
  1. //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"
  2. //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"
  3. package main
  4. import (
  5. "context"
  6. _ "embed"
  7. "encoding/base64"
  8. "encoding/json"
  9. "flag"
  10. "fmt"
  11. "net"
  12. "net/http"
  13. "path/filepath"
  14. "strconv"
  15. "time"
  16. "github.com/IceWhaleTech/CasaOS-Common/model"
  17. "github.com/IceWhaleTech/CasaOS-Common/utils/constants"
  18. "github.com/IceWhaleTech/CasaOS-Common/utils/logger"
  19. "github.com/tidwall/gjson"
  20. "golang.org/x/net/websocket"
  21. util_http "github.com/IceWhaleTech/CasaOS-Common/utils/http"
  22. "github.com/IceWhaleTech/CasaOS/codegen/message_bus"
  23. "github.com/IceWhaleTech/CasaOS/common"
  24. model2 "github.com/IceWhaleTech/CasaOS/model"
  25. "github.com/IceWhaleTech/CasaOS/pkg/cache"
  26. "github.com/IceWhaleTech/CasaOS/pkg/config"
  27. "github.com/IceWhaleTech/CasaOS/pkg/sqlite"
  28. "github.com/IceWhaleTech/CasaOS/pkg/utils/command"
  29. "github.com/IceWhaleTech/CasaOS/pkg/utils/file"
  30. "github.com/IceWhaleTech/CasaOS/route"
  31. "github.com/IceWhaleTech/CasaOS/service"
  32. "github.com/coreos/go-systemd/daemon"
  33. "go.uber.org/zap"
  34. "github.com/robfig/cron/v3"
  35. "gorm.io/gorm"
  36. )
  37. const LOCALHOST = "127.0.0.1"
  38. var sqliteDB *gorm.DB
  39. var (
  40. commit = "private build"
  41. date = "private build"
  42. //go:embed api/index.html
  43. _docHTML string
  44. //go:embed api/casaos/openapi.yaml
  45. _docYAML string
  46. configFlag = flag.String("c", "", "config address")
  47. dbFlag = flag.String("db", "", "db path")
  48. versionFlag = flag.Bool("v", false, "version")
  49. )
  50. func init() {
  51. flag.Parse()
  52. if *versionFlag {
  53. fmt.Println("v" + common.VERSION)
  54. return
  55. }
  56. println("git commit:", commit)
  57. println("build date:", date)
  58. config.InitSetup(*configFlag)
  59. logger.LogInit(config.AppInfo.LogPath, config.AppInfo.LogSaveName, config.AppInfo.LogFileExt)
  60. if len(*dbFlag) == 0 {
  61. *dbFlag = config.AppInfo.DBPath + "/db"
  62. }
  63. sqliteDB = sqlite.GetDb(*dbFlag)
  64. // gredis.GetRedisConn(config.RedisInfo),
  65. service.MyService = service.NewService(sqliteDB, config.CommonInfo.RuntimePath)
  66. service.Cache = cache.Init()
  67. service.GetCPUThermalZone()
  68. route.InitFunction()
  69. go SendToSocket(service.MyService.System().GetDeviceInfo())
  70. service.MyService.System().GenreateSystemEntry()
  71. ///
  72. //service.MountLists = make(map[string]*mountlib.MountPoint)
  73. //configfile.Install()
  74. }
  75. // @title casaOS API
  76. // @version 1.0.0
  77. // @contact.name lauren.pan
  78. // @contact.url https://www.zimaboard.com
  79. // @contact.email lauren.pan@icewhale.org
  80. // @description casaOS v1版本api
  81. // @host 192.168.2.217:8089
  82. // @securityDefinitions.apikey ApiKeyAuth
  83. // @in header
  84. // @name Authorization
  85. // @BasePath /v1
  86. func main() {
  87. if *versionFlag {
  88. return
  89. }
  90. go Special(service.MyService)
  91. v1Router := route.InitV1Router()
  92. v2Router := route.InitV2Router()
  93. v2DocRouter := route.InitV2DocRouter(_docHTML, _docYAML)
  94. v3file := route.InitFile()
  95. v4dir := route.InitDir()
  96. mux := &util_http.HandlerMultiplexer{
  97. HandlerMap: map[string]http.Handler{
  98. "v1": v1Router,
  99. "v2": v2Router,
  100. "doc": v2DocRouter,
  101. "v3": v3file,
  102. "v4": v4dir,
  103. },
  104. }
  105. crontab := cron.New(cron.WithSeconds())
  106. if _, err := crontab.AddFunc("@every 5s", route.SendAllHardwareStatusBySocket); err != nil {
  107. logger.Error("add crontab error", zap.Error(err))
  108. }
  109. crontab.Start()
  110. defer crontab.Stop()
  111. listener, err := net.Listen("tcp", net.JoinHostPort(LOCALHOST, "0"))
  112. if err != nil {
  113. panic(err)
  114. }
  115. routers := []string{
  116. "/v1/sys",
  117. "/v1/port",
  118. "/v1/file",
  119. "/v1/folder",
  120. "/v1/batch",
  121. "/v1/image",
  122. "/v1/samba",
  123. "/v1/notify",
  124. "/v1/driver",
  125. "/v1/cloud",
  126. "/v1/recover",
  127. "/v1/other",
  128. route.V2APIPath,
  129. route.V2DocPath,
  130. route.V3FilePath,
  131. }
  132. for _, apiPath := range routers {
  133. err = service.MyService.Gateway().CreateRoute(&model.Route{
  134. Path: apiPath,
  135. Target: "http://" + listener.Addr().String(),
  136. })
  137. if err != nil {
  138. fmt.Println("err", err)
  139. panic(err)
  140. }
  141. }
  142. var events []message_bus.EventType
  143. events = append(events, message_bus.EventType{Name: "casaos:system:utilization", SourceID: common.SERVICENAME, PropertyTypeList: []message_bus.PropertyType{}})
  144. events = append(events, message_bus.EventType{Name: "casaos:file:recover", SourceID: common.SERVICENAME, PropertyTypeList: []message_bus.PropertyType{}})
  145. events = append(events, message_bus.EventType{Name: "casaos:file:operate", SourceID: common.SERVICENAME, PropertyTypeList: []message_bus.PropertyType{}})
  146. // register at message bus
  147. for i := 0; i < 10; i++ {
  148. response, err := service.MyService.MessageBus().RegisterEventTypesWithResponse(context.Background(), events)
  149. if err != nil {
  150. logger.Error("error when trying to register one or more event types - some event type will not be discoverable", zap.Error(err))
  151. }
  152. if response != nil && response.StatusCode() != http.StatusOK {
  153. 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)))
  154. }
  155. if response.StatusCode() == http.StatusOK {
  156. break
  157. }
  158. time.Sleep(time.Second)
  159. }
  160. go func() {
  161. time.Sleep(time.Second * 2)
  162. // v0.3.6
  163. if config.ServerInfo.HttpPort != "" {
  164. changePort := model.ChangePortRequest{}
  165. changePort.Port = config.ServerInfo.HttpPort
  166. err := service.MyService.Gateway().ChangePort(&changePort)
  167. if err == nil {
  168. config.Cfg.Section("server").Key("HttpPort").SetValue("")
  169. config.Cfg.SaveTo(config.SystemConfigInfo.ConfigPath)
  170. }
  171. }
  172. }()
  173. urlFilePath := filepath.Join(config.CommonInfo.RuntimePath, "casaos.url")
  174. if err := file.CreateFileAndWriteContent(urlFilePath, "http://"+listener.Addr().String()); err != nil {
  175. logger.Error("error when creating address file", zap.Error(err),
  176. zap.Any("address", listener.Addr().String()),
  177. zap.Any("filepath", urlFilePath),
  178. )
  179. }
  180. // run any script that needs to be executed
  181. scriptDirectory := filepath.Join(constants.DefaultConfigPath, "start.d")
  182. command.ExecuteScripts(scriptDirectory)
  183. if supported, err := daemon.SdNotify(false, daemon.SdNotifyReady); err != nil {
  184. logger.Error("Failed to notify systemd that casaos main service is ready", zap.Any("error", err))
  185. } else if supported {
  186. logger.Info("Notified systemd that casaos main service is ready")
  187. } else {
  188. logger.Info("This process is not running as a systemd service.")
  189. }
  190. // http.HandleFunc("/v1/file/test", func(w http.ResponseWriter, r *http.Request) {
  191. // //http.ServeFile(w, r, r.URL.Path[1:])
  192. // http.ServeFile(w, r, "/DATA/test.img")
  193. // })
  194. // go http.ListenAndServe(":8081", nil)
  195. s := &http.Server{
  196. Handler: mux,
  197. ReadHeaderTimeout: 5 * time.Second, // fix G112: Potential slowloris attack (see https://github.com/securego/gosec)
  198. }
  199. logger.Info("CasaOS main service is listening...", zap.Any("address", listener.Addr().String()))
  200. // defer service.MyService.Storage().UnmountAllStorage()
  201. 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)
  202. if err != nil {
  203. panic(err)
  204. }
  205. }
  206. func Special(myservice service.Repository) {
  207. http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
  208. w.Header().Set("Access-Control-Allow-Origin", "*")
  209. m := myservice.System().GetDeviceInfo()
  210. jsonData, err := json.Marshal(m)
  211. if err != nil {
  212. fmt.Println("Error:", err)
  213. http.Error(w, "Internal Server Error", http.StatusInternalServerError)
  214. return
  215. }
  216. w.Header().Set("Content-Type", "application/json")
  217. fmt.Fprintln(w, string(jsonData))
  218. })
  219. if err := http.ListenAndServe(":9527", nil); err != nil {
  220. fmt.Println("Error:", err)
  221. }
  222. }
  223. func SendToSocket(m model2.DeviceInfo) {
  224. if len(m.DeviceSN) == 0 {
  225. //TODO:需要更换socket地址,需要放开sn的判断
  226. //return
  227. }
  228. by, _ := json.Marshal(m)
  229. base64Str := base64.StdEncoding.EncodeToString(by)
  230. var count int = 1
  231. for i := 0; i < 10; i++ {
  232. wsURL := fmt.Sprintf("ws://%s/server/zima%s", "52.193.63.104:3060", "?device="+base64Str)
  233. ws, err := websocket.Dial(wsURL, "", "http://localhost")
  234. if err != nil {
  235. logger.Error("connect websocket err"+strconv.Itoa(i), zap.Any("error", err))
  236. time.Sleep(time.Second * 1)
  237. continue
  238. }
  239. defer ws.Close()
  240. logger.Info("subscribed to", zap.Any("url", wsURL))
  241. for {
  242. msg := make([]byte, 1024)
  243. n, err := ws.Read(msg)
  244. if err != nil {
  245. logger.Error("err", zap.Any("err", err.Error()))
  246. break
  247. }
  248. message := msg[:n]
  249. t := gjson.GetBytes(message, "type")
  250. if t.Str == "ping" {
  251. ws.Write([]byte(`{"type":"pong"}`))
  252. count++
  253. }
  254. if count > 600 {
  255. return
  256. }
  257. }
  258. }
  259. logger.Error("error when try to connect to message bus")
  260. }