Skip to content

Commit

Permalink
repository: remove generic usage, move middlewares in provider initia…
Browse files Browse the repository at this point in the history
…lization

Signed-off-by: Adphi <philippe.adrien.nousse@gmail.com>
  • Loading branch information
Adphi committed Oct 2, 2023
1 parent 4eef862 commit 646e535
Show file tree
Hide file tree
Showing 7 changed files with 170 additions and 105 deletions.
39 changes: 39 additions & 0 deletions pkg/codec/codec.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
// Copyright 2023 Linka Cloud All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package codec

type Codec[T any] interface {
Encode(v T) ([]byte, error)
Decode(b []byte) (T, error)
Name() string
}

type CodecFuncs[T any] struct {
Format string
EncodeFunc func(v T) ([]byte, error)
DecodeFunc func(b []byte) (T, error)
}

func (c CodecFuncs[T]) Encode(a T) ([]byte, error) {
return c.EncodeFunc(a)
}

func (c CodecFuncs[T]) Decode(b []byte) (T, error) {
return c.DecodeFunc(b)
}

func (c CodecFuncs[T]) Name() string {
return c.Format
}
13 changes: 4 additions & 9 deletions pkg/packages/registry.go → pkg/packages/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ package packages

import (
"context"
"net/http"

"github.com/gorilla/mux"

Expand All @@ -25,9 +24,10 @@ import (

type Provider interface {
Register(m *mux.Router)
Repository() repository.Provider
}

type ProviderFactory func(ctx context.Context, backend string, key []byte) (Provider, error)
type ProviderFactory func(ctx context.Context) (Provider, error)

var providers = map[string]ProviderFactory{}

Expand All @@ -37,17 +37,12 @@ func Register(name string, factory ProviderFactory) {

func Init(ctx context.Context, r *mux.Router, backend string, key []byte) error {
for k, v := range providers {
p, err := v(ctx, backend, key)
p, err := v(ctx)
if err != nil {
return err
}
sub := r.PathPrefix("/" + k).Subrouter()
sub.Use(func(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
ctx := repository.ContextWithAuth(r.Context(), r)
next.ServeHTTP(w, r.WithContext(ctx))
})
})
sub.Use(repository.StorageMiddleware(p.Repository(), backend, key)("repo"))
p.Register(sub)
}
return nil
Expand Down
61 changes: 22 additions & 39 deletions pkg/packages/rpm/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,28 +43,28 @@ func init() {
packages.Register("rpm", newProvider)
}

func newProvider(_ context.Context, backend string, key []byte) (packages.Provider, error) {
return &provider{mdwl: repository.StorageMiddleware[*Package, *repo](&repo{}, backend, key)}, nil
func newProvider(_ context.Context) (packages.Provider, error) {
return &provider{}, nil
}

type provider struct {
mdwl repository.StorageMiddlewareFunc
}
type provider struct{}

func (p *provider) Register(r *mux.Router) {
r.Use(p.mdwl("repo"))
r.HandleFunc("/{repo:.+}.repo", p.repositoryConfig).Methods(http.MethodGet)
r.HandleFunc("/{repo:.+}/"+RepositoryPublicKey, p.repositoryKey).Methods(http.MethodGet)
r.HandleFunc("/{repo:.+}/upload", p.uploadPackage).Methods(http.MethodPut)
r.HandleFunc("/{repo:.+}/repodata/{filename}", p.repositoryFile).Methods(http.MethodGet)
r.HandleFunc("/{repo:.+}/{filename}", p.downloadPackage).Methods(http.MethodGet)
r.HandleFunc("/{repo:.+}/{filename}", p.deletePackage).Methods(http.MethodDelete)
r.HandleFunc("/{repo:.+}.repo", p.config).Methods(http.MethodGet)
r.HandleFunc("/{repo:.+}/upload", p.upload).Methods(http.MethodPut)
r.HandleFunc("/{repo:.+}/repodata/{filename}", p.repository).Methods(http.MethodGet)
r.HandleFunc("/{repo:.+}/{filename}", p.download).Methods(http.MethodGet)
r.HandleFunc("/{repo:.+}/{filename}", p.delete).Methods(http.MethodDelete)
}

func (p *provider) Repository() repository.Provider {
return &repo{}
}

func (p *provider) repositoryConfig(w http.ResponseWriter, r *http.Request) {
func (p *provider) config(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
name := mux.Vars(r)["repo"]
if _, ok := repository.FromContext[*Package, *repo](ctx); !ok {
if _, ok := repository.FromContext(ctx); !ok {
http.Error(w, "missing storage in context", http.StatusInternalServerError)
return
}
Expand All @@ -82,24 +82,7 @@ func (p *provider) repositoryConfig(w http.ResponseWriter, r *http.Request) {
w.Write([]byte(fmt.Sprintf(definition, strings.NewReplacer("/", "-").Replace(name), url, RepositoryPublicKey)))
}

func (p *provider) repositoryKey(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
repo, ok := repository.FromContext[*Package, *repo](ctx)
if !ok {
http.Error(w, "missing storage in context", http.StatusInternalServerError)
return
}
rc, err := repo.Open(ctx, RepositoryPublicKey)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
defer rc.Close()
w.Header().Set("Content-Type", "text/plain; charset=utf-8")
io.Copy(w, rc)
}

func (p *provider) uploadPackage(w http.ResponseWriter, r *http.Request) {
func (p *provider) upload(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()

var (
Expand All @@ -112,7 +95,7 @@ func (p *provider) uploadPackage(w http.ResponseWriter, r *http.Request) {
reader, size = r.Body, r.ContentLength
}
defer reader.Close()
repo, ok := repository.FromContext[*Package, *repo](ctx)
repo, ok := repository.FromContext(ctx)
if !ok {
http.Error(w, "missing storage in context", http.StatusInternalServerError)
return
Expand All @@ -133,10 +116,10 @@ func (p *provider) uploadPackage(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusCreated)
}

func (p *provider) downloadPackage(w http.ResponseWriter, r *http.Request) {
func (p *provider) download(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
file := mux.Vars(r)["filename"]
repo, ok := repository.FromContext[*Package, *repo](ctx)
repo, ok := repository.FromContext(ctx)
if !ok {
http.Error(w, "missing storage in context", http.StatusInternalServerError)
return
Expand All @@ -151,10 +134,10 @@ func (p *provider) downloadPackage(w http.ResponseWriter, r *http.Request) {
}
}

func (p *provider) deletePackage(w http.ResponseWriter, r *http.Request) {
func (p *provider) delete(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
file := mux.Vars(r)["filename"]
repo, ok := repository.FromContext[*Package, *repo](ctx)
repo, ok := repository.FromContext(ctx)
if !ok {
http.Error(w, "missing storage in context", http.StatusInternalServerError)
return
Expand All @@ -169,10 +152,10 @@ func (p *provider) deletePackage(w http.ResponseWriter, r *http.Request) {
}
}

func (p *provider) repositoryFile(w http.ResponseWriter, r *http.Request) {
func (p *provider) repository(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
file := mux.Vars(r)["filename"]
repo, ok := repository.FromContext[*Package, *repo](ctx)
repo, ok := repository.FromContext(ctx)
if !ok {
http.Error(w, "missing storage in context", http.StatusInternalServerError)
return
Expand Down
23 changes: 21 additions & 2 deletions pkg/packages/rpm/repository.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (
"context"
"crypto/sha256"
"encoding/hex"
"encoding/json"
"encoding/xml"
"io"
"strings"
Expand All @@ -30,6 +31,7 @@ import (
"golang.org/x/crypto/openpgp/packet"

"go.linka.cloud/artifact-registry/pkg/buffer"
"go.linka.cloud/artifact-registry/pkg/codec"
"go.linka.cloud/artifact-registry/pkg/repository"
)

Expand Down Expand Up @@ -59,15 +61,32 @@ type Repomd struct {
Data []*RepoData `xml:"data"`
}

var _ repository.Repository[*Package] = (*repo)(nil)
var _ repository.Provider = (*repo)(nil)

type repo struct{}

func (r *repo) Name() string {
return "rpm"
}

func (r *repo) Index(ctx context.Context, key string, packages ...*Package) ([]repository.Artifact, error) {
func (r *repo) Codec() repository.Codec {
return codec.CodecFuncs[repository.Artifact]{
Format: "json",
EncodeFunc: func(v repository.Artifact) ([]byte, error) {
return json.Marshal(v)
},
DecodeFunc: func(b []byte) (repository.Artifact, error) {
var v Package
if err := json.Unmarshal(b, &v); err != nil {
return nil, err
}
return &v, nil
},
}
}

func (r *repo) Index(ctx context.Context, key string, a ...repository.Artifact) ([]repository.Artifact, error) {
packages := repository.MustAs[*Package](a)
primary, primaryFile, err := buildPrimary(ctx, packages...)
if err != nil {
return nil, err
Expand Down
14 changes: 7 additions & 7 deletions pkg/repository/auth.go → pkg/repository/auth/auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,23 +12,23 @@
// See the License for the specific language governing permissions and
// limitations under the License.

package repository
package auth

import (
"context"
)

type Auth interface {
type Basic interface {
BasicAuth() (username, password string, ok bool)
}

type authKey struct{}
type key struct{}

func ContextWithAuth(ctx context.Context, a Auth) context.Context {
return context.WithValue(ctx, authKey{}, a)
func Context(ctx context.Context, a Basic) context.Context {
return context.WithValue(ctx, key{}, a)
}

func authFromContext(ctx context.Context) Auth {
a, _ := ctx.Value(authKey{}).(Auth)
func FromContext(ctx context.Context) Basic {
a, _ := ctx.Value(key{}).(Basic)
return a
}
Loading

0 comments on commit 646e535

Please sign in to comment.