|
| 1 | +# SDK |
| 2 | + |
| 3 | +## Overview |
| 4 | + |
| 5 | +An SDK is a set of services that an FSC node can use to implement its logic. An SDK is installed in the `main.go` file of a node in the following manner: |
| 6 | +```go |
| 7 | +func main() { |
| 8 | + n := fscnode.NewEmpty("") |
| 9 | + n.InstallSDK(iou.NewSDK(n)) |
| 10 | + |
| 11 | + n.Execute(func() error { |
| 12 | + registry := viewregistry.GetRegistry(n) |
| 13 | + if err := registry.RegisterFactory("init", &views.ApproverInitViewFactory{}); err != nil { |
| 14 | + return err |
| 15 | + } |
| 16 | + registry.RegisterResponder(&views.ApproverView{}, &views.CreateIOUView{}) |
| 17 | + registry.RegisterResponder(&views.ApproverView{}, &views.UpdateIOUView{}) |
| 18 | + |
| 19 | + return nil |
| 20 | + }) |
| 21 | +} |
| 22 | +``` |
| 23 | + |
| 24 | +In this example the services included in the `iou.SDK` can be used by |
| 25 | +* the views of the node, i.e. `ApproverView`, `ApproverInitViewFactory` |
| 26 | +* other services |
| 27 | + |
| 28 | +The services contained in an SDK depend on other services defined in other SDKs. Hence, each SDK is built on top of other SDKs. As a result, installing and starting an SDK will install and instantiate the whole chain up to the root, and as a result we do not need to install multiple SDKs. |
| 29 | + |
| 30 | +## Base SDKs |
| 31 | + |
| 32 | +This project provides the following SDKs as a base: |
| 33 | +* **View SDK:** |
| 34 | + * Config service |
| 35 | + * View registry |
| 36 | + * Communication with other FSC nodes |
| 37 | + * Identity resolution |
| 38 | + * Signers and verifiers |
| 39 | + * KVS |
| 40 | + * Logging |
| 41 | + * Metrics |
| 42 | + * Event publisher/subscriber |
| 43 | +* **Fabric SDK:** Built on top of ViewSDK, it adds following functionality: |
| 44 | + * Config service for Fabric |
| 45 | + * Network provider for connection to the Fabric network |
| 46 | + * Finality handlers |
| 47 | + * Identity providers |
| 48 | + * Endorser transaction handling |
| 49 | + * Vault |
| 50 | +* **Orion SDK:** Built on top of ViewSDK, it adds following functionality: |
| 51 | + * Config service for Orion |
| 52 | + * Network provider for connection to the Orion network |
| 53 | + * Finality handlers |
| 54 | + * Identity providers |
| 55 | + |
| 56 | +## Developing new SDKs |
| 57 | + |
| 58 | +If new functionality is needed for the purposes of an application, this can be added with the definition of a new SDK that builds on top of the SDK(s) that contain the services we depend on. |
| 59 | + |
| 60 | +Hence, by defining a new SDK, we achieve following goals: |
| 61 | +* Leverage services provided by other SDKs by combining them and using them as a base |
| 62 | +* Define new services that will be used by our views |
| 63 | +* Overwrite existing services and modify the behavior of the base SDKs |
| 64 | +* Register further drivers, handlers, etc. |
| 65 | +* Registering new or existing services to the Service Provider to make them available to the views |
| 66 | + |
| 67 | +A general structure for a new SDK would be as follows: |
| 68 | +```go |
| 69 | +package myapp |
| 70 | + |
| 71 | +import ( |
| 72 | + "errors" |
| 73 | + |
| 74 | + "github.com/hyperledger-labs/fabric-smart-client/pkg/node" |
| 75 | + "github.com/hyperledger-labs/fabric-smart-client/platform/common/sdk/dig" |
| 76 | + digutils "github.com/hyperledger-labs/fabric-smart-client/platform/common/utils/dig" |
| 77 | + "github.com/hyperledger-labs/fabric-smart-client/platform/fabric" |
| 78 | + fabricsdk "github.com/hyperledger-labs/fabric-smart-client/platform/fabric/sdk/dig" |
| 79 | + "github.com/hyperledger-labs/fabric-smart-client/platform/fabric/services/weaver" |
| 80 | +) |
| 81 | + |
| 82 | +type SDK struct { |
| 83 | + dig.SDK |
| 84 | +} |
| 85 | + |
| 86 | +func NewSDK(registry node.Registry) *SDK { |
| 87 | + return &SDK{SDK: fabricsdk.NewSDK(registry)} |
| 88 | +} |
| 89 | + |
| 90 | +func (p *SDK) Install() error { |
| 91 | + // Optional: Install new services relevant to myapp |
| 92 | + if err := errors.Join( |
| 93 | + p.Container().Provide(newService1), |
| 94 | + p.Container().Provide(newService2), |
| 95 | + ); err != nil { |
| 96 | + return err |
| 97 | + } |
| 98 | + // Install services from parent SDKs |
| 99 | + if err := p.SDK.Install(); err != nil { |
| 100 | + return err |
| 101 | + } |
| 102 | + |
| 103 | + // Optional: Register new or existing services (from parent SDKs that haven't been registered), so they can be used by the views. |
| 104 | + return errors.Join( |
| 105 | + digutils.Register[NewService1](p.Container()), |
| 106 | + digutils.Register[ExistingService1](p.Container()), |
| 107 | + ) |
| 108 | +} |
| 109 | + |
| 110 | +// Optional: Adapt Start logic |
| 111 | + |
| 112 | +func (p *SDK) Start(ctx context.Context) error { |
| 113 | + //Call Start of parent SDKs |
| 114 | + if err := p.SDK.Start(ctx); err != nil { |
| 115 | + return err |
| 116 | + } |
| 117 | + |
| 118 | + // Implement optional further logic, such as registering handlers, drivers, calling init views. |
| 119 | +} |
| 120 | + |
| 121 | +// Optional: Adapt PostStart logic |
| 122 | + |
| 123 | +func (p *SDK) PostStart(ctx context.Context) error { |
| 124 | + //Call PostStart of parent SDKs |
| 125 | + if err := p.SDK.PostStart(ctx); err != nil { |
| 126 | + return err |
| 127 | + } |
| 128 | + |
| 129 | + // Implement optional further logic, such as starting services or listeners. |
| 130 | +} |
| 131 | + |
| 132 | + |
| 133 | +func newService1() NewService1 {...} |
| 134 | +func newService2() NewService2 {...} |
| 135 | +``` |
| 136 | + |
| 137 | +Now the new services can be used from within the views: |
| 138 | +```go |
| 139 | +func (a *MyNewView) Call(context view.Context) (interface{}, error) { |
| 140 | + service1, err := GetService1(context) |
| 141 | + // Further logic |
| 142 | +} |
| 143 | + |
| 144 | +func GetService1(ctx view.ServiceProvider) (myapp.Service1, error) { |
| 145 | + s, err := ctx.GetService(reflect.TypeOf((*myapp.Service1)(nil))) |
| 146 | + if err != nil { |
| 147 | + return nil, err |
| 148 | + } |
| 149 | + return s.(myapp.Service1), nil |
| 150 | +} |
| 151 | +``` |
| 152 | + |
| 153 | +Note that multiple SDKs can also be combined and used as a base: |
| 154 | +```go |
| 155 | +func NewSDK(registry node.Registry) *SDK { |
| 156 | + return &SDK{SDK: fabricsdk.NewFrom(orionsdk.NewFrom(viewsdk.NewSDK(registry)))} |
| 157 | +} |
| 158 | +``` |
| 159 | +The order in which the SDKs is not relevant when it comes to dependency injection, but it may be important for the logic of `Start` and `PostStart`. |
| 160 | + |
| 161 | +For further supported functionality and details on dependency injection, consult the [`dig` documentation](https://github.com/uber-go/dig). |
0 commit comments