-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
2d9d353
commit 9a812c1
Showing
9 changed files
with
308 additions
and
65 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -50,6 +50,12 @@ endpoints: # Endpoints for envelopes | |
template: | | ||
{{ .Message.Subject }} | ||
{{ .Message.Text }} | ||
bridges: | ||
- from: [email protected] | ||
endpoints: | ||
- telegram endpoint | ||
- console endpoint | ||
``` | ||
## Usage | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
package config | ||
|
||
type Bridge struct { | ||
Name string `json:"name" mapstructure:"name"` | ||
From string `json:"from" mapstructure:"from"` | ||
To string `json:"to" mapstructure:"to"` | ||
FromRegex string `json:"from_regex" mapstructure:"from_regex"` | ||
ToRegex string `json:"to_regex" mapstructure:"to_regex"` | ||
Endpoints []string `json:"endpoints" mapstructure:"endpoints"` | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,71 +1,29 @@ | ||
package bridge | ||
|
||
import ( | ||
"context" | ||
"log" | ||
|
||
"github.com/ItsNotGoodName/smtpbridge/core" | ||
"github.com/ItsNotGoodName/smtpbridge/core/endpoint" | ||
"github.com/ItsNotGoodName/smtpbridge/core/envelope" | ||
"github.com/ItsNotGoodName/smtpbridge/core/event" | ||
) | ||
|
||
type ( | ||
Service interface{} | ||
) | ||
|
||
type BridgeService struct { | ||
eventPub *event.Pub | ||
envelopeService envelope.Service | ||
endpointService endpoint.Service | ||
} | ||
|
||
func NewBridgeService(pub *event.Pub, envelopeService envelope.Service, endpointService endpoint.Service) *BridgeService { | ||
return &BridgeService{ | ||
eventPub: pub, | ||
envelopeService: envelopeService, | ||
endpointService: endpointService, | ||
Bridge struct { | ||
Filter Filter | ||
Endpoints []string | ||
} | ||
} | ||
|
||
func (bs *BridgeService) Run(ctx context.Context, doneC chan<- struct{}) { | ||
log.Println("bridge.BridgeService.Run: started") | ||
|
||
eventChan := make(chan event.Event, 100) | ||
|
||
bs.eventPub.Subscribe(event.TopicEnvelopeCreated, eventChan) | ||
for { | ||
select { | ||
case <-ctx.Done(): | ||
log.Println("bridge.BridgeService.Run: stopped") | ||
doneC <- struct{}{} | ||
return | ||
case event := <-eventChan: | ||
env := event.Data.(*envelope.Envelope) | ||
|
||
// Convert envelope attachments to endpoint attachments | ||
atts := []endpoint.Attachment{} | ||
for _, att := range env.Attachments { | ||
data, err := bs.envelopeService.GetData(ctx, &att) | ||
if err != nil && err != core.ErrDataNotFound { | ||
log.Println("bridge.BridgeService.Run:", err) | ||
continue | ||
} | ||
|
||
atts = append(atts, endpoint.NewAttachment(&att, data)) | ||
} | ||
CreateBridgeRequest struct { | ||
Name string | ||
From string | ||
FromRegex string | ||
To string | ||
ToRegex string | ||
Endpoints []string | ||
} | ||
|
||
ends := bs.endpointService.ListEndpoint() | ||
Service interface { | ||
CreateBridge(req *CreateBridgeRequest) error | ||
ListBridge() []Bridge | ||
} | ||
) | ||
|
||
// Send to all endpoints | ||
for _, end := range ends { | ||
text, err := end.Text(env) | ||
if err != nil { | ||
log.Println("bridge.BridgeService.Run:", err) | ||
} else { | ||
end.Sender.Send(ctx, text, atts) | ||
} | ||
} | ||
} | ||
func NewBridge(filter Filter, endpoints []string) Bridge { | ||
return Bridge{ | ||
Filter: filter, | ||
Endpoints: endpoints, | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
package bridge | ||
|
||
import ( | ||
"regexp" | ||
|
||
"github.com/ItsNotGoodName/smtpbridge/core/envelope" | ||
) | ||
|
||
type Filter struct { | ||
To string | ||
From string | ||
toRegexp *regexp.Regexp | ||
fromRegexp *regexp.Regexp | ||
} | ||
|
||
func NewFilter(from, to, fromRegex, toRegex string) (Filter, error) { | ||
var fromRegexp, toRegexp *regexp.Regexp | ||
var err error | ||
if fromRegex != "" { | ||
fromRegexp, err = regexp.Compile(fromRegex) | ||
if err != nil { | ||
return Filter{}, err | ||
} | ||
} | ||
if toRegex != "" { | ||
toRegexp, err = regexp.Compile(toRegex) | ||
if err != nil { | ||
return Filter{}, err | ||
} | ||
} | ||
|
||
return Filter{ | ||
From: from, | ||
To: to, | ||
fromRegexp: fromRegexp, | ||
toRegexp: toRegexp, | ||
}, nil | ||
} | ||
|
||
func (f *Filter) Match(msg *envelope.Message) bool { | ||
if f.toRegexp != nil { | ||
found := false | ||
for to := range msg.To { | ||
if f.toRegexp.MatchString(to) { | ||
found = true | ||
break | ||
} | ||
} | ||
|
||
if !found { | ||
return false | ||
} | ||
} else if f.To != "" { | ||
if _, ok := msg.To[f.To]; !ok { | ||
return false | ||
} | ||
} | ||
|
||
if f.fromRegexp != nil { | ||
if !f.fromRegexp.MatchString(msg.From) { | ||
return false | ||
} | ||
} else if f.From != "" { | ||
if msg.From != f.From { | ||
return false | ||
} | ||
} | ||
|
||
return true | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
package bridge | ||
|
||
import ( | ||
"testing" | ||
|
||
"github.com/ItsNotGoodName/smtpbridge/core/envelope" | ||
"github.com/stretchr/testify/assert" | ||
) | ||
|
||
func TestFilter(t *testing.T) { | ||
type FilterTest struct { | ||
Filter Filter | ||
Match bool | ||
} | ||
|
||
newFilter := func(to, from, toRegex, fromRegex string) Filter { | ||
filter, err := NewFilter(from, to, fromRegex, toRegex) | ||
assert.Nil(t, err) | ||
return filter | ||
} | ||
|
||
msg := envelope.Message{ | ||
From: "foo", | ||
To: map[string]struct{}{"bar": {}}, | ||
} | ||
|
||
tests := []FilterTest{ | ||
{Filter: newFilter("bar", "", "", ""), Match: true}, | ||
{Filter: newFilter("bar", "foo", "", ""), Match: true}, | ||
{Filter: newFilter("bar", "foorr", "", ""), Match: false}, | ||
{Filter: newFilter("barr", "", "", ""), Match: false}, | ||
{Filter: newFilter("", "barrr", "", ""), Match: false}, | ||
{Filter: newFilter("", "", "", "f.$"), Match: false}, | ||
{Filter: newFilter("", "", "", "f"), Match: true}, | ||
{Filter: newFilter("", "", "b", ""), Match: true}, | ||
{Filter: newFilter("bar", "", "f", ""), Match: false}, | ||
{Filter: newFilter("bar", "", "b", ""), Match: true}, | ||
{Filter: newFilter("bar", "", "b", "x"), Match: false}, | ||
} | ||
|
||
for _, test := range tests { | ||
assert.Equal(t, test.Filter.Match(&msg), test.Match) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,137 @@ | ||
package bridge | ||
|
||
import ( | ||
"context" | ||
"errors" | ||
"fmt" | ||
"log" | ||
"sync" | ||
|
||
"github.com/ItsNotGoodName/smtpbridge/core" | ||
"github.com/ItsNotGoodName/smtpbridge/core/endpoint" | ||
"github.com/ItsNotGoodName/smtpbridge/core/envelope" | ||
"github.com/ItsNotGoodName/smtpbridge/core/event" | ||
) | ||
|
||
type BridgeService struct { | ||
eventPub *event.Pub | ||
envelopeService envelope.Service | ||
endpointService endpoint.Service | ||
bridgesMu sync.Mutex | ||
bridges []Bridge | ||
} | ||
|
||
func NewBridgeService(pub *event.Pub, envelopeService envelope.Service, endpointService endpoint.Service) *BridgeService { | ||
return &BridgeService{ | ||
eventPub: pub, | ||
envelopeService: envelopeService, | ||
endpointService: endpointService, | ||
} | ||
} | ||
|
||
func (bs *BridgeService) ListBridge() []Bridge { | ||
bridges := []Bridge{} | ||
|
||
bs.bridgesMu.Lock() | ||
bridges = append(bridges, bs.bridges...) | ||
bs.bridgesMu.Unlock() | ||
|
||
return bridges | ||
} | ||
|
||
func (bs *BridgeService) CreateBridge(req *CreateBridgeRequest) error { | ||
for _, end := range req.Endpoints { | ||
if _, err := bs.endpointService.GetEndpoint(end); err != nil { | ||
return fmt.Errorf("%w: '%s'", err, end) | ||
} | ||
} | ||
|
||
filter, err := NewFilter(req.To, req.From, req.ToRegex, req.FromRegex) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
bridge := NewBridge(filter, req.Endpoints) | ||
bs.bridgesMu.Lock() | ||
bs.bridges = append(bs.bridges, bridge) | ||
bs.bridgesMu.Unlock() | ||
|
||
return nil | ||
} | ||
|
||
func (bs *BridgeService) send(ctx context.Context, env *envelope.Envelope) error { | ||
// Convert envelope attachments to endpoint attachments | ||
atts := []endpoint.Attachment{} | ||
for _, att := range env.Attachments { | ||
data, err := bs.envelopeService.GetData(ctx, &att) | ||
if err != nil { | ||
if errors.Is(err, core.ErrDataNotFound) { | ||
log.Println("bridge.BridgeService.send:", err) | ||
continue | ||
} | ||
return err | ||
} | ||
|
||
atts = append(atts, endpoint.NewAttachment(&att, data)) | ||
} | ||
|
||
for _, brid := range bs.ListBridge() { | ||
// Match bridge | ||
if !brid.Filter.Match(&env.Message) { | ||
continue | ||
} | ||
|
||
// Send to all endpoints | ||
if len(brid.Endpoints) == 0 { | ||
for _, end := range bs.endpointService.ListEndpoint() { | ||
text, err := end.Text(env) | ||
if err != nil { | ||
log.Println("bridge.BridgeService.send:", err) | ||
continue | ||
} | ||
|
||
end.Sender.Send(ctx, text, atts) | ||
} | ||
|
||
return nil | ||
} | ||
|
||
// Send to endpoints | ||
for _, endpoitName := range brid.Endpoints { | ||
end, err := bs.endpointService.GetEndpoint(endpoitName) | ||
if err != nil { | ||
log.Println("bridge.BridgeService.Run:", err) | ||
continue | ||
} | ||
|
||
text, err := end.Text(env) | ||
if err != nil { | ||
log.Println("bridge.BridgeService.Run:", err) | ||
continue | ||
} | ||
|
||
end.Sender.Send(ctx, text, atts) | ||
} | ||
} | ||
|
||
return nil | ||
} | ||
|
||
func (bs *BridgeService) Run(ctx context.Context, doneC chan<- struct{}) { | ||
log.Println("bridge.BridgeService.Run: started") | ||
|
||
eventChan := make(chan event.Event, 100) | ||
bs.eventPub.Subscribe(event.TopicEnvelopeCreated, eventChan) | ||
for { | ||
select { | ||
case <-ctx.Done(): | ||
log.Println("bridge.BridgeService.Run: stopped") | ||
doneC <- struct{}{} | ||
return | ||
case event := <-eventChan: | ||
if err := bs.send(ctx, event.Data.(*envelope.Envelope)); err != nil { | ||
log.Println("bridge.BridgeService.Run:", err) | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.