1st class functions and doc improvements
This commit is contained in:
Родитель
6ef5c39261
Коммит
aa38b995b4
|
@ -14,6 +14,14 @@ type Factory interface {
|
|||
New(next Policy, po *PolicyOptions) Policy
|
||||
}
|
||||
|
||||
// FactoryFunc is an adapter that allows the use of an ordinary function as a Factory interface.
|
||||
type FactoryFunc func(next Policy, po *PolicyOptions) PolicyFunc
|
||||
|
||||
// New calls f(next,po).
|
||||
func (f FactoryFunc) New(next Policy, po *PolicyOptions) Policy {
|
||||
return f(next, po)
|
||||
}
|
||||
|
||||
// The Policy interface represents a mutable Policy object created by a Factory. The object can mutate/process
|
||||
// the HTTP request and then forward it on to the next Policy object in the linked-list. The returned
|
||||
// Response goes backward through the linked-list for additional processing.
|
||||
|
@ -26,6 +34,14 @@ type Policy interface {
|
|||
Do(ctx context.Context, request Request) (Response, error)
|
||||
}
|
||||
|
||||
// PolicyFunc is an adapter that allows the use of an ordinary function as a Policy interface.
|
||||
type PolicyFunc func(ctx context.Context, request Request) (Response, error)
|
||||
|
||||
// Do calls f(ctx, request).
|
||||
func (f PolicyFunc) Do(ctx context.Context, request Request) (Response, error) {
|
||||
return f(ctx, request)
|
||||
}
|
||||
|
||||
// Options configures a Pipeline's behavior.
|
||||
type Options struct {
|
||||
HTTPSender Factory // If sender is nil, then the pipeline's default client is used to send the HTTP requests.
|
||||
|
@ -210,30 +226,18 @@ func newDefaultHTTPClient() *http.Client {
|
|||
|
||||
// newDefaultHTTPClientFactory creates a DefaultHTTPClientPolicyFactory object that sends HTTP requests to a Go's default http.Client.
|
||||
func newDefaultHTTPClientFactory() Factory {
|
||||
return &defaultHTTPClientPolicyFactory{}
|
||||
return FactoryFunc(func(next Policy, po *PolicyOptions) PolicyFunc {
|
||||
return func(ctx context.Context, request Request) (Response, error) {
|
||||
r, err := pipelineHTTPClient.Do(request.WithContext(ctx))
|
||||
if err != nil {
|
||||
err = NewError(err, "HTTP request failed")
|
||||
}
|
||||
return NewHTTPResponse(r), err
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
type defaultHTTPClientPolicyFactory struct {
|
||||
}
|
||||
|
||||
// Create initializes a logging policy object.
|
||||
func (f *defaultHTTPClientPolicyFactory) New(next Policy, po *PolicyOptions) Policy {
|
||||
return &defaultHTTPClientPolicy{po: po}
|
||||
}
|
||||
|
||||
type defaultHTTPClientPolicy struct {
|
||||
po *PolicyOptions
|
||||
}
|
||||
|
||||
func (p *defaultHTTPClientPolicy) Do(ctx context.Context, request Request) (Response, error) {
|
||||
r, err := pipelineHTTPClient.Do(request.WithContext(ctx))
|
||||
if err != nil {
|
||||
err = NewError(err, "HTTP request failed")
|
||||
}
|
||||
return NewHTTPResponse(r), err
|
||||
}
|
||||
|
||||
var mfm = methodFactoryMarker{}
|
||||
var mfm = methodFactoryMarker{} // Singleton
|
||||
|
||||
// MethodFactoryMarker returns a special marker Factory object. When Pipeline's Do method is called, any
|
||||
// MethodMarkerFactory object is replaced with the specified methodFactory object. If nil is passed fro Do's
|
||||
|
@ -245,6 +249,6 @@ func MethodFactoryMarker() Factory {
|
|||
type methodFactoryMarker struct {
|
||||
}
|
||||
|
||||
func (mpmf methodFactoryMarker) New(next Policy, po *PolicyOptions) Policy {
|
||||
func (methodFactoryMarker) New(next Policy, po *PolicyOptions) Policy {
|
||||
panic("methodFactoryMarker policy should have been replaced with a method policy")
|
||||
}
|
||||
|
|
|
@ -157,4 +157,5 @@ can see the Response but cannot see the additional struct with the deserialized
|
|||
Policy objects have returned, the pipeline.Response interface is returned by Pipeline's Do method.
|
||||
The caller of this method can perform a type assertion attempting to get back to the struct type
|
||||
really returned by the Policy object. If the type assertion is successful, the caller now has
|
||||
access to both the http.Response and the deserialized struct object.*/package pipeline
|
||||
access to both the http.Response and the deserialized struct object.*/
|
||||
package pipeline
|
||||
|
|
|
@ -10,12 +10,12 @@ type causer interface {
|
|||
}
|
||||
|
||||
// ErrorNode can be an embedded field in a private error object. This field
|
||||
// adds Program Counter support and a 'cause' (reference to a preceeding error).
|
||||
// adds Program Counter support and a 'cause' (reference to a preceding error).
|
||||
// When initializing a error type with this embedded field, initialize the
|
||||
// ErrorNode field by calling ErrorNode{}.Initialize(cause).
|
||||
type ErrorNode struct {
|
||||
pc uintptr // Represents a Program Counter that you can get symbols for.
|
||||
cause error // Refers to the preceeding error (or nil)
|
||||
cause error // Refers to the preceding error (or nil)
|
||||
}
|
||||
|
||||
// Error returns a string with the PC's symbols or "" if the PC is invalid.
|
||||
|
@ -78,7 +78,7 @@ func (e ErrorNode) Timeout() bool {
|
|||
}
|
||||
|
||||
// Initialize is used to initialize an embedded ErrorNode field.
|
||||
// It captures the caller's program counter and saves the cause (preceeding error).
|
||||
// It captures the caller's program counter and saves the cause (preceding error).
|
||||
// To initialize the field, use "ErrorNode{}.Initialize(cause, 3)". A callersToSkip
|
||||
// value of 3 is very common; but, depending on your code nesting, you may need
|
||||
// a different value.
|
||||
|
@ -89,7 +89,7 @@ func (ErrorNode) Initialize(cause error, callersToSkip int) ErrorNode {
|
|||
return ErrorNode{pc: pc[0], cause: cause}
|
||||
}
|
||||
|
||||
// Cause walks all the preceeding errors and return the originating error.
|
||||
// Cause walks all the preceding errors and return the originating error.
|
||||
func Cause(err error) error {
|
||||
for err != nil {
|
||||
cause, ok := err.(causer)
|
||||
|
@ -102,7 +102,7 @@ func Cause(err error) error {
|
|||
}
|
||||
|
||||
// NewError creates a simple string error (like Error.New). But, this
|
||||
// error also captures the caller's Program Counter and the preceeding error.
|
||||
// error also captures the caller's Program Counter and the preceding error.
|
||||
func NewError(cause error, format string, v ...interface{}) error {
|
||||
return &pcError{
|
||||
ErrorNode: ErrorNode{}.Initialize(cause, 3),
|
||||
|
@ -117,5 +117,5 @@ type pcError struct {
|
|||
}
|
||||
|
||||
// Error satisfies the error interface. It shows the error with Program Counter
|
||||
// symbols and calls Error on the preceeding error so you can see the full error chain.
|
||||
// symbols and calls Error on the preceding error so you can see the full error chain.
|
||||
func (e *pcError) Error() string { return e.ErrorNode.Error(e.msg) }
|
||||
|
|
|
@ -1,48 +0,0 @@
|
|||
package pipeline
|
||||
|
||||
import (
|
||||
"context"
|
||||
)
|
||||
|
||||
// Here is the template for defining your own Factory & Policy:
|
||||
|
||||
// newMyPolicyFactory creates a 'My' policy factory. Make this function
|
||||
// public if this should be callable from another package; everything
|
||||
// else about the factory/policy should remain private to the package.
|
||||
func newMyPolicyFactory( /* Desired parameters */ ) Factory {
|
||||
return &myPolicyFactory{ /* Set desired fields */ }
|
||||
}
|
||||
|
||||
type myPolicyFactory struct {
|
||||
// Desired fields (goroutine-safe because the factory is shared by many Policy objects)
|
||||
}
|
||||
|
||||
// New initializes a Xxx policy object.
|
||||
func (f *myPolicyFactory) New(next Policy, po *PolicyOptions) Policy {
|
||||
return &myPolicy{next: next, po: po /* Set desired fields */}
|
||||
}
|
||||
|
||||
type myPolicy struct {
|
||||
next Policy
|
||||
po *PolicyOptions // Optional private field
|
||||
// Additional desired fields (mutable for use by this specific Policy object)
|
||||
}
|
||||
|
||||
func (p *myPolicy) Do(ctx context.Context, request Request) (response Response, err error) {
|
||||
// TODO: Put your policy behavior code here
|
||||
// Your code should NOT mutate the ctx or request parameters
|
||||
// However, you can make a copy of the request and mutate the copy
|
||||
// You can also pass a different Context on.
|
||||
|
||||
// Forward the request to the next node in the pipeline:
|
||||
response, err = p.next.Do(ctx, request)
|
||||
|
||||
// Process the response here. You can deserialize the body into an object.
|
||||
// If you do this, also define a struct that wraps an http.Response & your
|
||||
// deserialized struct. Have your wrapper struct implement the
|
||||
// pipeline.Response interface and then return your struct (via the interface)
|
||||
// After the pipeline completes, take response and perform a type assertion
|
||||
// to get back to the wrapper struct so you can access the deserialized object.
|
||||
|
||||
return // Return the response & err
|
||||
}
|
|
@ -0,0 +1,75 @@
|
|||
package pipeline_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/Azure/azure-pipeline-go/pipeline"
|
||||
)
|
||||
|
||||
// Here is the template for defining your own Factory & Policy:
|
||||
|
||||
// newMyPolicyFactory creates a 'My' policy factory. Make this function
|
||||
// public if this should be callable from another package; everything
|
||||
// else about the factory/policy should remain private to the package.
|
||||
func newMyPolicyFactory( /* Desired parameters */ ) pipeline.Factory {
|
||||
return &myPolicyFactory{ /* Set desired fields */ }
|
||||
}
|
||||
|
||||
type myPolicyFactory struct {
|
||||
// Desired fields (goroutine-safe because the factory is shared by many Policy objects)
|
||||
}
|
||||
|
||||
// New initializes a Xxx policy object.
|
||||
func (f *myPolicyFactory) New(next pipeline.Policy, po *pipeline.PolicyOptions) pipeline.Policy {
|
||||
return &myPolicy{next: next, po: po /* Set desired fields */}
|
||||
}
|
||||
|
||||
type myPolicy struct {
|
||||
next pipeline.Policy
|
||||
po *pipeline.PolicyOptions // Optional private field
|
||||
// Additional desired fields (mutable for use by this specific Policy object)
|
||||
}
|
||||
|
||||
func (p *myPolicy) Do(ctx context.Context, request pipeline.Request) (response pipeline.Response, err error) {
|
||||
// TODO: Put your policy behavior code here
|
||||
// Your code should NOT mutate the ctx or request parameters
|
||||
// However, you can make a copy of the request and mutate the copy
|
||||
// You can also pass a different Context on.
|
||||
// You can optionally use po (PolicyOptions) in this func.
|
||||
|
||||
// Forward the request to the next node in the pipeline:
|
||||
response, err = p.next.Do(ctx, request)
|
||||
|
||||
// Process the response here. You can deserialize the body into an object.
|
||||
// If you do this, also define a struct that wraps an http.Response & your
|
||||
// deserialized struct. Have your wrapper struct implement the
|
||||
// pipeline.Response interface and then return your struct (via the interface)
|
||||
// After the pipeline completes, take response and perform a type assertion
|
||||
// to get back to the wrapper struct so you can access the deserialized object.
|
||||
|
||||
return // Return the response & err
|
||||
}
|
||||
|
||||
func newMyPolicyFactory2( /* Desired parameters */ ) pipeline.Factory {
|
||||
return pipeline.FactoryFunc(func(next pipeline.Policy, po *pipeline.PolicyOptions) pipeline.PolicyFunc {
|
||||
return func(ctx context.Context, request pipeline.Request) (response pipeline.Response, err error) {
|
||||
// TODO: Put your policy behavior code here
|
||||
// Your code should NOT mutate the ctx or request parameters
|
||||
// However, you can make a copy of the request and mutate the copy
|
||||
// You can also pass a different Context on.
|
||||
// You can optionally use po (PolicyOptions) in this func.
|
||||
|
||||
// Forward the request to the next node in the pipeline:
|
||||
response, err = next.Do(ctx, request)
|
||||
|
||||
// Process the response here. You can deserialize the body into an object.
|
||||
// If you do this, also define a struct that wraps an http.Response & your
|
||||
// deserialized struct. Have your wrapper struct implement the
|
||||
// pipeline.Response interface and then return your struct (via the interface)
|
||||
// After the pipeline completes, take response and perform a type assertion
|
||||
// to get back to the wrapper struct so you can access the deserialized object.
|
||||
|
||||
return // Return the response & err
|
||||
}
|
||||
})
|
||||
}
|
Загрузка…
Ссылка в новой задаче