// newHost returns an initialized Host, taking a set of dependencies as input. // By making the dependencies an argument of the 'new' call, the host can be // mocked such that the dependencies can return unexpected errors or unique // behaviors during testing, enabling easier testing of the failure modes of // the Host. func newHost(dependencies dependencies, cs modules.ConsensusSet, tpool modules.TransactionPool, wallet modules.Wallet, listenerAddress string, persistDir string) (*Host, error) { // Check that all the dependencies were provided. if cs == nil { return nil, errNilCS } if tpool == nil { return nil, errNilTpool } if wallet == nil { return nil, errNilWallet } // Create the host object. h := &Host{ cs: cs, tpool: tpool, wallet: wallet, dependencies: dependencies, lockedStorageObligations: make(map[types.FileContractID]*siasync.TryMutex), persistDir: persistDir, } // Call stop in the event of a partial startup. var err error defer func() { if err != nil { err = composeErrors(h.tg.Stop(), err) } }() // Create the perist directory if it does not yet exist. err = dependencies.mkdirAll(h.persistDir, 0700) if err != nil { return nil, err } // Initialize the logger, and set up the stop call that will close the // logger. h.log, err = dependencies.newLogger(filepath.Join(h.persistDir, logFile)) if err != nil { return nil, err } h.tg.AfterStop(func() { err = h.log.Close() if err != nil { // State of the logger is uncertain, a Println will have to // suffice. fmt.Println("Error when closing the logger:", err) } }) // Add the storage manager to the host, and set up the stop call that will // close the storage manager. h.StorageManager, err = storagemanager.New(filepath.Join(persistDir, "storagemanager")) if err != nil { h.log.Println("Could not open the storage manager:", err) return nil, err } h.tg.AfterStop(func() { err = h.StorageManager.Close() if err != nil { h.log.Println("Could not close storage manager:", err) } }) // After opening the database, it must be initialized. Most commonly, // nothing happens. But for new databases, a set of buckets must be // created. Initialization is also a good time to run sanity checks. err = h.initDB() if err != nil { h.log.Println("Could not initalize database:", err) return nil, err } // Load the prior persistence structures, and configure the host to save // before shutting down. err = h.load() if err != nil { return nil, err } h.tg.AfterStop(func() { err = h.saveSync() if err != nil { h.log.Println("Could not save host upon shutdown:", err) } }) // Initialize the networking. err = h.initNetworking(listenerAddress) if err != nil { h.log.Println("Could not initialize host networking:", err) return nil, err } return h, nil }
// newHost returns an initialized Host, taking a set of dependencies as input. // By making the dependencies an argument of the 'new' call, the host can be // mocked such that the dependencies can return unexpected errors or unique // behaviors during testing, enabling easier testing of the failure modes of // the Host. func newHost(dependencies dependencies, cs modules.ConsensusSet, tpool modules.TransactionPool, wallet modules.Wallet, listenerAddress string, persistDir string) (*Host, error) { // Check that all the dependencies were provided. if cs == nil { return nil, errNilCS } if tpool == nil { return nil, errNilTpool } if wallet == nil { return nil, errNilWallet } // Create the host object. h := &Host{ cs: cs, tpool: tpool, wallet: wallet, dependencies: dependencies, lockedStorageObligations: make(map[types.FileContractID]struct{}), persistDir: persistDir, } // Call stop in the event of a partial startup. var err error defer func() { if err != nil { err = composeErrors(h.tg.Stop(), err) } }() // Add the storage manager to the host. h.StorageManager, err = storagemanager.New(filepath.Join(persistDir, "storagemanager")) if err != nil { return nil, err } // Create the perist directory if it does not yet exist. err = dependencies.mkdirAll(h.persistDir, 0700) if err != nil { return nil, err } // Initialize the logger. Logging should be initialized ASAP, because the // rest of the initialization makes use of the logger. h.log, err = dependencies.newLogger(filepath.Join(h.persistDir, logFile)) if err != nil { return nil, err } // Open the database containing the host's storage obligation metadata. h.db, err = dependencies.openDatabase(dbMetadata, filepath.Join(h.persistDir, dbFilename)) if err != nil { // An error will be returned if the database has the wrong version, but // as of writing there was only one version of the database and all // other databases would be incompatible. _ = h.log.Close() return nil, err } // After opening the database, it must be initialized. Most commonly, // nothing happens. But for new databases, a set of buckets must be // created. Initialization is also a good time to run sanity checks. err = h.initDB() if err != nil { _ = h.log.Close() _ = h.db.Close() return nil, err } // Load the prior persistence structures. err = h.load() if err != nil { _ = h.log.Close() _ = h.db.Close() return nil, err } // Get the host established on the network. err = h.initNetworking(listenerAddress) if err != nil { _ = h.log.Close() _ = h.db.Close() return nil, err } return h, nil }