Skip to content

Instantly share code, notes, and snippets.

@patterns
Created October 28, 2016 10:41
Show Gist options
  • Save patterns/cef6f4f1608ac4a38227870dd08f00dd to your computer and use it in GitHub Desktop.
Save patterns/cef6f4f1608ac4a38227870dd08f00dd to your computer and use it in GitHub Desktop.
Microsvc to compare adapters vs facade
#
# examples of calling svc from CLI
./hash
curl -XPOST -d'{"s":"hello"}' localhost:8080/hash
./hash -algo=SHA256
curl -XPOST -d'{"s":"hello"}' localhost:8080/hash
package main
import (
"crypto/sha1"
"crypto/sha256"
"fmt"
)
// Adaptee is the existing functionality.
type Adaptee struct {
Salt []byte
}
// Hash is calculated with Salt prefixed
func (a Adaptee) Hash(data []byte) []byte {
sz := len(data) + len(a.Salt)
t := make([]byte, sz)
copy(t, a.Salt)
copy(t[len(a.Salt):], data)
h := sha1.New()
h.Write(t)
digest := h.Sum(nil)
return digest
}
// Target is the *new* contract
type Target struct {
Salt []byte
Algo string
}
// Facade to hide ctors behind a *static*
type Facade struct {}
func (t Target) GetDigest(data string) string {
sz := len(data) + len(t.Salt)
d := make([]byte, sz)
copy(d, t.Salt)
copy(d[len(t.Salt):], []byte(data))
h := sha256.New()
h.Write(d)
digest := h.Sum(nil)
return fmt.Sprintf("%x", digest)
}
// Adapter is the part that sits in between the Client and Target/Adaptee
type Adapter struct {
Salt []byte
Algo string
Calc func(string) string
}
// New is a ctor to handle Target approach
func (Adapter) New2(target Target) Adapter {
a := Adapter{target.Salt, target.Algo, target.GetDigest}
return a
}
// New is a ctor to bridge the original Adaptee
func (Adapter) New(target Adaptee) Adapter {
a := Adapter{
target.Salt,
"SHA1",
func(data string) string {
d := target.Hash([]byte(data))
return fmt.Sprintf("%x", d)
},
}
return a
}
// Calc is a convenience method to simplify the diff options
func (Facade) Calc(data string) string {
var a Adapter
if algorithm == "SHA256" {
// Adapter2 configured to SHA256
a = Adapter{}.New2(Target{[]byte(salt), "SHA256"})
} else {
// Adapter1 configured to original SHA1
a = Adapter{}.New(Adaptee{[]byte(salt)})
}
return a.Calc(data)
}
package main
import (
"flag"
"encoding/json"
"errors"
"log"
"net/http"
"golang.org/x/net/context"
"github.com/go-kit/kit/endpoint"
httptransport "github.com/go-kit/kit/transport/http"
)
// StringService provides operations on strings.
type StringService interface {
Hash(string) (string, error)
}
type stringService struct{}
func (stringService) Hash(s string) (string, error) {
if s == "" {
return "", ErrEmpty
}
// Adapter1 configured to original SHA1
//adapter1 := Adapter{}.New(Adaptee{[]byte(salt)})
//d1 := adapter1.Calc(s)
d1 := Facade{}.Calc(s)
return d1, nil
}
var salt string
var algorithm string
func init() {
flag.StringVar(&salt, "salt", "seedXYZ", "Salt value to prefix")
flag.StringVar(&algorithm, "algo", "SHA1", "Algorithm of hash")
flag.Parse()
}
func main() {
ctx := context.Background()
svc := stringService{}
hashHandler := httptransport.NewServer(
ctx,
makeHashEndpoint(svc),
decodeHashRequest,
encodeResponse,
)
http.Handle("/hash", hashHandler)
log.Fatal(http.ListenAndServe(":8080", nil))
}
func makeHashEndpoint(svc StringService) endpoint.Endpoint {
return func(ctx context.Context, request interface{}) (interface{}, error) {
req := request.(hashRequest)
v, err := svc.Hash(req.S)
if err != nil {
return hashResponse{v, err.Error()}, nil
}
return hashResponse{v, ""}, nil
}
}
func decodeHashRequest(_ context.Context, r *http.Request) (interface{}, error) {
var request hashRequest
if err := json.NewDecoder(r.Body).Decode(&request); err != nil {
return nil, err
}
return request, nil
}
func encodeResponse(_ context.Context, w http.ResponseWriter, response interface{}) error {
return json.NewEncoder(w).Encode(response)
}
type hashRequest struct {
S string `json:"s"`
}
type hashResponse struct {
V string `json:"v"`
Err string `json:"err,omitempty"` // errors don't define JSON marshaling
}
// ErrEmpty is returned when an input string is empty.
var ErrEmpty = errors.New("empty string")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment