112 lines
3.6 KiB
Go
112 lines
3.6 KiB
Go
package comm
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"log"
|
|
|
|
"github.com/eternal-flame-AD/yoake/internal/comm/email"
|
|
"github.com/eternal-flame-AD/yoake/internal/comm/gotify"
|
|
"github.com/eternal-flame-AD/yoake/internal/comm/model"
|
|
"github.com/eternal-flame-AD/yoake/internal/util"
|
|
)
|
|
|
|
type Communicator struct {
|
|
commMethods map[string]model.CommMethod
|
|
fallbackCommunicators []string
|
|
}
|
|
|
|
var (
|
|
errMethodNotSupported = errors.New("method not supported")
|
|
)
|
|
|
|
func (c *Communicator) actualSendGenericMessage(tryMethod string, message model.GenericMessage) error {
|
|
if comm, ok := c.commMethods[tryMethod]; ok {
|
|
if convertedMsg, err := ConvertGenericMessage(&message, comm.SupportedMIME()); err == nil {
|
|
return comm.SendGenericMessage(*convertedMsg)
|
|
} else {
|
|
return err
|
|
}
|
|
}
|
|
return errMethodNotSupported
|
|
}
|
|
|
|
// GetMethod returns the method with the given name.
|
|
func (c *Communicator) GetMethod(method string) model.CommMethod {
|
|
return c.commMethods[method]
|
|
}
|
|
|
|
// GetMethodsByMIME returns a list of methods that support the given MIME type as the message type, MIME convertions were considered.
|
|
func (c *Communicator) GetMethodsByMIME(mime string) []model.CommMethod {
|
|
var result []model.CommMethod
|
|
for _, comm := range c.commMethods {
|
|
if util.Contain(ConvertOutMIMEToSupportedInMIME(comm.SupportedMIME()), mime) {
|
|
result = append(result, comm)
|
|
}
|
|
}
|
|
return result
|
|
}
|
|
|
|
type ErrorSentWithFallback struct {
|
|
OriginalError error
|
|
OrignalMethod string
|
|
FallbackMethod string
|
|
}
|
|
|
|
func (e ErrorSentWithFallback) Error() string {
|
|
return fmt.Sprintf("used fallback method %s because original method %s reeported error: %v", e.FallbackMethod, e.OrignalMethod, e.OriginalError)
|
|
}
|
|
|
|
// SendGenericMethods sends a message using the preferred method
|
|
// if the preferred method failed to send the message, fallback methods will be tried,
|
|
// and an ErrorSentWithFabback will be returned if any fallback method succeeded.
|
|
// if fallback methods failed as well the original error will be returned.
|
|
func (c *Communicator) SendGenericMessage(preferredMethod string, message model.GenericMessage, force bool) error {
|
|
if preferredMethod == "" {
|
|
preferredMethod = c.fallbackCommunicators[0]
|
|
}
|
|
if origErr := c.actualSendGenericMessage(preferredMethod, message); origErr != nil {
|
|
if force {
|
|
log.Printf("Failed to send message using preferred method %s: %v", preferredMethod, origErr)
|
|
return origErr
|
|
}
|
|
log.Printf("Failed to send message using preferred method %s: %v. trying fallback methods", preferredMethod, origErr)
|
|
for _, fallback := range c.fallbackCommunicators {
|
|
if fallback == preferredMethod {
|
|
continue
|
|
}
|
|
if err := c.actualSendGenericMessage(fallback, message); err == nil {
|
|
log.Printf("Sent message using fallback method %s", fallback)
|
|
return ErrorSentWithFallback{
|
|
OriginalError: origErr,
|
|
OrignalMethod: preferredMethod,
|
|
FallbackMethod: fallback,
|
|
}
|
|
} else {
|
|
log.Printf("Failed to send message using fallback method %s: %v", fallback, err)
|
|
}
|
|
}
|
|
return origErr
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func InitCommunicator() *Communicator {
|
|
comm := &Communicator{
|
|
commMethods: make(map[string]model.CommMethod),
|
|
}
|
|
if emailHandler, err := email.NewHandler(); err == nil {
|
|
comm.commMethods["email"] = emailHandler
|
|
comm.fallbackCommunicators = append(comm.fallbackCommunicators, "email")
|
|
} else {
|
|
log.Printf("Failed to initialize email communicator: %v", err)
|
|
}
|
|
if gotifyHandler, err := gotify.NewClient(); err == nil {
|
|
comm.commMethods["gotify"] = gotifyHandler
|
|
comm.fallbackCommunicators = append(comm.fallbackCommunicators, "gotify")
|
|
} else {
|
|
log.Printf("Failed to initialize gotify communicator: %v", err)
|
|
}
|
|
|
|
return comm
|
|
}
|