mirror of
https://gitlab.com/ric_harvey/MailHog.git
synced 2025-03-15 13:04:46 +00:00
Start converting to use github.com/ian-kent/gotcha
This commit is contained in:
parent
bc56772c03
commit
5409809872
5 changed files with 114 additions and 270 deletions
2
Makefile
2
Makefile
|
@ -11,6 +11,8 @@ release: release-deps
|
||||||
gox
|
gox
|
||||||
|
|
||||||
deps:
|
deps:
|
||||||
|
go get github.com/ian-kent/gotcha/...
|
||||||
|
go get github.com/ian-kent/go-log/...
|
||||||
go get github.com/jteeuwen/go-bindata/...
|
go get github.com/jteeuwen/go-bindata/...
|
||||||
go get labix.org/v2/mgo
|
go get labix.org/v2/mgo
|
||||||
|
|
||||||
|
|
|
@ -4,28 +4,25 @@ import (
|
||||||
"log"
|
"log"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
|
||||||
"net/http"
|
|
||||||
"net/smtp"
|
"net/smtp"
|
||||||
"strconv"
|
"strconv"
|
||||||
"bufio"
|
|
||||||
"strings"
|
"strings"
|
||||||
"github.com/ian-kent/Go-MailHog/mailhog/data"
|
"github.com/ian-kent/Go-MailHog/mailhog/data"
|
||||||
"github.com/ian-kent/Go-MailHog/mailhog/config"
|
"github.com/ian-kent/Go-MailHog/mailhog/config"
|
||||||
"github.com/ian-kent/Go-MailHog/mailhog/storage"
|
"github.com/ian-kent/Go-MailHog/mailhog/storage"
|
||||||
"github.com/ian-kent/Go-MailHog/mailhog/http/router"
|
gotcha "github.com/ian-kent/gotcha/app"
|
||||||
|
"github.com/ian-kent/gotcha/http"
|
||||||
)
|
)
|
||||||
|
|
||||||
type APIv1 struct {
|
type APIv1 struct {
|
||||||
config *config.Config
|
config *config.Config
|
||||||
exitChannel chan int
|
|
||||||
server *http.Server
|
|
||||||
eventlisteners []*EventListener
|
eventlisteners []*EventListener
|
||||||
|
app *gotcha.App
|
||||||
}
|
}
|
||||||
|
|
||||||
type EventListener struct {
|
type EventListener struct {
|
||||||
conn net.Conn
|
session *http.Session
|
||||||
bufrw *bufio.ReadWriter
|
ch chan []byte
|
||||||
}
|
}
|
||||||
|
|
||||||
type ReleaseConfig struct {
|
type ReleaseConfig struct {
|
||||||
|
@ -34,25 +31,24 @@ type ReleaseConfig struct {
|
||||||
Port string
|
Port string
|
||||||
}
|
}
|
||||||
|
|
||||||
func CreateAPIv1(exitCh chan int, conf *config.Config, server *http.Server) *APIv1 {
|
func CreateAPIv1(conf *config.Config, app *gotcha.App) *APIv1 {
|
||||||
log.Println("Creating API v1")
|
log.Println("Creating API v1")
|
||||||
apiv1 := &APIv1{
|
apiv1 := &APIv1{
|
||||||
config: conf,
|
config: conf,
|
||||||
exitChannel: exitCh,
|
|
||||||
server: server,
|
|
||||||
eventlisteners: make([]*EventListener, 0),
|
eventlisteners: make([]*EventListener, 0),
|
||||||
|
app: app,
|
||||||
}
|
}
|
||||||
|
|
||||||
r := server.Handler.(*router.Router)
|
r := app.Router
|
||||||
|
|
||||||
r.Get("^/api/v1/messages/?$", apiv1.messages)
|
r.Get("/api/v1/messages/?", apiv1.messages)
|
||||||
r.Delete("^/api/v1/messages/?$", apiv1.delete_all)
|
r.Delete("/api/v1/messages/?", apiv1.delete_all)
|
||||||
r.Get("^/api/v1/messages/([0-9a-f]+)/?$", apiv1.message)
|
r.Get("/api/v1/messages/(?P<id>[0-9a-f]+)/?", apiv1.message)
|
||||||
r.Delete("^/api/v1/messages/([0-9a-f]+)/?$", apiv1.delete_one)
|
r.Delete("/api/v1/messages/(?P<id>[0-9a-f]+)/?", apiv1.delete_one)
|
||||||
r.Get("^/api/v1/messages/([0-9a-f]+)/download/?$", apiv1.download)
|
r.Get("/api/v1/messages/(?P<id>[0-9a-f]+)/download/?", apiv1.download)
|
||||||
r.Get("^/api/v1/messages/([0-9a-f]+)/mime/part/(\\d+)/download/?$", apiv1.download_part)
|
r.Get("/api/v1/messages/(?P<id>[0-9a-f]+)/mime/part/(\\d+)/download/?", apiv1.download_part)
|
||||||
r.Post("^/api/v1/messages/([0-9a-f]+)/release/?$", apiv1.release_one)
|
r.Post("/api/v1/messages/(?P<id>[0-9a-f]+)/release/?", apiv1.release_one)
|
||||||
r.Get("^/api/v1/events/?$", apiv1.eventstream)
|
r.Get("/api/v1/events/?", apiv1.eventstream)
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
for {
|
for {
|
||||||
|
@ -63,8 +59,6 @@ func CreateAPIv1(exitCh chan int, conf *config.Config, server *http.Server) *API
|
||||||
json := string(bytes)
|
json := string(bytes)
|
||||||
log.Printf("Sending content: %s\n", json)
|
log.Printf("Sending content: %s\n", json)
|
||||||
apiv1.broadcast(json)
|
apiv1.broadcast(json)
|
||||||
case <- exitCh:
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
@ -75,7 +69,7 @@ func CreateAPIv1(exitCh chan int, conf *config.Config, server *http.Server) *API
|
||||||
func (apiv1 *APIv1) broadcast(json string) {
|
func (apiv1 *APIv1) broadcast(json string) {
|
||||||
log.Println("[APIv1] BROADCAST /api/v1/events")
|
log.Println("[APIv1] BROADCAST /api/v1/events")
|
||||||
for _, l := range apiv1.eventlisteners {
|
for _, l := range apiv1.eventlisteners {
|
||||||
log.Printf("Sending to connection: %s\n", l.conn.RemoteAddr())
|
log.Printf("Sending to connection: %s\n", l.session.Request.RemoteAddr)
|
||||||
|
|
||||||
lines := strings.Split(json, "\n")
|
lines := strings.Split(json, "\n")
|
||||||
data := ""
|
data := ""
|
||||||
|
@ -85,49 +79,32 @@ func (apiv1 *APIv1) broadcast(json string) {
|
||||||
data += "\n"
|
data += "\n"
|
||||||
|
|
||||||
size := fmt.Sprintf("%X", len(data) + 1)
|
size := fmt.Sprintf("%X", len(data) + 1)
|
||||||
l.bufrw.Write([]byte(size + "\r\n"))
|
l.ch <- []byte(size + "\r\n")
|
||||||
|
|
||||||
lines = strings.Split(data, "\n")
|
lines = strings.Split(data, "\n")
|
||||||
for _, ln := range lines {
|
for _, ln := range lines {
|
||||||
l.bufrw.Write([]byte(ln + "\n"))
|
l.ch <- []byte(ln + "\n")
|
||||||
}
|
|
||||||
_, err := l.bufrw.Write([]byte("\r\n"))
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("Error writing to connection: %s\n", err)
|
|
||||||
l.conn.Close()
|
|
||||||
// TODO remove from array
|
|
||||||
}
|
|
||||||
|
|
||||||
err = l.bufrw.Flush()
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("Error flushing buffer: %s\n", err)
|
|
||||||
l.conn.Close()
|
|
||||||
// TODO remove from array
|
|
||||||
}
|
}
|
||||||
|
l.ch <- []byte("\r\n")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (apiv1 *APIv1) eventstream(w http.ResponseWriter, r *http.Request, route *router.Route) {
|
func (apiv1 *APIv1) eventstream(session *http.Session) {
|
||||||
log.Println("[APIv1] GET /api/v1/events")
|
log.Println("[APIv1] GET /api/v1/events")
|
||||||
w.Header().Set("Content-Type", "text/event-stream")
|
|
||||||
w.Header().Set("Cache-Control", "no-cache")
|
apiv1.eventlisteners = append(apiv1.eventlisteners, &EventListener{
|
||||||
w.Header().Set("Connection", "keep-alive")
|
session,
|
||||||
w.Write([]byte("\n\n"))
|
session.Response.Chunked(),
|
||||||
hj, ok := w.(http.Hijacker)
|
})
|
||||||
if !ok {
|
|
||||||
log.Println("[APIv1] Connection hijack failed")
|
session.Response.Headers.Add("Content-Type", "text/event-stream")
|
||||||
return
|
session.Response.Headers.Add("Cache-Control", "no-cache")
|
||||||
}
|
session.Response.Headers.Add("Connection", "keep-alive")
|
||||||
conn, bufrw, err := hj.Hijack()
|
session.Response.Write([]byte("\n\n"))
|
||||||
if err != nil {
|
session.Response.Send()
|
||||||
log.Println("[APIv1] Connection hijack failed")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
apiv1.eventlisteners = append(apiv1.eventlisteners, &EventListener{conn, bufrw})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (apiv1 *APIv1) messages(w http.ResponseWriter, r *http.Request, route *router.Route) {
|
func (apiv1 *APIv1) messages(session *http.Session) {
|
||||||
log.Println("[APIv1] GET /api/v1/messages")
|
log.Println("[APIv1] GET /api/v1/messages")
|
||||||
|
|
||||||
// TODO start, limit
|
// TODO start, limit
|
||||||
|
@ -135,122 +112,118 @@ func (apiv1 *APIv1) messages(w http.ResponseWriter, r *http.Request, route *rout
|
||||||
case *storage.MongoDB:
|
case *storage.MongoDB:
|
||||||
messages, _ := apiv1.config.Storage.(*storage.MongoDB).List(0, 1000)
|
messages, _ := apiv1.config.Storage.(*storage.MongoDB).List(0, 1000)
|
||||||
bytes, _ := json.Marshal(messages)
|
bytes, _ := json.Marshal(messages)
|
||||||
w.Header().Set("Content-Type", "text/json")
|
session.Response.Headers.Add("Content-Type", "text/json")
|
||||||
w.Write(bytes)
|
session.Response.Write(bytes)
|
||||||
case *storage.Memory:
|
case *storage.Memory:
|
||||||
messages, _ := apiv1.config.Storage.(*storage.Memory).List(0, 1000)
|
messages, _ := apiv1.config.Storage.(*storage.Memory).List(0, 1000)
|
||||||
bytes, _ := json.Marshal(messages)
|
bytes, _ := json.Marshal(messages)
|
||||||
w.Header().Set("Content-Type", "text/json")
|
session.Response.Headers.Add("Content-Type", "text/json")
|
||||||
w.Write(bytes)
|
session.Response.Write(bytes)
|
||||||
default:
|
default:
|
||||||
w.WriteHeader(500)
|
session.Response.Status = 500
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (apiv1 *APIv1) message(w http.ResponseWriter, r *http.Request, route *router.Route) {
|
func (apiv1 *APIv1) message(session *http.Session) {
|
||||||
|
id := session.Stash["id"].(string)
|
||||||
match := route.Pattern.FindStringSubmatch(r.URL.Path)
|
|
||||||
id := match[1]
|
|
||||||
log.Printf("[APIv1] GET /api/v1/messages/%s\n", id)
|
log.Printf("[APIv1] GET /api/v1/messages/%s\n", id)
|
||||||
|
|
||||||
switch apiv1.config.Storage.(type) {
|
switch apiv1.config.Storage.(type) {
|
||||||
case *storage.MongoDB:
|
case *storage.MongoDB:
|
||||||
message, _ := apiv1.config.Storage.(*storage.MongoDB).Load(id)
|
message, _ := apiv1.config.Storage.(*storage.MongoDB).Load(id)
|
||||||
bytes, _ := json.Marshal(message)
|
bytes, _ := json.Marshal(message)
|
||||||
w.Header().Set("Content-Type", "text/json")
|
session.Response.Headers.Add("Content-Type", "text/json")
|
||||||
w.Write(bytes)
|
session.Response.Write(bytes)
|
||||||
case *storage.Memory:
|
case *storage.Memory:
|
||||||
message, _ := apiv1.config.Storage.(*storage.Memory).Load(id)
|
message, _ := apiv1.config.Storage.(*storage.Memory).Load(id)
|
||||||
bytes, _ := json.Marshal(message)
|
bytes, _ := json.Marshal(message)
|
||||||
w.Header().Set("Content-Type", "text/json")
|
session.Response.Headers.Add("Content-Type", "text/json")
|
||||||
w.Write(bytes)
|
session.Response.Write(bytes)
|
||||||
default:
|
default:
|
||||||
w.WriteHeader(500)
|
session.Response.Status = 500
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (apiv1 *APIv1) download(w http.ResponseWriter, r *http.Request, route *router.Route) {
|
func (apiv1 *APIv1) download(session *http.Session) {
|
||||||
match := route.Pattern.FindStringSubmatch(r.URL.Path)
|
id := session.Stash["id"].(string)
|
||||||
id := match[1]
|
log.Printf("[APIv1] GET /api/v1/messages/%s\n", id)
|
||||||
log.Printf("[APIv1] GET /api/v1/messages/%s/download\n", id)
|
|
||||||
|
|
||||||
w.Header().Set("Content-Type", "message/rfc822")
|
session.Response.Headers.Add("Content-Type", "message/rfc822")
|
||||||
w.Header().Set("Content-Disposition", "attachment; filename=\"" + id + ".eml\"")
|
session.Response.Headers.Add("Content-Disposition", "attachment; filename=\"" + id + ".eml\"")
|
||||||
|
|
||||||
switch apiv1.config.Storage.(type) {
|
switch apiv1.config.Storage.(type) {
|
||||||
case *storage.MongoDB:
|
case *storage.MongoDB:
|
||||||
message, _ := apiv1.config.Storage.(*storage.MongoDB).Load(id)
|
message, _ := apiv1.config.Storage.(*storage.MongoDB).Load(id)
|
||||||
for h, l := range message.Content.Headers {
|
for h, l := range message.Content.Headers {
|
||||||
for _, v := range l {
|
for _, v := range l {
|
||||||
w.Write([]byte(h + ": " + v + "\r\n"))
|
session.Response.Write([]byte(h + ": " + v + "\r\n"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
w.Write([]byte("\r\n" + message.Content.Body))
|
session.Response.Write([]byte("\r\n" + message.Content.Body))
|
||||||
case *storage.Memory:
|
case *storage.Memory:
|
||||||
message, _ := apiv1.config.Storage.(*storage.Memory).Load(id)
|
message, _ := apiv1.config.Storage.(*storage.Memory).Load(id)
|
||||||
for h, l := range message.Content.Headers {
|
for h, l := range message.Content.Headers {
|
||||||
for _, v := range l {
|
for _, v := range l {
|
||||||
w.Write([]byte(h + ": " + v + "\r\n"))
|
session.Response.Write([]byte(h + ": " + v + "\r\n"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
w.Write([]byte("\r\n" + message.Content.Body))
|
session.Response.Write([]byte("\r\n" + message.Content.Body))
|
||||||
default:
|
default:
|
||||||
w.WriteHeader(500)
|
session.Response.Status = 500
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (apiv1 *APIv1) download_part(w http.ResponseWriter, r *http.Request, route *router.Route) {
|
func (apiv1 *APIv1) download_part(session *http.Session) {
|
||||||
match := route.Pattern.FindStringSubmatch(r.URL.Path)
|
id := session.Stash["id"].(string)
|
||||||
id := match[1]
|
part, _ := strconv.Atoi(session.Stash["part"].(string))
|
||||||
part, _ := strconv.Atoi(match[2])
|
|
||||||
log.Printf("[APIv1] GET /api/v1/messages/%s/mime/part/%d/download\n", id, part)
|
log.Printf("[APIv1] GET /api/v1/messages/%s/mime/part/%d/download\n", id, part)
|
||||||
|
|
||||||
// TODO extension from content-type?
|
// TODO extension from content-type?
|
||||||
|
|
||||||
w.Header().Set("Content-Disposition", "attachment; filename=\"" + id + "-part-" + match[2] + "\"")
|
session.Response.Headers.Add("Content-Disposition", "attachment; filename=\"" + id + "-part-" + strconv.Itoa(part) + "\"")
|
||||||
|
|
||||||
switch apiv1.config.Storage.(type) {
|
switch apiv1.config.Storage.(type) {
|
||||||
case *storage.MongoDB:
|
case *storage.MongoDB:
|
||||||
message, _ := apiv1.config.Storage.(*storage.MongoDB).Load(id)
|
message, _ := apiv1.config.Storage.(*storage.MongoDB).Load(id)
|
||||||
for h, l := range message.MIME.Parts[part].Headers {
|
for h, l := range message.MIME.Parts[part].Headers {
|
||||||
for _, v := range l {
|
for _, v := range l {
|
||||||
w.Header().Set(h, v)
|
session.Response.Headers.Add(h, v)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
w.Write([]byte("\r\n" + message.MIME.Parts[part].Body))
|
session.Response.Write([]byte("\r\n" + message.MIME.Parts[part].Body))
|
||||||
case *storage.Memory:
|
case *storage.Memory:
|
||||||
message, _ := apiv1.config.Storage.(*storage.Memory).Load(id)
|
message, _ := apiv1.config.Storage.(*storage.Memory).Load(id)
|
||||||
for h, l := range message.MIME.Parts[part].Headers {
|
for h, l := range message.MIME.Parts[part].Headers {
|
||||||
for _, v := range l {
|
for _, v := range l {
|
||||||
w.Header().Set(h, v)
|
session.Response.Headers.Add(h, v)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
w.Write([]byte("\r\n" + message.MIME.Parts[part].Body))
|
session.Response.Write([]byte("\r\n" + message.MIME.Parts[part].Body))
|
||||||
default:
|
default:
|
||||||
w.WriteHeader(500)
|
session.Response.Status = 500
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (apiv1 *APIv1) delete_all(w http.ResponseWriter, r *http.Request, route *router.Route) {
|
func (apiv1 *APIv1) delete_all(session *http.Session) {
|
||||||
log.Println("[APIv1] POST /api/v1/messages")
|
log.Println("[APIv1] POST /api/v1/messages")
|
||||||
|
|
||||||
w.Header().Set("Content-Type", "text/json")
|
session.Response.Headers.Add("Content-Type", "text/json")
|
||||||
switch apiv1.config.Storage.(type) {
|
switch apiv1.config.Storage.(type) {
|
||||||
case *storage.MongoDB:
|
case *storage.MongoDB:
|
||||||
apiv1.config.Storage.(*storage.MongoDB).DeleteAll()
|
apiv1.config.Storage.(*storage.MongoDB).DeleteAll()
|
||||||
case *storage.Memory:
|
case *storage.Memory:
|
||||||
apiv1.config.Storage.(*storage.Memory).DeleteAll()
|
apiv1.config.Storage.(*storage.Memory).DeleteAll()
|
||||||
default:
|
default:
|
||||||
w.WriteHeader(500)
|
session.Response.Status = 500
|
||||||
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (apiv1 *APIv1) release_one(w http.ResponseWriter, r *http.Request, route *router.Route) {
|
func (apiv1 *APIv1) release_one(session *http.Session) {
|
||||||
match := route.Pattern.FindStringSubmatch(r.URL.Path)
|
id := session.Stash["id"].(string)
|
||||||
id := match[1]
|
|
||||||
log.Printf("[APIv1] POST /api/v1/messages/%s/release\n", id)
|
log.Printf("[APIv1] POST /api/v1/messages/%s/release\n", id)
|
||||||
|
|
||||||
w.Header().Set("Content-Type", "text/json")
|
session.Response.Headers.Add("Content-Type", "text/json")
|
||||||
var msg = &data.Message{}
|
var msg = &data.Message{}
|
||||||
switch apiv1.config.Storage.(type) {
|
switch apiv1.config.Storage.(type) {
|
||||||
case *storage.MongoDB:
|
case *storage.MongoDB:
|
||||||
|
@ -258,16 +231,17 @@ func (apiv1 *APIv1) release_one(w http.ResponseWriter, r *http.Request, route *r
|
||||||
case *storage.Memory:
|
case *storage.Memory:
|
||||||
msg, _ = apiv1.config.Storage.(*storage.Memory).Load(id)
|
msg, _ = apiv1.config.Storage.(*storage.Memory).Load(id)
|
||||||
default:
|
default:
|
||||||
w.WriteHeader(500)
|
session.Response.Status = 500
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
decoder := json.NewDecoder(r.Body)
|
decoder := json.NewDecoder(session.Request.Body())
|
||||||
var cfg ReleaseConfig
|
var cfg ReleaseConfig
|
||||||
err := decoder.Decode(&cfg)
|
err := decoder.Decode(&cfg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("Error decoding request body: %s", err)
|
log.Printf("Error decoding request body: %s", err)
|
||||||
w.WriteHeader(500)
|
session.Response.Status = 500
|
||||||
w.Write([]byte("Error decoding request body"))
|
session.Response.Write([]byte("Error decoding request body"))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -285,24 +259,23 @@ func (apiv1 *APIv1) release_one(w http.ResponseWriter, r *http.Request, route *r
|
||||||
err = smtp.SendMail(cfg.Host + ":" + cfg.Port, nil, "nobody@" + apiv1.config.Hostname, []string{cfg.Email}, bytes)
|
err = smtp.SendMail(cfg.Host + ":" + cfg.Port, nil, "nobody@" + apiv1.config.Hostname, []string{cfg.Email}, bytes)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("Failed to release message: %s", err)
|
log.Printf("Failed to release message: %s", err)
|
||||||
w.WriteHeader(500)
|
session.Response.Status = 500
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
log.Printf("Message released successfully")
|
log.Printf("Message released successfully")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (apiv1 *APIv1) delete_one(w http.ResponseWriter, r *http.Request, route *router.Route) {
|
func (apiv1 *APIv1) delete_one(session *http.Session) {
|
||||||
match := route.Pattern.FindStringSubmatch(r.URL.Path)
|
id := session.Stash["id"].(string)
|
||||||
id := match[1]
|
|
||||||
log.Printf("[APIv1] POST /api/v1/messages/%s/delete\n", id)
|
log.Printf("[APIv1] POST /api/v1/messages/%s/delete\n", id)
|
||||||
|
|
||||||
w.Header().Set("Content-Type", "text/json")
|
session.Response.Headers.Add("Content-Type", "text/json")
|
||||||
switch apiv1.config.Storage.(type) {
|
switch apiv1.config.Storage.(type) {
|
||||||
case *storage.MongoDB:
|
case *storage.MongoDB:
|
||||||
apiv1.config.Storage.(*storage.MongoDB).DeleteOne(id)
|
apiv1.config.Storage.(*storage.MongoDB).DeleteOne(id)
|
||||||
case *storage.Memory:
|
case *storage.Memory:
|
||||||
apiv1.config.Storage.(*storage.Memory).DeleteOne(id)
|
apiv1.config.Storage.(*storage.Memory).DeleteOne(id)
|
||||||
default:
|
default:
|
||||||
w.WriteHeader(500)
|
session.Response.Status = 500
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,79 +0,0 @@
|
||||||
package router;
|
|
||||||
|
|
||||||
import (
|
|
||||||
"regexp"
|
|
||||||
"net/http"
|
|
||||||
)
|
|
||||||
|
|
||||||
// http://stackoverflow.com/questions/6564558/wildcards-in-the-pattern-for-http-handlefunc
|
|
||||||
|
|
||||||
type Route struct {
|
|
||||||
Methods map[string]int
|
|
||||||
Pattern *regexp.Regexp
|
|
||||||
Handler HandlerFunc
|
|
||||||
}
|
|
||||||
|
|
||||||
type HandlerFunc func(http.ResponseWriter, *http.Request, *Route)
|
|
||||||
|
|
||||||
//type Handler http.Handler
|
|
||||||
func (f HandlerFunc) ServeHTTP(w http.ResponseWriter, r *http.Request, route *Route) {
|
|
||||||
f(w, r, route)
|
|
||||||
}
|
|
||||||
|
|
||||||
type Router struct {
|
|
||||||
routes []*Route
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *Router) Get(pattern string, handler HandlerFunc) {
|
|
||||||
h.Handler([]string{"GET"}, regexp.MustCompile(pattern), handler)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *Router) Post(pattern string, handler HandlerFunc) {
|
|
||||||
h.Handler([]string{"POST"}, regexp.MustCompile(pattern), handler)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *Router) Put(pattern string, handler HandlerFunc) {
|
|
||||||
h.Handler([]string{"PUT"}, regexp.MustCompile(pattern), handler)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *Router) Delete(pattern string, handler HandlerFunc) {
|
|
||||||
h.Handler([]string{"DELETE"}, regexp.MustCompile(pattern), handler)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *Router) Patch(pattern string, handler HandlerFunc) {
|
|
||||||
h.Handler([]string{"PATCH"}, regexp.MustCompile(pattern), handler)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *Router) Options(pattern string, handler HandlerFunc) {
|
|
||||||
h.Handler([]string{"OPTIONS"}, regexp.MustCompile(pattern), handler)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *Router) Handler(methods []string, pattern *regexp.Regexp, handler HandlerFunc) {
|
|
||||||
m := make(map[string]int,0)
|
|
||||||
for _, v := range methods {
|
|
||||||
m[v] = 1
|
|
||||||
}
|
|
||||||
h.routes = append(h.routes, &Route{m, pattern, handler})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *Router) HandleFunc(methods []string, pattern *regexp.Regexp, handler func(http.ResponseWriter, *http.Request, *Route)) {
|
|
||||||
m := make(map[string]int,0)
|
|
||||||
for _, v := range methods {
|
|
||||||
m[v] = 1
|
|
||||||
}
|
|
||||||
h.routes = append(h.routes, &Route{m, pattern, HandlerFunc(handler)})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *Router) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
|
||||||
for _, route := range h.routes {
|
|
||||||
if route.Pattern.MatchString(r.URL.Path) {
|
|
||||||
_, ok := route.Methods[r.Method]
|
|
||||||
if ok {
|
|
||||||
route.Handler.ServeHTTP(w, r, route)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// no pattern matched; send 404 response
|
|
||||||
http.NotFound(w, r)
|
|
||||||
}
|
|
|
@ -1,86 +1,14 @@
|
||||||
package http
|
package http
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"net/http"
|
"github.com/ian-kent/gotcha/http"
|
||||||
"strings"
|
"html/template"
|
||||||
"log"
|
|
||||||
"github.com/ian-kent/Go-MailHog/mailhog/config"
|
|
||||||
"github.com/ian-kent/Go-MailHog/mailhog/http/api"
|
|
||||||
"github.com/ian-kent/Go-MailHog/mailhog/http/router"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var exitChannel chan int
|
func Index(session *http.Session) {
|
||||||
var cfg *config.Config
|
html, _ := session.RenderTemplate("index.html")
|
||||||
|
|
||||||
// TODO clean this mess up
|
session.Stash["Page"] = "Browse"
|
||||||
|
session.Stash["Content"] = template.HTML(html)
|
||||||
func web_exit(w http.ResponseWriter, r *http.Request, route *router.Route) {
|
session.Render("layout.html")
|
||||||
web_headers(w)
|
|
||||||
w.Write([]byte("Exiting MailHog!"))
|
|
||||||
exitChannel <- 1
|
|
||||||
}
|
|
||||||
|
|
||||||
func web_index(w http.ResponseWriter, r *http.Request, route *router.Route) {
|
|
||||||
web_headers(w)
|
|
||||||
data, _ := cfg.Assets("assets/templates/index.html")
|
|
||||||
w.Write([]byte(web_render(string(data))))
|
|
||||||
}
|
|
||||||
|
|
||||||
func web_static(w http.ResponseWriter, r *http.Request, route *router.Route) {
|
|
||||||
match := route.Pattern.FindStringSubmatch(r.URL.Path)
|
|
||||||
file := match[1]
|
|
||||||
log.Printf("[HTTP] GET %s\n", file)
|
|
||||||
|
|
||||||
if strings.HasSuffix(file, ".gif") {
|
|
||||||
w.Header().Set("Content-Type", "image/gif")
|
|
||||||
} else if strings.HasSuffix(file, ".png") {
|
|
||||||
w.Header().Set("Content-Type", "image/png")
|
|
||||||
} else if strings.HasSuffix(file, ".js") {
|
|
||||||
w.Header().Set("Content-Type", "text/javascript")
|
|
||||||
} else {
|
|
||||||
w.Header().Set("Content-Type", "text/plain")
|
|
||||||
}
|
|
||||||
|
|
||||||
data, err := cfg.Assets("assets" + file)
|
|
||||||
if err != nil {
|
|
||||||
w.WriteHeader(404)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
w.Write(data)
|
|
||||||
}
|
|
||||||
|
|
||||||
func web_render(content string) string {
|
|
||||||
data, _ := cfg.Assets("assets/templates/layout.html")
|
|
||||||
layout := string(data)
|
|
||||||
html := strings.Replace(layout, "<%= content %>", content, -1)
|
|
||||||
// TODO clean this up
|
|
||||||
html = strings.Replace(html, "<%= config[Hostname] %>", cfg.Hostname, -1)
|
|
||||||
return html
|
|
||||||
}
|
|
||||||
|
|
||||||
func web_headers(w http.ResponseWriter) {
|
|
||||||
w.Header().Set("Content-Type", "text/html")
|
|
||||||
}
|
|
||||||
|
|
||||||
func Start(exitCh chan int, conf *config.Config) {
|
|
||||||
exitChannel = exitCh
|
|
||||||
cfg = conf
|
|
||||||
|
|
||||||
r := &router.Router{}
|
|
||||||
server := &http.Server{
|
|
||||||
Addr: conf.HTTPBindAddr,
|
|
||||||
Handler: r,
|
|
||||||
}
|
|
||||||
|
|
||||||
r.Get("^/exit/?$", web_exit)
|
|
||||||
r.Get("^(/js/controllers.js)$", web_static)
|
|
||||||
r.Get("^(/images/hog.png)$", web_static)
|
|
||||||
r.Get("^(/images/github.png)$", web_static)
|
|
||||||
r.Get("^(/images/ajax-loader.gif)$", web_static)
|
|
||||||
r.Get("^/$", web_index)
|
|
||||||
|
|
||||||
api.CreateAPIv1(exitCh, conf, server)
|
|
||||||
|
|
||||||
server.ListenAndServe()
|
|
||||||
}
|
}
|
||||||
|
|
28
main.go
28
main.go
|
@ -3,12 +3,14 @@ package main
|
||||||
import (
|
import (
|
||||||
"flag"
|
"flag"
|
||||||
"github.com/ian-kent/Go-MailHog/mailhog/config"
|
"github.com/ian-kent/Go-MailHog/mailhog/config"
|
||||||
"github.com/ian-kent/Go-MailHog/mailhog/http"
|
|
||||||
"github.com/ian-kent/Go-MailHog/mailhog/smtp"
|
"github.com/ian-kent/Go-MailHog/mailhog/smtp"
|
||||||
|
"github.com/ian-kent/Go-MailHog/mailhog/http/api"
|
||||||
"github.com/ian-kent/Go-MailHog/mailhog/storage"
|
"github.com/ian-kent/Go-MailHog/mailhog/storage"
|
||||||
"log"
|
gotcha "github.com/ian-kent/gotcha/app"
|
||||||
|
"github.com/ian-kent/go-log/log"
|
||||||
"net"
|
"net"
|
||||||
"os"
|
"os"
|
||||||
|
mhhttp "github.com/ian-kent/Go-MailHog/mailhog/http"
|
||||||
)
|
)
|
||||||
|
|
||||||
var conf *config.Config
|
var conf *config.Config
|
||||||
|
@ -73,8 +75,26 @@ func main() {
|
||||||
}
|
}
|
||||||
|
|
||||||
func web_listen() {
|
func web_listen() {
|
||||||
log.Printf("[HTTP] Binding to address: %s\n", conf.HTTPBindAddr)
|
log.Info("[HTTP] Binding to address: %s", conf.HTTPBindAddr)
|
||||||
http.Start(exitCh, conf)
|
|
||||||
|
var app = gotcha.Create(Asset)
|
||||||
|
app.Config.Listen = conf.HTTPBindAddr
|
||||||
|
|
||||||
|
r := app.Router
|
||||||
|
|
||||||
|
r.Get("/images/(?P<file>.*)", r.Static("assets/images/{{file}}"))
|
||||||
|
r.Get("/js/(?P<file>.*)", r.Static("assets/js/{{file}}"))
|
||||||
|
r.Get("/", mhhttp.Index)
|
||||||
|
|
||||||
|
api.CreateAPIv1(conf, app)
|
||||||
|
|
||||||
|
app.Config.LeftDelim = ">>";
|
||||||
|
app.Config.RightDelim = "<<";
|
||||||
|
|
||||||
|
app.Start()
|
||||||
|
|
||||||
|
<-make(chan int)
|
||||||
|
exitCh<-1
|
||||||
}
|
}
|
||||||
|
|
||||||
func smtp_listen() *net.TCPListener {
|
func smtp_listen() *net.TCPListener {
|
||||||
|
|
Loading…
Add table
Reference in a new issue