mirror of
https://codeberg.org/pluja/kycnot.me
synced 2025-03-13 04:56:29 -04:00
195 lines
4.6 KiB
Go
195 lines
4.6 KiB
Go
package server
|
|
|
|
import (
|
|
"context"
|
|
"html/template"
|
|
"math/rand"
|
|
"net/http"
|
|
"os"
|
|
"path"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/allegro/bigcache/v3"
|
|
"github.com/dustin/go-humanize"
|
|
"github.com/iris-contrib/middleware/cors"
|
|
"github.com/kataras/iris/v12"
|
|
"github.com/kataras/iris/v12/middleware/rate"
|
|
"github.com/rs/zerolog/log"
|
|
|
|
"pluja.dev/kycnot.me/config"
|
|
"pluja.dev/kycnot.me/utils/pow"
|
|
)
|
|
|
|
type Server struct {
|
|
ListenAddr string
|
|
Router *iris.Application
|
|
PowChallenger *pow.PowChallenger
|
|
Cache *bigcache.BigCache
|
|
HttpClient *http.Client
|
|
}
|
|
|
|
func NewServer(listenAddr string) *Server {
|
|
app := iris.New()
|
|
cache, err := bigcache.New(context.Background(), bigcache.Config{
|
|
Shards: 1024,
|
|
LifeWindow: 30 * (24 * time.Hour),
|
|
MaxEntriesInWindow: 1000 * 10 * 60,
|
|
MaxEntrySize: 500,
|
|
Verbose: false,
|
|
HardMaxCacheSize: 0,
|
|
})
|
|
if err != nil {
|
|
log.Fatal().Err(err).Msg("Could not initialize cache")
|
|
}
|
|
|
|
return &Server{
|
|
ListenAddr: listenAddr,
|
|
Router: app,
|
|
PowChallenger: &pow.PowChallenger{},
|
|
Cache: cache,
|
|
HttpClient: &http.Client{},
|
|
}
|
|
}
|
|
|
|
func (s *Server) Run() error {
|
|
s.SetupMiddleware()
|
|
s.RegisterRoutes()
|
|
s.RegisterViews()
|
|
s.PowChallenger.Init()
|
|
return s.Router.Listen(s.ListenAddr, iris.WithSitemap("https://kycnot.me"))
|
|
}
|
|
|
|
func (s *Server) SetupMiddleware() {
|
|
s.Router.Use(iris.Compression)
|
|
|
|
if config.Conf.Dev {
|
|
log.Debug().Msg("CORS is enabled")
|
|
crs := cors.New(cors.Options{
|
|
AllowedOrigins: []string{"*"}, // allows everything, use that to change the hosts.
|
|
AllowCredentials: true,
|
|
})
|
|
s.Router.Use(crs)
|
|
} else {
|
|
crs := cors.New(cors.Options{
|
|
AllowedOrigins: []string{"*"}, // allows everything, use that to change the hosts.
|
|
AllowCredentials: true,
|
|
})
|
|
s.Router.Use(crs)
|
|
}
|
|
|
|
if config.Conf.Dev {
|
|
s.Router.Logger().SetLevel("debug")
|
|
s.Router.Use(iris.Cache304(10 * time.Second))
|
|
} else {
|
|
s.Router.Logger().SetLevel("warn")
|
|
s.Router.Use(iris.Cache304(24 * 60 * 60))
|
|
}
|
|
}
|
|
|
|
func (s *Server) RegisterRoutes() {
|
|
// Static routes
|
|
s.Router.Favicon(path.Join(os.Getenv("ROOT_DIR"), "/frontend/static", "/assets/favicon.webp"))
|
|
s.Router.HandleDir("/static", iris.Dir(path.Join(os.Getenv("ROOT_DIR"), "/frontend/static")))
|
|
|
|
// GET
|
|
s.Router.Get("/", s.handleIndex)
|
|
s.Router.Get("/about", s.handleAbout)
|
|
s.Router.Get("/pending", s.handlePending)
|
|
s.Router.Get("/service/{name:string}", s.handleService)
|
|
s.Router.Get("/exchange/{name:string}", s.handleService)
|
|
s.Router.Get("/point/{id:string}", s.handleAttribute)
|
|
s.Router.Get("/attr/{id:string}", s.handleAttribute)
|
|
s.Router.Get("/request/service", s.handleRequestServiceForm)
|
|
|
|
// Miscellaneous Routes
|
|
s.Router.Get("/pgp", s.handlePgp)
|
|
s.Router.Get("/nostr", s.handleNostr)
|
|
|
|
// POST
|
|
s.Router.Post("/new/service", s.handlePostRequestServiceForm)
|
|
|
|
// API routes
|
|
genericApi := s.Router.Party("/api/g")
|
|
{
|
|
genericApi.Get("/pow/verify/{id}/{nonce:int}", s.handleVerifyPow)
|
|
genericApi.Get("/picture/{id}", s.handleApiPicture)
|
|
}
|
|
|
|
v1Api := s.Router.Party("/api/v1")
|
|
{
|
|
limitV1 := rate.Limit(rate.Every(1*time.Minute), 5, rate.PurgeEvery(time.Minute, 5*time.Minute))
|
|
v1Api.Use(limitV1)
|
|
v1Api.Get("/service/{name:string}", s.handleApiService)
|
|
v1Api.Get("/service/{name:string}/summary", s.handleScoreSummary)
|
|
}
|
|
}
|
|
|
|
func (s *Server) RegisterViews() {
|
|
// Use blocks as the templating engine
|
|
blocks := iris.Blocks("./frontend/templates", ".html")
|
|
if config.Conf.Dev {
|
|
blocks.Reload(true)
|
|
}
|
|
blocks.Engine.Funcs(template.FuncMap{
|
|
"attr": func(s string) template.HTMLAttr {
|
|
return template.HTMLAttr(s)
|
|
},
|
|
"safe": func(s string) template.HTML {
|
|
return template.HTML(s)
|
|
},
|
|
"randomElem": func(vs []string) string {
|
|
if len(vs) == 0 {
|
|
return ""
|
|
}
|
|
return vs[rand.Intn(len(vs))]
|
|
},
|
|
"shortText": func(s string) string {
|
|
if len(s) > 50 {
|
|
return strings.TrimSpace(s[:50]) + "..."
|
|
}
|
|
return s
|
|
},
|
|
"humanizePbTimeString": func(t string) string {
|
|
if t == "" {
|
|
return "Unknown"
|
|
}
|
|
|
|
layout := "2006-01-02 15:04:05.000Z"
|
|
|
|
tm, err := time.Parse(layout, t)
|
|
if err != nil {
|
|
return t
|
|
}
|
|
return humanize.Time(tm)
|
|
},
|
|
"dateString": func(t string) string {
|
|
if t == "" {
|
|
return "Unknown"
|
|
}
|
|
|
|
layout := "2006-01-02 15:04:05.000Z"
|
|
|
|
tm, err := time.Parse(layout, t)
|
|
if err != nil {
|
|
return t
|
|
}
|
|
return tm.Format("2006-01-02")
|
|
},
|
|
"isNew": func(t string) bool {
|
|
if t == "" {
|
|
return false
|
|
}
|
|
|
|
layout := "2006-01-02 15:04:05.000Z"
|
|
|
|
tm, err := time.Parse(layout, t)
|
|
if err != nil {
|
|
return false
|
|
}
|
|
return time.Since(tm) < 7*(24*time.Hour)
|
|
},
|
|
})
|
|
s.Router.RegisterView(blocks)
|
|
}
|