Reduce boilerplate in worker/UI

This commit is contained in:
Drew DeVault 2018-02-01 18:42:03 -05:00
parent ee73c41950
commit d24e4712a4
4 changed files with 100 additions and 74 deletions

View File

@ -11,12 +11,11 @@ import (
)
type AccountTab struct {
Config *config.AccountConfig
Worker worker.Worker
Parent *UIState
logger *log.Logger
counter int
callbacks map[types.WorkerMessage]func(msg types.WorkerMessage)
Config *config.AccountConfig
Worker *types.Worker
Parent *UIState
logger *log.Logger
counter int
}
func NewAccountTab(conf *config.AccountConfig,
@ -26,15 +25,14 @@ func NewAccountTab(conf *config.AccountConfig,
if err != nil {
return nil, err
}
go work.Run()
go work.Backend.Run()
acc := &AccountTab{
Config: conf,
Worker: work,
logger: logger,
callbacks: make(map[types.WorkerMessage]func(msg types.WorkerMessage)),
Config: conf,
Worker: work,
logger: logger,
}
acc.postAction(types.Configure{Config: conf}, nil)
acc.postAction(types.Connect{}, func(msg types.WorkerMessage) {
acc.Worker.PostAction(types.Configure{Config: conf}, nil)
acc.Worker.PostAction(types.Connect{}, func(msg types.WorkerMessage) {
if _, ok := msg.(types.Ack); ok {
acc.logger.Println("Connected.")
} else {
@ -68,36 +66,22 @@ func (acc *AccountTab) Render(at Geometry) {
}
func (acc *AccountTab) GetChannel() chan types.WorkerMessage {
return acc.Worker.GetMessages()
}
func (acc *AccountTab) postAction(msg types.WorkerMessage,
cb func(msg types.WorkerMessage)) {
acc.logger.Printf("-> %T\n", msg)
acc.Worker.PostAction(msg)
if cb != nil {
acc.callbacks[msg] = cb
delete(acc.callbacks, msg)
}
return acc.Worker.Messages
}
func (acc *AccountTab) HandleMessage(msg types.WorkerMessage) {
acc.logger.Printf("<- %T\n", msg)
if cb, ok := acc.callbacks[msg.InResponseTo()]; ok {
cb(msg)
}
msg = acc.Worker.ProcessMessage(msg)
switch msg.(type) {
case types.Ack:
// no-op
case types.ApproveCertificate:
// TODO: Ask the user
acc.logger.Println("Approving certificate")
acc.postAction(types.Ack{
acc.Worker.PostAction(types.Ack{
Message: types.RespondTo(msg),
}, nil)
default:
acc.postAction(types.Unsupported{
acc.Worker.PostAction(types.Unsupported{
Message: types.RespondTo(msg),
}, nil)
}

View File

@ -4,7 +4,6 @@ import (
"crypto/tls"
"crypto/x509"
"fmt"
"log"
"net/url"
"strings"
@ -23,9 +22,6 @@ type imapClient struct {
}
type IMAPWorker struct {
messages chan types.WorkerMessage
actions chan types.WorkerMessage
config struct {
scheme string
insecure bool
@ -33,33 +29,18 @@ type IMAPWorker struct {
user *url.Userinfo
}
worker *types.Worker
client *imapClient
updates chan client.Update
logger *log.Logger
}
func NewIMAPWorker(logger *log.Logger) *IMAPWorker {
func NewIMAPWorker(worker *types.Worker) *IMAPWorker {
return &IMAPWorker{
messages: make(chan types.WorkerMessage, 50),
actions: make(chan types.WorkerMessage, 50),
updates: make(chan client.Update, 50),
logger: logger,
worker: worker,
updates: make(chan client.Update, 50),
}
}
func (w *IMAPWorker) GetMessages() chan types.WorkerMessage {
return w.messages
}
func (w *IMAPWorker) PostAction(msg types.WorkerMessage) {
w.actions <- msg
}
func (w *IMAPWorker) postMessage(msg types.WorkerMessage) {
w.logger.Printf("=> %T\n", msg)
w.messages <- msg
}
func (w *IMAPWorker) verifyPeerCert(msg types.WorkerMessage) func(
rawCerts [][]byte, _ [][]*x509.Certificate) error {
@ -77,9 +58,9 @@ func (w *IMAPWorker) verifyPeerCert(msg types.WorkerMessage) func(
Message: types.RespondTo(msg),
CertPool: pool,
}
w.postMessage(request)
w.worker.PostMessage(request, nil)
response := <-w.actions
response := <-w.worker.Actions
if response.InResponseTo() != request {
return fmt.Errorf("Expected UI to answer cert request")
}
@ -176,24 +157,24 @@ func (w *IMAPWorker) handleMessage(msg types.WorkerMessage) error {
func (w *IMAPWorker) Run() {
for {
select {
case msg := <-w.actions:
w.logger.Printf("<= %T\n", msg)
case msg := <-w.worker.Actions:
msg = w.worker.ProcessAction(msg)
if err := w.handleMessage(msg); err == errUnsupported {
w.postMessage(types.Unsupported{
w.worker.PostMessage(types.Unsupported{
Message: types.RespondTo(msg),
})
}, nil)
} else if err != nil {
w.postMessage(types.Error{
w.worker.PostMessage(types.Error{
Message: types.RespondTo(msg),
Error: err,
})
}, nil)
} else {
w.postMessage(types.Ack{
w.worker.PostMessage(types.Ack{
Message: types.RespondTo(msg),
})
}, nil)
}
case update := <-w.updates:
w.logger.Printf("[= %T", update)
w.worker.Logger.Printf("(= %T", update)
}
}
}

59
worker/types/worker.go Normal file
View File

@ -0,0 +1,59 @@
package types
import (
"log"
)
type Backend interface {
Run()
}
type Worker struct {
Actions chan WorkerMessage
Backend Backend
Callbacks map[WorkerMessage]func(msg WorkerMessage)
Messages chan WorkerMessage
Logger *log.Logger
}
func (worker *Worker) PostAction(msg WorkerMessage,
cb func(msg WorkerMessage)) {
worker.Logger.Printf("=> %T\n", msg)
worker.Actions <- msg
if cb != nil {
worker.Callbacks[msg] = cb
}
}
func (worker *Worker) PostMessage(msg WorkerMessage,
cb func(msg WorkerMessage)) {
worker.Logger.Printf("-> %T\n", msg)
worker.Messages <- msg
if cb != nil {
worker.Callbacks[msg] = cb
}
}
func (worker *Worker) ProcessMessage(msg WorkerMessage) WorkerMessage {
worker.Logger.Printf("<= %T\n", msg)
if cb, ok := worker.Callbacks[msg.InResponseTo()]; ok {
cb(msg)
delete(worker.Callbacks, msg)
}
return msg
}
func (worker *Worker) ProcessAction(msg WorkerMessage) WorkerMessage {
worker.Logger.Printf("<- %T\n", msg)
if cb, ok := worker.Callbacks[msg.InResponseTo()]; ok {
cb(msg)
delete(worker.Callbacks, msg)
}
return msg
}

View File

@ -9,22 +9,24 @@ import (
"net/url"
)
type Worker interface {
GetMessages() chan types.WorkerMessage
PostAction(types.WorkerMessage)
Run()
}
// Guesses the appropriate worker type based on the given source string
func NewWorker(source string, logger *log.Logger) (Worker, error) {
func NewWorker(source string, logger *log.Logger) (*types.Worker, error) {
u, err := url.Parse(source)
if err != nil {
return nil, err
}
worker := &types.Worker{
Actions: make(chan types.WorkerMessage, 50),
Callbacks: make(map[types.WorkerMessage]func(msg types.WorkerMessage)),
Messages: make(chan types.WorkerMessage, 50),
Logger: logger,
}
switch u.Scheme {
case "imap":
case "imaps":
return imap.NewIMAPWorker(logger), nil
worker.Backend = imap.NewIMAPWorker(worker)
default:
return nil, fmt.Errorf("Unknown backend %s", u.Scheme)
}
return nil, fmt.Errorf("Unknown backend %s", u.Scheme)
return worker, nil
}