diff --git a/pkg/didcomm/protocol/exchange/exchange.go b/pkg/didcomm/protocol/exchange/exchange.go index bb87dc47f4..77702d7a2c 100644 --- a/pkg/didcomm/protocol/exchange/exchange.go +++ b/pkg/didcomm/protocol/exchange/exchange.go @@ -68,6 +68,11 @@ type Connection struct { DIDDoc *did.Doc `json:"did_doc,omitempty"` } +// provider contains dependencies for the Exchange protocol and is typically created by using aries.Context() +type provider interface { + transport.OutboundTransport +} + // GenerateInviteWithPublicDID generates the DID exchange invitation string with public DID func GenerateInviteWithPublicDID(invite *Invitation) (string, error) { if invite.ID == "" || invite.DID == "" { @@ -86,8 +91,20 @@ func GenerateInviteWithKeyAndEndpoint(invite *Invitation) (string, error) { return encodedExchangeInvitation(invite) } +// Protocol for exchange protocol +type Protocol struct { + transport.OutboundTransport +} + +// New instanstiated new exchange client +// The argument takes a implementation of transport.OutboundTransport (dependencies required for Exchange protocol) and +// this is typically called by using aries.Context() +func New(prov provider) *Protocol { + return &Protocol{prov} +} + // SendExchangeRequest sends exchange request -func SendExchangeRequest(exchangeRequest *Request, destination string, transport transport.OutboundTransport) error { +func (p *Protocol) SendExchangeRequest(exchangeRequest *Request, destination string) error { if exchangeRequest == nil { return errors.New("exchangeRequest cannot be nil") } @@ -95,12 +112,12 @@ func SendExchangeRequest(exchangeRequest *Request, destination string, transport exchangeRequest.Type = connectionRequest // ignore response data as it is not used in this communication mode as defined in the spec - _, err := marshalAndSend(exchangeRequest, "Error Marshalling Exchange Request", destination, transport) + _, err := p.marshalAndSend(exchangeRequest, "Error Marshalling Exchange Request", destination) return err } // SendExchangeResponse sends exchange response -func SendExchangeResponse(exchangeResponse *Response, destination string, transport transport.OutboundTransport) error { +func (p *Protocol) SendExchangeResponse(exchangeResponse *Response, destination string) error { if exchangeResponse == nil { return errors.New("exchangeResponse cannot be nil") } @@ -108,7 +125,7 @@ func SendExchangeResponse(exchangeResponse *Response, destination string, transp exchangeResponse.Type = connectionResponse // ignore response data as it is not used in this communication mode as defined in the spec - _, err := marshalAndSend(exchangeResponse, "Error Marshalling Exchange Response", destination, transport) + _, err := p.marshalAndSend(exchangeResponse, "Error Marshalling Exchange Response", destination) return err } @@ -123,10 +140,10 @@ func encodedExchangeInvitation(inviteMessage *Invitation) (string, error) { return base64.URLEncoding.EncodeToString(invitationJSON), nil } -func marshalAndSend(data interface{}, errorMsg, destination string, transport transport.OutboundTransport) (string, error) { +func (p *Protocol) marshalAndSend(data interface{}, errorMsg, destination string) (string, error) { jsonString, err := json.Marshal(data) if err != nil { return "", errors.Errorf("%s : %w", errorMsg, err) } - return transport.Send(string(jsonString), destination) + return p.Send(string(jsonString), destination) } diff --git a/pkg/didcomm/protocol/exchange/exchange_test.go b/pkg/didcomm/protocol/exchange/exchange_test.go index 6fb1b563c0..a4c85619c1 100644 --- a/pkg/didcomm/protocol/exchange/exchange_test.go +++ b/pkg/didcomm/protocol/exchange/exchange_test.go @@ -83,19 +83,19 @@ func TestGenerateInviteWithKeyAndEndpoint(t *testing.T) { } func TestSendRequest(t *testing.T) { - oTr := mocktransport.NewOutboundTransport(successResponse) + prov := New(mocktransport.NewOutboundTransport(successResponse)) req := &Request{ ID: "5678876542345", Label: "Bob", } - require.NoError(t, SendExchangeRequest(req, destinationURL, oTr)) - require.Error(t, SendExchangeRequest(nil, destinationURL, oTr)) + require.NoError(t, prov.SendExchangeRequest(req, destinationURL)) + require.Error(t, prov.SendExchangeRequest(nil, destinationURL)) } func TestSendResponse(t *testing.T) { - oTr := mocktransport.NewOutboundTransport(successResponse) + prov := New(mocktransport.NewOutboundTransport(successResponse)) resp := &Response{ ID: "12345678900987654321", @@ -104,6 +104,6 @@ func TestSendResponse(t *testing.T) { }, } - require.NoError(t, SendExchangeResponse(resp, destinationURL, oTr)) - require.Error(t, SendExchangeResponse(nil, destinationURL, oTr)) + require.NoError(t, prov.SendExchangeResponse(resp, destinationURL)) + require.Error(t, prov.SendExchangeResponse(nil, destinationURL)) } diff --git a/pkg/framework/aries/api/factory.go b/pkg/framework/aries/api/factory.go new file mode 100644 index 0000000000..d28961ec9f --- /dev/null +++ b/pkg/framework/aries/api/factory.go @@ -0,0 +1,16 @@ +/* +Copyright SecureKey Technologies Inc. All Rights Reserved. + +SPDX-License-Identifier: Apache-2.0 +*/ + +package api + +import ( + "github.com/hyperledger/aries-framework-go/pkg/didcomm/transport" +) + +// TransportProviderFactory allows overriding of aries protocol providers +type TransportProviderFactory interface { + CreateOutboundTransport() transport.OutboundTransport +} diff --git a/pkg/framework/aries/default.go b/pkg/framework/aries/default.go new file mode 100644 index 0000000000..bdb71fe34f --- /dev/null +++ b/pkg/framework/aries/default.go @@ -0,0 +1,33 @@ +/* +Copyright SecureKey Technologies Inc. All Rights Reserved. + +SPDX-License-Identifier: Apache-2.0 +*/ + +package aries + +import ( + "github.com/hyperledger/aries-framework-go/pkg/framework/aries/api" + "github.com/hyperledger/aries-framework-go/pkg/framework/aries/factory/transport" +) + +// defFramework provides default framework configs +type defFramework struct{} + +// transportProviderFactory provides default Outbound Transport provider factory +func (d defFramework) transportProviderFactory() api.TransportProviderFactory { + return transport.NewProviderFactory() +} + +// defFrameworkOpts provides default framework options +func defFrameworkOpts() []Option { + // get the default framework configs + def := defFramework{} + + var opts []Option + // protocol provider factory + opt := WithTransportProviderFactory(def.transportProviderFactory()) + opts = append(opts, opt) + + return opts +} diff --git a/pkg/framework/aries/factory/transport/transport_factory.go b/pkg/framework/aries/factory/transport/transport_factory.go new file mode 100644 index 0000000000..db2356512a --- /dev/null +++ b/pkg/framework/aries/factory/transport/transport_factory.go @@ -0,0 +1,27 @@ +/* +Copyright SecureKey Technologies Inc. All Rights Reserved. + +SPDX-License-Identifier: Apache-2.0 +*/ + +package transport + +import ( + "github.com/hyperledger/aries-framework-go/pkg/didcomm/transport" +) + +// ProviderFactory represents the default transport provider factory. +type ProviderFactory struct { +} + +// NewProviderFactory returns the default transport provider factory. +func NewProviderFactory() *ProviderFactory { + f := ProviderFactory{} + return &f +} + +// CreateOutboundTransport returns a new default implementation of outbound transport provider +func (f *ProviderFactory) CreateOutboundTransport() transport.OutboundTransport { + // TODO - https://github.com/hyperledger/aries-framework-go/issues/83 + return nil +} diff --git a/pkg/framework/aries/factory/transport/transport_factory_test.go b/pkg/framework/aries/factory/transport/transport_factory_test.go new file mode 100644 index 0000000000..ca9fc38548 --- /dev/null +++ b/pkg/framework/aries/factory/transport/transport_factory_test.go @@ -0,0 +1,18 @@ +/* +Copyright SecureKey Technologies Inc. All Rights Reserved. + +SPDX-License-Identifier: Apache-2.0 +*/ + +package transport + +import ( + "testing" + + "github.com/stretchr/testify/require" +) + +func TestNewProviderFactory(t *testing.T) { + f := NewProviderFactory() + require.Empty(t, f.CreateOutboundTransport()) +} diff --git a/pkg/framework/aries/framework.go b/pkg/framework/aries/framework.go new file mode 100644 index 0000000000..92f4af74b7 --- /dev/null +++ b/pkg/framework/aries/framework.go @@ -0,0 +1,52 @@ +/* +Copyright SecureKey Technologies Inc. All Rights Reserved. + +SPDX-License-Identifier: Apache-2.0 +*/ + +package aries + +import ( + "github.com/hyperledger/aries-framework-go/pkg/framework/aries/api" + "github.com/hyperledger/aries-framework-go/pkg/framework/context" + errors "golang.org/x/xerrors" +) + +// Aries provides access to clients being managed by the framework. +type Aries struct { + transport api.TransportProviderFactory +} + +// Option configures the framework. +type Option func(opts *Aries) error + +// New initializes the Aries framework based on the set of options provided. +func New(opts ...Option) (*Aries, error) { + // get the default framework options + defOpts := defFrameworkOpts() + + frameworkOpts := &Aries{} + + // generate framework configs from options + for _, option := range append(defOpts, opts...) { + err := option(frameworkOpts) + if err != nil { + return nil, errors.Errorf("Error in option passed to New: %w", err) + } + } + + return frameworkOpts, nil +} + +// WithTransportProviderFactory injects a protocol provider factory interface to Aries +func WithTransportProviderFactory(ot api.TransportProviderFactory) Option { + return func(opts *Aries) error { + opts.transport = ot + return nil + } +} + +// Context provides handle to framework context +func (a *Aries) Context() (*context.Provider, error) { + return context.New(context.WithOutboundTransport(a.transport.CreateOutboundTransport())) +} diff --git a/pkg/framework/aries/framework_test.go b/pkg/framework/aries/framework_test.go new file mode 100644 index 0000000000..8aafeca3c6 --- /dev/null +++ b/pkg/framework/aries/framework_test.go @@ -0,0 +1,52 @@ +/* +Copyright SecureKey Technologies Inc. All Rights Reserved. + +SPDX-License-Identifier: Apache-2.0 +*/ + +package aries + +import ( + "testing" + + "github.com/hyperledger/aries-framework-go/pkg/didcomm/transport" + + "github.com/hyperledger/aries-framework-go/pkg/didcomm/protocol/exchange" + mocktransport "github.com/hyperledger/aries-framework-go/pkg/internal/didcomm/transport/mock" + "github.com/stretchr/testify/require" + errors "golang.org/x/xerrors" +) + +func TestFramework(t *testing.T) { + // framework new - error + _, err := New(func(opts *Aries) error { + return errors.New("error creating the framework option") + }) + require.Error(t, err) + + // framework new - success + aries, err := New(WithTransportProviderFactory(&mockTransportProviderFactory{})) + require.NoError(t, err) + + // context + ctx, err := aries.Context() + require.NoError(t, err) + + // exchange client + exClient := exchange.New(ctx.OutboundTransport()) + require.NoError(t, err) + + req := &exchange.Request{ + ID: "5678876542345", + Label: "Bob", + } + require.NoError(t, exClient.SendExchangeRequest(req, "http://example/didexchange")) + require.Error(t, exClient.SendExchangeRequest(req, "")) +} + +type mockTransportProviderFactory struct { +} + +func (f *mockTransportProviderFactory) CreateOutboundTransport() transport.OutboundTransport { + return mocktransport.NewOutboundTransport("success") +} diff --git a/pkg/framework/context/context.go b/pkg/framework/context/context.go new file mode 100644 index 0000000000..a84ca18ce6 --- /dev/null +++ b/pkg/framework/context/context.go @@ -0,0 +1,45 @@ +/* +Copyright SecureKey Technologies Inc. All Rights Reserved. + +SPDX-License-Identifier: Apache-2.0 +*/ + +package context + +import ( + "github.com/hyperledger/aries-framework-go/pkg/didcomm/transport" + errors "golang.org/x/xerrors" +) + +// Provider supplies the framework configuration to client objects. +type Provider struct { + outboundTransport transport.OutboundTransport +} + +// New instantiated new context provider +func New(opts ...ProviderOption) (*Provider, error) { + ctxProvider := Provider{} + for _, opt := range opts { + err := opt(&ctxProvider) + if err != nil { + return nil, errors.Errorf("Error in option passed to New: %w", err) + } + } + return &ctxProvider, nil +} + +// OutboundTransport returns the outbound transport provider +func (p *Provider) OutboundTransport() transport.OutboundTransport { + return p.outboundTransport +} + +// ProviderOption configures the framework. +type ProviderOption func(opts *Provider) error + +// WithOutboundTransport injects transport provider into the framework +func WithOutboundTransport(ot transport.OutboundTransport) ProviderOption { + return func(opts *Provider) error { + opts.outboundTransport = ot + return nil + } +} diff --git a/pkg/framework/context/context_test.go b/pkg/framework/context/context_test.go new file mode 100644 index 0000000000..59705d79b1 --- /dev/null +++ b/pkg/framework/context/context_test.go @@ -0,0 +1,30 @@ +/* +Copyright SecureKey Technologies Inc. All Rights Reserved. + +SPDX-License-Identifier: Apache-2.0 +*/ + +package context + +import ( + "testing" + + mocktransport "github.com/hyperledger/aries-framework-go/pkg/internal/didcomm/transport/mock" + "github.com/stretchr/testify/require" + errors "golang.org/x/xerrors" +) + +func TestNewProvider(t *testing.T) { + prov, err := New() + require.NoError(t, err) + require.Empty(t, prov.OutboundTransport()) + + prov, err = New(WithOutboundTransport(mocktransport.NewOutboundTransport("success"))) + require.NoError(t, err) + require.NotEmpty(t, prov.OutboundTransport()) + + _, err = New(func(opts *Provider) error { + return errors.New("error creating the framework option") + }) + require.Error(t, err) +}