1// SPDX-License-Identifier: ISC 2// Copyright (c) 2014-2020 Bitmark Inc. 3// Use of this source code is governed by an ISC 4// license that can be found in the LICENSE file. 5 6package announce 7 8import ( 9 "path" 10 "sync" 11 12 "github.com/bitmark-inc/bitmarkd/announce/broadcast" 13 "github.com/bitmark-inc/bitmarkd/announce/domain" 14 "github.com/bitmark-inc/bitmarkd/announce/parameter" 15 "github.com/bitmark-inc/bitmarkd/announce/receptor" 16 "github.com/bitmark-inc/bitmarkd/announce/rpc" 17 "github.com/bitmark-inc/bitmarkd/background" 18 "github.com/bitmark-inc/bitmarkd/fault" 19 "github.com/bitmark-inc/bitmarkd/messagebus" 20 "github.com/bitmark-inc/logger" 21) 22 23const ( 24 logCategory = "announce" 25) 26 27// file for storing saves peers 28const backupFile = "peers.json" 29 30// globals for background process 31type announcerData struct { 32 sync.RWMutex // to allow locking 33 34 log *logger.L 35 36 // RPC interface 37 rpcs rpc.RPC 38 39 // Receptor interface 40 receptors receptor.Receptor 41 42 backupFile string 43 44 // data for thread 45 brdc background.Process 46 47 domain background.Process 48 49 // for background 50 background *background.T 51 52 // set once during initialise 53 initialised bool 54} 55 56// global data 57var globalData announcerData 58 59// Initialise - set up the announcement system 60// pass a fully qualified domain for root node list 61// or empty string for no root nodes 62func Initialise(domainName, cacheDirectory string, f func(string) ([]string, error)) error { 63 globalData.Lock() 64 defer globalData.Unlock() 65 66 var err error 67 68 // no need to start if already started 69 if globalData.initialised { 70 return fault.AlreadyInitialised 71 } 72 73 globalData.log = logger.New(logCategory) 74 globalData.log.Info("starting…") 75 76 globalData.receptors = receptor.New(globalData.log) 77 globalData.backupFile = path.Join(cacheDirectory, backupFile) 78 79 globalData.log.Info("start restoring backup data…") 80 if err := receptor.Restore(globalData.backupFile, globalData.receptors); err != nil { 81 globalData.log.Errorf("fail to restore backup data: %s", err.Error()) 82 } 83 84 globalData.rpcs = rpc.New() 85 86 globalData.domain, err = domain.New( 87 globalData.log, 88 domainName, 89 globalData.receptors, 90 f, 91 ) 92 if nil != err { 93 return err 94 } 95 96 globalData.brdc = broadcast.New( 97 globalData.log, 98 globalData.receptors, 99 globalData.rpcs, 100 parameter.InitialiseInterval, 101 parameter.PollingInterval, 102 ) 103 104 // all data initialised 105 globalData.initialised = true 106 107 // start background processes 108 globalData.log.Info("start background…") 109 110 processes := background.Processes{ 111 globalData.domain, globalData.brdc, 112 } 113 114 globalData.background = background.Start(processes, messagebus.Bus.Announce.Chan()) 115 116 return nil 117} 118 119// Finalise - stop all background tasks 120func Finalise() error { 121 if !globalData.initialised { 122 return fault.NotInitialised 123 } 124 125 globalData.log.Info("shutting down…") 126 globalData.log.Flush() 127 128 // stop background 129 globalData.background.Stop() 130 131 // release message bus 132 messagebus.Bus.Announce.Release() 133 134 globalData.log.Info("start backing up peer data…") 135 if err := receptor.Backup(globalData.backupFile, globalData.receptors.Connectable()); err != nil { 136 globalData.log.Errorf("fail to backup peer data: %s", err.Error()) 137 } 138 139 // finally... 140 globalData.initialised = false 141 142 globalData.log.Info("finished") 143 globalData.log.Flush() 144 145 return nil 146} 147