1
0
mirror of https://github.com/jhillyerd/inbucket.git synced 2025-12-17 09:37:02 +00:00

Allow monitoring of a particular mailbox for #44

- No UI to access, just append /mailbox to /monitor URL
- Changed API URLs:
  - /api/v1/monitor/messages - all
  - /api/v1/monitor/messages/{name} - specific
This commit is contained in:
James Hillyerd
2017-01-22 13:51:55 -08:00
parent cf7bdee925
commit 00e4d3791c
6 changed files with 89 additions and 13 deletions

View File

@@ -16,6 +16,8 @@ func SetupRoutes(r *mux.Router) {
httpd.Handler(MailboxDeleteV1)).Name("MailboxDeleteV1").Methods("DELETE") httpd.Handler(MailboxDeleteV1)).Name("MailboxDeleteV1").Methods("DELETE")
r.Path("/api/v1/mailbox/{name}/{id}/source").Handler( r.Path("/api/v1/mailbox/{name}/{id}/source").Handler(
httpd.Handler(MailboxSourceV1)).Name("MailboxSourceV1").Methods("GET") httpd.Handler(MailboxSourceV1)).Name("MailboxSourceV1").Methods("GET")
r.Path("/api/v1/monitor/all/messages").Handler( r.Path("/api/v1/monitor/messages").Handler(
httpd.Handler(MonitorAllMessagesV1)).Name("MonitorAllMessagesV1").Methods("GET") httpd.Handler(MonitorAllMessagesV1)).Name("MonitorAllMessagesV1").Methods("GET")
r.Path("/api/v1/monitor/messages/{name}").Handler(
httpd.Handler(MonitorMailboxMessagesV1)).Name("MonitorMailboxMessagesV1").Methods("GET")
} }

View File

