github.com/kaleido-io/firefly@v0.0.0-20210622132723-8b4b6aacb971/internal/orchestrator/orchestrator.go (about) 1 // Copyright © 2021 Kaleido, Inc. 2 // 3 // SPDX-License-Identifier: Apache-2.0 4 // 5 // Licensed under the Apache License, Version 2.0 (the "License"); 6 // you may not use this file except in compliance with the License. 7 // You may obtain a copy of the License at 8 // 9 // http://www.apache.org/licenses/LICENSE-2.0 10 // 11 // Unless required by applicable law or agreed to in writing, software 12 // distributed under the License is distributed on an "AS IS" BASIS, 13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 // See the License for the specific language governing permissions and 15 // limitations under the License. 16 17 package orchestrator 18 19 import ( 20 "context" 21 "fmt" 22 23 "github.com/kaleido-io/firefly/internal/batch" 24 "github.com/kaleido-io/firefly/internal/blockchain/bifactory" 25 "github.com/kaleido-io/firefly/internal/broadcast" 26 "github.com/kaleido-io/firefly/internal/config" 27 "github.com/kaleido-io/firefly/internal/data" 28 "github.com/kaleido-io/firefly/internal/database/difactory" 29 "github.com/kaleido-io/firefly/internal/dataexchange/dxfactory" 30 "github.com/kaleido-io/firefly/internal/events" 31 "github.com/kaleido-io/firefly/internal/i18n" 32 "github.com/kaleido-io/firefly/internal/identity/iifactory" 33 "github.com/kaleido-io/firefly/internal/log" 34 "github.com/kaleido-io/firefly/internal/networkmap" 35 "github.com/kaleido-io/firefly/internal/privatemessaging" 36 "github.com/kaleido-io/firefly/internal/publicstorage/psfactory" 37 "github.com/kaleido-io/firefly/pkg/blockchain" 38 "github.com/kaleido-io/firefly/pkg/database" 39 "github.com/kaleido-io/firefly/pkg/dataexchange" 40 "github.com/kaleido-io/firefly/pkg/fftypes" 41 "github.com/kaleido-io/firefly/pkg/identity" 42 "github.com/kaleido-io/firefly/pkg/publicstorage" 43 ) 44 45 var ( 46 blockchainConfig = config.NewPluginConfig("blockchain") 47 databaseConfig = config.NewPluginConfig("database") 48 identityConfig = config.NewPluginConfig("identity") 49 publicstorageConfig = config.NewPluginConfig("publicstorage") 50 dataexchangeConfig = config.NewPluginConfig("dataexchange") 51 ) 52 53 // Orchestrator is the main interface behind the API, implementing the actions 54 type Orchestrator interface { 55 Init(ctx context.Context) error 56 Start() error 57 WaitStop() // The close itself is performed by canceling the context 58 Broadcast() broadcast.Manager 59 PrivateMessaging() privatemessaging.Manager 60 Events() events.EventManager 61 NetworkMap() networkmap.Manager 62 Data() data.Manager 63 64 // Subscription management 65 GetSubscriptions(ctx context.Context, ns string, filter database.AndFilter) ([]*fftypes.Subscription, error) 66 GetSubscriptionByID(ctx context.Context, ns, id string) (*fftypes.Subscription, error) 67 CreateSubscription(ctx context.Context, ns string, subDef *fftypes.Subscription) (*fftypes.Subscription, error) 68 DeleteSubscription(ctx context.Context, ns, id string) error 69 70 // Data Query 71 GetNamespace(ctx context.Context, ns string) (*fftypes.Namespace, error) 72 GetNamespaces(ctx context.Context, filter database.AndFilter) ([]*fftypes.Namespace, error) 73 GetTransactionByID(ctx context.Context, ns, id string) (*fftypes.Transaction, error) 74 GetTransactionOperations(ctx context.Context, ns, id string) ([]*fftypes.Operation, error) 75 GetTransactions(ctx context.Context, ns string, filter database.AndFilter) ([]*fftypes.Transaction, error) 76 GetMessageByID(ctx context.Context, ns, id string, withValues bool) (*fftypes.MessageInput, error) 77 GetMessages(ctx context.Context, ns string, filter database.AndFilter) ([]*fftypes.Message, error) 78 GetMessageTransaction(ctx context.Context, ns, id string) (*fftypes.Transaction, error) 79 GetMessageOperations(ctx context.Context, ns, id string) ([]*fftypes.Operation, error) 80 GetMessageEvents(ctx context.Context, ns, id string, filter database.AndFilter) ([]*fftypes.Event, error) 81 GetMessageData(ctx context.Context, ns, id string) ([]*fftypes.Data, error) 82 GetMessagesForData(ctx context.Context, ns, dataID string, filter database.AndFilter) ([]*fftypes.Message, error) 83 GetBatchByID(ctx context.Context, ns, id string) (*fftypes.Batch, error) 84 GetBatches(ctx context.Context, ns string, filter database.AndFilter) ([]*fftypes.Batch, error) 85 GetDataByID(ctx context.Context, ns, id string) (*fftypes.Data, error) 86 GetData(ctx context.Context, ns string, filter database.AndFilter) ([]*fftypes.Data, error) 87 GetDatatypeByID(ctx context.Context, ns, id string) (*fftypes.Datatype, error) 88 GetDatatypes(ctx context.Context, ns string, filter database.AndFilter) ([]*fftypes.Datatype, error) 89 GetOperationByID(ctx context.Context, ns, id string) (*fftypes.Operation, error) 90 GetOperations(ctx context.Context, ns string, filter database.AndFilter) ([]*fftypes.Operation, error) 91 GetEventByID(ctx context.Context, ns, id string) (*fftypes.Event, error) 92 GetEvents(ctx context.Context, ns string, filter database.AndFilter) ([]*fftypes.Event, error) 93 } 94 95 type orchestrator struct { 96 ctx context.Context 97 started bool 98 database database.Plugin 99 blockchain blockchain.Plugin 100 identity identity.Plugin 101 publicstorage publicstorage.Plugin 102 dataexchange dataexchange.Plugin 103 events events.EventManager 104 networkmap networkmap.Manager 105 batch batch.Manager 106 broadcast broadcast.Manager 107 messaging privatemessaging.Manager 108 data data.Manager 109 bc boundCallbacks 110 } 111 112 func NewOrchestrator() Orchestrator { 113 or := &orchestrator{} 114 115 // Initialize the config on all the factories 116 bifactory.InitPrefix(blockchainConfig) 117 difactory.InitPrefix(databaseConfig) 118 psfactory.InitPrefix(publicstorageConfig) 119 dxfactory.InitPrefix(dataexchangeConfig) 120 121 return or 122 } 123 124 func (or *orchestrator) Init(ctx context.Context) (err error) { 125 or.ctx = ctx 126 err = or.initPlugins(ctx) 127 if err == nil { 128 err = or.initComponents(ctx) 129 } 130 if err == nil { 131 err = or.initNamespaces(ctx) 132 } 133 // Bind together the blockchain interface callbacks, with the events manager 134 or.bc.bi = or.blockchain 135 or.bc.ei = or.events 136 or.bc.dx = or.dataexchange 137 return err 138 } 139 140 func (or *orchestrator) Start() error { 141 err := or.blockchain.Start() 142 if err == nil { 143 err = or.batch.Start() 144 } 145 if err == nil { 146 err = or.events.Start() 147 } 148 if err == nil { 149 err = or.broadcast.Start() 150 } 151 if err == nil { 152 err = or.messaging.Start() 153 } 154 or.started = true 155 return err 156 } 157 158 func (or *orchestrator) WaitStop() { 159 if !or.started { 160 return 161 } 162 if or.batch != nil { 163 or.batch.WaitStop() 164 or.batch = nil 165 } 166 if or.broadcast != nil { 167 or.broadcast.WaitStop() 168 or.broadcast = nil 169 } 170 or.started = false 171 } 172 173 func (or *orchestrator) Broadcast() broadcast.Manager { 174 return or.broadcast 175 } 176 177 func (or *orchestrator) PrivateMessaging() privatemessaging.Manager { 178 return or.messaging 179 } 180 181 func (or *orchestrator) Events() events.EventManager { 182 return or.events 183 } 184 185 func (or *orchestrator) NetworkMap() networkmap.Manager { 186 return or.networkmap 187 } 188 189 func (or *orchestrator) Data() data.Manager { 190 return or.data 191 } 192 193 func (or *orchestrator) initPlugins(ctx context.Context) (err error) { 194 195 if or.database == nil { 196 diType := config.GetString(config.DatabaseType) 197 if or.database, err = difactory.GetPlugin(ctx, diType); err != nil { 198 return err 199 } 200 } 201 if err = or.database.Init(ctx, databaseConfig.SubPrefix(or.database.Name()), or); err != nil { 202 return err 203 } 204 205 if or.identity == nil { 206 iiType := config.GetString(config.IdentityType) 207 if or.identity, err = iifactory.GetPlugin(ctx, iiType); err != nil { 208 return err 209 } 210 } 211 if err = or.identity.Init(ctx, identityConfig.SubPrefix(or.identity.Name()), or); err != nil { 212 return err 213 } 214 215 if or.blockchain == nil { 216 biType := config.GetString(config.BlockchainType) 217 if or.blockchain, err = bifactory.GetPlugin(ctx, biType); err != nil { 218 return err 219 } 220 } 221 if err = or.blockchain.Init(ctx, blockchainConfig.SubPrefix(or.blockchain.Name()), &or.bc); err != nil { 222 return err 223 } 224 225 if or.publicstorage == nil { 226 psType := config.GetString(config.PublicStorageType) 227 if or.publicstorage, err = psfactory.GetPlugin(ctx, psType); err != nil { 228 return err 229 } 230 } 231 if err = or.publicstorage.Init(ctx, publicstorageConfig.SubPrefix(or.publicstorage.Name()), or); err != nil { 232 return err 233 } 234 235 if or.dataexchange == nil { 236 dxType := config.GetString(config.DataexchangeType) 237 if or.dataexchange, err = dxfactory.GetPlugin(ctx, dxType); err != nil { 238 return err 239 } 240 } 241 return or.dataexchange.Init(ctx, dataexchangeConfig.SubPrefix(or.dataexchange.Name()), &or.bc) 242 } 243 244 func (or *orchestrator) initComponents(ctx context.Context) (err error) { 245 246 if or.data == nil { 247 or.data, err = data.NewDataManager(ctx, or.database, or.dataexchange) 248 if err != nil { 249 return err 250 } 251 } 252 253 if or.batch == nil { 254 or.batch, err = batch.NewBatchManager(ctx, or.database, or.data) 255 if err != nil { 256 return err 257 } 258 } 259 260 if or.broadcast == nil { 261 if or.broadcast, err = broadcast.NewBroadcastManager(ctx, or.database, or.identity, or.data, or.blockchain, or.dataexchange, or.publicstorage, or.batch); err != nil { 262 return err 263 } 264 } 265 266 if or.messaging == nil { 267 if or.messaging, err = privatemessaging.NewPrivateMessaging(ctx, or.database, or.identity, or.dataexchange, or.blockchain, or.batch, or.data); err != nil { 268 return err 269 } 270 } 271 272 if or.events == nil { 273 or.events, err = events.NewEventManager(ctx, or.publicstorage, or.database, or.identity, or.broadcast, or.messaging, or.data) 274 if err != nil { 275 return err 276 } 277 } 278 279 if or.networkmap == nil { 280 or.networkmap, err = networkmap.NewNetworkMap(ctx, or.database, or.broadcast, or.dataexchange, or.identity) 281 if err != nil { 282 return err 283 } 284 } 285 286 return nil 287 } 288 289 func (or *orchestrator) getPrefdefinedNamespaces(ctx context.Context) ([]*fftypes.Namespace, error) { 290 defaultNS := config.GetString(config.NamespacesDefault) 291 predefined := config.GetObjectArray(config.NamespacesPredefined) 292 namespaces := []*fftypes.Namespace{ 293 { 294 Name: fftypes.SystemNamespace, 295 Type: fftypes.NamespaceTypeSystem, 296 Description: i18n.Expand(ctx, i18n.MsgSystemNSDescription), 297 }, 298 } 299 foundDefault := false 300 for i, nsObject := range predefined { 301 name := nsObject.GetString("name") 302 err := fftypes.ValidateFFNameField(ctx, name, fmt.Sprintf("namespaces.predefined[%d].name", i)) 303 if err != nil { 304 return nil, err 305 } 306 foundDefault = foundDefault || name == defaultNS 307 description := nsObject.GetString("description") 308 dup := false 309 for _, existing := range namespaces { 310 if existing.Name == name { 311 log.L(ctx).Warnf("Duplicate predefined namespace (ignored): %s", name) 312 dup = true 313 } 314 } 315 if !dup { 316 namespaces = append(namespaces, &fftypes.Namespace{ 317 Type: fftypes.NamespaceTypeLocal, 318 Name: name, 319 Description: description, 320 }) 321 } 322 } 323 if !foundDefault { 324 return nil, i18n.NewError(ctx, i18n.MsgDefaultNamespaceNotFound, defaultNS) 325 } 326 return namespaces, nil 327 } 328 329 func (or *orchestrator) initNamespaces(ctx context.Context) error { 330 predefined, err := or.getPrefdefinedNamespaces(ctx) 331 if err != nil { 332 return err 333 } 334 for _, newNS := range predefined { 335 ns, err := or.database.GetNamespace(ctx, newNS.Name) 336 if err != nil { 337 return err 338 } 339 var updated bool 340 if ns == nil { 341 updated = true 342 newNS.ID = fftypes.NewUUID() 343 newNS.Created = fftypes.Now() 344 } else { 345 // Only update if the description has changed, and the one in our DB is locally defined 346 updated = ns.Description != newNS.Description && ns.Type == fftypes.NamespaceTypeLocal 347 } 348 if updated { 349 if err := or.database.UpsertNamespace(ctx, newNS, true); err != nil { 350 return err 351 } 352 } 353 } 354 return nil 355 }