aboutsummaryrefslogtreecommitdiff
path: root/forged/internal/incoming
diff options
context:
space:
mode:
authorRunxi Yu <me@runxiyu.org>2025-08-18 03:12:41 +0800
committerRunxi Yu <me@runxiyu.org>2025-08-18 03:12:41 +0800
commitf7dde29539536a67687cbeff9662a9617e077150 (patch)
treed976eb1f64062a65da4e689bd650ad84be737c52 /forged/internal/incoming
parentMove sql to inside forged (diff)
downloadforge-f7dde29539536a67687cbeff9662a9617e077150.tar.gz
forge-f7dde29539536a67687cbeff9662a9617e077150.tar.zst
forge-f7dde29539536a67687cbeff9662a9617e077150.zip
Make the index page work
Diffstat (limited to 'forged/internal/incoming')
-rw-r--r--forged/internal/incoming/hooks/hooks.go5
-rw-r--r--forged/internal/incoming/lmtp/lmtp.go5
-rw-r--r--forged/internal/incoming/ssh/ssh.go11
-rw-r--r--forged/internal/incoming/web/handler.go8
-rw-r--r--forged/internal/incoming/web/handlers/group.go7
-rw-r--r--forged/internal/incoming/web/handlers/index.go24
-rw-r--r--forged/internal/incoming/web/handlers/not_implemented.go11
-rw-r--r--forged/internal/incoming/web/handlers/repo/handler.go15
-rw-r--r--forged/internal/incoming/web/handlers/repo/index.go8
-rw-r--r--forged/internal/incoming/web/router.go59
-rw-r--r--forged/internal/incoming/web/server.go8
-rw-r--r--forged/internal/incoming/web/types/types.go10
12 files changed, 137 insertions, 34 deletions
diff --git a/forged/internal/incoming/hooks/hooks.go b/forged/internal/incoming/hooks/hooks.go
index d0f57f5..941b03f 100644
--- a/forged/internal/incoming/hooks/hooks.go
+++ b/forged/internal/incoming/hooks/hooks.go
@@ -10,12 +10,14 @@ import (
"github.com/gliderlabs/ssh"
"go.lindenii.runxiyu.org/forge/forged/internal/common/cmap"
"go.lindenii.runxiyu.org/forge/forged/internal/common/misc"
+ "go.lindenii.runxiyu.org/forge/forged/internal/global"
)
type Server struct {
hookMap cmap.Map[string, hookInfo]
socketPath string
executablesPath string
+ globalData *global.GlobalData
}
type hookInfo struct {
session ssh.Session
@@ -30,11 +32,12 @@ type hookInfo struct {
contribReq string
}
-func New(config Config) (server *Server) {
+func New(config Config, globalData *global.GlobalData) (server *Server) {
return &Server{
socketPath: config.Socket,
executablesPath: config.Execs,
hookMap: cmap.Map[string, hookInfo]{},
+ globalData: globalData,
}
}
diff --git a/forged/internal/incoming/lmtp/lmtp.go b/forged/internal/incoming/lmtp/lmtp.go
index 61b1caf..d7e5ef4 100644
--- a/forged/internal/incoming/lmtp/lmtp.go
+++ b/forged/internal/incoming/lmtp/lmtp.go
@@ -8,6 +8,7 @@ import (
"time"
"go.lindenii.runxiyu.org/forge/forged/internal/common/misc"
+ "go.lindenii.runxiyu.org/forge/forged/internal/global"
)
type Server struct {
@@ -16,15 +17,17 @@ type Server struct {
maxSize int64
writeTimeout uint32
readTimeout uint32
+ globalData *global.GlobalData
}
-func New(config Config) (server *Server) {
+func New(config Config, globalData *global.GlobalData) (server *Server) {
return &Server{
socket: config.Socket,
domain: config.Domain,
maxSize: config.MaxSize,
writeTimeout: config.WriteTimeout,
readTimeout: config.ReadTimeout,
+ globalData: globalData,
}
}
diff --git a/forged/internal/incoming/ssh/ssh.go b/forged/internal/incoming/ssh/ssh.go
index 9338eca..dc03501 100644
--- a/forged/internal/incoming/ssh/ssh.go
+++ b/forged/internal/incoming/ssh/ssh.go
@@ -9,26 +9,27 @@ import (
gliderssh "github.com/gliderlabs/ssh"
"go.lindenii.runxiyu.org/forge/forged/internal/common/misc"
+ "go.lindenii.runxiyu.org/forge/forged/internal/global"
gossh "golang.org/x/crypto/ssh"
)
type Server struct {
gliderServer *gliderssh.Server
privkey gossh.Signer
- pubkeyString string
- pubkeyFP string
net string
addr string
root string
shutdownTimeout uint32
+ globalData *global.GlobalData
}
-func New(config Config) (server *Server, err error) {
+func New(config Config, globalData *global.GlobalData) (server *Server, err error) {
server = &Server{
net: config.Net,
addr: config.Addr,
root: config.Root,
shutdownTimeout: config.ShutdownTimeout,
+ globalData: globalData,
} //exhaustruct:ignore
var privkeyBytes []byte
@@ -43,8 +44,8 @@ func New(config Config) (server *Server, err error) {
return server, fmt.Errorf("parse SSH private key: %w", err)
}
- server.pubkeyString = misc.BytesToString(gossh.MarshalAuthorizedKey(server.privkey.PublicKey()))
- server.pubkeyFP = gossh.FingerprintSHA256(server.privkey.PublicKey())
+ server.globalData.SSHPubkey = misc.BytesToString(gossh.MarshalAuthorizedKey(server.privkey.PublicKey()))
+ server.globalData.SSHFingerprint = gossh.FingerprintSHA256(server.privkey.PublicKey())
server.gliderServer = &gliderssh.Server{
Handler: handle,
diff --git a/forged/internal/incoming/web/handler.go b/forged/internal/incoming/web/handler.go
index da2a2e0..bc50b33 100644
--- a/forged/internal/incoming/web/handler.go
+++ b/forged/internal/incoming/web/handler.go
@@ -5,6 +5,8 @@ import (
"net/http"
"go.lindenii.runxiyu.org/forge/forged/internal/common/misc"
+ "go.lindenii.runxiyu.org/forge/forged/internal/database/queries"
+ "go.lindenii.runxiyu.org/forge/forged/internal/global"
handlers "go.lindenii.runxiyu.org/forge/forged/internal/incoming/web/handlers"
repoHandlers "go.lindenii.runxiyu.org/forge/forged/internal/incoming/web/handlers/repo"
"go.lindenii.runxiyu.org/forge/forged/internal/incoming/web/templates"
@@ -14,8 +16,8 @@ type handler struct {
r *Router
}
-func NewHandler(cfg Config) http.Handler {
- h := &handler{r: NewRouter().ReverseProxy(cfg.ReverseProxy)}
+func NewHandler(cfg Config, globalData *global.GlobalData, queries *queries.Queries) *handler {
+ h := &handler{r: NewRouter().ReverseProxy(cfg.ReverseProxy).Global(globalData).Queries(queries)}
staticFS := http.FileServer(http.Dir(cfg.StaticPath))
h.r.ANYHTTP("-/static/*rest",
@@ -36,7 +38,7 @@ func NewHandler(cfg Config) http.Handler {
indexHTTP := handlers.NewIndexHTTP(renderer)
groupHTTP := handlers.NewGroupHTTP(renderer)
repoHTTP := repoHandlers.NewHTTP(renderer)
- notImpl := handlers.NewNotImplementedHTTP()
+ notImpl := handlers.NewNotImplementedHTTP(renderer)
// Index
h.r.GET("/", indexHTTP.Index)
diff --git a/forged/internal/incoming/web/handlers/group.go b/forged/internal/incoming/web/handlers/group.go
index 0c631c3..e56a3b5 100644
--- a/forged/internal/incoming/web/handlers/group.go
+++ b/forged/internal/incoming/web/handlers/group.go
@@ -12,7 +12,11 @@ type GroupHTTP struct {
r templates.Renderer
}
-func NewGroupHTTP(r templates.Renderer) *GroupHTTP { return &GroupHTTP{r: r} }
+func NewGroupHTTP(r templates.Renderer) *GroupHTTP {
+ return &GroupHTTP{
+ r: r,
+ }
+}
func (h *GroupHTTP) Index(w http.ResponseWriter, r *http.Request, _ wtypes.Vars) {
base := wtypes.Base(r)
@@ -22,4 +26,3 @@ func (h *GroupHTTP) Index(w http.ResponseWriter, r *http.Request, _ wtypes.Vars)
GroupPath: "/" + strings.Join(base.GroupPath, "/") + "/",
})
}
-
diff --git a/forged/internal/incoming/web/handlers/index.go b/forged/internal/incoming/web/handlers/index.go
index 259ca4a..22e6201 100644
--- a/forged/internal/incoming/web/handlers/index.go
+++ b/forged/internal/incoming/web/handlers/index.go
@@ -4,7 +4,9 @@ import (
"log"
"net/http"
+ "go.lindenii.runxiyu.org/forge/forged/internal/database/queries"
"go.lindenii.runxiyu.org/forge/forged/internal/incoming/web/templates"
+ "go.lindenii.runxiyu.org/forge/forged/internal/incoming/web/types"
wtypes "go.lindenii.runxiyu.org/forge/forged/internal/incoming/web/types"
)
@@ -12,13 +14,25 @@ type IndexHTTP struct {
r templates.Renderer
}
-func NewIndexHTTP(r templates.Renderer) *IndexHTTP { return &IndexHTTP{r: r} }
+func NewIndexHTTP(r templates.Renderer) *IndexHTTP {
+ return &IndexHTTP{
+ r: r,
+ }
+}
-func (h *IndexHTTP) Index(w http.ResponseWriter, _ *http.Request, _ wtypes.Vars) {
- err := h.r.Render(w, "index", struct {
- Title string
+func (h *IndexHTTP) Index(w http.ResponseWriter, r *http.Request, _ wtypes.Vars) {
+ groups, err := types.Base(r).Queries.GetRootGroups(r.Context())
+ if err != nil {
+ http.Error(w, "failed to get root groups", http.StatusInternalServerError)
+ log.Println("failed to get root groups", "error", err)
+ return
+ }
+ err = h.r.Render(w, "index", struct {
+ BaseData *types.BaseData
+ Groups []queries.GetRootGroupsRow
}{
- Title: "Home",
+ BaseData: types.Base(r),
+ Groups: groups,
})
if err != nil {
log.Println("failed to render index page", "error", err)
diff --git a/forged/internal/incoming/web/handlers/not_implemented.go b/forged/internal/incoming/web/handlers/not_implemented.go
index 472f73b..6813c88 100644
--- a/forged/internal/incoming/web/handlers/not_implemented.go
+++ b/forged/internal/incoming/web/handlers/not_implemented.go
@@ -3,12 +3,19 @@ package handlers
import (
"net/http"
+ "go.lindenii.runxiyu.org/forge/forged/internal/incoming/web/templates"
wtypes "go.lindenii.runxiyu.org/forge/forged/internal/incoming/web/types"
)
-type NotImplementedHTTP struct{}
+type NotImplementedHTTP struct {
+ r templates.Renderer
+}
-func NewNotImplementedHTTP() *NotImplementedHTTP { return &NotImplementedHTTP{} }
+func NewNotImplementedHTTP(r templates.Renderer) *NotImplementedHTTP {
+ return &NotImplementedHTTP{
+ r: r,
+ }
+}
func (h *NotImplementedHTTP) Handle(w http.ResponseWriter, _ *http.Request, _ wtypes.Vars) {
http.Error(w, "not implemented", http.StatusNotImplemented)
diff --git a/forged/internal/incoming/web/handlers/repo/handler.go b/forged/internal/incoming/web/handlers/repo/handler.go
new file mode 100644
index 0000000..2881d7d
--- /dev/null
+++ b/forged/internal/incoming/web/handlers/repo/handler.go
@@ -0,0 +1,15 @@
+package repo
+
+import (
+ "go.lindenii.runxiyu.org/forge/forged/internal/incoming/web/templates"
+)
+
+type HTTP struct {
+ r templates.Renderer
+}
+
+func NewHTTP(r templates.Renderer) *HTTP {
+ return &HTTP{
+ r: r,
+ }
+}
diff --git a/forged/internal/incoming/web/handlers/repo/index.go b/forged/internal/incoming/web/handlers/repo/index.go
index dd1382f..1a804b2 100644
--- a/forged/internal/incoming/web/handlers/repo/index.go
+++ b/forged/internal/incoming/web/handlers/repo/index.go
@@ -4,16 +4,9 @@ import (
"net/http"
"strings"
- "go.lindenii.runxiyu.org/forge/forged/internal/incoming/web/templates"
wtypes "go.lindenii.runxiyu.org/forge/forged/internal/incoming/web/types"
)
-type HTTP struct {
- r templates.Renderer
-}
-
-func NewHTTP(r templates.Renderer) *HTTP { return &HTTP{r: r} }
-
func (h *HTTP) Index(w http.ResponseWriter, r *http.Request, v wtypes.Vars) {
base := wtypes.Base(r)
repo := v["repo"]
@@ -25,4 +18,3 @@ func (h *HTTP) Index(w http.ResponseWriter, r *http.Request, v wtypes.Vars) {
Repo: repo,
})
}
-
diff --git a/forged/internal/incoming/web/router.go b/forged/internal/incoming/web/router.go
index 46eb935..7c2717d 100644
--- a/forged/internal/incoming/web/router.go
+++ b/forged/internal/incoming/web/router.go
@@ -1,15 +1,18 @@
package web
import (
+ "fmt"
"net/http"
"net/url"
"sort"
"strings"
+ "go.lindenii.runxiyu.org/forge/forged/internal/database/queries"
+ "go.lindenii.runxiyu.org/forge/forged/internal/global"
wtypes "go.lindenii.runxiyu.org/forge/forged/internal/incoming/web/types"
)
-type UserResolver func(*http.Request) (id int, username string, err error)
+type UserResolver func(*http.Request) (id string, username string, err error)
type ErrorRenderers struct {
BadRequest func(http.ResponseWriter, *wtypes.BaseData, string)
@@ -57,13 +60,21 @@ type Router struct {
routes []route
errors ErrorRenderers
user UserResolver
- global any
+ global *global.GlobalData
reverseProxy bool
+ queries *queries.Queries
}
func NewRouter() *Router { return &Router{} }
-func (r *Router) Global(v any) *Router { r.global = v; return r }
+func (r *Router) Global(g *global.GlobalData) *Router {
+ r.global = g
+ return r
+}
+func (r *Router) Queries(q *queries.Queries) *Router {
+ r.queries = q
+ return r
+}
func (r *Router) ReverseProxy(enabled bool) *Router { r.reverseProxy = enabled; return r }
func (r *Router) Errors(e ErrorRenderers) *Router { r.errors = e; return r }
func (r *Router) UserResolver(u UserResolver) *Router { r.user = u; return r }
@@ -138,6 +149,13 @@ func (r *Router) ServeHTTP(w http.ResponseWriter, req *http.Request) {
Global: r.global,
URLSegments: segments,
DirMode: dirMode,
+ Queries: r.queries,
+ }
+
+ bd.RefType, bd.RefName, err = GetParamRefTypeName(req)
+ if err != nil {
+ r.err400(w, bd, "Error parsing ref query parameters: "+err.Error())
+ return
}
if r.user != nil {
@@ -379,3 +397,38 @@ func (r *Router) err500(w http.ResponseWriter, b *wtypes.BaseData, msg string) {
}
http.Error(w, msg, http.StatusInternalServerError)
}
+
+func GetParamRefTypeName(request *http.Request) (retRefType, retRefName string, err error) {
+ rawQuery := request.URL.RawQuery
+ queryValues, err := url.ParseQuery(rawQuery)
+ if err != nil {
+ return
+ }
+ done := false
+ for _, refType := range []string{"commit", "branch", "tag"} {
+ refName, ok := queryValues[refType]
+ if ok {
+ if done {
+ err = errDupRefSpec
+ return
+ }
+ done = true
+ if len(refName) != 1 {
+ err = errDupRefSpec
+ return
+ }
+ retRefName = refName[0]
+ retRefType = refType
+ }
+ }
+ if !done {
+ retRefType = ""
+ retRefName = ""
+ err = nil // actually returning empty strings is enough?
+ }
+ return
+}
+
+var (
+ errDupRefSpec = fmt.Errorf("duplicate ref specifications")
+)
diff --git a/forged/internal/incoming/web/server.go b/forged/internal/incoming/web/server.go
index 6229bf0..f81886f 100644
--- a/forged/internal/incoming/web/server.go
+++ b/forged/internal/incoming/web/server.go
@@ -9,6 +9,8 @@ import (
"time"
"go.lindenii.runxiyu.org/forge/forged/internal/common/misc"
+ "go.lindenii.runxiyu.org/forge/forged/internal/database/queries"
+ "go.lindenii.runxiyu.org/forge/forged/internal/global"
)
type Server struct {
@@ -17,11 +19,12 @@ type Server struct {
root string
httpServer *http.Server
shutdownTimeout uint32
+ globalData *global.GlobalData
}
-func New(config Config) (server *Server) {
+func New(config Config, globalData *global.GlobalData, queries *queries.Queries) *Server {
httpServer := &http.Server{
- Handler: NewHandler(config),
+ Handler: NewHandler(config, globalData, queries),
ReadTimeout: time.Duration(config.ReadTimeout) * time.Second,
WriteTimeout: time.Duration(config.WriteTimeout) * time.Second,
IdleTimeout: time.Duration(config.IdleTimeout) * time.Second,
@@ -33,6 +36,7 @@ func New(config Config) (server *Server) {
root: config.Root,
shutdownTimeout: config.ShutdownTimeout,
httpServer: httpServer,
+ globalData: globalData,
}
}
diff --git a/forged/internal/incoming/web/types/types.go b/forged/internal/incoming/web/types/types.go
index d47b13a..1301fe9 100644
--- a/forged/internal/incoming/web/types/types.go
+++ b/forged/internal/incoming/web/types/types.go
@@ -3,18 +3,24 @@ package types
import (
"context"
"net/http"
+
+ "go.lindenii.runxiyu.org/forge/forged/internal/database/queries"
+ "go.lindenii.runxiyu.org/forge/forged/internal/global"
)
// BaseData is per-request context computed by the router and read by handlers.
// Keep it small and stable; page-specific data should live in view models.
type BaseData struct {
- Global any
- UserID int
+ UserID string
Username string
URLSegments []string
DirMode bool
GroupPath []string
SeparatorIndex int
+ RefType string
+ RefName string
+ Global *global.GlobalData
+ Queries *queries.Queries
}
type ctxKey struct{}