208 lines
3.8 KiB
Go
208 lines
3.8 KiB
Go
package main
|
|
|
|
import (
|
|
"git.tcp.direct/kayos/common/hash"
|
|
"git.tcp.direct/kayos/common/pool"
|
|
valid "github.com/asaskevich/govalidator"
|
|
"github.com/gin-gonic/gin"
|
|
"github.com/rs/zerolog"
|
|
"github.com/rs/zerolog/log"
|
|
|
|
"github.com/json-iterator/go"
|
|
|
|
"git.tcp.direct/tcp.direct/tcp.ac/config"
|
|
)
|
|
|
|
var json = jsoniter.ConfigCompatibleWithStandardLibrary
|
|
|
|
var str = pool.NewStringFactory()
|
|
|
|
type EntryType uint8
|
|
|
|
const (
|
|
Image EntryType = iota
|
|
Text
|
|
URL
|
|
// Custom is for user uploads of arbitrary formats.
|
|
Custom
|
|
)
|
|
|
|
type UserID uint64
|
|
|
|
// Entry FIXME: not currently used
|
|
type Entry interface {
|
|
TypeCode() string
|
|
UID() string
|
|
DelKey() string
|
|
OwnerID() uint64
|
|
Private() bool
|
|
Sum() []byte
|
|
Bytes() []byte
|
|
}
|
|
|
|
type Post struct {
|
|
entryType EntryType
|
|
b2sum []byte
|
|
data []byte
|
|
owner UserID
|
|
uid, key string
|
|
priv bool
|
|
log *zerolog.Logger
|
|
}
|
|
|
|
func (p *Post) setLogger() {
|
|
pl := log.Logger.With().Str("caller", p.TypeCode(true)+":"+p.UID()).
|
|
Bool("private", p.priv).Logger()
|
|
p.log = &pl
|
|
}
|
|
|
|
func newPost(entryType EntryType, data []byte, priv bool) *Post {
|
|
p := &Post{
|
|
entryType: entryType,
|
|
priv: priv,
|
|
data: data,
|
|
}
|
|
p.setLogger()
|
|
return p
|
|
}
|
|
|
|
func typeToString(t EntryType, long bool) string {
|
|
s := str.Get()
|
|
defer str.MustPut(s)
|
|
switch t {
|
|
case Image:
|
|
s.WriteString("i")
|
|
if long {
|
|
s.WriteString("mg")
|
|
}
|
|
case Text:
|
|
s.WriteString("t")
|
|
if long {
|
|
s.WriteString("xt")
|
|
}
|
|
case URL:
|
|
s.WriteString("u")
|
|
if long {
|
|
s.WriteString("rl")
|
|
}
|
|
case Custom:
|
|
s.WriteString("e")
|
|
if long {
|
|
s.WriteString("tc")
|
|
}
|
|
default:
|
|
panic("unknown entry type")
|
|
}
|
|
return s.String()
|
|
}
|
|
|
|
func (p *Post) TypeCode(long bool) (code string) {
|
|
return typeToString(p.entryType, long)
|
|
}
|
|
|
|
func (p *Post) UID() string {
|
|
return p.uid
|
|
}
|
|
|
|
func (p *Post) DelKey() string {
|
|
return p.key
|
|
}
|
|
|
|
func (p *Post) Private() bool {
|
|
return p.priv
|
|
}
|
|
|
|
func (p *Post) Log() *zerolog.Logger {
|
|
if p.log != nil {
|
|
return p.log
|
|
}
|
|
p.setLogger()
|
|
return p.log
|
|
}
|
|
|
|
func validateKey(rKey string) bool {
|
|
if len(rKey) != config.DeleteKeySize || !valid.IsAlphanumeric(rKey) {
|
|
return false
|
|
}
|
|
return true
|
|
}
|
|
|
|
type Response struct {
|
|
View string `json:"view,omitempty"`
|
|
Delete string `json:"delete,omitempty"`
|
|
Error string `json:"error,omitempty"`
|
|
}
|
|
|
|
func (p *Post) viewURL() string {
|
|
s := str.Get()
|
|
defer str.MustPut(s)
|
|
s.WriteString(config.BaseURL)
|
|
s.WriteString(p.TypeCode(false))
|
|
s.WriteString("/")
|
|
s.WriteString(p.UID())
|
|
return s.String()
|
|
}
|
|
|
|
func (p *Post) delURL() string {
|
|
if p.key == "" {
|
|
return ""
|
|
}
|
|
s := str.Get()
|
|
defer str.MustPut(s)
|
|
s.WriteString(config.BaseURL)
|
|
s.WriteString("d/")
|
|
s.WriteString(p.TypeCode(false))
|
|
s.WriteString("/")
|
|
s.WriteString(p.DelKey())
|
|
return s.String()
|
|
}
|
|
|
|
func (p *Post) String() string {
|
|
resp := new(Response)
|
|
resp.View = p.viewURL()
|
|
resp.Delete = p.delURL()
|
|
str, _ := json.MarshalToString(resp)
|
|
return str
|
|
}
|
|
|
|
func (p *Post) NewPostResponse(responder any) {
|
|
view := p.viewURL()
|
|
log.Info().
|
|
Str("type", p.TypeCode(false)).
|
|
Str("uid", p.UID()).Str("key", p.DelKey()).
|
|
Bool("private", p.Private()).Msgf("success: %s", view)
|
|
|
|
urlString := p.TypeCode(true)
|
|
delString := "del"
|
|
// for backwards compatibility with image scripts.
|
|
if p.TypeCode(false) == "i" {
|
|
urlString = "Imgurl"
|
|
delString = "ToDelete"
|
|
}
|
|
|
|
if cg, ginok := responder.(*gin.Context); ginok {
|
|
cg.JSON(201, gin.H{urlString: view, delString: p.delURL()})
|
|
}
|
|
if ct, tdok := responder.(*textValidator); tdok {
|
|
js, err := json.Marshal(gin.H{urlString: view, delString: p.delURL()})
|
|
if err != nil {
|
|
log.Error().Interface("post", p).
|
|
Err(err).Msg("json marshal failed")
|
|
ct.out = []byte("{\"error\":\"internal server error\"}")
|
|
}
|
|
ct.out = js
|
|
}
|
|
return
|
|
}
|
|
|
|
func (p *Post) Sum() []byte {
|
|
if p.b2sum == nil && p.data != nil {
|
|
p.b2sum = hash.Sum(hash.TypeBlake2b, p.data)
|
|
}
|
|
return p.b2sum
|
|
}
|
|
|
|
func (p *Post) Bytes() []byte {
|
|
return p.data
|
|
}
|