merp/merp.go

183 lines
4.1 KiB
Go
Raw Normal View History

2019-11-08 12:35:27 +00:00
package merp
2019-10-25 16:17:14 +00:00
2019-10-27 12:38:03 +00:00
import "encoding/json"
2019-10-25 16:17:14 +00:00
import "net/http"
import "time"
2019-10-27 12:38:03 +00:00
2019-11-08 13:01:57 +00:00
import "github.com/astaxie/beego/orm"
2019-10-25 16:17:14 +00:00
import "github.com/gin-gonic/gin"
2019-10-27 13:26:07 +00:00
import "github.com/google/uuid"
import "github.com/rs/zerolog/log"
2019-10-29 17:12:59 +00:00
import "github.com/sneak/merp/models"
2019-10-27 12:38:03 +00:00
2019-11-18 08:14:05 +00:00
const MAX_MERPS_TO_RETURN = 50
const LONGPOLL_TIMEOUT_SECS = 60
func decodeJSON(in []byte) (interface{}, error) {
2019-10-29 16:40:30 +00:00
var out interface{}
err := json.Unmarshal(in, &out)
if err != nil {
log.Error().Msg("error decoding json")
return nil, err
2019-10-29 16:40:30 +00:00
}
return out, nil
2019-10-29 16:40:30 +00:00
}
2019-11-11 23:11:38 +00:00
func (ms *Server) listenForMerps() gin.HandlerFunc {
// /listen/for/merps/from/my-thing-name
return func(c *gin.Context) {
2019-11-18 08:14:05 +00:00
thing := c.Param("thing")
if thing != "" {
if thingRegex.MatchString(thing) == false {
c.JSON(http.StatusPreconditionFailed, gin.H{
"this": "failed",
"status": http.StatusPreconditionFailed,
"because": "invalid thing format, try [a-zA-Z0-9-_.]",
})
return
}
}
el := NewEventListener(MerpTopic(thing))
timeout := time.After(LONGPOLL_TIMEOUT_SECS * time.Second)
// Keep trying until we're timed out or got a result or got an error
for {
select {
case <-c.Done():
// unregister listener and close conn FIXME
case <-timeout:
// unregister listener and close conn FIXME
case newMerpJSON := <-el.NewMerpJSONChannel:
log.Info().Msg(newMerpJSON)
// send them some json FIXME
}
}
2019-11-11 23:11:38 +00:00
}
}
func (ms *Server) getLatestMerps() gin.HandlerFunc {
return func(c *gin.Context) {
2019-10-29 16:40:30 +00:00
thing := c.Param("thing")
2019-11-08 13:01:57 +00:00
2019-11-08 12:55:54 +00:00
if thing != "" {
2019-11-11 23:11:38 +00:00
if thingRegex.MatchString(thing) == false {
2019-11-08 12:55:54 +00:00
c.JSON(http.StatusPreconditionFailed, gin.H{
"this": "failed",
"status": http.StatusPreconditionFailed,
"because": "invalid thing format, try [a-zA-Z0-9-_]",
})
return
}
2019-11-08 13:01:57 +00:00
}
var qs orm.QuerySeter
if thing == "" {
2019-11-18 08:14:05 +00:00
qs = ms.db.QueryTable("merp").OrderBy("-created").Limit(MAX_MERPS_TO_RETURN)
2019-11-08 12:55:54 +00:00
} else {
2019-11-18 08:14:05 +00:00
qs = ms.db.QueryTable("merp").Filter("thing", thing).OrderBy("-created").Limit(MAX_MERPS_TO_RETURN)
2019-10-29 16:40:30 +00:00
}
var merps []*models.Merp
qs.All(&merps)
2019-11-08 12:41:18 +00:00
output := make([]map[string]interface{}, 0)
2019-10-29 16:40:30 +00:00
for _, merp := range merps {
outelem := make(map[string]interface{})
outelem["thing"] = merp.Thing
outjs, err := decodeJSON([]byte(merp.Content))
if err != nil {
2019-10-29 16:40:30 +00:00
outelem["content"] = gin.H{}
} else {
outelem["content"] = outjs
}
outelem["created"] = merp.Created
output = append(output, outelem)
}
c.JSON(http.StatusOK, gin.H{
"this": "succeeded",
"by": "getting",
"the": "merps",
"with": output,
})
2019-10-27 12:38:03 +00:00
}
2019-10-25 16:17:14 +00:00
}
func (ms *Server) handleNewMerp() gin.HandlerFunc {
return func(c *gin.Context) {
2019-10-27 13:26:07 +00:00
// request time
2019-10-25 16:17:14 +00:00
thing := c.Param("thing")
2019-11-11 23:11:38 +00:00
if thingRegex.MatchString(thing) == false {
2019-10-25 16:17:14 +00:00
c.JSON(http.StatusPreconditionFailed, gin.H{
2019-10-27 12:38:03 +00:00
"this": "failed",
"status": http.StatusPreconditionFailed,
"because": "invalid thing format, try a-zA-Z0-9-_",
2019-10-25 16:17:14 +00:00
})
return
}
2019-10-27 12:38:03 +00:00
2019-10-27 13:26:07 +00:00
// FIXME rate limit this a bit on thing+clientip+json to cut down on
// repeated messages
content := make(map[string]interface{})
respContent := gin.H{}
2019-10-27 12:38:03 +00:00
// FIXME support POST data as well
2019-10-27 13:26:07 +00:00
2019-10-25 16:17:14 +00:00
for k, v := range c.Request.URL.Query() {
content[k] = v[0]
2019-10-27 13:26:07 +00:00
respContent[k] = v[0]
2019-10-25 16:17:14 +00:00
}
2019-10-27 13:26:07 +00:00
u := uuid.New()
2019-10-27 12:38:03 +00:00
at := time.Now().UTC()
atString := at.Format(time.RFC3339)
2019-10-29 16:40:30 +00:00
serialized, jsonerr := json.MarshalIndent(content, "", " ")
2019-10-27 12:38:03 +00:00
if jsonerr != nil {
c.JSON(
http.StatusPreconditionFailed,
gin.H{
"this": "failed",
"status": http.StatusPreconditionFailed,
2019-10-27 13:26:07 +00:00
"because": jsonerr.Error(),
2019-10-27 12:38:03 +00:00
},
)
return
}
merp := models.Merp{
Created: at,
Thing: thing,
Content: string(serialized),
2019-10-27 13:26:07 +00:00
UUID: u.String(),
2019-10-27 12:38:03 +00:00
}
_, err := ms.db.Insert(&merp)
2019-10-27 12:38:03 +00:00
2019-10-27 13:26:07 +00:00
if err != nil {
c.JSON(
http.StatusPreconditionFailed,
gin.H{
"this": "failed",
"status": http.StatusPreconditionFailed,
"because": err.Error(),
},
)
return
}
2019-10-27 12:38:03 +00:00
2019-10-25 16:17:14 +00:00
c.JSON(http.StatusOK, gin.H{
"this": "succeeded",
"by": "merping",
"the": "merp",
"with": gin.H{
2019-11-07 08:51:35 +00:00
"thing": thing,
"created": atString,
"content": respContent,
"transaction": u.String(),
2019-10-25 16:17:14 +00:00
},
})
}
}