github.com/e154/smart-home@v0.17.2-0.20240311175135-e530a6e5cd45/system/initial/initial.go (about) 1 // This file is part of the Smart Home 2 // Program complex distribution https://github.com/e154/smart-home 3 // Copyright (C) 2016-2023, Filippov Alex 4 // 5 // This library is free software: you can redistribute it and/or 6 // modify it under the terms of the GNU Lesser General Public 7 // License as published by the Free Software Foundation; either 8 // version 3 of the License, or (at your option) any later version. 9 // 10 // This library is distributed in the hope that it will be useful, 11 // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 // Library General Public License for more details. 14 // 15 // You should have received a copy of the GNU Lesser General Public 16 // License along with this library. If not, see 17 // <https://www.gnu.org/licenses/>. 18 19 package initial 20 21 import ( 22 "context" 23 "encoding/hex" 24 "errors" 25 "fmt" 26 "go.uber.org/fx" 27 "gorm.io/gorm" 28 29 . "github.com/e154/smart-home/adaptors" 30 "github.com/e154/smart-home/api" 31 "github.com/e154/smart-home/common/apperr" 32 "github.com/e154/smart-home/common/encryptor" 33 "github.com/e154/smart-home/common/events" 34 "github.com/e154/smart-home/common/logger" 35 m "github.com/e154/smart-home/models" 36 _ "github.com/e154/smart-home/plugins" 37 "github.com/e154/smart-home/system/access_list" 38 "github.com/e154/smart-home/system/automation" 39 "github.com/e154/smart-home/system/bus" 40 "github.com/e154/smart-home/system/gate/client" 41 . "github.com/e154/smart-home/system/initial/assertions" 42 "github.com/e154/smart-home/system/initial/demo" 43 localMigrations "github.com/e154/smart-home/system/initial/local_migrations" 44 "github.com/e154/smart-home/system/logging_ws" 45 "github.com/e154/smart-home/system/media" 46 "github.com/e154/smart-home/system/scheduler" 47 "github.com/e154/smart-home/system/scripts" 48 "github.com/e154/smart-home/system/supervisor" 49 "github.com/e154/smart-home/system/terminal" 50 "github.com/e154/smart-home/system/validation" 51 "github.com/e154/smart-home/version" 52 ) 53 54 var ( 55 log = logger.MustGetLogger("initial") 56 ) 57 58 // Initial ... 59 type Initial struct { 60 adaptors *Adaptors 61 scriptService scripts.ScriptService 62 accessList access_list.AccessListService 63 supervisor supervisor.Supervisor 64 automation automation.Automation 65 api *api.Api 66 gateClient *client.GateClient 67 validation *validation.Validate 68 localMigrations *localMigrations.Migrations 69 demo *demo.Demos 70 eventBus bus.Bus 71 db *gorm.DB 72 } 73 74 // NewInitial ... 75 func NewInitial(lc fx.Lifecycle, 76 adaptors *Adaptors, 77 scriptService scripts.ScriptService, 78 accessList access_list.AccessListService, 79 supervisor supervisor.Supervisor, 80 automation automation.Automation, 81 api *api.Api, 82 gateClient *client.GateClient, 83 validation *validation.Validate, 84 _ *logging_ws.LoggingWs, 85 localMigrations *localMigrations.Migrations, 86 demo *demo.Demos, 87 _ *scheduler.Scheduler, 88 _ *media.Media, 89 db *gorm.DB, 90 eventBus bus.Bus, 91 _ *terminal.Terminal) *Initial { 92 initial := &Initial{ 93 adaptors: adaptors, 94 scriptService: scriptService, 95 accessList: accessList, 96 supervisor: supervisor, 97 automation: automation, 98 api: api, 99 gateClient: gateClient, 100 validation: validation, 101 localMigrations: localMigrations, 102 demo: demo, 103 db: db, 104 eventBus: eventBus, 105 } 106 lc.Append(fx.Hook{ 107 OnStart: func(ctx context.Context) (err error) { 108 return initial.Start(ctx) 109 }, 110 OnStop: func(ctx context.Context) (err error) { 111 return initial.Shutdown(ctx) 112 }, 113 }) 114 return initial 115 } 116 117 // InstallDemoData ... 118 func (n *Initial) InstallDemoData() { 119 120 log.Info("install demo data") 121 122 tx := n.adaptors.Begin() 123 124 // install demo 125 _ = n.demo.InstallByName(context.TODO(), tx, "example1") 126 127 _ = tx.Commit() 128 129 log.Info("complete") 130 } 131 132 // checkForUpgrade ... 133 func (n *Initial) checkForUpgrade() { 134 135 defer func() { 136 fmt.Println("") 137 }() 138 139 const name = "initialVersion" 140 v, err := n.adaptors.Variable.GetByName(context.Background(), name) 141 if err != nil { 142 143 if errors.Is(err, apperr.ErrNotFound) { 144 v = m.Variable{ 145 Name: name, 146 Value: fmt.Sprintf("%d", 1), 147 System: true, 148 } 149 err = n.adaptors.Variable.Add(context.Background(), v) 150 So(err, ShouldBeNil) 151 } 152 } 153 154 oldVersion := v.Value 155 So(err, ShouldBeNil) 156 157 var currentVersion string 158 if currentVersion, err = n.localMigrations.Up(context.TODO(), n.adaptors, oldVersion); err != nil { 159 return 160 } 161 162 v.Value = currentVersion 163 err = n.adaptors.Variable.Update(context.Background(), v) 164 So(err, ShouldBeNil) 165 } 166 167 // Start ... 168 func (n *Initial) Start(ctx context.Context) (err error) { 169 n.checkForUpgrade() 170 171 variable, _ := n.adaptors.Variable.GetByName(ctx, "encryptor") 172 val, _ := hex.DecodeString(variable.Value) 173 encryptor.SetKey(val) 174 175 _ = n.eventBus.Subscribe("system/models/variables/+", n.eventHandler) 176 _ = n.eventBus.Subscribe("system", n.eventHandler) 177 178 _ = n.gateClient.Start() 179 _ = n.supervisor.Start(ctx) 180 _ = n.automation.Start() 181 go func() { 182 _ = n.api.Start() 183 }() 184 return 185 } 186 187 // Shutdown ... 188 func (n *Initial) Shutdown(ctx context.Context) (err error) { 189 _ = n.eventBus.Unsubscribe("system/models/variables/+", n.eventHandler) 190 _ = n.eventBus.Unsubscribe("system", n.eventHandler) 191 _ = n.api.Shutdown(ctx) 192 return 193 } 194 195 func (n *Initial) eventHandler(_ string, message interface{}) { 196 switch v := message.(type) { 197 case events.EventGetServerVersion: 198 n.eventBus.Publish("system", events.EventServerVersion{ 199 Common: events.Common{ 200 Owner: events.OwnerSystem, 201 SessionID: v.SessionID, 202 User: v.User, 203 }, 204 Version: version.GetVersion(), 205 }) 206 case events.EventUpdatedVariableModel: 207 if v.Name == "timezone" && v.Value != "" { 208 log.Infof("update database timezone to: \"%s\"", v.Value) 209 n.db.Exec(`SET TIME ZONE '?';`, v.Value) 210 } 211 } 212 }