@@ -9,6 +9,7 @@ import (
"github.com/jhillyerd/inbucket/log" "github.com/jhillyerd/inbucket/log"
"github.com/jhillyerd/inbucket/msghub" "github.com/jhillyerd/inbucket/msghub"
"github.com/jhillyerd/inbucket/rest/model" "github.com/jhillyerd/inbucket/rest/model"
"github.com/jhillyerd/inbucket/smtpd"
) )
const ( const (
@@ -33,15 +34,18 @@ var upgrader = websocket.Upgrader{
// msgListener handles messages from the msghub // msgListener handles messages from the msghub
type msgListener struct { type msgListener struct {
hub *msghub.Hub hub *msghub.Hub // Global message hub
c chan msghub.Message c chan msghub.Message // Queue of messages from Receive()
mailbox string // Name of mailbox to monitor, "" == all mailboxes
} }
// newMsgListener creates a listener and registers it // newMsgListener creates a listener and registers it. Optional mailbox parameter will restrict
func newMsgListener(hub *msghub.Hub) *msgListener { // messages sent to WebSocket to that mailbox only.
func newMsgListener(hub *msghub.Hub, mailbox string) *msgListener {
ml := &msgListener{ ml := &msgListener{
hub: hub, hub: hub,
c: make(chan msghub.Message, 100), c: make(chan msghub.Message, 100),
mailbox: mailbox,
} }
hub.AddListener(ml) hub.AddListener(ml)
return ml return ml
@@ -49,11 +53,15 @@ func newMsgListener(hub *msghub.Hub) *msgListener {
// Receive handles an incoming message // Receive handles an incoming message
func (ml *msgListener) Receive(msg msghub.Message) error { func (ml *msgListener) Receive(msg msghub.Message) error {
if ml.mailbox != "" && ml.mailbox != msg.Mailbox {
// Did not match mailbox name
return nil
}
ml.c <- msg ml.c <- msg
return nil return nil
} }
// WSReader makes sure the websocket client is still connected // WSReader makes sure the websocket client is still connected, discards any messages from client
func (ml *msgListener) WSReader(conn *websocket.Conn) { func (ml *msgListener) WSReader(conn *websocket.Conn) {
defer ml.Close() defer ml.Close()
conn.SetReadLimit(maxMessageSize) conn.SetReadLimit(maxMessageSize)
@@ -152,7 +160,34 @@ func MonitorAllMessagesV1(
log.Tracef("HTTP[%v] Upgraded to websocket", req.RemoteAddr) log.Tracef("HTTP[%v] Upgraded to websocket", req.RemoteAddr)
// Create, register listener; then interact with conn // Create, register listener; then interact with conn
ml := newMsgListener(ctx.MsgHub) ml := newMsgListener(ctx.MsgHub, "")
go ml.WSWriter(conn)
ml.WSReader(conn)
return nil
}
func MonitorMailboxMessagesV1(
w http.ResponseWriter, req *http.Request, ctx *httpd.Context) (err error) {
name, err := smtpd.ParseMailboxName(ctx.Vars["name"])
if err != nil {
return err
}
// Upgrade to Websocket
conn, err := upgrader.Upgrade(w, req, nil)
if err != nil {
return err
}
httpd.ExpWebSocketConnectsCurrent.Add(1)
defer func() {
_ = conn.Close()
httpd.ExpWebSocketConnectsCurrent.Add(-1)
}()
log.Tracef("HTTP[%v] Upgraded to websocket", req.RemoteAddr)
// Create, register listener; then interact with conn
ml := newMsgListener(ctx.MsgHub, name)
go ml.WSWriter(conn) go ml.WSWriter(conn)
ml.WSReader(conn) ml.WSReader(conn)

View File

@@ -1,6 +1,6 @@
var baseURL = window.location.protocol + '//' + window.location.host; var baseURL = window.location.protocol + '//' + window.location.host;
function startMonitor() { function startMonitor(mailbox) {
$.addTemplateFormatter({ $.addTemplateFormatter({
"date": function(value, template) { "date": function(value, template) {
return moment(value).calendar(); return moment(value).calendar();
@@ -13,7 +13,10 @@ function startMonitor() {
} }
}); });
var uri = '/api/v1/monitor/all/messages' var uri = '/api/v1/monitor/messages'
if (mailbox) {
uri += '/' + mailbox;
}
var l = window.location; var l = window.location;
var url = ((l.protocol === "https:") ? "wss://" : "ws://") + l.host + uri var url = ((l.protocol === "https:") ? "wss://" : "ws://") + l.host + uri
var ws = new WebSocket(url); var ws = new WebSocket(url);

View File

@@ -5,7 +5,7 @@
<script> <script>
$(document).ready(function () { $(document).ready(function () {
$('#nav-monitor').addClass('active'); $('#nav-monitor').addClass('active');
startMonitor(); startMonitor('{{.name}}');
}); });
</script> </script>
<script type="text/html" id="message-template"> <script type="text/html" id="message-template">
@@ -32,7 +32,12 @@ $(document).ready(function () {
<button class="btn btn-primary" onclick="clearClick();">Clear</button> <button class="btn btn-primary" onclick="clearClick();">Clear</button>
</div> </div>
<p class="small">Messages will be listed here shortly after delivery.</p> <p class="small">
Messages will be listed here shortly after delivery.
{{with .name}}
Only showing messages for mailbox <code>{{.}}</code>.
{{end}}
</p>
<div class="table-responsive clearfix"> <div class="table-responsive clearfix">
<table class="table table-condensed table-hover"> <table class="table table-condensed table-hover">

View File

@@ -8,6 +8,7 @@ import (
"github.com/jhillyerd/inbucket/config" "github.com/jhillyerd/inbucket/config"
"github.com/jhillyerd/inbucket/httpd" "github.com/jhillyerd/inbucket/httpd"
"github.com/jhillyerd/inbucket/smtpd"
) )
// RootIndex serves the Inbucket landing page // RootIndex serves the Inbucket landing page
@@ -49,6 +50,34 @@ func RootMonitor(w http.ResponseWriter, req *http.Request, ctx *httpd.Context) (
}) })
} }
// RootMonitorMailbox serves the Inbucket monitor page for a particular mailbox
func RootMonitorMailbox(w http.ResponseWriter, req *http.Request, ctx *httpd.Context) (err error) {
if !config.GetWebConfig().MonitorVisible {
ctx.Session.AddFlash("Monitor is disabled in configuration", "errors")
_ = ctx.Session.Save(req, w)
http.Redirect(w, req, httpd.Reverse("RootIndex"), http.StatusSeeOther)
return nil
}
name, err := smtpd.ParseMailboxName(ctx.Vars["name"])
if err != nil {
ctx.Session.AddFlash(err.Error(), "errors")
_ = ctx.Session.Save(req, w)
http.Redirect(w, req, httpd.Reverse("RootIndex"), http.StatusSeeOther)
return nil
}
// Get flash messages, save session
errorFlash := ctx.Session.Flashes("errors")
if err = ctx.Session.Save(req, w); err != nil {
return err
}
// Render template
return httpd.RenderTemplate("root/monitor.html", w, map[string]interface{}{
"ctx": ctx,
"errorFlash": errorFlash,
"name": name,
})
}
// RootStatus serves the Inbucket status page // RootStatus serves the Inbucket status page
func RootStatus(w http.ResponseWriter, req *http.Request, ctx *httpd.Context) (err error) { func RootStatus(w http.ResponseWriter, req *http.Request, ctx *httpd.Context) (err error) {
smtpListener := fmt.Sprintf("%s:%d", config.GetSMTPConfig().IP4address.String(), smtpListener := fmt.Sprintf("%s:%d", config.GetSMTPConfig().IP4address.String(),

View File

@@ -12,6 +12,8 @@ func SetupRoutes(r *mux.Router) {
httpd.Handler(RootIndex)).Name("RootIndex").Methods("GET") httpd.Handler(RootIndex)).Name("RootIndex").Methods("GET")
r.Path("/monitor").Handler( r.Path("/monitor").Handler(
httpd.Handler(RootMonitor)).Name("RootMonitor").Methods("GET") httpd.Handler(RootMonitor)).Name("RootMonitor").Methods("GET")
r.Path("/monitor/{name}").Handler(
httpd.Handler(RootMonitorMailbox)).Name("RootMonitorMailbox").Methods("GET")
r.Path("/status").Handler( r.Path("/status").Handler(
httpd.Handler(RootStatus)).Name("RootStatus").Methods("GET") httpd.Handler(RootStatus)).Name("RootStatus").Methods("GET")
r.Path("/link/{name}/{id}").Handler( r.Path("/link/{name}/{id}").Handler(