Skip to content

Commit

Permalink
Merge pull request #324 from bavix/typofix
Browse files Browse the repository at this point in the history
[3.x] tech dept
  • Loading branch information
rez1dent3 authored Jul 7, 2024
2 parents fc1e72a + d23ce64 commit f1a1ccb
Show file tree
Hide file tree
Showing 16 changed files with 710 additions and 289 deletions.
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ require (
github.com/bavix/features v1.0.0
github.com/bavix/gripmock-sdk-go v1.0.4
github.com/bavix/gripmock-ui v1.0.0-alpha5
github.com/bavix/gripmock/protogen v0.0.0-20240706174427-ef324cdfb46b
github.com/bavix/gripmock/protogen v0.0.0-20240706201937-fc1e72a8ad5f
github.com/cristalhq/base64 v0.1.2
github.com/goccy/go-yaml v1.11.3
github.com/google/uuid v1.6.0
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ github.com/bavix/gripmock-sdk-go v1.0.4 h1:FDBlusqVFoy5Yo49khztYqfVt9+NSEf1mIl1n
github.com/bavix/gripmock-sdk-go v1.0.4/go.mod h1:/1cmn8VuN6Pc7ttMejqXLYpvf1CJF08ezoEA9lJIZiU=
github.com/bavix/gripmock-ui v1.0.0-alpha5 h1:+2vWLZPeGGrpBSENWXIfyf6bwN+Pou+XucX0XlccLQo=
github.com/bavix/gripmock-ui v1.0.0-alpha5/go.mod h1:XEH4YYEKL+wEDtONntoWm6JxjbVWzl7XtDYztUTBfeA=
github.com/bavix/gripmock/protogen v0.0.0-20240706174427-ef324cdfb46b h1:YCLXlvREBDiqSZX8D4e0DtPQB0jm55cl4YsllmB0B4k=
github.com/bavix/gripmock/protogen v0.0.0-20240706174427-ef324cdfb46b/go.mod h1:ARIfXpB9cyL9jIr7C1yrhwnb3wCSrewPNLdyG4URmJk=
github.com/bavix/gripmock/protogen v0.0.0-20240706201937-fc1e72a8ad5f h1:B/nZWWeQRXb4SQFHQWw45cMAnZ6eu/T6TAkJFpTqLHw=
github.com/bavix/gripmock/protogen v0.0.0-20240706201937-fc1e72a8ad5f/go.mod h1:ARIfXpB9cyL9jIr7C1yrhwnb3wCSrewPNLdyG4URmJk=
github.com/bmatcuk/doublestar v1.1.1/go.mod h1:UD6OnuiIn0yFxxA2le/rnRU1G4RaI4UvFv1sNto9p6w=
github.com/bufbuild/protocompile v0.14.0 h1:z3DW4IvXE5G/uTOnSQn+qwQQxvhckkTWLS/0No/o7KU=
github.com/bufbuild/protocompile v0.14.0/go.mod h1:N6J1NYzkspJo3ZwyL4Xjvli86XOj1xq4qAasUFxGups=
Expand Down
2 changes: 1 addition & 1 deletion go.work
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
go 1.22.2
go 1.22.5

use (
.
Expand Down
70 changes: 41 additions & 29 deletions internal/app/rest_server.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"log"
"net/http"
"os"
"path"
"strings"
"sync/atomic"
"time"
Expand All @@ -30,10 +31,10 @@ var (
)

type RestServer struct {
ok atomic.Bool
stuber *stuber.Budgerigar
convertor *yaml2json.Convertor
caser cases.Caser
ok atomic.Bool
reflector *grpcreflector.GReflector
}

Expand All @@ -49,15 +50,12 @@ func NewRestServer(path string, reflector *grpcreflector.GReflector) (*RestServe

if path != "" {
server.readStubs(path) // TODO: someday you will need to rewrite this code
server.ok.Store(true)
}

return server, nil
}

func (h *RestServer) ServiceReady() {
h.ok.Store(true)
}

func (h *RestServer) ServicesList(w http.ResponseWriter, r *http.Request) {
services, err := h.reflector.Services(r.Context())
if err != nil {
Expand Down Expand Up @@ -288,49 +286,66 @@ func (h *RestServer) writeResponseError(err error, w http.ResponseWriter) {
}
}

func (h *RestServer) readStubs(path string) {
files, err := os.ReadDir(path)
// readStubs reads all the stubs from the given directory and its subdirectories,
// and adds them to the server's stub store.
// The stub files can be in yaml or json format.
// If a file is in yaml format, it will be converted to json format.
func (h *RestServer) readStubs(pathDir string) {
files, err := os.ReadDir(pathDir)
if err != nil {
log.Printf("Can't read stub from %s. %v\n", path, err)
log.Printf("can't read stubs from %s: %v", pathDir, err)

return
}

for _, file := range files {
// If the file is a directory, recursively read its stubs.
if file.IsDir() {
h.readStubs(path + "/" + file.Name())
h.readStubs(path.Join(pathDir, file.Name()))

continue
}

byt, err := os.ReadFile(path + "/" + file.Name())
// Read the stub file and add it to the server's stub store.
stubs, err := h.readStub(path.Join(pathDir, file.Name()))
if err != nil {
log.Printf("Error when reading file %s. %v. skipping...", file.Name(), err)
log.Printf("cant read stubs from %s: %v", file.Name(), err)

continue
}

if strings.HasSuffix(file.Name(), ".yaml") || strings.HasSuffix(file.Name(), ".yml") {
byt, err = h.convertor.Execute(file.Name(), byt)
if err != nil {
log.Printf("Error when unmarshalling file %s. %v. skipping...", file.Name(), err)

continue
}
}

var storageStubs []*stuber.Stub
h.stuber.PutMany(stubs...)
}
}

if err = jsondecoder.UnmarshalSlice(byt, &storageStubs); err != nil {
log.Printf("Error when unmarshalling file %s. %v %v. skipping...", file.Name(), string(byt), err)
// readStub reads a stub file and returns a slice of stubs.
// The stub file can be in yaml or json format.
// If the file is in yaml format, it will be converted to json format.
func (h *RestServer) readStub(path string) ([]*stuber.Stub, error) {
// Read the file
byt, err := os.ReadFile(path)
if err != nil {
return nil, fmt.Errorf("error when reading file %s: %w", path, err)
}

continue
// If the file is in yaml format, convert it to json format
if strings.HasSuffix(path, ".yaml") || strings.HasSuffix(path, ".yml") {
byt, err = h.convertor.Execute(path, byt)
if err != nil {
return nil, fmt.Errorf("error when unmarshalling file %s: %w", path, err)
}
}

h.stuber.PutMany(storageStubs...)
// Unmarshal the json into a slice of stubs
var stubs []*stuber.Stub
if err := jsondecoder.UnmarshalSlice(byt, &stubs); err != nil {
return nil, fmt.Errorf("error when unmarshalling file %s: %v %w", path, string(byt), err)
}

return stubs, nil
}

// validateStub validates if the stub is valid or not.
func validateStub(stub *stuber.Stub) error {
if stub.Service == "" {
return ErrServiceIsMissing
Expand All @@ -353,12 +368,9 @@ func validateStub(stub *stuber.Stub) error {
return fmt.Errorf("input cannot be empty")
}

// TODO: validate all input case

if stub.Output.Error == "" && stub.Output.Data == nil && stub.Output.Code == nil {
// fixme
//nolint:goerr113,perfsprint
return fmt.Errorf("output can't be empty")
return fmt.Errorf("output cannot be empty")
}

return nil
Expand Down
21 changes: 11 additions & 10 deletions internal/pkg/muxmiddleware/logger.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,33 +11,34 @@ import (
"github.com/bavix/gripmock/pkg/jsondecoder"
)

// RequestLogger logs the request and response.
func RequestLogger(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
logger := zerolog.Ctx(r.Context())
ww := &responseWriter{w: w, status: http.StatusOK}
ip, err := getIP(r)
now := time.Now()
start := time.Now()

bodyBytes, _ := io.ReadAll(r.Body)
r.Body.Close() // must close
r.Body.Close()
r.Body = io.NopCloser(bytes.NewBuffer(bodyBytes))

next.ServeHTTP(ww, r)

event := logger.Info().Err(err).
event := logger.Info().
Err(err).
IPAddr("ip", ip).
Str("method", r.Method).
Str("url", r.URL.RequestURI())
Str("url", r.URL.RequestURI()).
Dur("elapsed", time.Since(start)).
Str("ua", r.UserAgent()).
Int("bytes", ww.bytesWritten).
Int("code", ww.status)

if err := jsondecoder.UnmarshalSlice(bodyBytes, nil); err == nil {
event.RawJSON("input", bodyBytes)
}

event.
Dur("elapsed", time.Since(now)).
Str("ua", r.UserAgent()).
Int("bytes", ww.bytes).
Int("code", ww.status).
Send()
event.Send()
})
}
26 changes: 13 additions & 13 deletions internal/pkg/muxmiddleware/resp_writer.go
Original file line number Diff line number Diff line change
@@ -1,28 +1,28 @@
package muxmiddleware

import "net/http"
import (
"net/http"
)

type responseWriter struct {
w http.ResponseWriter

status int
bytes int
status int
bytesWritten int
}

func (r *responseWriter) Header() http.Header {
return r.w.Header()
func (rw *responseWriter) Header() http.Header {
return rw.w.Header()
}

func (r *responseWriter) Write(bytes []byte) (int, error) {
n, err := r.w.Write(bytes)

r.bytes += n
func (rw *responseWriter) Write(bytes []byte) (int, error) {
n, err := rw.w.Write(bytes)
rw.bytesWritten += n

return n, err
}

func (r *responseWriter) WriteHeader(statusCode int) {
r.w.WriteHeader(statusCode)

r.status = statusCode
func (rw *responseWriter) WriteHeader(statusCode int) {
rw.status = statusCode
rw.w.WriteHeader(statusCode)
}
22 changes: 12 additions & 10 deletions internal/pkg/muxmiddleware/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,22 +6,24 @@ import (
"strings"
)

// getIP returns the IP address from the request headers.
// It returns the IP address from the X-Forwarded-For header if it exists,
// otherwise it returns the IP address from the RemoteAddr field.
func getIP(r *http.Request) (net.IP, error) {
ips := r.Header.Get("X-Forwarded-For")
splitIps := strings.Split(ips, ",")

if len(splitIps) > 0 {
netIP := net.ParseIP(splitIps[len(splitIps)-1])

if netIP != nil {
return netIP, nil
if forwardedFor := r.Header.Get("X-Forwarded-For"); forwardedFor != "" {
ips := strings.Split(forwardedFor, ",")
if len(ips) > 0 {
ip := strings.TrimSpace(ips[len(ips)-1])
if parsedIP := net.ParseIP(ip); parsedIP != nil {
return parsedIP, nil
}
}
}

ip, _, err := net.SplitHostPort(r.RemoteAddr)
host, _, err := net.SplitHostPort(r.RemoteAddr)
if err != nil {
return nil, err
}

return net.ParseIP(ip), nil
return net.ParseIP(host), nil
}
Loading

0 comments on commit f1a1ccb

Please sign in to comment.