github.com/e154/smart-home@v0.17.2-0.20240311175135-e530a6e5cd45/plugins/email/actor.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 email 20 21 import ( 22 "context" 23 "strings" 24 25 "gopkg.in/gomail.v2" 26 27 "github.com/e154/smart-home/adaptors" 28 "github.com/e154/smart-home/common" 29 "github.com/e154/smart-home/common/apperr" 30 m "github.com/e154/smart-home/models" 31 "github.com/e154/smart-home/plugins/notify" 32 notifyCommon "github.com/e154/smart-home/plugins/notify/common" 33 "github.com/e154/smart-home/system/supervisor" 34 ) 35 36 // Actor ... 37 type Actor struct { 38 *supervisor.BaseActor 39 adaptors *adaptors.Adaptors 40 notify *notify.Notify 41 Auth string 42 Pass string 43 Smtp string 44 Port int64 45 Sender string 46 } 47 48 // NewActor ... 49 func NewActor(entity *m.Entity, 50 service supervisor.Service) *Actor { 51 52 actor := &Actor{ 53 BaseActor: supervisor.NewBaseActor(entity, service), 54 Auth: entity.Settings[AttrAuth].String(), 55 Pass: entity.Settings[AttrPass].Decrypt(), 56 Smtp: entity.Settings[AttrSmtp].String(), 57 Port: entity.Settings[AttrPort].Int64(), 58 Sender: entity.Settings[AttrSender].String(), 59 notify: notify.NewNotify(service.Adaptors()), 60 } 61 62 return actor 63 } 64 65 func (e *Actor) Destroy() { 66 e.Service.EventBus().Unsubscribe(notify.TopicNotify, e.eventHandler) 67 e.notify.Shutdown() 68 } 69 70 // Spawn ... 71 func (e *Actor) Spawn() { 72 e.Service.EventBus().Subscribe(notify.TopicNotify, e.eventHandler, false) 73 e.notify.Start() 74 } 75 76 // Send ... 77 func (e *Actor) Send(address string, message *m.Message) error { 78 79 if e.Auth == "" || e.Pass == "" || e.Smtp == "" || e.Port == 0 || e.Sender == "" { 80 return apperr.ErrBadActorSettingsParameters 81 } 82 83 attr := NewMessageParams() 84 _, _ = attr.Deserialize(message.Attributes) 85 subject := attr[AttrSubject].String() 86 87 defer func() { 88 //go func() { _ = e.UpdateStatus() }() 89 log.Infof("Sent email '%s' to: '%s'", subject, address) 90 }() 91 92 if common.TestMode() { 93 return nil 94 } 95 96 m := gomail.NewMessage() 97 m.SetHeaders(map[string][]string{ 98 "From": {e.Sender}, 99 "Reply-To": {e.Sender}, 100 "To": {address}, 101 "Subject": {subject}, 102 }) 103 104 m.SetBody("text/html", attr[AttrBody].String()) 105 106 d := gomail.NewPlainDialer(e.Smtp, int(e.Port), e.Auth, e.Pass) 107 if err := d.DialAndSend(m); err != nil { 108 return err 109 } 110 111 return nil 112 } 113 114 // UpdateStatus ... 115 func (e *Actor) UpdateStatus() (err error) { 116 117 var attributeValues = make(m.AttributeValue) 118 // ... 119 120 e.AttrMu.Lock() 121 var changed bool 122 if changed, err = e.Attrs.Deserialize(attributeValues); !changed { 123 if err != nil { 124 log.Warn(err.Error()) 125 } 126 } 127 e.AttrMu.Unlock() 128 129 e.SaveState(false, true) 130 131 return 132 } 133 134 // Save ... 135 func (e *Actor) Save(msg notifyCommon.Message) (addresses []string, message *m.Message) { 136 message = &m.Message{ 137 Type: Name, 138 Attributes: msg.Attributes, 139 } 140 var err error 141 if message.Id, err = e.Service.Adaptors().Message.Add(context.Background(), message); err != nil { 142 log.Error(err.Error()) 143 } 144 145 attr := NewMessageParams() 146 _, _ = attr.Deserialize(message.Attributes) 147 148 addresses = strings.Split(attr[AttrAddresses].String(), ",") 149 return 150 } 151 152 // MessageParams ... 153 func (e *Actor) MessageParams() m.Attributes { 154 return NewMessageParams() 155 } 156 157 func (e *Actor) eventHandler(_ string, event interface{}) { 158 159 switch v := event.(type) { 160 case notifyCommon.Message: 161 if v.EntityId != nil && *v.EntityId == e.Id { 162 e.notify.SaveAndSend(v, e) 163 } 164 } 165 }