github.com/ebakus/go-ebakus@v1.0.5-0.20200520105415-dbccef9ec421/node/service.go (about) 1 // Copyright 2019 The ebakus/go-ebakus Authors 2 // This file is part of the ebakus/go-ebakus library. 3 // 4 // The ebakus/go-ebakus library is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU Lesser General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // The ebakus/go-ebakus library is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU Lesser General Public License for more details. 13 // 14 // You should have received a copy of the GNU Lesser General Public License 15 // along with the ebakus/go-ebakus library. If not, see <http://www.gnu.org/licenses/>. 16 17 package node 18 19 import ( 20 "path/filepath" 21 "reflect" 22 23 "github.com/ebakus/go-ebakus/accounts" 24 "github.com/ebakus/go-ebakus/core/rawdb" 25 "github.com/ebakus/go-ebakus/ethdb" 26 "github.com/ebakus/go-ebakus/event" 27 "github.com/ebakus/go-ebakus/log" 28 "github.com/ebakus/go-ebakus/p2p" 29 "github.com/ebakus/go-ebakus/rpc" 30 "github.com/ebakus/ebakusdb" 31 ) 32 33 // ServiceContext is a collection of service independent options inherited from 34 // the protocol stack, that is passed to all constructors to be optionally used; 35 // as well as utility methods to operate on the service environment. 36 type ServiceContext struct { 37 config *Config 38 services map[reflect.Type]Service // Index of the already constructed services 39 EventMux *event.TypeMux // Event multiplexer used for decoupled notifications 40 AccountManager *accounts.Manager // Account manager created by the node. 41 } 42 43 // OpenDatabase opens an existing database with the given name (or creates one 44 // if no previous can be found) from within the node's data directory. If the 45 // node is an ephemeral one, a memory database is returned. 46 func (ctx *ServiceContext) OpenDatabase(name string, cache int, handles int, namespace string) (ethdb.Database, error) { 47 if ctx.config.DataDir == "" { 48 return rawdb.NewMemoryDatabase(), nil 49 } 50 return rawdb.NewLevelDBDatabase(ctx.config.ResolvePath(name), cache, handles, namespace) 51 } 52 53 // OpenDatabaseWithFreezer opens an existing database with the given name (or 54 // creates one if no previous can be found) from within the node's data directory, 55 // also attaching a chain freezer to it that moves ancient chain data from the 56 // database to immutable append-only files. If the node is an ephemeral one, a 57 // memory database is returned. 58 func (ctx *ServiceContext) OpenDatabaseWithFreezer(name string, cache int, handles int, freezer string, namespace string) (ethdb.Database, error) { 59 if ctx.config.DataDir == "" { 60 return rawdb.NewMemoryDatabase(), nil 61 } 62 root := ctx.config.ResolvePath(name) 63 64 switch { 65 case freezer == "": 66 freezer = filepath.Join(root, "ancient") 67 case !filepath.IsAbs(freezer): 68 freezer = ctx.config.ResolvePath(freezer) 69 } 70 return rawdb.NewLevelDBDatabaseWithFreezer(root, cache, handles, freezer, namespace) 71 } 72 73 // OpenEbakusDatabase opens an existing database with the given name (or creates one 74 // if no previous can be found) from within the node's data directory. 75 func (ctx *ServiceContext) OpenEbakusDatabase(name string, cache int, handles int) (*ebakusdb.DB, error) { 76 if ctx.config.DataDir == "" { 77 return nil, nil // TODO: Implement a memory only version for tests 78 } 79 80 db, err := ebakusdb.Open(ctx.config.ResolvePath(name), 0666, nil) 81 if err != nil { 82 return nil, err 83 } 84 85 // Assign custom value encoders to the db 86 db.SetCustomEncoder(GobMarshal, GobUnmarshal) 87 88 log.Info("Ebakus state database initialized", "database", db.GetPath()) 89 90 return db, nil 91 } 92 93 // ResolvePath resolves a user path into the data directory if that was relative 94 // and if the user actually uses persistent storage. It will return an empty string 95 // for emphemeral storage and the user's own input for absolute paths. 96 func (ctx *ServiceContext) ResolvePath(path string) string { 97 return ctx.config.ResolvePath(path) 98 } 99 100 // Service retrieves a currently running service registered of a specific type. 101 func (ctx *ServiceContext) Service(service interface{}) error { 102 element := reflect.ValueOf(service).Elem() 103 if running, ok := ctx.services[element.Type()]; ok { 104 element.Set(reflect.ValueOf(running)) 105 return nil 106 } 107 return ErrServiceUnknown 108 } 109 110 // ExtRPCEnabled returns the indicator whether node enables the external 111 // RPC(http, ws or graphql). 112 func (ctx *ServiceContext) ExtRPCEnabled() bool { 113 return ctx.config.ExtRPCEnabled() 114 } 115 116 // ServiceConstructor is the function signature of the constructors needed to be 117 // registered for service instantiation. 118 type ServiceConstructor func(ctx *ServiceContext) (Service, error) 119 120 // Service is an individual protocol that can be registered into a node. 121 // 122 // Notes: 123 // 124 // • Service life-cycle management is delegated to the node. The service is allowed to 125 // initialize itself upon creation, but no goroutines should be spun up outside of the 126 // Start method. 127 // 128 // • Restart logic is not required as the node will create a fresh instance 129 // every time a service is started. 130 type Service interface { 131 // Protocols retrieves the P2P protocols the service wishes to start. 132 Protocols() []p2p.Protocol 133 134 // APIs retrieves the list of RPC descriptors the service provides 135 APIs() []rpc.API 136 137 // Start is called after all services have been constructed and the networking 138 // layer was also initialized to spawn any goroutines required by the service. 139 Start(server *p2p.Server) error 140 141 // Stop terminates all goroutines belonging to the service, blocking until they 142 // are all terminated. 143 Stop() error 144 }