func main() { // Create our Gotcha application var app = gotcha.Create(Asset) // Set the logger output pattern log.Logger().Appender().SetLayout(layout.Pattern("[%d] [%p] %m")) log.Logger().SetLevel(log.Stol("TRACE")) // Get the router r := app.Router // Create some routes r.Get("/", example) r.Post("/", examplepost) r.Get("/foo", example2) r.Get("/bar", example3) r.Get("/stream", streamed) r.Get("/err", err) // Serve static content (but really use a CDN) r.Get("/images/(?P<file>.*)", r.Static("assets/images/{{file}}")) r.Get("/css/(?P<file>.*)", r.Static("assets/css/{{file}}")) // Listen to some events app.On(events.BeforeHandler, func(session *http.Session, next func()) { n := 0 c, ok := session.Request.Cookies["test"] if ok { n, _ = strconv.Atoi(c.Value) } session.Stash["test"] = n log.Printf("Got BeforeHandler event! n = %d", n) next() }) app.On(events.AfterHandler, func(session *http.Session, next func()) { n := session.Stash["test"].(int) + 1 session.Response.Cookies.Set(&nethttp.Cookie{ Name: "test", Value: strconv.Itoa(n), }) log.Println("Got AfterHandler event!") next() }) app.On(events.AfterResponse, func(session *http.Session, next func()) { log.Println("Got AfterResponse event!") next() }) // Start our application app.Start() <-make(chan int) }
func (apiv2 *APIv2) search(w http.ResponseWriter, req *http.Request) { log.Println("[APIv2] GET /api/v2/search") apiv2.defaultOptions(w, req) start, limit := apiv2.getStartLimit(w, req) kind := req.URL.Query().Get("kind") if kind != "from" && kind != "to" && kind != "containing" { w.WriteHeader(400) return } query := req.URL.Query().Get("query") if len(query) == 0 { w.WriteHeader(400) return } var res messagesResult messages, total, _ := apiv2.config.Storage.Search(kind, query, start, limit) res.Count = len([]data.Message(*messages)) res.Start = start res.Items = []data.Message(*messages) res.Total = total b, _ := json.Marshal(res) w.Header().Add("Content-Type", "application/json") w.Write(b) }
func CreateAPIv1(conf *config.Config, r *pat.Router) *APIv1 { log.Println("Creating API v1") apiv1 := &APIv1{ config: conf, } stream = goose.NewEventStream() r.Path("/api/v1/messages").Methods("GET").HandlerFunc(apiv1.messages) r.Path("/api/v1/messages").Methods("DELETE").HandlerFunc(apiv1.delete_all) r.Path("/api/v1/messages").Methods("OPTIONS").HandlerFunc(apiv1.defaultOptions) r.Path("/api/v1/messages/{id}").Methods("GET").HandlerFunc(apiv1.message) r.Path("/api/v1/messages/{id}").Methods("DELETE").HandlerFunc(apiv1.delete_one) r.Path("/api/v1/messages/{id}").Methods("OPTIONS").HandlerFunc(apiv1.defaultOptions) r.Path("/api/v1/messages/{id}/download").Methods("GET").HandlerFunc(apiv1.download) r.Path("/api/v1/messages/{id}/download").Methods("OPTIONS").HandlerFunc(apiv1.defaultOptions) r.Path("/api/v1/messages/{id}/mime/part/{part}/download").Methods("GET").HandlerFunc(apiv1.download_part) r.Path("/api/v1/messages/{id}/mime/part/{part}/download").Methods("OPTIONS").HandlerFunc(apiv1.defaultOptions) r.Path("/api/v1/messages/{id}/release").Methods("POST").HandlerFunc(apiv1.release_one) r.Path("/api/v1/messages/{id}/release").Methods("OPTIONS").HandlerFunc(apiv1.defaultOptions) r.Path("/api/v1/events").Methods("GET").HandlerFunc(apiv1.eventstream) r.Path("/api/v1/events").Methods("OPTIONS").HandlerFunc(apiv1.defaultOptions) go func() { keepaliveTicker := time.Tick(time.Minute) for { select { case msg := <-apiv1.config.MessageChan: log.Println("Got message in APIv1 event stream") bytes, _ := json.MarshalIndent(msg, "", " ") json := string(bytes) log.Printf("Sending content: %s\n", json) apiv1.broadcast(json) case <-keepaliveTicker: apiv1.keepalive() } } }() return apiv1 }
func (apiv2 *APIv2) listOutgoingSMTP(w http.ResponseWriter, req *http.Request) { log.Println("[APIv2] GET /api/v2/outgoing-smtp") apiv2.defaultOptions(w, req) b, _ := json.Marshal(apiv2.config.OutgoingSMTP) w.Header().Add("Content-Type", "application/json") w.Write(b) }
func (apiv1 *APIv1) eventstream(w http.ResponseWriter, req *http.Request) { log.Println("[APIv1] GET /api/v1/events") //apiv1.defaultOptions(session) if len(apiv1.config.CORSOrigin) > 0 { w.Header().Add("Access-Control-Allow-Origin", apiv1.config.CORSOrigin) w.Header().Add("Access-Control-Allow-Methods", "OPTIONS,GET,POST,DELETE") } stream.AddReceiver(w) }
func (apiv2 *APIv2) deleteJim(w http.ResponseWriter, req *http.Request) { log.Println("[APIv2] DELETE /api/v2/jim") apiv2.defaultOptions(w, req) if apiv2.config.Monkey == nil { w.WriteHeader(404) return } apiv2.config.Monkey = nil }
func (apiv2 *APIv2) jim(w http.ResponseWriter, req *http.Request) { log.Println("[APIv2] GET /api/v2/jim") apiv2.defaultOptions(w, req) if apiv2.config.Monkey == nil { w.WriteHeader(404) return } b, _ := json.Marshal(apiv2.config.Monkey) w.Header().Add("Content-Type", "application/json") w.Write(b) }
func (apiv2 *APIv2) updateJim(w http.ResponseWriter, req *http.Request) { log.Println("[APIv2] PUT /api/v2/jim") apiv2.defaultOptions(w, req) if apiv2.config.Monkey == nil { w.WriteHeader(404) return } err := apiv2.newJimFromBody(w, req) if err != nil { w.WriteHeader(400) } }
func (apiv1 *APIv1) delete_all(w http.ResponseWriter, req *http.Request) { log.Println("[APIv1] POST /api/v1/messages") apiv1.defaultOptions(w, req) w.Header().Add("Content-Type", "text/json") switch apiv1.config.Storage.(type) { case *storage.MongoDB: apiv1.config.Storage.(*storage.MongoDB).DeleteAll() case *storage.InMemory: apiv1.config.Storage.(*storage.InMemory).DeleteAll() default: w.WriteHeader(500) return } }
func (apiv2 *APIv2) createJim(w http.ResponseWriter, req *http.Request) { log.Println("[APIv2] POST /api/v2/jim") apiv2.defaultOptions(w, req) if apiv2.config.Monkey != nil { w.WriteHeader(400) return } apiv2.config.Monkey = config.Jim // Try, but ignore errors // Could be better (e.g., ok if no json, error if badly formed json) // but this works for now apiv2.newJimFromBody(w, req) w.WriteHeader(201) }
func (apiv2 *APIv2) messages(w http.ResponseWriter, req *http.Request) { log.Println("[APIv2] GET /api/v2/messages") apiv2.defaultOptions(w, req) start, limit := apiv2.getStartLimit(w, req) var res messagesResult messages, _ := apiv2.config.Storage.List(start, limit) res.Count = len([]data.Message(*messages)) res.Start = start res.Items = []data.Message(*messages) res.Total = apiv2.config.Storage.Count() bytes, _ := json.Marshal(res) w.Header().Add("Content-Type", "text/json") w.Write(bytes) }
func (apiv1 *APIv1) messages(w http.ResponseWriter, req *http.Request) { log.Println("[APIv1] GET /api/v1/messages") apiv1.defaultOptions(w, req) // TODO start, limit switch apiv1.config.Storage.(type) { case *storage.MongoDB: messages, _ := apiv1.config.Storage.(*storage.MongoDB).List(0, 1000) bytes, _ := json.Marshal(messages) w.Header().Add("Content-Type", "text/json") w.Write(bytes) case *storage.InMemory: messages, _ := apiv1.config.Storage.(*storage.InMemory).List(0, 1000) bytes, _ := json.Marshal(messages) w.Header().Add("Content-Type", "text/json") w.Write(bytes) default: w.WriteHeader(500) } }
func CreateAPIv2(conf *config.Config, r *pat.Router) *APIv2 { log.Println("Creating API v2") apiv2 := &APIv2{ config: conf, } r.Path("/api/v2/messages").Methods("GET").HandlerFunc(apiv2.messages) r.Path("/api/v2/messages").Methods("OPTIONS").HandlerFunc(apiv2.defaultOptions) r.Path("/api/v2/search").Methods("GET").HandlerFunc(apiv2.search) r.Path("/api/v2/search").Methods("OPTIONS").HandlerFunc(apiv2.defaultOptions) r.Path("/api/v2/jim").Methods("GET").HandlerFunc(apiv2.jim) r.Path("/api/v2/jim").Methods("POST").HandlerFunc(apiv2.createJim) r.Path("/api/v2/jim").Methods("PUT").HandlerFunc(apiv2.updateJim) r.Path("/api/v2/jim").Methods("DELETE").HandlerFunc(apiv2.deleteJim) r.Path("/api/v2/jim").Methods("OPTIONS").HandlerFunc(apiv2.defaultOptions) r.Path("/api/v2/outgoing-smtp").Methods("GET").HandlerFunc(apiv2.listOutgoingSMTP) r.Path("/api/v2/outgoing-smtp").Methods("OPTIONS").HandlerFunc(apiv2.defaultOptions) return apiv2 }
func (apiv1 *APIv1) broadcast(json string) { log.Println("[APIv1] BROADCAST /api/v1/events") b := []byte(json) stream.Notify("data", b) }
// keepalive sends an empty keep alive message. // // This not only can keep connections alive, but also will detect broken // connections. Without this it is possible for the server to become // unresponsive due to too many open files. func (apiv1 *APIv1) keepalive() { log.Println("[APIv1] KEEPALIVE /api/v1/events") stream.Notify("keepalive", []byte{}) }