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  }