Skip to content

Commit

Permalink
feat: Add more code
Browse files Browse the repository at this point in the history
  • Loading branch information
dadav committed Feb 27, 2024
1 parent 8927a0a commit 953919e
Show file tree
Hide file tree
Showing 4 changed files with 91 additions and 33 deletions.
4 changes: 3 additions & 1 deletion cmd/serve.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,9 @@ to quickly create a Cobra application.`,
r.Use(customMiddleware.RequireUserAgent)

if config.FallbackProxyUrl != "" {
r.Use(customMiddleware.ProxyFallback(config.FallbackProxyUrl))
r.Use(customMiddleware.ProxyFallback(config.FallbackProxyUrl, func(status int) bool {
return status != http.StatusOK
}))
}

r.Use(middleware.Recoverer)
Expand Down
52 changes: 38 additions & 14 deletions internal/api/v3/module.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,14 @@ package v3
import (
"context"
"errors"
"fmt"
"net/http"
"net/url"
"slices"
"strconv"
"strings"

"github.com/dadav/gorge/internal/backend"
"github.com/dadav/gorge/internal/log"
gen "github.com/dadav/gorge/pkg/gen/v3/openapi"
)

Expand Down Expand Up @@ -71,11 +73,16 @@ type GetModule404Response struct {
Errors []string `json:"errors,omitempty"`
}

type GetModule500Response struct {
Message string `json:"message,omitempty"`
Errors []string `json:"errors,omitempty"`
}

// GetModule - Fetch module
func (s *ModuleOperationsApi) GetModule(ctx context.Context, moduleSlug string, withHtml bool, includeFields []string, excludeFields []string, ifModifiedSince string) (gen.ImplResponse, error) {
module, err := backend.ConfiguredBackend.GetModuleBySlug(moduleSlug)
if err != nil {
// log.Log.Error(err)
log.Log.Error(err)
return gen.Response(
http.StatusNotFound,
GetModule404Response{
Expand All @@ -92,85 +99,102 @@ func (s *ModuleOperationsApi) GetModules(ctx context.Context, limit int32, offse
results := []gen.Module{}
filtered := []gen.Module{}
allModules := backend.ConfiguredBackend.GetAllModules()
params := url.Values{}
params.Add("offset", strconv.Itoa(int(offset)))
params.Add("limit", strconv.Itoa(int(limit)))

if int(offset)+1 > len(allModules) {
return gen.Response(404, GetModule404Response{
Message: "Invalid offset",
Errors: []string{"The given offset is larger than the total number of (filtered) modules."},
}), nil
}

for _, m := range allModules {
for _, m := range allModules[offset:] {
var filterMatched, filterSet bool
if query != "" {
filterSet = true
filterMatched = strings.Contains(m.Slug, query) || strings.Contains(m.Owner.Slug, query)
params.Add("query", query)
}

if tag != "" {
filterSet = true
filterMatched = slices.Contains(m.CurrentRelease.Tags, tag)
params.Add("tag", tag)
}

if owner != "" {
filterSet = true
filterMatched = m.Owner.Username == owner
params.Add("owner", owner)
}

if withTasks {
filterSet = true
filterMatched = len(m.CurrentRelease.Tasks) > 0
params.Add("with_tasks", strconv.FormatBool(withTasks))
}

if withPlans {
filterSet = true
filterMatched = len(m.CurrentRelease.Plans) > 0
params.Add("with_plans", strconv.FormatBool(withPlans))
}

if withPdk {
filterSet = true
filterMatched = m.CurrentRelease.Pdk
params.Add("with_pdk", strconv.FormatBool(withPdk))
}

if premium {
filterSet = true
filterMatched = m.Premium
params.Add("premium", strconv.FormatBool(premium))
}

if excludePremium {
filterSet = true
filterMatched = !m.Premium
params.Add("exclude_premium", strconv.FormatBool(excludePremium))
}

if len(endorsements) > 0 {
filterSet = true
filterMatched = m.Endorsement != nil && slices.Contains(endorsements, *m.Endorsement)
params.Add("endorsements", "["+strings.Join(endorsements, ",")+"]")
}

if !filterSet || filterMatched {
filtered = append(filtered, *m)
}
}

if int(offset)+1 > len(filtered) {
return gen.Response(400, gen.GetFile400Response{
Message: "Invalid offset",
Errors: []string{"The given offset is larger than the total number of (filtered) modules."},
}), nil
}

i := 1
for _, module := range filtered[offset:] {
for _, module := range filtered {
if i > int(limit) {
break
}
results = append(results, module)
i++
}

// TODO: Create url with all specified query parameters
firstInf := interface{}("/v3/modules?limit=20&offset=0")
currentInf := interface{}(fmt.Sprintf("/v3/modules?limit=%d&offset=%d", limit, offset))
base, _ := url.Parse("/v3/modules")
base.RawQuery = params.Encode()
currentInf := interface{}(base.String())
params.Set("offset", "0")
firstInf := interface{}(base.String())
params.Set("offset", strconv.Itoa(int(offset)+len(results)))
nextInf := interface{}(base.String())

return gen.Response(http.StatusOK, gen.GetModules200Response{
Pagination: gen.GetModules200ResponsePagination{
Limit: limit,
Offset: offset,
First: &firstInf,
Current: &currentInf,
Next: &nextInf,
Total: int32(len(allModules)),
},
Results: results,
Expand Down
58 changes: 42 additions & 16 deletions internal/api/v3/release.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@ import (
"context"
"errors"
"net/http"
"net/url"
"os"
"path/filepath"
"strconv"
"strings"

"github.com/dadav/gorge/internal/backend"
Expand Down Expand Up @@ -85,7 +87,7 @@ func (s *ReleaseOperationsApi) GetFile(ctx context.Context, filename string) (ge
return gen.Response(http.StatusNotFound, gen.GetFile404Response{
Message: http.StatusText(http.StatusNotFound),
Errors: []string{"The file does not exist."},
}), err
}), nil
}
}

Expand All @@ -105,12 +107,12 @@ func (s *ReleaseOperationsApi) GetRelease(ctx context.Context, releaseSlug strin
return gen.Response(http.StatusNotFound, gen.GetFile404Response{
Message: http.StatusText(http.StatusNotFound),
Errors: []string{"release not found"},
}), err
}), nil
}
return gen.Response(http.StatusInternalServerError, GetRelease500Response{
Message: http.StatusText(http.StatusInternalServerError),
Errors: []string{"error while reading release metadata"},
}), err
}), nil
}

return gen.Response(http.StatusOK, gen.Release{
Expand Down Expand Up @@ -153,36 +155,60 @@ func (s *ReleaseOperationsApi) GetReleases(ctx context.Context, limit int32, off
results := []gen.Release{}
filtered := []gen.Release{}
allReleases := backend.ConfiguredBackend.GetAllReleases()
params := url.Values{}
params.Add("offset", strconv.Itoa(int(offset)))
params.Add("limit", strconv.Itoa(int(limit)))

if int(offset)+1 > len(allReleases) {
return gen.Response(404, GetRelease404Response{
Message: "Invalid offset",
Errors: []string{"The given offset is larger than the total number of modules."},
}), nil
}

for _, r := range allReleases[offset:] {
var filterMatched, filterSet bool

for _, r := range allReleases {
if module != "" && r.Module.Slug != module {
continue
filterSet = true
filterMatched = r.Module.Slug == module
params.Add("module", module)
}
if owner != "" && r.Module.Owner.Slug != owner {
continue
}

filtered = append(filtered, *r)
}

if int(offset)+1 > len(filtered) {
return gen.Response(400, GetRelease404Response{
Message: "Invalid offset",
Errors: []string{"The given offset is larger than the total number of modules."},
}), nil
if !filterSet || filterMatched {
filtered = append(filtered, *r)
}
}

i := 1
for _, release := range filtered[offset:] {
for _, release := range filtered {
if i > int(limit) {
break
}
results = append(results, release)
i++
}

base, _ := url.Parse("/v3/releases")
base.RawQuery = params.Encode()
currentInf := interface{}(base.String())
params.Set("offset", "0")
firstInf := interface{}(base.String())
params.Set("offset", strconv.Itoa(int(offset)+len(results)))
nextInf := interface{}(base.String())

return gen.Response(http.StatusOK, gen.GetReleases200Response{
Pagination: gen.GetReleases200ResponsePagination{},
Results: results,
Pagination: gen.GetReleases200ResponsePagination{
Limit: limit,
Offset: offset,
First: &firstInf,
Current: &currentInf,
Next: &nextInf,
Total: int32(len(allReleases)),
},
Results: results,
}), nil
}
10 changes: 8 additions & 2 deletions internal/middleware/proxy.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,20 +30,21 @@ func (w *capturedResponseWriter) sendOriginalResponse() {
w.ResponseWriter.Write(w.body)
}

func ProxyFallback(upstreamHost string) func(next http.Handler) http.Handler {
func ProxyFallback(upstreamHost string, forwardToProxy func(int) bool) func(next http.Handler) http.Handler {
return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// capture response
capturedResponseWriter := &capturedResponseWriter{ResponseWriter: w}
next.ServeHTTP(capturedResponseWriter, r)

if capturedResponseWriter.status == http.StatusNotFound {
if forwardToProxy(capturedResponseWriter.status) {
log.Log.Infof("Forwarding request to %s\n", upstreamHost)
forwardRequest(w, r, upstreamHost)
return
}

// If the response status is not 404, serve the original response
log.Log.Info("sending original response")
capturedResponseWriter.sendOriginalResponse()
})
}
Expand All @@ -69,6 +70,9 @@ func forwardRequest(w http.ResponseWriter, r *http.Request, forwardHost string)
return
}

// Set the parameters
forwardedRequest.URL.RawQuery = r.URL.RawQuery

// Copy headers from the original request
forwardedRequest.Header = make(http.Header)
for key, values := range r.Header {
Expand All @@ -94,6 +98,8 @@ func forwardRequest(w http.ResponseWriter, r *http.Request, forwardHost string)
}
}

log.Log.Debugf("Response of proxied request is %d\n", resp.StatusCode)

// Write the response status code
w.WriteHeader(resp.StatusCode)

Expand Down

0 comments on commit 953919e

Please sign in to comment.